mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
f828becdb2
71 changed files with 1871 additions and 609 deletions
|
|
@ -552,7 +552,42 @@ public final class NavigateToChatControllerParams {
|
|||
public let customChatNavigationStack: [EnginePeer.Id]?
|
||||
public let skipAgeVerification: Bool
|
||||
|
||||
public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: Location, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, botAppStart: ChatControllerInitialBotAppStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: ChatControllerActivateInput? = nil, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, useBackAnimation: Bool = false, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, reportReason: NavigateToChatControllerParams.ReportReason? = nil, animated: Bool = true, forceAnimatedScroll: Bool = false, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [ChatNavigationStackItem] = [], changeColors: Bool = false, setupController: @escaping (ChatController) -> Void = { _ in }, pushController: ((ChatController, Bool, @escaping () -> Void) -> Void)? = nil, completion: @escaping (ChatController) -> Void = { _ in }, chatListCompletion: @escaping (ChatListController) -> Void = { _ in }, forceOpenChat: Bool = false, customChatNavigationStack: [EnginePeer.Id]? = nil, skipAgeVerification: Bool = false) {
|
||||
public init(
|
||||
navigationController: NavigationController,
|
||||
chatController: ChatController? = nil,
|
||||
context: AccountContext,
|
||||
chatLocation: Location,
|
||||
chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil),
|
||||
subject: ChatControllerSubject? = nil,
|
||||
botStart: ChatControllerInitialBotStart? = nil,
|
||||
attachBotStart: ChatControllerInitialAttachBotStart? = nil,
|
||||
botAppStart: ChatControllerInitialBotAppStart? = nil,
|
||||
updateTextInputState: ChatTextInputState? = nil,
|
||||
activateInput: ChatControllerActivateInput? = nil,
|
||||
keepStack: NavigateToChatKeepStack = .default,
|
||||
useExisting: Bool = true,
|
||||
useBackAnimation: Bool = false,
|
||||
purposefulAction: (() -> Void)? = nil,
|
||||
scrollToEndIfExists: Bool = false,
|
||||
activateMessageSearch: (ChatSearchDomain, String)? = nil,
|
||||
peekData: ChatPeekTimeout? = nil,
|
||||
peerNearbyData: ChatPeerNearbyData? = nil,
|
||||
reportReason: NavigateToChatControllerParams.ReportReason? = nil,
|
||||
animated: Bool = true,
|
||||
forceAnimatedScroll: Bool = false,
|
||||
options: NavigationAnimationOptions = [],
|
||||
parentGroupId: PeerGroupId? = nil,
|
||||
chatListFilter: Int32? = nil,
|
||||
chatNavigationStack: [ChatNavigationStackItem] = [],
|
||||
changeColors: Bool = false,
|
||||
setupController: @escaping (ChatController) -> Void = { _ in },
|
||||
pushController: ((ChatController, Bool, @escaping () -> Void) -> Void)? = nil,
|
||||
completion: @escaping (ChatController) -> Void = { _ in },
|
||||
chatListCompletion: @escaping (ChatListController) -> Void = { _ in },
|
||||
forceOpenChat: Bool = false,
|
||||
customChatNavigationStack: [EnginePeer.Id]? = nil,
|
||||
skipAgeVerification: Bool = false
|
||||
) {
|
||||
self.navigationController = navigationController
|
||||
self.chatController = chatController
|
||||
self.chatLocationContextHolder = chatLocationContextHolder
|
||||
|
|
|
|||
|
|
@ -800,6 +800,7 @@ public enum ChatControllerSubject: Equatable {
|
|||
case pinnedMessages(id: EngineMessage.Id?)
|
||||
case messageOptions(peerIds: [EnginePeer.Id], ids: [EngineMessage.Id], info: MessageOptionsInfo)
|
||||
case customChatContents(contents: ChatCustomContentsProtocol)
|
||||
case botForumThread(forumId: EnginePeer.Id, threadId: Int64)
|
||||
|
||||
public static func ==(lhs: ChatControllerSubject, rhs: ChatControllerSubject) -> Bool {
|
||||
switch lhs {
|
||||
|
|
@ -833,6 +834,12 @@ public enum ChatControllerSubject: Equatable {
|
|||
} else {
|
||||
return false
|
||||
}
|
||||
case let .botForumThread(forumId, threadId):
|
||||
if case .botForumThread(forumId, threadId) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -587,7 +587,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
|||
}
|
||||
}
|
||||
|
||||
public func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId: Int64, isPinned: Bool?, isClosed: Bool?, chatListController: ViewController?, joined: Bool, canSelect: Bool, customEdit: ((ContextController) -> Void)? = nil, customPinUnpin: ((ContextController) -> Void)? = nil, reorder: (() -> Void)? = nil) -> Signal<[ContextMenuItem], NoError> {
|
||||
public func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId: Int64, isPinned: Bool?, isClosed: Bool?, chatListController: ViewController?, joined: Bool, canSelect: Bool, customEdit: ((ContextController) -> Void)? = nil, customPinUnpin: ((ContextController) -> Void)? = nil, reorder: (() -> Void)? = nil, onDeleted: (() -> Void)? = nil) -> Signal<[ContextMenuItem], NoError> {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with({ $0 })
|
||||
let strings = presentationData.strings
|
||||
|
||||
|
|
@ -914,32 +914,33 @@ public func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, thr
|
|||
})))
|
||||
}
|
||||
if channel.hasPermission(.deleteAllMessages) {
|
||||
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: { [weak chatListController] _, f in
|
||||
f(.default)
|
||||
|
||||
if let chatListController = chatListController as? ChatListControllerImpl {
|
||||
chatListController.deletePeerThread(peerId: peerId, threadId: threadId)
|
||||
} else if let chatListController {
|
||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
items.append(ActionSheetTextItem(title: presentationData.strings.ChatList_DeleteTopicConfirmationText, parseMarkdown: true))
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.ChatList_DeleteTopicConfirmationAction, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
let _ = context.engine.peers.removeForumChannelThread(id: peerId, threadId: threadId).startStandalone(completed: {
|
||||
})
|
||||
}))
|
||||
|
||||
actionSheet.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
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: { [weak chatListController] c, _ in
|
||||
c?.dismiss(completion: {
|
||||
if let chatListController = chatListController as? ChatListControllerImpl {
|
||||
chatListController.deletePeerThread(peerId: peerId, threadId: threadId)
|
||||
} else if let chatListController {
|
||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
items.append(ActionSheetTextItem(title: presentationData.strings.ChatList_DeleteTopicConfirmationText, parseMarkdown: true))
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.ChatList_DeleteTopicConfirmationAction, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
onDeleted?()
|
||||
let _ = context.engine.peers.removeForumChannelThread(id: peerId, threadId: threadId).startStandalone(completed: {
|
||||
})
|
||||
}))
|
||||
|
||||
actionSheet.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])
|
||||
])
|
||||
])
|
||||
chatListController.present(actionSheet, in: .window(.root))
|
||||
}
|
||||
chatListController.present(actionSheet, in: .window(.root))
|
||||
}
|
||||
})
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1027,144 +1027,174 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
}
|
||||
|
||||
self.chatListDisplayNode.mainContainerNode.peerSelected = { [weak self] peer, threadId, animated, activateInput, promoInfo in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
var forumSourcePeer: Signal<EnginePeer?, NoError> = .single(nil)
|
||||
if case let .savedMessagesChats(peerId) = self.location, peerId != self.context.account.peerId {
|
||||
forumSourcePeer = self.context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)
|
||||
)
|
||||
}
|
||||
|
||||
let _ = (combineLatest(queue: .mainQueue(),
|
||||
self.context.account.postbox.combinedView(keys: [.cachedPeerData(peerId: peer.id)])
|
||||
|> take(1),
|
||||
forumSourcePeer
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] combinedView, forumSourcePeer in
|
||||
guard let self, let cachedDataView = combinedView.views[.cachedPeerData(peerId: peer.id)] as? CachedPeerDataView else {
|
||||
return
|
||||
}
|
||||
guard let navigationController = self.navigationController as? NavigationController else {
|
||||
Task { @MainActor [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
var peer = peer
|
||||
var threadId = threadId
|
||||
if let forumSourcePeer {
|
||||
threadId = peer.id.toInt64()
|
||||
peer = forumSourcePeer
|
||||
var subject: ChatControllerSubject?
|
||||
if let threadIdValue = threadId, case let .user(user) = peer {
|
||||
threadId = nil
|
||||
|
||||
if case let .known(linkedForumId) = await self.context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.LinkedBotForumPeerId(id: user.id)
|
||||
).get(), let linkedForumId {
|
||||
subject = .botForumThread(forumId: linkedForumId, threadId: threadIdValue)
|
||||
}
|
||||
} else if case let .user(user) = peer {
|
||||
if case let .known(linkedForumId) = await self.context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.LinkedBotForumPeerId(id: user.id)
|
||||
).get(), let linkedForumId {
|
||||
subject = .botForumThread(forumId: linkedForumId, threadId: EngineMessage.newTopicThreadId)
|
||||
}
|
||||
}
|
||||
|
||||
var scrollToEndIfExists = false
|
||||
if let layout = self.validLayout, case .regular = layout.metrics.widthClass {
|
||||
scrollToEndIfExists = true
|
||||
var forumSourcePeer: Signal<EnginePeer?, NoError> = .single(nil)
|
||||
if case let .savedMessagesChats(peerId) = self.location, peerId != self.context.account.peerId {
|
||||
forumSourcePeer = self.context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)
|
||||
)
|
||||
}
|
||||
|
||||
var openAsInlineForum = true
|
||||
|
||||
if case let .channel(channel) = peer, channel.flags.contains(.isMonoforum) {
|
||||
openAsInlineForum = false
|
||||
} else if case let .channel(channel) = peer, channel.flags.contains(.displayForumAsTabs) {
|
||||
openAsInlineForum = false
|
||||
} else {
|
||||
if let cachedData = cachedDataView.cachedPeerData as? CachedChannelData, case let .known(viewForumAsMessages) = cachedData.viewForumAsMessages, viewForumAsMessages {
|
||||
let _ = (combineLatest(queue: .mainQueue(),
|
||||
self.context.account.postbox.combinedView(keys: [.cachedPeerData(peerId: peer.id)])
|
||||
|> take(1),
|
||||
forumSourcePeer
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] combinedView, forumSourcePeer in
|
||||
guard let self, let cachedDataView = combinedView.views[.cachedPeerData(peerId: peer.id)] as? CachedPeerDataView else {
|
||||
return
|
||||
}
|
||||
guard let navigationController = self.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
|
||||
var peer = peer
|
||||
var threadId = threadId
|
||||
if let forumSourcePeer {
|
||||
threadId = peer.id.toInt64()
|
||||
peer = forumSourcePeer
|
||||
}
|
||||
|
||||
var scrollToEndIfExists = false
|
||||
if let layout = self.validLayout, case .regular = layout.metrics.widthClass {
|
||||
scrollToEndIfExists = true
|
||||
}
|
||||
|
||||
var openAsInlineForum = true
|
||||
|
||||
if case let .channel(channel) = peer, channel.flags.contains(.isMonoforum) {
|
||||
openAsInlineForum = false
|
||||
} else if case let .channel(channel) = peer, channel.flags.contains(.displayForumAsTabs) {
|
||||
openAsInlineForum = false
|
||||
}
|
||||
}
|
||||
|
||||
if openAsInlineForum, case let .channel(channel) = peer, channel.isForum, threadId == nil {
|
||||
self.chatListDisplayNode.clearHighlightAnimated(true)
|
||||
if self.chatListDisplayNode.inlineStackContainerNode?.location == .forum(peerId: channel.id) {
|
||||
self.setInlineChatList(location: nil)
|
||||
} else {
|
||||
self.setInlineChatList(location: .forum(peerId: channel.id))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if case let .channel(channel) = peer, channel.isForumOrMonoForum, let threadId {
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
|
||||
navigationController: navigationController,
|
||||
context: self.context,
|
||||
chatLocation: .replyThread(ChatReplyThreadMessage(
|
||||
peerId: peer.id,
|
||||
threadId: threadId,
|
||||
channelMessageId: nil,
|
||||
isChannelPost: false,
|
||||
isForumPost: true,
|
||||
isMonoforumPost: channel.isMonoForum,
|
||||
maxMessage: nil,
|
||||
maxReadIncomingMessageId: nil,
|
||||
maxReadOutgoingMessageId: nil,
|
||||
unreadCount: 0,
|
||||
initialFilledHoles: IndexSet(),
|
||||
initialAnchor: .automatic,
|
||||
isNotAvailable: false
|
||||
)),
|
||||
subject: nil,
|
||||
keepStack: .always
|
||||
))
|
||||
|
||||
self.chatListDisplayNode.clearHighlightAnimated(true)
|
||||
} else {
|
||||
var navigationAnimationOptions: NavigationAnimationOptions = []
|
||||
var groupId: EngineChatList.Group = .root
|
||||
if case let .chatList(groupIdValue) = self.location {
|
||||
groupId = groupIdValue
|
||||
if case .root = groupIdValue {
|
||||
navigationAnimationOptions = .removeOnMasterDetails
|
||||
if let cachedData = cachedDataView.cachedPeerData as? CachedChannelData, case let .known(viewForumAsMessages) = cachedData.viewForumAsMessages, viewForumAsMessages {
|
||||
openAsInlineForum = false
|
||||
}
|
||||
}
|
||||
|
||||
let chatLocation: NavigateToChatControllerParams.Location
|
||||
chatLocation = .peer(peer)
|
||||
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: chatLocation, activateInput: (activateInput && !peer.isDeleted) ? .text : nil, scrollToEndIfExists: scrollToEndIfExists, animated: !scrollToEndIfExists, options: navigationAnimationOptions, parentGroupId: groupId._asGroup(), chatListFilter: self.chatListDisplayNode.mainContainerNode.currentItemNode.chatListFilter?.id, completion: { [weak self] controller in
|
||||
guard let self else {
|
||||
return
|
||||
if openAsInlineForum, case let .channel(channel) = peer, channel.isForum, threadId == nil {
|
||||
self.chatListDisplayNode.clearHighlightAnimated(true)
|
||||
if self.chatListDisplayNode.inlineStackContainerNode?.location == .forum(peerId: channel.id) {
|
||||
self.setInlineChatList(location: nil)
|
||||
} else {
|
||||
self.setInlineChatList(location: .forum(peerId: channel.id))
|
||||
}
|
||||
self.chatListDisplayNode.mainContainerNode.currentItemNode.clearHighlightAnimated(true)
|
||||
return
|
||||
}
|
||||
|
||||
if case let .channel(channel) = peer, channel.isForumOrMonoForum, let threadId {
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
|
||||
navigationController: navigationController,
|
||||
context: self.context,
|
||||
chatLocation: .replyThread(ChatReplyThreadMessage(
|
||||
peerId: peer.id,
|
||||
threadId: threadId,
|
||||
channelMessageId: nil,
|
||||
isChannelPost: false,
|
||||
isForumPost: true,
|
||||
isMonoforumPost: channel.isMonoForum,
|
||||
maxMessage: nil,
|
||||
maxReadIncomingMessageId: nil,
|
||||
maxReadOutgoingMessageId: nil,
|
||||
unreadCount: 0,
|
||||
initialFilledHoles: IndexSet(),
|
||||
initialAnchor: .automatic,
|
||||
isNotAvailable: false
|
||||
)),
|
||||
subject: subject,
|
||||
keepStack: .always
|
||||
))
|
||||
|
||||
if let promoInfo = promoInfo {
|
||||
switch promoInfo {
|
||||
case .proxy:
|
||||
let _ = (ApplicationSpecificNotice.getProxyAdsAcknowledgment(accountManager: self.context.sharedContext.accountManager)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] value in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if !value {
|
||||
controller.displayPromoAnnouncement(text: self.presentationData.strings.DialogList_AdNoticeAlert)
|
||||
let _ = ApplicationSpecificNotice.setProxyAdsAcknowledgment(accountManager: self.context.sharedContext.accountManager).startStandalone()
|
||||
}
|
||||
})
|
||||
case let .psa(type, _):
|
||||
let _ = (ApplicationSpecificNotice.getPsaAcknowledgment(accountManager: self.context.sharedContext.accountManager, peerId: peer.id)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] value in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if !value {
|
||||
var text = self.presentationData.strings.ChatList_GenericPsaAlert
|
||||
let key = "ChatList.PsaAlert.\(type)"
|
||||
if let string = self.presentationData.strings.primaryComponent.dict[key] {
|
||||
text = string
|
||||
} else if let string = self.presentationData.strings.secondaryComponent?.dict[key] {
|
||||
text = string
|
||||
}
|
||||
|
||||
controller.displayPromoAnnouncement(text: text)
|
||||
let _ = ApplicationSpecificNotice.setPsaAcknowledgment(accountManager: self.context.sharedContext.accountManager, peerId: peer.id).startStandalone()
|
||||
}
|
||||
})
|
||||
self.chatListDisplayNode.clearHighlightAnimated(true)
|
||||
} else {
|
||||
var navigationAnimationOptions: NavigationAnimationOptions = []
|
||||
var groupId: EngineChatList.Group = .root
|
||||
if case let .chatList(groupIdValue) = self.location {
|
||||
groupId = groupIdValue
|
||||
if case .root = groupIdValue {
|
||||
navigationAnimationOptions = .removeOnMasterDetails
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
let chatLocation: NavigateToChatControllerParams.Location
|
||||
chatLocation = .peer(peer)
|
||||
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
|
||||
navigationController: navigationController,
|
||||
context: self.context,
|
||||
chatLocation: chatLocation,
|
||||
subject: subject,
|
||||
activateInput: (activateInput && !peer.isDeleted) ? .text : nil,
|
||||
scrollToEndIfExists: scrollToEndIfExists,
|
||||
animated: !scrollToEndIfExists,
|
||||
options: navigationAnimationOptions,
|
||||
parentGroupId: groupId._asGroup(),
|
||||
chatListFilter: self.chatListDisplayNode.mainContainerNode.currentItemNode.chatListFilter?.id, completion: { [weak self] controller in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.chatListDisplayNode.mainContainerNode.currentItemNode.clearHighlightAnimated(true)
|
||||
|
||||
if let promoInfo = promoInfo {
|
||||
switch promoInfo {
|
||||
case .proxy:
|
||||
let _ = (ApplicationSpecificNotice.getProxyAdsAcknowledgment(accountManager: self.context.sharedContext.accountManager)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] value in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if !value {
|
||||
controller.displayPromoAnnouncement(text: self.presentationData.strings.DialogList_AdNoticeAlert)
|
||||
let _ = ApplicationSpecificNotice.setProxyAdsAcknowledgment(accountManager: self.context.sharedContext.accountManager).startStandalone()
|
||||
}
|
||||
})
|
||||
case let .psa(type, _):
|
||||
let _ = (ApplicationSpecificNotice.getPsaAcknowledgment(accountManager: self.context.sharedContext.accountManager, peerId: peer.id)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] value in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if !value {
|
||||
var text = self.presentationData.strings.ChatList_GenericPsaAlert
|
||||
let key = "ChatList.PsaAlert.\(type)"
|
||||
if let string = self.presentationData.strings.primaryComponent.dict[key] {
|
||||
text = string
|
||||
} else if let string = self.presentationData.strings.secondaryComponent?.dict[key] {
|
||||
text = string
|
||||
}
|
||||
|
||||
controller.displayPromoAnnouncement(text: text)
|
||||
let _ = ApplicationSpecificNotice.setPsaAcknowledgment(accountManager: self.context.sharedContext.accountManager, peerId: peer.id).startStandalone()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
self.chatListDisplayNode.mainContainerNode.groupSelected = { [weak self] groupId in
|
||||
|
|
|
|||
|
|
@ -580,6 +580,9 @@ public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
|
|||
if threadId == nil, self.interaction.searchTextHighightState != nil, case let .channel(channel) = peerData.peer.peer, channel.isForumOrMonoForum {
|
||||
threadId = message.threadId
|
||||
}
|
||||
if case let .user(user) = peer, let botInfo = user.botInfo, botInfo.flags.contains(.hasForum), let forumTopicData = peerData.forumTopicData {
|
||||
threadId = forumTopicData.id
|
||||
}
|
||||
self.interaction.messageSelected(peer, threadId, message, peerData.promoInfo)
|
||||
} else if let peer = peerData.peer.peer {
|
||||
self.interaction.peerSelected(peer, nil, nil, peerData.promoInfo, false)
|
||||
|
|
@ -2509,6 +2512,9 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
forumThread = (threadInfo.id, threadInfo.info.title, threadInfo.info.icon, threadInfo.info.iconColor, nil, false)
|
||||
}
|
||||
}
|
||||
if let forumTopicData, forumThread == nil, case let .user(user) = itemPeer.chatMainPeer, let botInfo = user.botInfo, botInfo.flags.contains(.hasForum) {
|
||||
forumThread = (forumTopicData.id, forumTopicData.title, forumTopicData.iconFileId, forumTopicData.iconColor, forumTopicData.threadPeer, forumTopicData.isUnread)
|
||||
}
|
||||
|
||||
let messageText: String
|
||||
if let currentChatListText = currentChatListText, currentChatListText.0 == text {
|
||||
|
|
@ -3421,7 +3427,12 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
}
|
||||
} else if forumThread != nil || !topForumTopicItems.isEmpty {
|
||||
if let forumThread = forumThread {
|
||||
isFirstForumThreadSelectable = forumThread.isUnread
|
||||
if case let .peer(peer) = item.content, case .user = peer.peer.chatMainPeer {
|
||||
isFirstForumThreadSelectable = false
|
||||
} else {
|
||||
isFirstForumThreadSelectable = forumThread.isUnread
|
||||
}
|
||||
|
||||
forumThreads.append((id: forumThread.id, threadPeer: forumThread.threadPeer, title: NSAttributedString(string: forumThread.title, font: textFont, textColor: forumThread.isUnread || isSearching ? theme.authorNameColor : theme.messageTextColor), iconId: forumThread.iconId, iconColor: forumThread.iconColor))
|
||||
}
|
||||
for topicItem in topForumTopicItems {
|
||||
|
|
@ -3475,7 +3486,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
textMaxWidth -= 18.0
|
||||
}
|
||||
|
||||
let (textLayout, textApply) = textLayout(TextNodeLayoutArguments(attributedString: textAttributedString, backgroundColor: nil, maximumNumberOfLines: (authorAttributedString == nil && itemTags.isEmpty) ? 2 : 1, truncationType: .end, constrainedSize: CGSize(width: textMaxWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: textCutout, insets: UIEdgeInsets(top: 2.0, left: 1.0, bottom: 2.0, right: 1.0)))
|
||||
let (textLayout, textApply) = textLayout(TextNodeLayoutArguments(attributedString: textAttributedString, backgroundColor: nil, maximumNumberOfLines: (authorAttributedString == nil && itemTags.isEmpty && forumThread == nil) ? 2 : 1, truncationType: .end, constrainedSize: CGSize(width: textMaxWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: textCutout, insets: UIEdgeInsets(top: 2.0, left: 1.0, bottom: 2.0, right: 1.0)))
|
||||
|
||||
let maxTitleLines: Int
|
||||
switch item.index {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ final class MutableCachedPeerDataView: MutablePostboxView {
|
|||
}
|
||||
|
||||
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
|
||||
if let cachedPeerData = transaction.currentUpdatedCachedPeerData[self.peerId] {
|
||||
if let cachedPeerData = transaction.currentUpdatedCachedPeerData[self.peerId]?.updated {
|
||||
self.cachedPeerData = cachedPeerData
|
||||
if self.trackAssociatedMessages {
|
||||
self.associatedMessages.removeAll()
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ final class ChatListTable: Table {
|
|||
return result
|
||||
}
|
||||
|
||||
func replay(historyOperationsByPeerId: [PeerId: [MessageHistoryOperation]], updatedPeerChatListEmbeddedStates: Set<PeerId>, updatedChatListInclusions: [PeerId: PeerChatListInclusion], messageHistoryTable: MessageHistoryTable, peerChatInterfaceStateTable: PeerChatInterfaceStateTable, operations: inout [PeerGroupId: [ChatListOperation]]) {
|
||||
func replay(postbox: PostboxImpl, historyOperationsByPeerId: [PeerId: [MessageHistoryOperation]], updatedPeerChatListEmbeddedStates: Set<PeerId>, updatedPeerCachedData: [PeerId: (previous: CachedPeerData?, updated: CachedPeerData)], updatedChatListInclusions: [PeerId: PeerChatListInclusion], messageHistoryTable: MessageHistoryTable, peerChatInterfaceStateTable: PeerChatInterfaceStateTable, operations: inout [PeerGroupId: [ChatListOperation]]) {
|
||||
var changedPeerIds = Set<PeerId>()
|
||||
for peerId in historyOperationsByPeerId.keys {
|
||||
changedPeerIds.insert(peerId)
|
||||
|
|
@ -384,6 +384,23 @@ final class ChatListTable: Table {
|
|||
for peerId in updatedChatListInclusions.keys {
|
||||
changedPeerIds.insert(peerId)
|
||||
}
|
||||
for (peerId, update) in updatedPeerCachedData {
|
||||
if let previous = update.previous {
|
||||
if self.seedConfiguration.decodeAssociatedChatListPeerId(previous) != self.seedConfiguration.decodeAssociatedChatListPeerId(update.updated) {
|
||||
changedPeerIds.insert(peerId)
|
||||
}
|
||||
} else {
|
||||
changedPeerIds.insert(peerId)
|
||||
}
|
||||
}
|
||||
var additionalChangedPeerIds = Set<PeerId>()
|
||||
for peerId in changedPeerIds {
|
||||
//TODO:release move this to seed configuration
|
||||
if let peer = postbox.peerTable.get(peerId), peer.id.namespace._internalGetInt32Value() == 2, let associatedPeerId = peer.associatedPeerId, associatedPeerId.namespace._internalGetInt32Value() == 0 {
|
||||
additionalChangedPeerIds.insert(associatedPeerId)
|
||||
}
|
||||
}
|
||||
changedPeerIds.formUnion(additionalChangedPeerIds)
|
||||
|
||||
self.ensureInitialized(groupId: .root)
|
||||
|
||||
|
|
@ -396,8 +413,8 @@ final class ChatListTable: Table {
|
|||
let topMessage = messageHistoryTable.topIndex(peerId: peerId)
|
||||
let embeddedChatStateOverrideTimestamp = peerChatInterfaceStateTable.get(peerId)?.overrideChatTimestamp
|
||||
|
||||
let rawTopMessageIndex: MessageIndex?
|
||||
let topMessageIndex: MessageIndex?
|
||||
var rawTopMessageIndex: MessageIndex?
|
||||
var topMessageIndex: MessageIndex?
|
||||
if let topMessage = topMessage {
|
||||
var updatedTimestamp = topMessage.timestamp
|
||||
rawTopMessageIndex = MessageIndex(id: topMessage.id, timestamp: topMessage.timestamp)
|
||||
|
|
@ -413,6 +430,18 @@ final class ChatListTable: Table {
|
|||
rawTopMessageIndex = nil
|
||||
}
|
||||
|
||||
if let cachedData = postbox.cachedPeerDataTable.get(peerId), let associatedChatListPeerId = self.seedConfiguration.decodeAssociatedChatListPeerId(cachedData) {
|
||||
if let associatedTopMessage = messageHistoryTable.topIndex(peerId: associatedChatListPeerId) {
|
||||
if let currentTopMessageIndex = topMessageIndex {
|
||||
if currentTopMessageIndex.timestamp < associatedTopMessage.timestamp {
|
||||
topMessageIndex = MessageIndex(id: currentTopMessageIndex.id, timestamp: associatedTopMessage.timestamp)
|
||||
}
|
||||
} else {
|
||||
topMessageIndex = MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 1), timestamp: associatedTopMessage.timestamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var updatedIndex = self.indexTable.setTopMessageIndex(peerId: peerId, index: topMessageIndex)
|
||||
if let updatedInclusion = updatedChatListInclusions[peerId] {
|
||||
updatedIndex = self.indexTable.setInclusion(peerId: peerId, inclusion: updatedInclusion)
|
||||
|
|
|
|||
|
|
@ -1040,19 +1040,71 @@ public final class ChatListView {
|
|||
self.groupId = mutableView.groupId
|
||||
|
||||
var entries: [ChatListEntry] = []
|
||||
|
||||
//TODO:release
|
||||
var linkedEntries: [PeerId: [MutableChatListEntry.MessageEntryData]] = [:]
|
||||
if "".isEmpty {
|
||||
for entry in mutableView.sampledState.entries {
|
||||
guard case let .MessageEntry(entryData) = entry else {
|
||||
continue
|
||||
}
|
||||
if let peer = entryData.renderedPeer.peer, peer.id.namespace._internalGetInt32Value() == 2, let associatedPeerId = peer.associatedPeerId, associatedPeerId.namespace._internalGetInt32Value() == 0 {
|
||||
if linkedEntries[associatedPeerId] == nil {
|
||||
linkedEntries[associatedPeerId] = []
|
||||
}
|
||||
linkedEntries[associatedPeerId]?.append(entryData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for entry in mutableView.sampledState.entries {
|
||||
switch entry {
|
||||
case let .MessageEntry(entryData):
|
||||
if let peer = entryData.renderedPeer.peer, peer.id.namespace._internalGetInt32Value() == 2, let associatedPeerId = peer.associatedPeerId, associatedPeerId.namespace._internalGetInt32Value() == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
//TODO:release
|
||||
var index = entryData.index
|
||||
var messages = entryData.messages
|
||||
var readState = entryData.readState
|
||||
var forumTopicData = entryData.displayAsRegularChat ? nil : entryData.forumTopicData
|
||||
if let linkedEntries = linkedEntries[entryData.index.messageIndex.id.peerId] {
|
||||
for entry in linkedEntries {
|
||||
if entry.index.messageIndex.timestamp >= index.messageIndex.timestamp {
|
||||
index = ChatListIndex(pinningIndex: index.pinningIndex, messageIndex: MessageIndex(id: index.messageIndex.id, timestamp: entry.index.messageIndex.timestamp))
|
||||
messages = entry.messages
|
||||
forumTopicData = entry.forumTopicData
|
||||
}
|
||||
if let entryReadState = entry.readState {
|
||||
if var readStateValue = readState {
|
||||
var states = readStateValue.state.states
|
||||
for (namespace, state) in entryReadState.state.states {
|
||||
if let index = states.firstIndex(where: { $0.0 == namespace }) {
|
||||
states[index] = (namespace, states[index].1.withAddedCount(state.count))
|
||||
} else {
|
||||
states.append((namespace, state))
|
||||
}
|
||||
}
|
||||
readStateValue.state = .init(states: states)
|
||||
readState = readStateValue
|
||||
} else {
|
||||
readState = entryReadState
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entries.append(.MessageEntry(ChatListEntry.MessageEntryData(
|
||||
index: entryData.index,
|
||||
messages: entryData.messages,
|
||||
readState: entryData.readState,
|
||||
index: index,
|
||||
messages: messages,
|
||||
readState: readState,
|
||||
isRemovedFromTotalUnreadCount: entryData.isRemovedFromTotalUnreadCount,
|
||||
embeddedInterfaceState: entryData.embeddedInterfaceState,
|
||||
renderedPeer: entryData.renderedPeer,
|
||||
presence: entryData.presence,
|
||||
summaryInfo: entryData.tagSummaryInfo,
|
||||
forumTopicData: entryData.displayAsRegularChat ? nil : entryData.forumTopicData,
|
||||
forumTopicData: forumTopicData,
|
||||
topForumTopics: entryData.displayAsRegularChat ? [] : entryData.topForumTopics,
|
||||
hasFailed: entryData.hasFailedMessages,
|
||||
isContact: entryData.isContact,
|
||||
|
|
|
|||
|
|
@ -651,6 +651,8 @@ public struct MessageGroupInfo: Equatable {
|
|||
}
|
||||
|
||||
public final class Message {
|
||||
public static let newTopicThreadId: Int64 = Int64(Int32.max - 1)
|
||||
|
||||
public final class AssociatedThreadInfo: Equatable {
|
||||
public let title: String
|
||||
public let icon: Int64?
|
||||
|
|
@ -905,6 +907,7 @@ public struct MessageThreadKey: Hashable {
|
|||
|
||||
public final class StoreMessage {
|
||||
public let id: StoreMessageId
|
||||
public let customStableId: UInt32?
|
||||
public let timestamp: Int32
|
||||
public let globallyUniqueId: Int64?
|
||||
public let groupingKey: Int64?
|
||||
|
|
@ -919,8 +922,9 @@ public final class StoreMessage {
|
|||
public let attributes: [MessageAttribute]
|
||||
public let media: [Media]
|
||||
|
||||
public init(id: MessageId, globallyUniqueId: Int64?, groupingKey: Int64?, threadId: Int64?, timestamp: Int32, flags: StoreMessageFlags, tags: MessageTags, globalTags: GlobalMessageTags, localTags: LocalMessageTags, forwardInfo: StoreMessageForwardInfo?, authorId: PeerId?, text: String, attributes: [MessageAttribute], media: [Media]) {
|
||||
public init(id: MessageId, customStableId: UInt32?, globallyUniqueId: Int64?, groupingKey: Int64?, threadId: Int64?, timestamp: Int32, flags: StoreMessageFlags, tags: MessageTags, globalTags: GlobalMessageTags, localTags: LocalMessageTags, forwardInfo: StoreMessageForwardInfo?, authorId: PeerId?, text: String, attributes: [MessageAttribute], media: [Media]) {
|
||||
self.id = .Id(id)
|
||||
self.customStableId = customStableId
|
||||
self.globallyUniqueId = globallyUniqueId
|
||||
self.groupingKey = groupingKey
|
||||
self.threadId = threadId
|
||||
|
|
@ -936,8 +940,9 @@ public final class StoreMessage {
|
|||
self.media = media
|
||||
}
|
||||
|
||||
public init(peerId: PeerId, namespace: MessageId.Namespace, globallyUniqueId: Int64?, groupingKey: Int64?, threadId: Int64?, timestamp: Int32, flags: StoreMessageFlags, tags: MessageTags, globalTags: GlobalMessageTags, localTags: LocalMessageTags, forwardInfo: StoreMessageForwardInfo?, authorId: PeerId?, text: String, attributes: [MessageAttribute], media: [Media]) {
|
||||
public init(peerId: PeerId, namespace: MessageId.Namespace, customStableId: UInt32?, globallyUniqueId: Int64?, groupingKey: Int64?, threadId: Int64?, timestamp: Int32, flags: StoreMessageFlags, tags: MessageTags, globalTags: GlobalMessageTags, localTags: LocalMessageTags, forwardInfo: StoreMessageForwardInfo?, authorId: PeerId?, text: String, attributes: [MessageAttribute], media: [Media]) {
|
||||
self.id = .Partial(peerId, namespace)
|
||||
self.customStableId = customStableId
|
||||
self.timestamp = timestamp
|
||||
self.globallyUniqueId = globallyUniqueId
|
||||
self.groupingKey = groupingKey
|
||||
|
|
@ -953,8 +958,9 @@ public final class StoreMessage {
|
|||
self.media = media
|
||||
}
|
||||
|
||||
public init(id: StoreMessageId, globallyUniqueId: Int64?, groupingKey: Int64?, threadId: Int64?, timestamp: Int32, flags: StoreMessageFlags, tags: MessageTags, globalTags: GlobalMessageTags, localTags: LocalMessageTags, forwardInfo: StoreMessageForwardInfo?, authorId: PeerId?, text: String, attributes: [MessageAttribute], media: [Media]) {
|
||||
public init(id: StoreMessageId, customStableId: UInt32?, globallyUniqueId: Int64?, groupingKey: Int64?, threadId: Int64?, timestamp: Int32, flags: StoreMessageFlags, tags: MessageTags, globalTags: GlobalMessageTags, localTags: LocalMessageTags, forwardInfo: StoreMessageForwardInfo?, authorId: PeerId?, text: String, attributes: [MessageAttribute], media: [Media]) {
|
||||
self.id = id
|
||||
self.customStableId = customStableId
|
||||
self.timestamp = timestamp
|
||||
self.globallyUniqueId = globallyUniqueId
|
||||
self.groupingKey = groupingKey
|
||||
|
|
@ -978,33 +984,38 @@ public final class StoreMessage {
|
|||
}
|
||||
}
|
||||
|
||||
public func withUpdatedCustomStableId(_ customStableId: UInt32?) -> StoreMessage {
|
||||
return StoreMessage(id: self.id, customStableId: customStableId, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: self.forwardInfo, authorId: self.authorId, text: self.text, attributes: attributes, media: self.media)
|
||||
}
|
||||
|
||||
public func withUpdatedFlags(_ flags: StoreMessageFlags) -> StoreMessage {
|
||||
if flags == self.flags {
|
||||
return self
|
||||
} else {
|
||||
return StoreMessage(id: self.id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, threadId: self.threadId, timestamp: self.timestamp, flags: flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: self.forwardInfo, authorId: self.authorId, text: self.text, attributes: attributes, media: self.media)
|
||||
return StoreMessage(id: self.id, customStableId: self.customStableId, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, threadId: self.threadId, timestamp: self.timestamp, flags: flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: self.forwardInfo, authorId: self.authorId, text: self.text, attributes: attributes, media: self.media)
|
||||
}
|
||||
}
|
||||
|
||||
public func withUpdatedMedia(_ media: [Media]) -> StoreMessage {
|
||||
return StoreMessage(id: self.id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: self.forwardInfo, authorId: self.authorId, text: self.text, attributes: self.attributes, media: media)
|
||||
return StoreMessage(id: self.id, customStableId: self.customStableId, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: self.forwardInfo, authorId: self.authorId, text: self.text, attributes: self.attributes, media: media)
|
||||
}
|
||||
|
||||
public func withUpdatedAttributes(_ attributes: [MessageAttribute]) -> StoreMessage {
|
||||
return StoreMessage(id: self.id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: self.forwardInfo, authorId: self.authorId, text: self.text, attributes: attributes, media: self.media)
|
||||
return StoreMessage(id: self.id, customStableId: self.customStableId, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: self.localTags, forwardInfo: self.forwardInfo, authorId: self.authorId, text: self.text, attributes: attributes, media: self.media)
|
||||
}
|
||||
|
||||
public func withUpdatedLocalTags(_ localTags: LocalMessageTags) -> StoreMessage {
|
||||
if localTags == self.localTags {
|
||||
return self
|
||||
} else {
|
||||
return StoreMessage(id: self.id, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: localTags, forwardInfo: self.forwardInfo, authorId: self.authorId, text: self.text, attributes: self.attributes, media: self.media)
|
||||
return StoreMessage(id: self.id, customStableId: self.customStableId, globallyUniqueId: self.globallyUniqueId, groupingKey: self.groupingKey, threadId: self.threadId, timestamp: self.timestamp, flags: self.flags, tags: self.tags, globalTags: self.globalTags, localTags: localTags, forwardInfo: self.forwardInfo, authorId: self.authorId, text: self.text, attributes: self.attributes, media: self.media)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class InternalStoreMessage {
|
||||
let id: MessageId
|
||||
let customStableId: UInt32?
|
||||
let timestamp: Int32
|
||||
let globallyUniqueId: Int64?
|
||||
let groupingKey: Int64?
|
||||
|
|
@ -1024,8 +1035,9 @@ final class InternalStoreMessage {
|
|||
return MessageIndex(id: self.id, timestamp: self.timestamp)
|
||||
}
|
||||
|
||||
init(id: MessageId, timestamp: Int32, globallyUniqueId: Int64?, groupingKey: Int64?, threadId: Int64?, flags: StoreMessageFlags, tags: MessageTags, globalTags: GlobalMessageTags, localTags: LocalMessageTags, customTags: [MemoryBuffer], forwardInfo: StoreMessageForwardInfo?, authorId: PeerId?, text: String, attributes: [MessageAttribute], media: [Media]) {
|
||||
init(id: MessageId, customStableId: UInt32?, timestamp: Int32, globallyUniqueId: Int64?, groupingKey: Int64?, threadId: Int64?, flags: StoreMessageFlags, tags: MessageTags, globalTags: GlobalMessageTags, localTags: LocalMessageTags, customTags: [MemoryBuffer], forwardInfo: StoreMessageForwardInfo?, authorId: PeerId?, text: String, attributes: [MessageAttribute], media: [Media]) {
|
||||
self.id = id
|
||||
self.customStableId = customStableId
|
||||
self.timestamp = timestamp
|
||||
self.globallyUniqueId = globallyUniqueId
|
||||
self.groupingKey = groupingKey
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ final class MessageCustomTagHoleIndexTable: Table {
|
|||
if !self.metadataTable.isPeerCustomTagInitialized(peerId: peerId, threadId: threadId, tag: tag) {
|
||||
self.metadataTable.setPeerCustomTagInitialized(peerId: peerId, threadId: threadId, tag: tag)
|
||||
|
||||
if let namespaces = self.seedConfiguration.messageThreadHoles[peerId.namespace] {
|
||||
if let namespaces = self.seedConfiguration.messageThreadHoles(peerId.namespace, threadId) {
|
||||
for namespace in namespaces {
|
||||
var operations: [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]] = [:]
|
||||
self.addInternal(peerId: peerId, threadId: threadId, tag: tag, tagValue: tagValue, namespace: namespace, range: 1 ... (Int32.max - 1), operations: &operations)
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ final class MessageCustomTagWithTagHoleIndexTable: Table {
|
|||
if !self.metadataTable.isPeerCustomTagInitialized(peerId: peerId, threadId: threadId, tag: tag, regularTag: regularTag) {
|
||||
self.metadataTable.setPeerCustomTagInitialized(peerId: peerId, threadId: threadId, tag: tag, regularTag: regularTag)
|
||||
|
||||
if let namespaces = self.seedConfiguration.messageThreadHoles[peerId.namespace] {
|
||||
if let namespaces = self.seedConfiguration.messageThreadHoles(peerId.namespace, threadId) {
|
||||
for namespace in namespaces {
|
||||
var operations: [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]] = [:]
|
||||
self.addInternal(peerId: peerId, threadId: threadId, tag: tag, tagValue: tagValue, regularTag: regularTag, namespace: namespace, range: 1 ... (Int32.max - 1), operations: &operations)
|
||||
|
|
|
|||
|
|
@ -431,10 +431,10 @@ final class MessageHistoryTable: Table {
|
|||
for message in messages {
|
||||
switch message.id {
|
||||
case let .Id(id):
|
||||
internalStoreMessages.append(InternalStoreMessage(id: id, timestamp: message.timestamp, globallyUniqueId: message.globallyUniqueId, groupingKey: message.groupingKey, threadId: message.threadId, flags: message.flags, tags: message.tags, globalTags: message.globalTags, localTags: message.localTags, customTags: self.seedConfiguration.customTagsFromAttributes(message.attributes), forwardInfo: message.forwardInfo, authorId: message.authorId, text: message.text, attributes: message.attributes, media: message.media))
|
||||
internalStoreMessages.append(InternalStoreMessage(id: id, customStableId: message.customStableId, timestamp: message.timestamp, globallyUniqueId: message.globallyUniqueId, groupingKey: message.groupingKey, threadId: message.threadId, flags: message.flags, tags: message.tags, globalTags: message.globalTags, localTags: message.localTags, customTags: self.seedConfiguration.customTagsFromAttributes(message.attributes), forwardInfo: message.forwardInfo, authorId: message.authorId, text: message.text, attributes: message.attributes, media: message.media))
|
||||
case let .Partial(peerId, namespace):
|
||||
let id = self.historyMetadataTable.getNextMessageIdAndIncrement(peerId, namespace: namespace)
|
||||
internalStoreMessages.append(InternalStoreMessage(id: id, timestamp: message.timestamp, globallyUniqueId: message.globallyUniqueId, groupingKey: message.groupingKey, threadId: message.threadId, flags: message.flags, tags: message.tags, globalTags: message.globalTags, localTags: message.localTags, customTags: self.seedConfiguration.customTagsFromAttributes(message.attributes), forwardInfo: message.forwardInfo, authorId: message.authorId, text: message.text, attributes: message.attributes, media: message.media))
|
||||
internalStoreMessages.append(InternalStoreMessage(id: id, customStableId: message.customStableId, timestamp: message.timestamp, globallyUniqueId: message.globallyUniqueId, groupingKey: message.groupingKey, threadId: message.threadId, flags: message.flags, tags: message.tags, globalTags: message.globalTags, localTags: message.localTags, customTags: self.seedConfiguration.customTagsFromAttributes(message.attributes), forwardInfo: message.forwardInfo, authorId: message.authorId, text: message.text, attributes: message.attributes, media: message.media))
|
||||
}
|
||||
}
|
||||
return internalStoreMessages
|
||||
|
|
@ -1084,7 +1084,7 @@ final class MessageHistoryTable: Table {
|
|||
var type: Int8 = 0
|
||||
sharedBuffer.write(&type, offset: 0, length: 1)
|
||||
|
||||
var stableId: UInt32 = self.historyMetadataTable.getNextStableMessageIndexId()
|
||||
var stableId: UInt32 = message.customStableId ?? self.historyMetadataTable.getNextStableMessageIndexId()
|
||||
sharedBuffer.write(&stableId, offset: 0, length: 4)
|
||||
|
||||
var stableVersion: UInt32 = 0
|
||||
|
|
@ -2115,7 +2115,7 @@ final class MessageHistoryTable: Table {
|
|||
|
||||
let updatedIndex = MessageIndex(id: index.id, timestamp: timestamp)
|
||||
|
||||
let _ = self.justUpdate(index, message: InternalStoreMessage(id: previousMessage.id, timestamp: timestamp, globallyUniqueId: previousMessage.globallyUniqueId, groupingKey: previousMessage.groupingKey, threadId: previousMessage.threadId, flags: StoreMessageFlags(previousMessage.flags), tags: previousMessage.tags, globalTags: previousMessage.globalTags, localTags: previousMessage.localTags, customTags: previousMessage.customTags, forwardInfo: storeForwardInfo, authorId: previousMessage.authorId, text: previousMessage.text, attributes: parsedAttributes, media: parsedMedia), keepLocalTags: false, sharedKey: self.key(updatedIndex), sharedBuffer: WriteBuffer(), sharedEncoder: PostboxEncoder(), unsentMessageOperations: &unsentMessageOperations, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, updatedGroupInfos: &updatedGroupInfos, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×tampBasedMessageAttributesOperations, updatedMedia: &updatedMedia)
|
||||
let _ = self.justUpdate(index, message: InternalStoreMessage(id: previousMessage.id, customStableId: nil, timestamp: timestamp, globallyUniqueId: previousMessage.globallyUniqueId, groupingKey: previousMessage.groupingKey, threadId: previousMessage.threadId, flags: StoreMessageFlags(previousMessage.flags), tags: previousMessage.tags, globalTags: previousMessage.globalTags, localTags: previousMessage.localTags, customTags: previousMessage.customTags, forwardInfo: storeForwardInfo, authorId: previousMessage.authorId, text: previousMessage.text, attributes: parsedAttributes, media: parsedMedia), keepLocalTags: false, sharedKey: self.key(updatedIndex), sharedBuffer: WriteBuffer(), sharedEncoder: PostboxEncoder(), unsentMessageOperations: &unsentMessageOperations, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, updatedGroupInfos: &updatedGroupInfos, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×tampBasedMessageAttributesOperations, updatedMedia: &updatedMedia)
|
||||
return (previousMessage.tags, previousMessage.globalTags)
|
||||
} else {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ final class MessageHistoryThreadHoleIndexTable: Table {
|
|||
postboxLog("MessageHistoryThreadHoleIndexTable: Initializing \(peerId) \(threadId)")
|
||||
self.metadataTable.setIsThreadHoleIndexInitialized(peerId: peerId, threadId: threadId)
|
||||
|
||||
if let messageNamespaces = self.seedConfiguration.messageThreadHoles[peerId.namespace] {
|
||||
if let messageNamespaces = self.seedConfiguration.messageThreadHoles(peerId.namespace, threadId) {
|
||||
for namespace in messageNamespaces {
|
||||
var operations: [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]] = [:]
|
||||
self.add(peerId: peerId, threadId: threadId, namespace: namespace, space: .everywhere, range: 1 ... (Int32.max - 1), operations: &operations)
|
||||
|
|
|
|||
|
|
@ -332,6 +332,7 @@ final class MutableMessageHistoryView: MutablePostboxView {
|
|||
private var userId: Int64?
|
||||
|
||||
fileprivate var peerStoryStats: [PeerId: PeerStoryStats] = [:]
|
||||
fileprivate var typingDraft: Message?
|
||||
|
||||
init(
|
||||
postbox: PostboxImpl,
|
||||
|
|
@ -410,6 +411,8 @@ final class MutableMessageHistoryView: MutablePostboxView {
|
|||
self.render(postbox: postbox)
|
||||
let _ = self.updateStoryStats(postbox: postbox)
|
||||
|
||||
self.reloadTypingDraft(postbox: postbox)
|
||||
|
||||
let _ = self.updateThreadInfos(postbox: postbox, updatedIds: nil)
|
||||
}
|
||||
|
||||
|
|
@ -436,6 +439,8 @@ final class MutableMessageHistoryView: MutablePostboxView {
|
|||
self.sampledState = self.state.sample(postbox: postbox, clipHoles: self.clipHoles)
|
||||
|
||||
let _ = self.updateStoryStats(postbox: postbox)
|
||||
|
||||
self.reloadTypingDraft(postbox: postbox)
|
||||
}
|
||||
|
||||
func refreshDueToExternalTransaction(postbox: PostboxImpl) -> Bool {
|
||||
|
|
@ -447,14 +452,14 @@ final class MutableMessageHistoryView: MutablePostboxView {
|
|||
switch self.peerIds {
|
||||
case let .single(peerId, threadId):
|
||||
if threadId == nil {
|
||||
if let updatedData = transaction.currentUpdatedCachedPeerData[peerId] {
|
||||
if let updatedData = transaction.currentUpdatedCachedPeerData[peerId]?.updated {
|
||||
if updatedData.associatedHistoryMessageId != nil {
|
||||
self.peerIds = .associated(peerId, updatedData.associatedHistoryMessageId)
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .associated(peerId, associatedId):
|
||||
if let updatedData = transaction.currentUpdatedCachedPeerData[peerId] {
|
||||
if let updatedData = transaction.currentUpdatedCachedPeerData[peerId]?.updated {
|
||||
if updatedData.associatedHistoryMessageId != associatedId {
|
||||
self.peerIds = .associated(peerId, updatedData.associatedHistoryMessageId)
|
||||
}
|
||||
|
|
@ -839,7 +844,7 @@ final class MutableMessageHistoryView: MutablePostboxView {
|
|||
switch additionalDatas[i] {
|
||||
case let .cachedPeerData(peerId, currentData):
|
||||
currentCachedPeerData = currentData
|
||||
if let updatedData = transaction.currentUpdatedCachedPeerData[peerId] {
|
||||
if let updatedData = transaction.currentUpdatedCachedPeerData[peerId]?.updated {
|
||||
if currentData?.messageIds != updatedData.messageIds {
|
||||
updatedCachedPeerDataMessages = true
|
||||
}
|
||||
|
|
@ -1039,9 +1044,79 @@ final class MutableMessageHistoryView: MutablePostboxView {
|
|||
}
|
||||
}
|
||||
|
||||
switch self.peerIds {
|
||||
case let .single(peerId, threadId):
|
||||
let location = PeerAndThreadId(peerId: peerId, threadId: threadId)
|
||||
if let typingDraftUpdate = transaction.updatedTypingDrafts[location] {
|
||||
if let typingDraft = typingDraftUpdate.value {
|
||||
self.typingDraft = self.renderTypingDraft(postbox: postbox, typingDraft: typingDraft)
|
||||
} else {
|
||||
self.typingDraft = nil
|
||||
}
|
||||
hasChanges = true
|
||||
}
|
||||
case .external:
|
||||
break
|
||||
case .associated:
|
||||
break
|
||||
}
|
||||
|
||||
return hasChanges
|
||||
}
|
||||
|
||||
private func reloadTypingDraft(postbox: PostboxImpl) {
|
||||
guard case let .single(peerId, threadId) = self.peerIds else {
|
||||
self.typingDraft = nil
|
||||
return
|
||||
}
|
||||
guard let typingDraft = postbox.currentTypingDrafts[PeerAndThreadId(peerId: peerId, threadId: threadId)] else {
|
||||
self.typingDraft = nil
|
||||
return
|
||||
}
|
||||
self.typingDraft = self.renderTypingDraft(postbox: postbox, typingDraft: typingDraft)
|
||||
}
|
||||
|
||||
private func renderTypingDraft(postbox: PostboxImpl, typingDraft: PostboxImpl.TypingDraft) -> Message? {
|
||||
guard case let .single(peerId, threadId) = self.peerIds else {
|
||||
return nil
|
||||
}
|
||||
guard let peer = postbox.peerTable.get(peerId), let author = postbox.peerTable.get(typingDraft.authorId) else {
|
||||
return nil
|
||||
}
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
peers[peer.id] = peer
|
||||
peers[author.id] = author
|
||||
return Message(
|
||||
stableId: typingDraft.stableId,
|
||||
stableVersion: typingDraft.stableVersion,
|
||||
id: MessageId(
|
||||
peerId: peerId,
|
||||
namespace: 1,
|
||||
id: Int32.max - 50000),
|
||||
globallyUniqueId: nil,
|
||||
groupingKey: nil,
|
||||
groupInfo: nil,
|
||||
threadId: threadId,
|
||||
timestamp: typingDraft.timestamp,
|
||||
flags: [.Incoming],
|
||||
tags: [],
|
||||
globalTags: [],
|
||||
localTags: [],
|
||||
customTags: [],
|
||||
forwardInfo: nil,
|
||||
author: author,
|
||||
text: typingDraft.text,
|
||||
attributes: typingDraft.attributes,
|
||||
media: [],
|
||||
peers: peers,
|
||||
associatedMessages: SimpleDictionary(),
|
||||
associatedMessageIds: [],
|
||||
associatedMedia: [:],
|
||||
associatedThreadInfo: nil,
|
||||
associatedStories: [:]
|
||||
)
|
||||
}
|
||||
|
||||
private func updateThreadInfos(postbox: PostboxImpl, updatedIds: Set<MessageHistoryThreadsTable.ItemId>?) -> Bool {
|
||||
if self.mapReadStatesFromThreads, case let .single(peerId, peerThreadId) = self.peerIds, peerThreadId == nil {
|
||||
switch self.sampledState {
|
||||
|
|
@ -1446,6 +1521,16 @@ public final class MessageHistoryView: PostboxView {
|
|||
}
|
||||
}
|
||||
|
||||
if !self.holeLater, let typingDraft = mutableView.typingDraft {
|
||||
entries.append(MessageHistoryEntry(
|
||||
message: typingDraft,
|
||||
isRead: false,
|
||||
location: nil,
|
||||
monthLocation: nil,
|
||||
attributes: MutableMessageHistoryEntryAttributes(authorIsContact: false)
|
||||
))
|
||||
}
|
||||
|
||||
self.entries = entries
|
||||
self.peerStoryStats = mutableView.peerStoryStats
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ final class MutablePeerView: MutablePostboxView {
|
|||
var peersUpdated = false
|
||||
var updateMessages = false
|
||||
|
||||
if let cachedData = updatedCachedPeerData[self.contactPeerId], self.cachedData == nil || !self.cachedData!.isEqual(to: cachedData) {
|
||||
if let cachedData = updatedCachedPeerData[self.contactPeerId]?.updated, self.cachedData == nil || !self.cachedData!.isEqual(to: cachedData) {
|
||||
if self.cachedData?.messageIds != cachedData.messageIds {
|
||||
updateMessages = true
|
||||
}
|
||||
|
|
@ -286,7 +286,7 @@ final class MutablePeerView: MutablePostboxView {
|
|||
}
|
||||
|
||||
if let associatedPeerId = peer.associatedPeerId {
|
||||
if let value = updatedCachedPeerData[associatedPeerId] {
|
||||
if let value = updatedCachedPeerData[associatedPeerId]?.updated {
|
||||
if let current = self.associatedCachedData[associatedPeerId] {
|
||||
if !current.isEqual(to: value) {
|
||||
self.associatedCachedData[associatedPeerId] = value
|
||||
|
|
|
|||
|
|
@ -1393,6 +1393,27 @@ public final class Transaction {
|
|||
assert(!self.disposed)
|
||||
self.postbox!.reindexSavedMessagesCustomTagsWithTagsIfNeeded(peerId: peerId, threadId: threadId, tag: tag)
|
||||
}
|
||||
|
||||
public func getCurrentTypingDraft(location: PeerAndThreadId) -> (id: Int64, stableId: UInt32, authorId: PeerId, timestamp: Int32, text: String, attributes: [MessageAttribute])? {
|
||||
assert(!self.disposed)
|
||||
if let value = self.postbox!.currentTypingDrafts[location] {
|
||||
return (
|
||||
value.id,
|
||||
value.stableId,
|
||||
value.authorId,
|
||||
value.timestamp,
|
||||
value.text,
|
||||
value.attributes
|
||||
)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public func combineTypingDrafts(locations: Set<PeerAndThreadId>, update: (PeerAndThreadId, (id: Int64, authorId: PeerId, timestamp: Int32, text: String, attributes: [MessageAttribute])?) -> (id: Int64, authorId: PeerId, timestamp: Int32, text: String, attributes: [MessageAttribute])?) {
|
||||
assert(!self.disposed)
|
||||
self.postbox!.combineTypingDrafts(locations: locations, update: update)
|
||||
}
|
||||
}
|
||||
|
||||
public enum PostboxResult {
|
||||
|
|
@ -1594,7 +1615,7 @@ final class PostboxImpl {
|
|||
private var currentUpdatedPeers: [PeerId: Peer] = [:]
|
||||
private var currentUpdatedPeerNotificationSettings: [PeerId: (PeerNotificationSettings?, PeerNotificationSettings)] = [:]
|
||||
private var currentUpdatedPeerNotificationBehaviorTimestamps: [PeerId: PeerNotificationSettingsBehaviorTimestamp] = [:]
|
||||
private var currentUpdatedCachedPeerData: [PeerId: CachedPeerData] = [:]
|
||||
private var currentUpdatedCachedPeerData: [PeerId: (previous: CachedPeerData?, updated: CachedPeerData)] = [:]
|
||||
private var currentUpdatedPeerPresences: [PeerId: PeerPresence] = [:]
|
||||
private var currentUpdatedPeerChatListEmbeddedStates = Set<PeerId>()
|
||||
private var currentUpdatedTotalUnreadStates: [PeerGroupId: ChatListTotalUnreadState] = [:]
|
||||
|
|
@ -1635,6 +1656,71 @@ final class PostboxImpl {
|
|||
private var currentStoryTopItemEvents: [StoryTopItemsTable.Event] = []
|
||||
private var currentStoryEvents: [StoryTable.Event] = []
|
||||
|
||||
struct TypingDraft: Equatable {
|
||||
var id: Int64
|
||||
var stableId: UInt32
|
||||
var stableVersion: UInt32
|
||||
var authorId: PeerId
|
||||
var timestamp: Int32
|
||||
var text: String
|
||||
var attributes: [MessageAttribute]
|
||||
var addedAtTimestamp: Double
|
||||
|
||||
init(id: Int64, stableId: UInt32, stableVersion: UInt32, authorId: PeerId, timestamp: Int32, text: String, attributes: [MessageAttribute], addedAtTimestamp: Double) {
|
||||
self.id = id
|
||||
self.stableId = stableId
|
||||
self.stableVersion = stableVersion
|
||||
self.authorId = authorId
|
||||
self.timestamp = timestamp
|
||||
self.text = text
|
||||
self.attributes = attributes
|
||||
self.addedAtTimestamp = addedAtTimestamp
|
||||
}
|
||||
|
||||
static func ==(lhs: TypingDraft, rhs: TypingDraft) -> Bool {
|
||||
if lhs.id != rhs.id {
|
||||
return false
|
||||
}
|
||||
if lhs.stableId != rhs.stableId {
|
||||
return false
|
||||
}
|
||||
if lhs.stableVersion != rhs.stableVersion {
|
||||
return false
|
||||
}
|
||||
if lhs.authorId != rhs.authorId {
|
||||
return false
|
||||
}
|
||||
if lhs.timestamp != rhs.timestamp {
|
||||
return false
|
||||
}
|
||||
if lhs.text != rhs.text {
|
||||
return false
|
||||
}
|
||||
if lhs.attributes.count != rhs.attributes.count {
|
||||
return false
|
||||
}
|
||||
for i in 0 ..< lhs.attributes.count {
|
||||
let lhsEncoder = PostboxEncoder()
|
||||
lhs.attributes[i].encode(lhsEncoder)
|
||||
let rhsEncoder = PostboxEncoder()
|
||||
rhs.attributes[i].encode(rhsEncoder)
|
||||
if lhsEncoder.makeData() != rhsEncoder.makeData() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
struct TypingDraftUpdate {
|
||||
var value: TypingDraft?
|
||||
}
|
||||
|
||||
fileprivate(set) var currentTypingDrafts: [PeerAndThreadId: TypingDraft] = [:]
|
||||
private var currentUpdatedTypingDrafts: [PeerAndThreadId: TypingDraftUpdate] = [:]
|
||||
private var nextTypingDraftExpirationTimestamp: Double?
|
||||
private var nextTypingDraftExpirationTimer: SwiftSignalKit.Timer?
|
||||
|
||||
var hiddenChatIds: Set<PeerId> {
|
||||
if self.currentHiddenChatIds.isEmpty {
|
||||
return Set()
|
||||
|
|
@ -2008,7 +2094,7 @@ final class PostboxImpl {
|
|||
if let forwardInfo = message.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
return .update(StoreMessage(id: message.id, globallyUniqueId: message.globallyUniqueId, groupingKey: message.groupingKey, threadId: message.threadId, timestamp: message.timestamp, flags: flags, tags: message.tags, globalTags: message.globalTags, localTags: message.localTags, forwardInfo: storeForwardInfo, authorId: message.author?.id, text: message.text, attributes: message.attributes, media: message.media))
|
||||
return .update(StoreMessage(id: message.id, customStableId: nil, globallyUniqueId: message.globallyUniqueId, groupingKey: message.groupingKey, threadId: message.threadId, timestamp: message.timestamp, flags: flags, tags: message.tags, globalTags: message.globalTags, localTags: message.localTags, forwardInfo: storeForwardInfo, authorId: message.author?.id, text: message.text, attributes: message.attributes, media: message.media))
|
||||
} else {
|
||||
return .skip
|
||||
}
|
||||
|
|
@ -2019,6 +2105,7 @@ final class PostboxImpl {
|
|||
}
|
||||
|
||||
deinit {
|
||||
self.nextTypingDraftExpirationTimer?.invalidate()
|
||||
if let tempDir = self.tempDir {
|
||||
TempBox.shared.dispose(tempDir)
|
||||
}
|
||||
|
|
@ -2401,6 +2488,89 @@ final class PostboxImpl {
|
|||
}
|
||||
}
|
||||
|
||||
fileprivate func combineTypingDrafts(locations: Set<PeerAndThreadId>, update: (PeerAndThreadId, (id: Int64, authorId: PeerId, timestamp: Int32, text: String, attributes: [MessageAttribute])?) -> (id: Int64, authorId: PeerId, timestamp: Int32, text: String, attributes: [MessageAttribute])?) {
|
||||
for location in locations {
|
||||
var updated: (id: Int64, authorId: PeerId, timestamp: Int32, text: String, attributes: [MessageAttribute])?
|
||||
let current = self.currentTypingDrafts[location]
|
||||
if let current {
|
||||
updated = update(location, (current.id, current.authorId, current.timestamp, current.text, current.attributes))
|
||||
} else {
|
||||
updated = update(location, nil)
|
||||
}
|
||||
if let updated {
|
||||
let stableId: UInt32
|
||||
let stableVersion: UInt32
|
||||
if let current, current.id == updated.id {
|
||||
stableId = current.stableId
|
||||
stableVersion = 100000 + current.stableVersion + 1
|
||||
} else {
|
||||
stableId = self.messageHistoryMetadataTable.getNextStableMessageIndexId()
|
||||
stableVersion = 100000
|
||||
}
|
||||
let mappedDraft = TypingDraft(id: updated.id, stableId: stableId, stableVersion: stableVersion, authorId: updated.authorId, timestamp: updated.timestamp, text: updated.text, attributes: updated.attributes, addedAtTimestamp: CFAbsoluteTimeGetCurrent())
|
||||
if self.currentTypingDrafts[location] != mappedDraft {
|
||||
self.currentTypingDrafts[location] = mappedDraft
|
||||
self.currentUpdatedTypingDrafts[location] = TypingDraftUpdate(value: mappedDraft)
|
||||
}
|
||||
} else if self.currentTypingDrafts[location] != nil {
|
||||
self.currentTypingDrafts.removeValue(forKey: location)
|
||||
self.currentUpdatedTypingDrafts[location] = TypingDraftUpdate(value: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func restartTypingDraftExpirationTimerIfNeeded() {
|
||||
let expirationTimeout: Double = 10.0
|
||||
|
||||
var nextTypingDraftExpirationTimestamp: Double?
|
||||
for (_, draft) in self.currentTypingDrafts {
|
||||
if let nextTypingDraftExpirationTimestampValue = nextTypingDraftExpirationTimestamp {
|
||||
nextTypingDraftExpirationTimestamp = min(draft.addedAtTimestamp + expirationTimeout, nextTypingDraftExpirationTimestampValue)
|
||||
} else {
|
||||
nextTypingDraftExpirationTimestamp = draft.addedAtTimestamp + expirationTimeout
|
||||
}
|
||||
}
|
||||
|
||||
if let nextTypingDraftExpirationTimestamp {
|
||||
if self.nextTypingDraftExpirationTimer == nil || nextTypingDraftExpirationTimestamp != self.nextTypingDraftExpirationTimestamp {
|
||||
let timeout = nextTypingDraftExpirationTimestamp - CFAbsoluteTimeGetCurrent()
|
||||
|
||||
self.nextTypingDraftExpirationTimer?.invalidate()
|
||||
self.nextTypingDraftExpirationTimer = SwiftSignalKit.Timer(timeout: max(0.0, timeout - 0.1), repeat: false, completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = self.transaction { _ in
|
||||
self.processTypingDraftExpirations(expirationTimeout: expirationTimeout)
|
||||
}.startStandalone()
|
||||
}, queue: self.queue)
|
||||
self.nextTypingDraftExpirationTimer?.start()
|
||||
}
|
||||
} else {
|
||||
self.nextTypingDraftExpirationTimestamp = nil
|
||||
if let nextTypingDraftExpirationTimer = self.nextTypingDraftExpirationTimer {
|
||||
self.nextTypingDraftExpirationTimer = nil
|
||||
nextTypingDraftExpirationTimer.invalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func processTypingDraftExpirations(expirationTimeout: Double) {
|
||||
let timestamp = CFAbsoluteTimeGetCurrent()
|
||||
var removedKeys: [PeerAndThreadId] = []
|
||||
for (key, draft) in self.currentTypingDrafts {
|
||||
if draft.addedAtTimestamp + expirationTimeout >= timestamp {
|
||||
removedKeys.append(key)
|
||||
}
|
||||
}
|
||||
if !removedKeys.isEmpty {
|
||||
for key in removedKeys {
|
||||
self.currentTypingDrafts.removeValue(forKey: key)
|
||||
self.currentUpdatedTypingDrafts[key] = TypingDraftUpdate(value: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func renderIntermediateMessage(_ message: IntermediateMessage) -> Message {
|
||||
let renderedMessage = self.messageHistoryTable.renderMessage(message, peerTable: self.peerTable, threadIndexTable: self.messageHistoryThreadIndexTable, storyTable: self.storyTable)
|
||||
|
||||
|
|
@ -2427,7 +2597,7 @@ final class PostboxImpl {
|
|||
}
|
||||
|
||||
private func beforeCommit(currentTransaction: Transaction) -> (updatedTransactionStateVersion: Int64?, updatedMasterClientId: Int64?) {
|
||||
self.chatListTable.replay(historyOperationsByPeerId: self.currentOperationsByPeerId, updatedPeerChatListEmbeddedStates: self.currentUpdatedPeerChatListEmbeddedStates, updatedChatListInclusions: self.currentUpdatedChatListInclusions, messageHistoryTable: self.messageHistoryTable, peerChatInterfaceStateTable: self.peerChatInterfaceStateTable, operations: &self.currentChatListOperations)
|
||||
self.chatListTable.replay(postbox: self, historyOperationsByPeerId: self.currentOperationsByPeerId, updatedPeerChatListEmbeddedStates: self.currentUpdatedPeerChatListEmbeddedStates, updatedPeerCachedData: self.currentUpdatedCachedPeerData, updatedChatListInclusions: self.currentUpdatedChatListInclusions, messageHistoryTable: self.messageHistoryTable, peerChatInterfaceStateTable: self.peerChatInterfaceStateTable, operations: &self.currentChatListOperations)
|
||||
|
||||
self.peerChatTopTaggedMessageIdsTable.replay(historyOperationsByPeerId: self.currentOperationsByPeerId)
|
||||
|
||||
|
|
@ -2534,7 +2704,8 @@ final class PostboxImpl {
|
|||
storySubscriptionsEvents: self.currentStorySubscriptionsEvents,
|
||||
storyItemsEvents: self.currentStoryItemsEvents,
|
||||
currentStoryTopItemEvents: self.currentStoryTopItemEvents,
|
||||
storyEvents: self.currentStoryEvents
|
||||
storyEvents: self.currentStoryEvents,
|
||||
updatedTypingDrafts: self.currentUpdatedTypingDrafts
|
||||
)
|
||||
var updatedTransactionState: Int64?
|
||||
var updatedMasterClientId: Int64?
|
||||
|
|
@ -2598,6 +2769,12 @@ final class PostboxImpl {
|
|||
self.currentStoryTopItemEvents.removeAll()
|
||||
self.currentStoryEvents.removeAll()
|
||||
|
||||
if !self.currentUpdatedTypingDrafts.isEmpty {
|
||||
self.currentUpdatedTypingDrafts.removeAll()
|
||||
|
||||
self.restartTypingDraftExpirationTimerIfNeeded()
|
||||
}
|
||||
|
||||
for table in self.tables {
|
||||
table.beforeCommit()
|
||||
}
|
||||
|
|
@ -2759,7 +2936,7 @@ final class PostboxImpl {
|
|||
let currentData = self.cachedPeerDataTable.get(peerId)
|
||||
if let updatedData = update(peerId, currentData) {
|
||||
self.cachedPeerDataTable.set(id: peerId, data: updatedData)
|
||||
self.currentUpdatedCachedPeerData[peerId] = updatedData
|
||||
self.currentUpdatedCachedPeerData[peerId] = (currentData, updatedData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ final class PostboxTransaction {
|
|||
let currentUpdatedPeers: [PeerId: Peer]
|
||||
let currentUpdatedPeerNotificationSettings: [PeerId: (PeerNotificationSettings?, PeerNotificationSettings)]
|
||||
let currentUpdatedPeerNotificationBehaviorTimestamps: [PeerId: PeerNotificationSettingsBehaviorTimestamp]
|
||||
let currentUpdatedCachedPeerData: [PeerId: CachedPeerData]
|
||||
let currentUpdatedCachedPeerData: [PeerId: (previous: CachedPeerData?, updated: CachedPeerData)]
|
||||
let currentUpdatedPeerPresences: [PeerId: PeerPresence]
|
||||
let currentUpdatedPeerChatListEmbeddedStates: Set<PeerId>
|
||||
let currentUpdatedTotalUnreadStates: [PeerGroupId: ChatListTotalUnreadState]
|
||||
|
|
@ -56,6 +56,7 @@ final class PostboxTransaction {
|
|||
let storyItemsEvents: [StoryItemsTable.Event]
|
||||
let currentStoryTopItemEvents: [StoryTopItemsTable.Event]
|
||||
let storyEvents: [StoryTable.Event]
|
||||
let updatedTypingDrafts: [PeerAndThreadId: PostboxImpl.TypingDraftUpdate]
|
||||
|
||||
var isEmpty: Bool {
|
||||
if currentUpdatedState != nil {
|
||||
|
|
@ -223,6 +224,9 @@ final class PostboxTransaction {
|
|||
if !self.storyEvents.isEmpty {
|
||||
return false
|
||||
}
|
||||
if !self.updatedTypingDrafts.isEmpty {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -236,7 +240,7 @@ final class PostboxTransaction {
|
|||
currentUpdatedPeerNotificationSettings: [PeerId: (PeerNotificationSettings?,
|
||||
PeerNotificationSettings)],
|
||||
currentUpdatedPeerNotificationBehaviorTimestamps: [PeerId: PeerNotificationSettingsBehaviorTimestamp],
|
||||
currentUpdatedCachedPeerData: [PeerId: CachedPeerData],
|
||||
currentUpdatedCachedPeerData: [PeerId: (previous: CachedPeerData?, updated: CachedPeerData)],
|
||||
currentUpdatedPeerPresences: [PeerId: PeerPresence],
|
||||
currentUpdatedPeerChatListEmbeddedStates: Set<PeerId>,
|
||||
currentUpdatedTotalUnreadStates: [PeerGroupId: ChatListTotalUnreadState],
|
||||
|
|
@ -281,7 +285,8 @@ final class PostboxTransaction {
|
|||
storySubscriptionsEvents: [StorySubscriptionsTable.Event],
|
||||
storyItemsEvents: [StoryItemsTable.Event],
|
||||
currentStoryTopItemEvents: [StoryTopItemsTable.Event],
|
||||
storyEvents: [StoryTable.Event]
|
||||
storyEvents: [StoryTable.Event],
|
||||
updatedTypingDrafts: [PeerAndThreadId: PostboxImpl.TypingDraftUpdate]
|
||||
) {
|
||||
self.currentUpdatedState = currentUpdatedState
|
||||
self.currentPeerHoleOperations = currentPeerHoleOperations
|
||||
|
|
@ -337,5 +342,6 @@ final class PostboxTransaction {
|
|||
self.storyItemsEvents = storyItemsEvents
|
||||
self.currentStoryTopItemEvents = currentStoryTopItemEvents
|
||||
self.storyEvents = storyEvents
|
||||
self.updatedTypingDrafts = updatedTypingDrafts
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ public final class SeedConfiguration {
|
|||
public let initializeChatListWithHole: (topLevel: ChatListHole?, groups: ChatListHole?)
|
||||
public let messageHoles: [PeerId.Namespace: [MessageId.Namespace: Set<MessageTags>]]
|
||||
public let upgradedMessageHoles: [PeerId.Namespace: [MessageId.Namespace: Set<MessageTags>]]
|
||||
public let messageThreadHoles: [PeerId.Namespace: [MessageId.Namespace]]
|
||||
public let messageThreadHoles: (PeerId.Namespace, Int64?) -> [MessageId.Namespace]?
|
||||
public let messageTagsWithSummary: MessageTags
|
||||
public let messageTagsWithThreadSummary: MessageTags
|
||||
public let existingGlobalMessageTags: GlobalMessageTags
|
||||
|
|
@ -77,6 +77,7 @@ public final class SeedConfiguration {
|
|||
public let decodeMessageThreadInfo: (CodableEntry) -> Message.AssociatedThreadInfo?
|
||||
public let decodeAutoremoveTimeout: (CachedPeerData) -> Int32?
|
||||
public let decodeDisplayPeerAsRegularChat: (CachedPeerData) -> Bool
|
||||
public let decodeAssociatedChatListPeerId: (CachedPeerData) -> PeerId?
|
||||
public let isPeerUpgradeMessage: (Message) -> Bool
|
||||
public let automaticThreadIndexInfo: (PeerId, Int64) -> StoredMessageHistoryThreadInfo?
|
||||
public let customTagsFromAttributes: ([MessageAttribute]) -> [MemoryBuffer]
|
||||
|
|
@ -90,7 +91,7 @@ public final class SeedConfiguration {
|
|||
),
|
||||
messageHoles: [PeerId.Namespace: [MessageId.Namespace: Set<MessageTags>]],
|
||||
upgradedMessageHoles: [PeerId.Namespace: [MessageId.Namespace: Set<MessageTags>]],
|
||||
messageThreadHoles: [PeerId.Namespace: [MessageId.Namespace]],
|
||||
messageThreadHoles: @escaping (PeerId.Namespace, Int64?) -> [MessageId.Namespace]?,
|
||||
existingMessageTags: MessageTags,
|
||||
messageTagsWithSummary: MessageTags,
|
||||
messageTagsWithThreadSummary: MessageTags,
|
||||
|
|
@ -108,6 +109,7 @@ public final class SeedConfiguration {
|
|||
decodeMessageThreadInfo: @escaping (CodableEntry) -> Message.AssociatedThreadInfo?,
|
||||
decodeAutoremoveTimeout: @escaping (CachedPeerData) -> Int32?,
|
||||
decodeDisplayPeerAsRegularChat: @escaping (CachedPeerData) -> Bool,
|
||||
decodeAssociatedChatListPeerId: @escaping (CachedPeerData) -> PeerId?,
|
||||
isPeerUpgradeMessage: @escaping (Message) -> Bool,
|
||||
automaticThreadIndexInfo: @escaping (PeerId, Int64) -> StoredMessageHistoryThreadInfo?,
|
||||
customTagsFromAttributes: @escaping ([MessageAttribute]) -> [MemoryBuffer],
|
||||
|
|
@ -134,6 +136,7 @@ public final class SeedConfiguration {
|
|||
self.decodeMessageThreadInfo = decodeMessageThreadInfo
|
||||
self.decodeAutoremoveTimeout = decodeAutoremoveTimeout
|
||||
self.decodeDisplayPeerAsRegularChat = decodeDisplayPeerAsRegularChat
|
||||
self.decodeAssociatedChatListPeerId = decodeAssociatedChatListPeerId
|
||||
self.isPeerUpgradeMessage = isPeerUpgradeMessage
|
||||
self.automaticThreadIndexInfo = automaticThreadIndexInfo
|
||||
self.customTagsFromAttributes = customTagsFromAttributes
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ enum AccountStateMutationOperation {
|
|||
case AddSecretMessages([Api.EncryptedMessage])
|
||||
case ReadSecretOutbox(peerId: PeerId, maxTimestamp: Int32, actionTimestamp: Int32)
|
||||
case AddPeerInputActivity(chatPeerId: PeerActivitySpace, peerId: PeerId?, activity: PeerInputActivity?)
|
||||
case AddPeerLiveTypingDraftUpdate(peerAndThreadId: PeerAndThreadId, id: Int64, timestamp: Int32, peerId: PeerId, text: String, entities: [MessageTextEntity])
|
||||
case UpdatePinnedItemIds(PeerGroupId, AccountStateUpdatePinnedItemIdsOperation)
|
||||
case UpdatePinnedSavedItemIds(AccountStateUpdatePinnedItemIdsOperation)
|
||||
case UpdatePinnedTopic(peerId: PeerId, threadId: Int64, isPinned: Bool)
|
||||
|
|
@ -592,6 +593,10 @@ struct AccountMutableState {
|
|||
self.addOperation(.AddPeerInputActivity(chatPeerId: chatPeerId, peerId: peerId, activity: activity))
|
||||
}
|
||||
|
||||
mutating func addPeerLiveTypingDraftUpdate(peerAndThreadId: PeerAndThreadId, id: Int64, timestamp: Int32, peerId: PeerId, text: String, entities: [MessageTextEntity]) {
|
||||
self.addOperation(.AddPeerLiveTypingDraftUpdate(peerAndThreadId: peerAndThreadId, id: id, timestamp: timestamp, peerId: peerId, text: text, entities: entities))
|
||||
}
|
||||
|
||||
mutating func addUpdatePinnedItemIds(groupId: PeerGroupId, operation: AccountStateUpdatePinnedItemIdsOperation) {
|
||||
self.addOperation(.UpdatePinnedItemIds(groupId, operation))
|
||||
}
|
||||
|
|
@ -714,7 +719,7 @@ struct AccountMutableState {
|
|||
|
||||
mutating func addOperation(_ operation: AccountStateMutationOperation) {
|
||||
switch operation {
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery, .UpdateMonoForumNoPaidException:
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .AddPeerLiveTypingDraftUpdate, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery, .UpdateMonoForumNoPaidException:
|
||||
break
|
||||
case let .AddMessages(messages, location):
|
||||
for message in messages {
|
||||
|
|
|
|||
|
|
@ -1071,7 +1071,7 @@ extension StoreMessage {
|
|||
|
||||
storeFlags.insert(.CanBeGroupedIntoFeed)
|
||||
|
||||
self.init(id: MessageId(peerId: peerId, namespace: namespace, id: id), globallyUniqueId: nil, groupingKey: groupingId, threadId: threadId, timestamp: date, flags: storeFlags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: forwardInfo, authorId: authorId, text: messageText, attributes: attributes, media: medias)
|
||||
self.init(id: MessageId(peerId: peerId, namespace: namespace, id: id), customStableId: nil, globallyUniqueId: nil, groupingKey: groupingId, threadId: threadId, timestamp: date, flags: storeFlags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: forwardInfo, authorId: authorId, text: messageText, attributes: attributes, media: medias)
|
||||
case .messageEmpty:
|
||||
return nil
|
||||
case let .messageService(flags, id, fromId, chatPeerId, savedPeerId, replyTo, date, action, reactions, ttlPeriod):
|
||||
|
|
@ -1210,7 +1210,7 @@ extension StoreMessage {
|
|||
storeFlags.insert(.ReactionsArePossible)
|
||||
}
|
||||
|
||||
self.init(id: MessageId(peerId: peerId, namespace: namespace, id: id), globallyUniqueId: nil, groupingKey: nil, threadId: threadId, timestamp: date, flags: storeFlags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: attributes, media: media)
|
||||
self.init(id: MessageId(peerId: peerId, namespace: namespace, id: id), customStableId: nil, globallyUniqueId: nil, groupingKey: nil, threadId: threadId, timestamp: date, flags: storeFlags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: attributes, media: media)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,7 +202,11 @@ public enum CreateForumChannelTopicError {
|
|||
}
|
||||
|
||||
func _internal_createForumChannelTopic(account: Account, peerId: PeerId, title: String, iconColor: Int32, iconFileId: Int64?) -> Signal<Int64, CreateForumChannelTopicError> {
|
||||
return account.postbox.transaction { transaction -> Peer? in
|
||||
return _internal_createForumChannelTopic(postbox: account.postbox, network: account.network, stateManager: account.stateManager, accountPeerId: account.peerId, peerId: peerId, title: title, iconColor: iconColor, iconFileId: iconFileId)
|
||||
}
|
||||
|
||||
func _internal_createForumChannelTopic(postbox: Postbox, network: Network, stateManager: AccountStateManager, accountPeerId: PeerId, peerId: PeerId, title: String, iconColor: Int32, iconFileId: Int64?) -> Signal<Int64, CreateForumChannelTopicError> {
|
||||
return postbox.transaction { transaction -> Peer? in
|
||||
return transaction.getPeer(peerId)
|
||||
}
|
||||
|> castError(CreateForumChannelTopicError.self)
|
||||
|
|
@ -218,7 +222,7 @@ func _internal_createForumChannelTopic(account: Account, peerId: PeerId, title:
|
|||
flags |= (1 << 3)
|
||||
}
|
||||
flags |= (1 << 0)
|
||||
return account.network.request(Api.functions.channels.createForumTopic(
|
||||
return network.request(Api.functions.channels.createForumTopic(
|
||||
flags: flags,
|
||||
channel: inputChannel,
|
||||
title: title,
|
||||
|
|
@ -231,14 +235,14 @@ func _internal_createForumChannelTopic(account: Account, peerId: PeerId, title:
|
|||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Int64, CreateForumChannelTopicError> in
|
||||
account.stateManager.addUpdates(result)
|
||||
stateManager.addUpdates(result)
|
||||
|
||||
var topicId: Int64?
|
||||
topicId = nil
|
||||
for update in result.allUpdates {
|
||||
switch update {
|
||||
case let .updateNewChannelMessage(message, _, _):
|
||||
if let message = StoreMessage(apiMessage: message, accountPeerId: account.peerId, peerIsForum: peer.isForum) {
|
||||
if let message = StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: peer.isForum) {
|
||||
if case let .Id(id) = message.id {
|
||||
topicId = Int64(id.id)
|
||||
}
|
||||
|
|
@ -249,12 +253,12 @@ func _internal_createForumChannelTopic(account: Account, peerId: PeerId, title:
|
|||
}
|
||||
|
||||
if let topicId {
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
return postbox.transaction { transaction -> Void in
|
||||
transaction.removeHole(peerId: peerId, threadId: topicId, namespace: Namespaces.Message.Cloud, space: .everywhere, range: 1 ... (Int32.max - 1))
|
||||
}
|
||||
|> castError(CreateForumChannelTopicError.self)
|
||||
|> mapToSignal { _ -> Signal<Int64, CreateForumChannelTopicError> in
|
||||
return resolveForumThreads(accountPeerId: account.peerId, postbox: account.postbox, source: .network(account.network), additionalPeers: AccumulatedPeers(), ids: [PeerAndBoundThreadId(peerId: peerId, threadId: topicId)])
|
||||
return resolveForumThreads(accountPeerId: accountPeerId, postbox: postbox, source: .network(network), additionalPeers: AccumulatedPeers(), ids: [PeerAndBoundThreadId(peerId: peerId, threadId: topicId)])
|
||||
|> castError(CreateForumChannelTopicError.self)
|
||||
|> map { _ -> Int64 in
|
||||
return topicId
|
||||
|
|
|
|||
|
|
@ -828,7 +828,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
|
|||
threadId = 1
|
||||
}
|
||||
|
||||
storeMessages.append(StoreMessage(peerId: peerId, namespace: messageNamespace, globallyUniqueId: randomId, groupingKey: localGroupingKey, threadId: threadId, timestamp: effectiveTimestamp, flags: flags, tags: tags, globalTags: globalTags, localTags: localTags, forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: mediaList))
|
||||
storeMessages.append(StoreMessage(peerId: peerId, namespace: messageNamespace, customStableId: nil, globallyUniqueId: randomId, groupingKey: localGroupingKey, threadId: threadId, timestamp: effectiveTimestamp, flags: flags, tags: tags, globalTags: globalTags, localTags: localTags, forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: mediaList))
|
||||
case let .forward(source, threadId, grouping, requestedAttributes, _):
|
||||
let sourceMessage = transaction.getMessage(source)
|
||||
if let sourceMessage = sourceMessage, let author = sourceMessage.author ?? sourceMessage.peers[sourceMessage.id.peerId] {
|
||||
|
|
@ -1073,7 +1073,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
|
|||
threadId = 1
|
||||
}
|
||||
|
||||
storeMessages.append(StoreMessage(peerId: peerId, namespace: messageNamespace, globallyUniqueId: randomId, groupingKey: localGroupingKey, threadId: threadId, timestamp: effectiveTimestamp, flags: flags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: forwardInfo, authorId: authorId, text: messageText, attributes: attributes, media: augmentedMediaList))
|
||||
storeMessages.append(StoreMessage(peerId: peerId, namespace: messageNamespace, customStableId: nil, globallyUniqueId: randomId, groupingKey: localGroupingKey, threadId: threadId, timestamp: effectiveTimestamp, flags: flags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: forwardInfo, authorId: authorId, text: messageText, attributes: attributes, media: augmentedMediaList))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -584,7 +584,7 @@ if "".isEmpty {
|
|||
}
|
||||
}
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: updatedMedia))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: updatedMedia))
|
||||
})
|
||||
}
|
||||
return .done(media)
|
||||
|
|
@ -1035,7 +1035,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
|
|||
}
|
||||
}
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: updatedMedia))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: updatedMedia))
|
||||
})
|
||||
}
|
||||
return .done(media)
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ private func generatePeerMediaMessage(network: Network, accountPeerId: EnginePee
|
|||
media.append(TelegramMediaAction(action: .setChatWallpaper(wallpaper: wallpaper, forBoth: forBoth)))
|
||||
}
|
||||
|
||||
return StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: accountPeerId, text: "", attributes: attributes, media: media)
|
||||
return StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, customStableId: nil, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: accountPeerId, text: "", attributes: attributes, media: media)
|
||||
}
|
||||
|
||||
private final class PendingPeerMediaUploadContext {
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ func _internal_requestEditLiveLocation(postbox: Postbox, network: Network, state
|
|||
}
|
||||
var updatedLocalTags = currentMessage.localTags
|
||||
updatedLocalTags.remove(.OutgoingLiveLocation)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: updatedLocalTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: updatedLocalTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1193,7 +1193,7 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
|
|||
}
|
||||
}
|
||||
|
||||
let message = StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, globallyUniqueId: nil, groupingKey: nil, threadId: nil, timestamp: date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: peerId, text: messageText, attributes: attributes, media: medias)
|
||||
let message = StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, customStableId: nil, globallyUniqueId: nil, groupingKey: nil, threadId: nil, timestamp: date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: peerId, text: messageText, attributes: attributes, media: medias)
|
||||
updatedState.addMessages([message], location: .UpperHistoryBlock)
|
||||
}
|
||||
}
|
||||
|
|
@ -1470,15 +1470,22 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
|
|||
let channelPeerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
|
||||
let threadId = topMsgId.flatMap { Int64($0) }
|
||||
|
||||
let activity = PeerInputActivity(apiType: type, peerId: nil, timestamp: date)
|
||||
var category: PeerActivitySpace.Category = .global
|
||||
if case .speakingInGroupCall = activity {
|
||||
category = .voiceChat
|
||||
} else if let threadId = threadId {
|
||||
category = .thread(threadId)
|
||||
if case let .sendMessageTextDraftAction(randomId, text) = type {
|
||||
switch text {
|
||||
case let .textWithEntities(text, entities):
|
||||
updatedState.addPeerLiveTypingDraftUpdate(peerAndThreadId: PeerAndThreadId(peerId: channelPeerId, threadId: threadId), id: randomId, timestamp: date, peerId: userId.peerId, text: text, entities: messageTextEntitiesFromApiEntities(entities))
|
||||
}
|
||||
} else {
|
||||
let activity = PeerInputActivity(apiType: type, peerId: nil, timestamp: date)
|
||||
var category: PeerActivitySpace.Category = .global
|
||||
if case .speakingInGroupCall = activity {
|
||||
category = .voiceChat
|
||||
} else if let threadId = threadId {
|
||||
category = .thread(threadId)
|
||||
}
|
||||
|
||||
updatedState.addPeerInputActivity(chatPeerId: PeerActivitySpace(peerId: channelPeerId, category: category), peerId: userId.peerId, activity: activity)
|
||||
}
|
||||
|
||||
updatedState.addPeerInputActivity(chatPeerId: PeerActivitySpace(peerId: channelPeerId, category: category), peerId: userId.peerId, activity: activity)
|
||||
}
|
||||
case let .updateEncryptedChatTyping(chatId):
|
||||
if let date = updatesDate, date + 60 > serverTime {
|
||||
|
|
@ -3583,7 +3590,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
|
|||
var currentAddQuickReplyMessages: OptimizeAddMessagesState?
|
||||
for operation in operations {
|
||||
switch operation {
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery, .UpdateMonoForumNoPaidException:
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .AddPeerLiveTypingDraftUpdate, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery, .UpdateMonoForumNoPaidException:
|
||||
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
|
||||
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
|
||||
}
|
||||
|
|
@ -3767,6 +3774,29 @@ func replayFinalState(
|
|||
|
||||
var addedOperationIncomingMessageIds: [MessageId] = []
|
||||
var addedConferenceInvitationMessagesIds: [MessageId] = []
|
||||
|
||||
enum LiveTypingDraftUpdate {
|
||||
struct Update {
|
||||
var id: Int64
|
||||
var authorId: PeerId
|
||||
var timestamp: Int32
|
||||
var text: String
|
||||
var entities: [MessageTextEntity]
|
||||
|
||||
init(id: Int64, authorId: PeerId, timestamp: Int32, text: String, entities: [MessageTextEntity]) {
|
||||
self.id = id
|
||||
self.authorId = authorId
|
||||
self.timestamp = timestamp
|
||||
self.text = text
|
||||
self.entities = entities
|
||||
}
|
||||
}
|
||||
|
||||
case update(Update)
|
||||
case cancel
|
||||
}
|
||||
|
||||
var liveTypingDraftUpdates: [PeerAndThreadId: LiveTypingDraftUpdate] = [:]
|
||||
|
||||
for operation in finalState.state.operations {
|
||||
switch operation {
|
||||
|
|
@ -3965,6 +3995,24 @@ func replayFinalState(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
var messages = messages
|
||||
|
||||
if case .UpperHistoryBlock = location {
|
||||
for i in 0 ..< messages.count {
|
||||
let message = messages[i]
|
||||
let chatPeerId = message.id.peerId
|
||||
let key = PeerAndThreadId(peerId: chatPeerId, threadId: message.threadId)
|
||||
|
||||
if liveTypingDraftUpdates[key] != nil {
|
||||
liveTypingDraftUpdates[key] = .cancel
|
||||
} else if let currentDraft = transaction.getCurrentTypingDraft(location: key) {
|
||||
liveTypingDraftUpdates[key] = .cancel
|
||||
messages[i] = messages[i].withUpdatedCustomStableId(currentDraft.stableId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = transaction.addMessages(messages, location: location)
|
||||
if case .UpperHistoryBlock = location {
|
||||
for message in messages {
|
||||
|
|
@ -3982,6 +4030,7 @@ func replayFinalState(
|
|||
} else {
|
||||
updatedTypingActivities[PeerActivitySpace(peerId: chatPeerId, category: .thread(threadId))]![authorId] = activityValue
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4317,7 +4366,7 @@ func replayFinalState(
|
|||
return .skip
|
||||
}
|
||||
attributes[j] = ReplyThreadMessageAttribute(count: attribute.count, latestUsers: attribute.latestUsers, commentsPeerId: attribute.commentsPeerId, maxMessageId: attribute.maxMessageId, maxReadMessageId: readMaxId)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
}
|
||||
}
|
||||
return .skip
|
||||
|
|
@ -4578,7 +4627,7 @@ func replayFinalState(
|
|||
return .skip
|
||||
}
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
case let .MergePeerPresences(statuses, explicit):
|
||||
|
|
@ -4622,6 +4671,14 @@ func replayFinalState(
|
|||
} else if chatPeerId.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
updatedSecretChatTypingActivities.insert(chatPeerId.peerId)
|
||||
}
|
||||
case let .AddPeerLiveTypingDraftUpdate(peerAndThreadId, id, timestamp, authorId, text, entities):
|
||||
liveTypingDraftUpdates[peerAndThreadId] = .update(LiveTypingDraftUpdate.Update(
|
||||
id: id,
|
||||
authorId: authorId,
|
||||
timestamp: timestamp,
|
||||
text: text,
|
||||
entities: entities
|
||||
))
|
||||
case let .UpdatePinnedItemIds(groupId, pinnedOperation):
|
||||
switch pinnedOperation {
|
||||
case let .pin(itemId):
|
||||
|
|
@ -4733,7 +4790,7 @@ func replayFinalState(
|
|||
break loop
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
case let .UpdateMessageForwardsCount(id, count):
|
||||
transaction.updateMessage(id, update: { currentMessage in
|
||||
|
|
@ -4748,7 +4805,7 @@ func replayFinalState(
|
|||
break loop
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
case let .UpdateInstalledStickerPacks(operation):
|
||||
stickerPackOperations.append(operation)
|
||||
|
|
@ -4932,7 +4989,7 @@ func replayFinalState(
|
|||
tags.remove(.unseenReaction)
|
||||
}
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
case .UpdateAttachMenuBots:
|
||||
syncAttachMenuBots = true
|
||||
|
|
@ -4957,6 +5014,7 @@ func replayFinalState(
|
|||
|
||||
return .update(StoreMessage(
|
||||
id: currentMessage.id,
|
||||
customStableId: nil,
|
||||
globallyUniqueId: currentMessage.globallyUniqueId,
|
||||
groupingKey: currentMessage.groupingKey,
|
||||
threadId: currentMessage.threadId,
|
||||
|
|
@ -5000,7 +5058,7 @@ func replayFinalState(
|
|||
}
|
||||
}
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: media))
|
||||
})
|
||||
case let .ResetForumTopic(topicId, data, pts):
|
||||
if finalState.state.resetForumTopicLists[topicId.peerId] == nil {
|
||||
|
|
@ -5691,6 +5749,26 @@ func replayFinalState(
|
|||
_internal_setStarsReactionDefaultPrivacy(privacy: updatedStarsReactionsDefaultPrivacy, transaction: transaction)
|
||||
}
|
||||
|
||||
if !liveTypingDraftUpdates.isEmpty {
|
||||
transaction.combineTypingDrafts(locations: Set(liveTypingDraftUpdates.keys), update: { key, current in
|
||||
guard let update = liveTypingDraftUpdates[key] else {
|
||||
return current
|
||||
}
|
||||
switch update {
|
||||
case let .update(update):
|
||||
return (
|
||||
update.id,
|
||||
update.authorId,
|
||||
update.timestamp,
|
||||
update.text,
|
||||
[TextEntitiesMessageAttribute(entities: update.entities)]
|
||||
)
|
||||
case .cancel:
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return AccountReplayedFinalState(
|
||||
state: finalState,
|
||||
addedIncomingMessageIds: addedIncomingMessageIds,
|
||||
|
|
|
|||
|
|
@ -450,7 +450,7 @@ public final class AccountViewTracker {
|
|||
break
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -798,7 +798,7 @@ public final class AccountViewTracker {
|
|||
if !foundReplies, let repliesCount = repliesCount {
|
||||
attributes.append(ReplyThreadMessageAttribute(count: repliesCount, latestUsers: recentRepliersPeerIds ?? [], commentsPeerId: commentsChannelId, maxMessageId: repliesMaxId, maxReadMessageId: repliesReadMaxId))
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -898,7 +898,7 @@ public final class AccountViewTracker {
|
|||
} else {
|
||||
tags.remove(.unseenReaction)
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
default:
|
||||
break
|
||||
|
|
@ -1595,7 +1595,7 @@ public final class AccountViewTracker {
|
|||
}
|
||||
var tags = currentMessage.tags
|
||||
tags.remove(.unseenPersonalMessage)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1645,7 +1645,7 @@ public final class AccountViewTracker {
|
|||
break loop
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
|
||||
transaction.setPendingMessageAction(type: .consumeUnseenPersonalMessage, id: id, action: ConsumePersonalMessageAction())
|
||||
|
|
@ -1678,7 +1678,7 @@ public final class AccountViewTracker {
|
|||
}
|
||||
var tags = currentMessage.tags
|
||||
tags.remove(.unseenReaction)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1719,7 +1719,7 @@ public final class AccountViewTracker {
|
|||
}
|
||||
var tags = currentMessage.tags
|
||||
tags.remove(.unseenReaction)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
|
||||
if transaction.getPendingMessageAction(type: .readReaction, id: id) == nil {
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
|||
}
|
||||
}
|
||||
|
||||
let updatedMessageValue = StoreMessage(id: updatedId, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: updatedTimestamp ?? currentMessage.timestamp, flags: [], tags: tags, globalTags: globalTags, localTags: currentMessage.localTags, forwardInfo: forwardInfo, authorId: currentMessage.author?.id, text: text, attributes: attributes, media: media)
|
||||
let updatedMessageValue = StoreMessage(id: updatedId, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: updatedTimestamp ?? currentMessage.timestamp, flags: [], tags: tags, globalTags: globalTags, localTags: currentMessage.localTags, forwardInfo: forwardInfo, authorId: currentMessage.author?.id, text: text, attributes: attributes, media: media)
|
||||
updatedMessage = updatedMessageValue
|
||||
|
||||
return .update(updatedMessageValue)
|
||||
|
|
@ -546,7 +546,7 @@ func applyUpdateGroupMessages(postbox: Postbox, stateManager: AccountStateManage
|
|||
|
||||
let (tags, globalTags) = tagsForStoreMessage(incoming: currentMessage.flags.contains(.Incoming), attributes: attributes, media: media, textEntities: entitiesAttribute?.entities, isPinned: currentMessage.tags.contains(.pinned))
|
||||
|
||||
return .update(StoreMessage(id: updatedId, globallyUniqueId: nil, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: updatedMessage.timestamp, flags: [], tags: tags, globalTags: globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: text, attributes: attributes, media: media))
|
||||
return .update(StoreMessage(id: updatedId, customStableId: nil, globallyUniqueId: nil, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: updatedMessage.timestamp, flags: [], tags: tags, globalTags: globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: text, attributes: attributes, media: media))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -883,7 +883,7 @@ private func validateBatch(postbox: Postbox, network: Network, transaction: Tran
|
|||
|
||||
let updatedFlags = StoreMessageFlags(currentMessage.flags)
|
||||
|
||||
return .update(StoreMessage(id: message.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: updatedFlags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: message.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: updatedFlags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -923,7 +923,7 @@ private func validateBatch(postbox: Postbox, network: Network, transaction: Tran
|
|||
default:
|
||||
break
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -956,7 +956,7 @@ private func validateBatch(postbox: Postbox, network: Network, transaction: Tran
|
|||
default:
|
||||
break
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
} else {
|
||||
_internal_deleteMessages(transaction: transaction, mediaBox: postbox.mediaBox, ids: [id])
|
||||
|
|
@ -991,7 +991,7 @@ private func validateBatch(postbox: Postbox, network: Network, transaction: Tran
|
|||
default:
|
||||
break
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1124,7 +1124,7 @@ private func validateReplyThreadBatch(postbox: Postbox, network: Network, transa
|
|||
|
||||
let updatedFlags = StoreMessageFlags(currentMessage.flags)
|
||||
|
||||
return .update(StoreMessage(id: message.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: updatedFlags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: message.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: updatedFlags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ func managedAutoremoveMessageOperations(network: Network, postbox: Postbox, isRe
|
|||
break
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: updatedMedia))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: updatedMedia))
|
||||
})
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ private func synchronizeConsumeMessageContents(transaction: Transaction, postbox
|
|||
}
|
||||
var updatedTags = currentMessage.tags
|
||||
updatedTags.remove(.unseenPersonalMessage)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -302,7 +302,7 @@ private func synchronizeConsumeMessageContents(transaction: Transaction, postbox
|
|||
}
|
||||
var updatedTags = currentMessage.tags
|
||||
updatedTags.remove(.unseenPersonalMessage)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -344,7 +344,7 @@ private func synchronizeReadMessageReactions(transaction: Transaction, postbox:
|
|||
}
|
||||
var updatedTags = currentMessage.tags
|
||||
updatedTags.remove(.unseenReaction)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -371,7 +371,7 @@ private func synchronizeReadMessageReactions(transaction: Transaction, postbox:
|
|||
}
|
||||
var updatedTags = currentMessage.tags
|
||||
updatedTags.remove(.unseenReaction)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1822,7 +1822,7 @@ private func sendMessage(auxiliaryMethods: AccountAuxiliaryMethods, postbox: Pos
|
|||
}
|
||||
}
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: timestamp, flags: flags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: updatedMedia))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: timestamp, flags: flags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: updatedMedia))
|
||||
})
|
||||
|
||||
maybeReadSecretOutgoingMessage(transaction: transaction, index: MessageIndex(id: message.id, timestamp: timestamp))
|
||||
|
|
@ -1982,6 +1982,7 @@ private func sendStandaloneMessage(auxiliaryMethods: AccountAuxiliaryMethods, po
|
|||
let storedMessage = StoreMessage(
|
||||
peerId: peerId,
|
||||
namespace: Namespaces.Message.Local,
|
||||
customStableId: nil,
|
||||
globallyUniqueId: globallyUniqueId,
|
||||
groupingKey: nil,
|
||||
threadId: nil,
|
||||
|
|
@ -2062,7 +2063,7 @@ private func sendServiceActionMessage(postbox: Postbox, network: Network, peerId
|
|||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: timestamp, flags: flags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: timestamp, flags: flags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
})
|
||||
|
||||
if let resultTimestamp = resultTimestamp {
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ func markUnseenPersonalMessage(transaction: Transaction, id: MessageId, addSynch
|
|||
break loop
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
|
||||
if addSynchronizeAction {
|
||||
|
|
@ -348,7 +348,7 @@ func markUnseenReactionMessage(transaction: Transaction, id: MessageId, addSynch
|
|||
}
|
||||
var tags = currentMessage.tags
|
||||
tags.remove(.unseenReaction)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
|
||||
if addSynchronizeAction {
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ public func updateMessageReactionsInteractively(account: Account, messageIds: [M
|
|||
|
||||
attributes.append(PendingReactionsMessageAttribute(accountPeerId: account.peerId, reactions: mappedReactions, isLarge: isLarge, storeAsRecentlyUsed: storeAsRecentlyUsed, isTags: currentMessage.areReactionsTags(accountPeerId: account.peerId)))
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -217,7 +217,7 @@ func _internal_sendStarsReactionsInteractively(account: Account, messageId: Mess
|
|||
|
||||
resolvedPrivacyValue = resolvedPrivacy
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
|
||||
return resolvedPrivacyValue
|
||||
|
|
@ -240,7 +240,7 @@ func cancelPendingSendStarsReactionInteractively(account: Account, messageId: Me
|
|||
}
|
||||
}
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
|> ignoreValues
|
||||
|
|
@ -281,7 +281,7 @@ func _internal_updateStarsReactionPrivacy(account: Account, messageId: MessageId
|
|||
attributes[j] = ReactionsMessageAttribute(canViewList: attribute.canViewList, isTags: attribute.isTags, reactions: attribute.reactions, recentPeers: attribute.recentPeers, topPeers: updatedTopPeers)
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
|
||||
var privacyPeerId: PeerId?
|
||||
|
|
@ -392,7 +392,7 @@ private func requestUpdateMessageReaction(postbox: Postbox, network: Network, st
|
|||
if let reactions = reactions {
|
||||
attributes.append(reactions)
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
stateManager.addUpdates(result)
|
||||
}
|
||||
|
|
@ -483,7 +483,7 @@ private func requestSendStarsReaction(postbox: Postbox, network: Network, stateM
|
|||
if let reactions {
|
||||
attributes.append(reactions)
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
stateManager.addUpdates(result)
|
||||
}
|
||||
|
|
@ -706,7 +706,7 @@ private func synchronizeMessageReactions(transaction: Transaction, postbox: Post
|
|||
break loop
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
|> ignoreValues
|
||||
|
|
@ -730,7 +730,7 @@ private func synchronizeMessageStarsReactions(transaction: Transaction, postbox:
|
|||
break loop
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
|> ignoreValues
|
||||
|
|
|
|||
|
|
@ -200,126 +200,124 @@ private final class PeerGlobalInputActivityContext {
|
|||
}
|
||||
|
||||
final class PeerInputActivityManager {
|
||||
private let queue = Queue()
|
||||
|
||||
private var nextEpisodeId: Int32 = 0
|
||||
private var nextUpdateId: Int32 = 0
|
||||
private var contexts: [PeerActivitySpace: PeerInputActivityContext] = [:]
|
||||
private var globalContext: PeerGlobalInputActivityContext?
|
||||
|
||||
func activities(peerId: PeerActivitySpace) -> Signal<[(PeerId, PeerInputActivityRecord)], NoError> {
|
||||
let queue = self.queue
|
||||
return Signal { [weak self] subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
queue.async {
|
||||
if let strongSelf = self {
|
||||
let context: PeerInputActivityContext
|
||||
if let currentContext = strongSelf.contexts[peerId] {
|
||||
context = currentContext
|
||||
} else {
|
||||
context = PeerInputActivityContext(queue: queue, notifyEmpty: {
|
||||
if let strongSelf = self {
|
||||
strongSelf.contexts.removeValue(forKey: peerId)
|
||||
|
||||
if let globalContext = strongSelf.globalContext {
|
||||
let activities = strongSelf.collectActivities()
|
||||
globalContext.notify(activities)
|
||||
}
|
||||
}
|
||||
}, notifyUpdated: {
|
||||
if let strongSelf = self, let globalContext = strongSelf.globalContext {
|
||||
let activities = strongSelf.collectActivities()
|
||||
globalContext.notify(activities)
|
||||
}
|
||||
})
|
||||
strongSelf.contexts[peerId] = context
|
||||
}
|
||||
let index = context.addSubscriber({ next in
|
||||
subscriber.putNext(next)
|
||||
})
|
||||
subscriber.putNext(context.topActivities())
|
||||
disposable.set(ActionDisposable {
|
||||
queue.async {
|
||||
if let strongSelf = self {
|
||||
if let currentContext = strongSelf.contexts[peerId] {
|
||||
currentContext.removeSubscriber(index)
|
||||
if currentContext.isEmpty() {
|
||||
strongSelf.contexts.removeValue(forKey: peerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
|
||||
private func collectActivities() -> [PeerActivitySpace: [(PeerId, PeerInputActivityRecord)]] {
|
||||
assert(self.queue.isCurrent())
|
||||
private final class Impl {
|
||||
let queue: Queue
|
||||
|
||||
var dict: [PeerActivitySpace: [(PeerId, PeerInputActivityRecord)]] = [:]
|
||||
for (chatPeerId, context) in self.contexts {
|
||||
dict[chatPeerId] = context.topActivities()
|
||||
var nextEpisodeId: Int32 = 0
|
||||
var nextUpdateId: Int32 = 0
|
||||
var contexts: [PeerActivitySpace: PeerInputActivityContext] = [:]
|
||||
var globalContext: PeerGlobalInputActivityContext?
|
||||
|
||||
init(queue: Queue) {
|
||||
self.queue = queue
|
||||
}
|
||||
return dict
|
||||
}
|
||||
|
||||
func allActivities() -> Signal<[PeerActivitySpace: [(PeerId, PeerInputActivityRecord)]], NoError> {
|
||||
let queue = self.queue
|
||||
return Signal { [weak self] subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
queue.async {
|
||||
if let strongSelf = self {
|
||||
let context: PeerGlobalInputActivityContext
|
||||
if let current = strongSelf.globalContext {
|
||||
context = current
|
||||
} else {
|
||||
context = PeerGlobalInputActivityContext()
|
||||
strongSelf.globalContext = context
|
||||
|
||||
func activities(peerId: PeerActivitySpace, onNext: @escaping ([(PeerId, PeerInputActivityRecord)]) -> Void) -> Disposable {
|
||||
let context: PeerInputActivityContext
|
||||
if let currentContext = self.contexts[peerId] {
|
||||
context = currentContext
|
||||
} else {
|
||||
context = PeerInputActivityContext(queue: queue, notifyEmpty: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let index = context.addSubscriber({ next in
|
||||
subscriber.putNext(next)
|
||||
})
|
||||
subscriber.putNext(strongSelf.collectActivities())
|
||||
self.contexts.removeValue(forKey: peerId)
|
||||
|
||||
disposable.set(ActionDisposable {
|
||||
queue.async {
|
||||
if let strongSelf = self {
|
||||
if let currentContext = strongSelf.globalContext {
|
||||
currentContext.removeSubscriber(index)
|
||||
if currentContext.isEmpty {
|
||||
strongSelf.globalContext = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if let globalContext = self.globalContext {
|
||||
let activities = self.collectActivities()
|
||||
globalContext.notify(activities)
|
||||
}
|
||||
}, notifyUpdated: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let globalContext = self.globalContext {
|
||||
let activities = self.collectActivities()
|
||||
globalContext.notify(activities)
|
||||
}
|
||||
})
|
||||
self.contexts[peerId] = context
|
||||
}
|
||||
let index = context.addSubscriber({ next in
|
||||
onNext(next)
|
||||
})
|
||||
onNext(context.topActivities())
|
||||
let queue = self.queue
|
||||
return ActionDisposable { [weak self] in
|
||||
queue.async {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let currentContext = self.contexts[peerId] {
|
||||
currentContext.removeSubscriber(index)
|
||||
if currentContext.isEmpty() {
|
||||
self.contexts.removeValue(forKey: peerId)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
|
||||
func addActivity(chatPeerId: PeerActivitySpace, peerId: PeerId, activity: PeerInputActivity, episodeId: Int32? = nil) {
|
||||
self.queue.async {
|
||||
|
||||
func allActivities(onNext: @escaping ([PeerActivitySpace: [(PeerId, PeerInputActivityRecord)]]) -> Void) -> Disposable {
|
||||
let context: PeerGlobalInputActivityContext
|
||||
if let current = self.globalContext {
|
||||
context = current
|
||||
} else {
|
||||
context = PeerGlobalInputActivityContext()
|
||||
self.globalContext = context
|
||||
}
|
||||
let index = context.addSubscriber({ next in
|
||||
onNext(next)
|
||||
})
|
||||
onNext(self.collectActivities())
|
||||
|
||||
let queue = self.queue
|
||||
return ActionDisposable { [weak self] in
|
||||
queue.async {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let currentContext = self.globalContext {
|
||||
currentContext.removeSubscriber(index)
|
||||
if currentContext.isEmpty {
|
||||
self.globalContext = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func collectActivities() -> [PeerActivitySpace: [(PeerId, PeerInputActivityRecord)]] {
|
||||
assert(self.queue.isCurrent())
|
||||
|
||||
var dict: [PeerActivitySpace: [(PeerId, PeerInputActivityRecord)]] = [:]
|
||||
for (chatPeerId, context) in self.contexts {
|
||||
dict[chatPeerId] = context.topActivities()
|
||||
}
|
||||
return dict
|
||||
}
|
||||
|
||||
func addActivity(chatPeerId: PeerActivitySpace, peerId: PeerId, activity: PeerInputActivity, episodeId: Int32?) {
|
||||
let context: PeerInputActivityContext
|
||||
if let currentContext = self.contexts[chatPeerId] {
|
||||
context = currentContext
|
||||
} else {
|
||||
context = PeerInputActivityContext(queue: self.queue, notifyEmpty: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.contexts.removeValue(forKey: chatPeerId)
|
||||
|
||||
if let globalContext = strongSelf.globalContext {
|
||||
let activities = strongSelf.collectActivities()
|
||||
globalContext.notify(activities)
|
||||
}
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.contexts.removeValue(forKey: chatPeerId)
|
||||
|
||||
if let globalContext = self.globalContext {
|
||||
let activities = self.collectActivities()
|
||||
globalContext.notify(activities)
|
||||
}
|
||||
}, notifyUpdated: { [weak self] in
|
||||
if let strongSelf = self, let globalContext = strongSelf.globalContext {
|
||||
let activities = strongSelf.collectActivities()
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let globalContext = self.globalContext {
|
||||
let activities = self.collectActivities()
|
||||
globalContext.notify(activities)
|
||||
}
|
||||
})
|
||||
|
|
@ -347,10 +345,8 @@ final class PeerInputActivityManager {
|
|||
globalContext.notify(activities)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeActivity(chatPeerId: PeerActivitySpace, peerId: PeerId, activity: PeerInputActivity, episodeId: Int32? = nil) {
|
||||
self.queue.async {
|
||||
|
||||
func removeActivity(chatPeerId: PeerActivitySpace, peerId: PeerId, activity: PeerInputActivity, episodeId: Int32?) {
|
||||
if let context = self.contexts[chatPeerId] {
|
||||
context.removeActivity(peerId: peerId, activity: activity, episodeId: episodeId)
|
||||
|
||||
|
|
@ -360,10 +356,8 @@ final class PeerInputActivityManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeAllActivities(chatPeerId: PeerActivitySpace, peerId: PeerId) {
|
||||
self.queue.async {
|
||||
|
||||
func removeAllActivities(chatPeerId: PeerActivitySpace, peerId: PeerId) {
|
||||
if let currentContext = self.contexts[chatPeerId] {
|
||||
currentContext.removeAllActivities(peerId: peerId)
|
||||
|
||||
|
|
@ -373,23 +367,17 @@ final class PeerInputActivityManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func transaction(_ f: @escaping (PeerInputActivityManager) -> Void) {
|
||||
self.queue.async {
|
||||
f(self)
|
||||
}
|
||||
}
|
||||
|
||||
func acquireActivity(chatPeerId: PeerActivitySpace, peerId: PeerId, activity: PeerInputActivity) -> Disposable {
|
||||
let disposable = MetaDisposable()
|
||||
let queue = self.queue
|
||||
queue.async {
|
||||
|
||||
func acquireActivity(chatPeerId: PeerActivitySpace, peerId: PeerId, activity: PeerInputActivity) -> Disposable {
|
||||
let queue = self.queue
|
||||
let episodeId = self.nextEpisodeId
|
||||
self.nextEpisodeId += 1
|
||||
|
||||
let update: () -> Void = { [weak self] in
|
||||
self?.addActivity(chatPeerId: chatPeerId, peerId: peerId, activity: activity, episodeId: episodeId)
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.addActivity(chatPeerId: chatPeerId, peerId: peerId, activity: activity, episodeId: episodeId)
|
||||
}
|
||||
|
||||
let timeout: Double
|
||||
|
|
@ -406,16 +394,69 @@ final class PeerInputActivityManager {
|
|||
timer.start()
|
||||
update()
|
||||
|
||||
disposable.set(ActionDisposable { [weak self] in
|
||||
return ActionDisposable { [weak self] in
|
||||
queue.async {
|
||||
timer.invalidate()
|
||||
guard let strongSelf = self else {
|
||||
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.removeActivity(chatPeerId: chatPeerId, peerId: peerId, activity: activity, episodeId: episodeId)
|
||||
self.removeActivity(chatPeerId: chatPeerId, peerId: peerId, activity: activity, episodeId: episodeId)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let queue = Queue()
|
||||
private let impl: QueueLocalObject<Impl>
|
||||
|
||||
init() {
|
||||
let queue = self.queue
|
||||
self.impl = QueueLocalObject(queue: queue, generate: {
|
||||
return Impl(queue: queue)
|
||||
})
|
||||
}
|
||||
|
||||
func activities(peerId: PeerActivitySpace) -> Signal<[(PeerId, PeerInputActivityRecord)], NoError> {
|
||||
return self.impl.signalWith { impl, subscriber in
|
||||
return impl.activities(peerId: peerId, onNext: subscriber.putNext)
|
||||
}
|
||||
}
|
||||
|
||||
func allActivities() -> Signal<[PeerActivitySpace: [(PeerId, PeerInputActivityRecord)]], NoError> {
|
||||
return self.impl.signalWith { impl, subscriber in
|
||||
return impl.allActivities(onNext: subscriber.putNext)
|
||||
}
|
||||
}
|
||||
|
||||
func addActivity(chatPeerId: PeerActivitySpace, peerId: PeerId, activity: PeerInputActivity, episodeId: Int32? = nil) {
|
||||
self.impl.with { impl in
|
||||
impl.addActivity(chatPeerId: chatPeerId, peerId: peerId, activity: activity, episodeId: episodeId)
|
||||
}
|
||||
}
|
||||
|
||||
func removeActivity(chatPeerId: PeerActivitySpace, peerId: PeerId, activity: PeerInputActivity, episodeId: Int32? = nil) {
|
||||
self.impl.with { impl in
|
||||
impl.removeActivity(chatPeerId: chatPeerId, peerId: peerId, activity: activity, episodeId: episodeId)
|
||||
}
|
||||
}
|
||||
|
||||
func removeAllActivities(chatPeerId: PeerActivitySpace, peerId: PeerId) {
|
||||
self.impl.with { impl in
|
||||
impl.removeAllActivities(chatPeerId: chatPeerId, peerId: peerId)
|
||||
}
|
||||
}
|
||||
|
||||
func transaction(_ f: @escaping (PeerInputActivityManager) -> Void) {
|
||||
self.queue.async {
|
||||
f(self)
|
||||
}
|
||||
}
|
||||
|
||||
func acquireActivity(chatPeerId: PeerActivitySpace, peerId: PeerId, activity: PeerInputActivity) -> Disposable {
|
||||
let disposable = MetaDisposable()
|
||||
self.impl.with { impl in
|
||||
disposable.set(impl.acquireActivity(chatPeerId: chatPeerId, peerId: peerId, activity: activity))
|
||||
}
|
||||
return disposable
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,21 +32,24 @@ private enum PendingMessageState {
|
|||
case uploading(groupId: Int64?)
|
||||
case waitingToBeSent(groupId: Int64?, content: PendingMessageUploadedContentAndReuploadInfo)
|
||||
case sending(groupId: Int64?)
|
||||
case waitingForNewTopic(message: Message)
|
||||
|
||||
var groupId: Int64? {
|
||||
switch self {
|
||||
case .none:
|
||||
return nil
|
||||
case let .collectingInfo(message):
|
||||
return message.groupingKey
|
||||
case let .waitingForUploadToStart(groupId, _):
|
||||
return groupId
|
||||
case let .uploading(groupId):
|
||||
return groupId
|
||||
case let .waitingToBeSent(groupId, _):
|
||||
return groupId
|
||||
case let .sending(groupId):
|
||||
return groupId
|
||||
case .none:
|
||||
return nil
|
||||
case let .collectingInfo(message):
|
||||
return message.groupingKey
|
||||
case let .waitingForUploadToStart(groupId, _):
|
||||
return groupId
|
||||
case let .uploading(groupId):
|
||||
return groupId
|
||||
case let .waitingToBeSent(groupId, _):
|
||||
return groupId
|
||||
case let .sending(groupId):
|
||||
return groupId
|
||||
case let .waitingForNewTopic(message):
|
||||
return message.groupingKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -115,6 +118,20 @@ public struct PeerPendingMessageDelivered {
|
|||
private final class PeerPendingMessagesSummaryContext {
|
||||
var messageDeliveredSubscribers = Bag<([PeerPendingMessageDelivered]) -> Void>()
|
||||
var messageFailedSubscribers = Bag<(PendingMessageFailureReason) -> Void>()
|
||||
var newTopicEvents = Bag<(PendingMessageManager.NewTopicEvent) -> Void>()
|
||||
|
||||
var isEmpty: Bool {
|
||||
if !self.messageDeliveredSubscribers.isEmpty {
|
||||
return false
|
||||
}
|
||||
if !self.messageFailedSubscribers.isEmpty {
|
||||
return false
|
||||
}
|
||||
if !self.newTopicEvents.isEmpty {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private enum PendingMessageResult {
|
||||
|
|
@ -158,7 +175,7 @@ private func failMessages(postbox: Postbox, ids: [MessageId]) -> Signal<Void, No
|
|||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
return .update(StoreMessage(id: id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -186,6 +203,11 @@ private final class CorrelationIdToSentMessageId {
|
|||
}
|
||||
|
||||
public final class PendingMessageManager {
|
||||
public enum NewTopicEvent {
|
||||
case willMove(fromThreadId: Int64, toThreadId: Int64)
|
||||
case didMove(fromThreadId: Int64, toThreadId: Int64)
|
||||
}
|
||||
|
||||
private let network: Network
|
||||
private let postbox: Postbox
|
||||
private let accountPeerId: PeerId
|
||||
|
|
@ -206,6 +228,8 @@ public final class PendingMessageManager {
|
|||
private var pendingMessageIds = Set<MessageId>()
|
||||
private let beginSendingMessagesDisposables = DisposableSet()
|
||||
|
||||
private var newTopicDisposables: [PeerId: Disposable] = [:]
|
||||
|
||||
private var peerSummaryContexts: [PeerId: PeerPendingMessagesSummaryContext] = [:]
|
||||
|
||||
var transformOutgoingMessageMedia: TransformOutgoingMessageMedia?
|
||||
|
|
@ -226,6 +250,9 @@ public final class PendingMessageManager {
|
|||
|
||||
deinit {
|
||||
self.beginSendingMessagesDisposables.dispose()
|
||||
for (_, disposable) in self.newTopicDisposables {
|
||||
disposable.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
func updatePendingMessageIds(_ messageIds: Set<MessageId>) {
|
||||
|
|
@ -422,9 +449,7 @@ public final class PendingMessageManager {
|
|||
assert(strongSelf.queue.isCurrent())
|
||||
|
||||
Logger.shared.log("PendingMessageManager", "begin sending, continued: \(ids)")
|
||||
|
||||
Logger.shared.log("PendingMessageManager", "beginSendingMessages messages.count: \(messages.count)")
|
||||
|
||||
|
||||
for message in messages.filter({ !$0.flags.contains(.Sending) }).sorted(by: { $0.id < $1.id }) {
|
||||
guard let messageContext = strongSelf.messageContexts[message.id] else {
|
||||
|
|
@ -435,14 +460,106 @@ public final class PendingMessageManager {
|
|||
messageContext.activityType = uploadActivityTypeForMessage(message)
|
||||
}
|
||||
messageContext.threadId = message.threadId
|
||||
strongSelf.collectUploadingInfo(messageContext: messageContext, message: message)
|
||||
|
||||
if messageContext.threadId == Message.newTopicThreadId {
|
||||
strongSelf.createNewTopic(messageContext: messageContext, message: message)
|
||||
} else {
|
||||
strongSelf.collectUploadingInfo(messageContext: messageContext, message: message)
|
||||
}
|
||||
}
|
||||
|
||||
var messagesToUpload: [(PendingMessageContext, Message, PendingMessageUploadedContentType, Signal<PendingMessageUploadedContentResult, PendingMessageUploadError>)] = []
|
||||
var messagesToForward: [PeerIdAndNamespace: [(PendingMessageContext, Message, ForwardSourceInfoAttribute)]] = [:]
|
||||
|
||||
Logger.shared.log("PendingMessageManager", "beginSendingMessages messageContexts.count: \(strongSelf.messageContexts.count)")
|
||||
|
||||
|
||||
for (messageContext, _) in strongSelf.messageContexts.values.compactMap({ messageContext -> (PendingMessageContext, Message)? in
|
||||
if case let .waitingForNewTopic(message) = messageContext.state {
|
||||
return (messageContext, message)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}).sorted(by: { lhs, rhs in
|
||||
return lhs.1.index < rhs.1.index
|
||||
}) {
|
||||
if case let .waitingForNewTopic(message) = messageContext.state {
|
||||
let messagePeerId = message.id.peerId
|
||||
if strongSelf.newTopicDisposables[messagePeerId] == nil {
|
||||
let disposable = MetaDisposable()
|
||||
strongSelf.newTopicDisposables[messagePeerId] = disposable
|
||||
|
||||
disposable.set(_internal_createForumChannelTopic(
|
||||
postbox: strongSelf.postbox,
|
||||
network: strongSelf.network,
|
||||
stateManager: strongSelf.stateManager,
|
||||
accountPeerId: strongSelf.accountPeerId,
|
||||
peerId: message.id.peerId,
|
||||
title: "Topic #\(message.stableId)",
|
||||
iconColor: 0,
|
||||
iconFileId: nil
|
||||
).startStrict(next: { [weak strongSelf] topicId in
|
||||
guard let strongSelf else {
|
||||
return
|
||||
}
|
||||
var moveMessageIds: [MessageId] = []
|
||||
for (_, messageContext) in strongSelf.messageContexts {
|
||||
if case let .waitingForNewTopic(message) = messageContext.state {
|
||||
if message.id.peerId == messagePeerId {
|
||||
moveMessageIds.append(message.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !moveMessageIds.isEmpty {
|
||||
if let context = strongSelf.peerSummaryContexts[messagePeerId] {
|
||||
for subscriber in context.newTopicEvents.copyItems() {
|
||||
subscriber(.willMove(fromThreadId: Message.newTopicThreadId, toThreadId: topicId))
|
||||
}
|
||||
}
|
||||
|
||||
let _ = (strongSelf.postbox.transaction { transaction -> [Message] in
|
||||
var result: [Message] = []
|
||||
for id in moveMessageIds {
|
||||
transaction.updateMessage(id, update: { currentMessage in
|
||||
var storeForwardInfo: StoreMessageForwardInfo?
|
||||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
return .update(StoreMessage(id: id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: topicId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
})
|
||||
if let message = transaction.getMessage(id) {
|
||||
result.append(message)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|> deliverOn(strongSelf.queue)).startStandalone(next: { [weak strongSelf] messages in
|
||||
guard let strongSelf else {
|
||||
return
|
||||
}
|
||||
for message in messages {
|
||||
if let context = strongSelf.messageContexts[message.id] {
|
||||
if case .waitingForNewTopic = context.state {
|
||||
context.state = .collectingInfo(message: message)
|
||||
}
|
||||
}
|
||||
}
|
||||
strongSelf.newTopicDisposables[messagePeerId]?.dispose()
|
||||
strongSelf.newTopicDisposables[messagePeerId] = nil
|
||||
strongSelf.beginSendingMessages(messages.map(\.id))
|
||||
|
||||
if let context = strongSelf.peerSummaryContexts[messagePeerId] {
|
||||
for subscriber in context.newTopicEvents.copyItems() {
|
||||
subscriber(.didMove(fromThreadId: Message.newTopicThreadId, toThreadId: topicId))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}, error: { _ in
|
||||
//TODO:release handle errors
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (messageContext, _) in strongSelf.messageContexts.values.compactMap({ messageContext -> (PendingMessageContext, Message)? in
|
||||
if case let .collectingInfo(message) = messageContext.state {
|
||||
|
|
@ -486,7 +603,6 @@ public final class PendingMessageManager {
|
|||
}
|
||||
|
||||
Logger.shared.log("PendingMessageManager", "beginSendingMessages messagesToUpload.count: \(messagesToUpload.count)")
|
||||
|
||||
|
||||
for (messageContext, message, type, contentUploadSignal) in messagesToUpload {
|
||||
if let paidStarsAttribute = message.paidStarsAttribute, paidStarsAttribute.postponeSending {
|
||||
|
|
@ -596,28 +712,32 @@ public final class PendingMessageManager {
|
|||
|
||||
loop: for (id, context) in self.messageContexts {
|
||||
switch context.state {
|
||||
case .none:
|
||||
continue loop
|
||||
case let .collectingInfo(message):
|
||||
if message.groupingKey == groupId {
|
||||
return nil
|
||||
}
|
||||
case let .waitingForUploadToStart(contextGroupId, _):
|
||||
if contextGroupId == groupId {
|
||||
return nil
|
||||
}
|
||||
case let .uploading(contextGroupId):
|
||||
if contextGroupId == groupId {
|
||||
return nil
|
||||
}
|
||||
case let .waitingToBeSent(contextGroupId, content):
|
||||
if contextGroupId == groupId {
|
||||
result.append((context, id, content))
|
||||
}
|
||||
case let .sending(contextGroupId):
|
||||
if contextGroupId == groupId {
|
||||
return nil
|
||||
}
|
||||
case .none:
|
||||
continue loop
|
||||
case let .collectingInfo(message):
|
||||
if message.groupingKey == groupId {
|
||||
return nil
|
||||
}
|
||||
case let .waitingForUploadToStart(contextGroupId, _):
|
||||
if contextGroupId == groupId {
|
||||
return nil
|
||||
}
|
||||
case let .uploading(contextGroupId):
|
||||
if contextGroupId == groupId {
|
||||
return nil
|
||||
}
|
||||
case let .waitingToBeSent(contextGroupId, content):
|
||||
if contextGroupId == groupId {
|
||||
result.append((context, id, content))
|
||||
}
|
||||
case let .sending(contextGroupId):
|
||||
if contextGroupId == groupId {
|
||||
return nil
|
||||
}
|
||||
case let .waitingForNewTopic(message):
|
||||
if message.groupingKey == groupId {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -665,6 +785,10 @@ public final class PendingMessageManager {
|
|||
}))
|
||||
}
|
||||
|
||||
private func createNewTopic(messageContext: PendingMessageContext, message: Message) {
|
||||
messageContext.state = .waitingForNewTopic(message: message)
|
||||
}
|
||||
|
||||
private func collectUploadingInfo(messageContext: PendingMessageContext, message: Message) {
|
||||
messageContext.state = .collectingInfo(message: message)
|
||||
}
|
||||
|
|
@ -724,7 +848,7 @@ public final class PendingMessageManager {
|
|||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
return .update(StoreMessage(id: id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
return modify
|
||||
|
|
@ -1307,7 +1431,7 @@ public final class PendingMessageManager {
|
|||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: flags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: flags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
})
|
||||
} else {
|
||||
let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: message.id.peerId, operation: .sendMessage(layer: layer, id: message.id, file: secretFile), state: state)
|
||||
|
|
@ -1323,7 +1447,7 @@ public final class PendingMessageManager {
|
|||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: flags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: flags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1332,7 +1456,7 @@ public final class PendingMessageManager {
|
|||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
return .update(StoreMessage(id: message.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: message.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1850,7 +1974,7 @@ public final class PendingMessageManager {
|
|||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
return .update(StoreMessage(id: message.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: message.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
})
|
||||
}).start()
|
||||
}
|
||||
|
|
@ -1864,7 +1988,7 @@ public final class PendingMessageManager {
|
|||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
return .update(StoreMessage(id: message.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: message.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1892,7 +2016,7 @@ public final class PendingMessageManager {
|
|||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -2030,7 +2154,7 @@ public final class PendingMessageManager {
|
|||
self.queue.async {
|
||||
if let current = self.peerSummaryContexts[peerId] {
|
||||
current.messageDeliveredSubscribers.remove(index)
|
||||
if current.messageDeliveredSubscribers.isEmpty {
|
||||
if current.isEmpty {
|
||||
self.peerSummaryContexts.removeValue(forKey: peerId)
|
||||
}
|
||||
}
|
||||
|
|
@ -2063,7 +2187,40 @@ public final class PendingMessageManager {
|
|||
self.queue.async {
|
||||
if let current = self.peerSummaryContexts[peerId] {
|
||||
current.messageFailedSubscribers.remove(index)
|
||||
if current.messageFailedSubscribers.isEmpty {
|
||||
if current.isEmpty {
|
||||
self.peerSummaryContexts.removeValue(forKey: peerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
|
||||
public func newTopicEvents(peerId: PeerId) -> Signal<NewTopicEvent, NoError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
self.queue.async {
|
||||
let summaryContext: PeerPendingMessagesSummaryContext
|
||||
if let current = self.peerSummaryContexts[peerId] {
|
||||
summaryContext = current
|
||||
} else {
|
||||
summaryContext = PeerPendingMessagesSummaryContext()
|
||||
self.peerSummaryContexts[peerId] = summaryContext
|
||||
}
|
||||
|
||||
let index = summaryContext.newTopicEvents.add({ reason in
|
||||
subscriber.putNext(reason)
|
||||
})
|
||||
|
||||
disposable.set(ActionDisposable {
|
||||
self.queue.async {
|
||||
if let current = self.peerSummaryContexts[peerId] {
|
||||
current.newTopicEvents.remove(index)
|
||||
if current.isEmpty {
|
||||
self.peerSummaryContexts.removeValue(forKey: peerId)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -567,7 +567,7 @@ extension StoreMessage {
|
|||
convenience init?(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32, timestamp: Int32, apiMessage: SecretApi8.DecryptedMessage, file: SecretChatFileReference?) {
|
||||
switch apiMessage {
|
||||
case let .decryptedMessage(randomId, _, message, _):
|
||||
self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: message, attributes: [], media: [])
|
||||
self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: message, attributes: [], media: [])
|
||||
case let .decryptedMessageService(randomId, _, action):
|
||||
switch action {
|
||||
case .decryptedMessageActionDeleteMessages:
|
||||
|
|
@ -579,9 +579,9 @@ extension StoreMessage {
|
|||
case .decryptedMessageActionReadMessages:
|
||||
return nil
|
||||
case .decryptedMessageActionScreenshotMessages:
|
||||
self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .historyScreenshot)])
|
||||
self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .historyScreenshot)])
|
||||
case let .decryptedMessageActionSetMessageTTL(ttlSeconds):
|
||||
self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(period: ttlSeconds, autoSettingSource: nil))])
|
||||
self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(period: ttlSeconds, autoSettingSource: nil))])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -894,7 +894,7 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32
|
|||
|
||||
let (tags, globalTags) = tagsForStoreMessage(incoming: true, attributes: attributes, media: parsedMedia, textEntities: entitiesAttribute?.entities, isPinned: false)
|
||||
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: parsedMedia), resources)
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: parsedMedia), resources)
|
||||
case let .decryptedMessageService(randomId, action):
|
||||
switch action {
|
||||
case .decryptedMessageActionDeleteMessages:
|
||||
|
|
@ -906,9 +906,9 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32
|
|||
case .decryptedMessageActionReadMessages:
|
||||
return nil
|
||||
case .decryptedMessageActionScreenshotMessages:
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .historyScreenshot)]), [])
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .historyScreenshot)]), [])
|
||||
case let .decryptedMessageActionSetMessageTTL(ttlSeconds):
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(period: ttlSeconds, autoSettingSource: nil))]), [])
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(period: ttlSeconds, autoSettingSource: nil))]), [])
|
||||
case .decryptedMessageActionResend:
|
||||
return nil
|
||||
case .decryptedMessageActionRequestKey:
|
||||
|
|
@ -1126,7 +1126,7 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32
|
|||
|
||||
let (tags, globalTags) = tagsForStoreMessage(incoming: true, attributes: attributes, media: parsedMedia, textEntities: entitiesAttribute?.entities, isPinned: false)
|
||||
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: groupingKey, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: parsedMedia), resources)
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: groupingKey, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: parsedMedia), resources)
|
||||
case let .decryptedMessageService(randomId, action):
|
||||
switch action {
|
||||
case .decryptedMessageActionDeleteMessages:
|
||||
|
|
@ -1138,9 +1138,9 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32
|
|||
case .decryptedMessageActionReadMessages:
|
||||
return nil
|
||||
case .decryptedMessageActionScreenshotMessages:
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .historyScreenshot)]), [])
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .historyScreenshot)]), [])
|
||||
case let .decryptedMessageActionSetMessageTTL(ttlSeconds):
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(period: ttlSeconds, autoSettingSource: nil))]), [])
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(period: ttlSeconds, autoSettingSource: nil))]), [])
|
||||
case .decryptedMessageActionResend:
|
||||
return nil
|
||||
case .decryptedMessageActionRequestKey:
|
||||
|
|
@ -1405,7 +1405,7 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32
|
|||
|
||||
let (tags, globalTags) = tagsForStoreMessage(incoming: true, attributes: attributes, media: parsedMedia, textEntities: entitiesAttribute?.entities, isPinned: false)
|
||||
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: groupingKey, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: parsedMedia), resources)
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: groupingKey, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: parsedMedia), resources)
|
||||
case let .decryptedMessageService(randomId, action):
|
||||
switch action {
|
||||
case .decryptedMessageActionDeleteMessages:
|
||||
|
|
@ -1417,9 +1417,9 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32
|
|||
case .decryptedMessageActionReadMessages:
|
||||
return nil
|
||||
case .decryptedMessageActionScreenshotMessages:
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .historyScreenshot)]), [])
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .historyScreenshot)]), [])
|
||||
case let .decryptedMessageActionSetMessageTTL(ttlSeconds):
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(period: ttlSeconds, autoSettingSource: nil))]), [])
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(period: ttlSeconds, autoSettingSource: nil))]), [])
|
||||
case .decryptedMessageActionResend:
|
||||
return nil
|
||||
case .decryptedMessageActionRequestKey:
|
||||
|
|
@ -1606,7 +1606,7 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32
|
|||
|
||||
let (tags, globalTags) = tagsForStoreMessage(incoming: true, attributes: attributes, media: parsedMedia, textEntities: entitiesAttribute?.entities, isPinned: false)
|
||||
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: groupingKey, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: parsedMedia), resources)
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: groupingKey, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: parsedMedia), resources)
|
||||
case let .decryptedMessageService(randomId, action):
|
||||
switch action {
|
||||
case .decryptedMessageActionDeleteMessages:
|
||||
|
|
@ -1618,9 +1618,9 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32
|
|||
case .decryptedMessageActionReadMessages:
|
||||
return nil
|
||||
case .decryptedMessageActionScreenshotMessages:
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .historyScreenshot)]), [])
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .historyScreenshot)]), [])
|
||||
case let .decryptedMessageActionSetMessageTTL(ttlSeconds):
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(period: ttlSeconds, autoSettingSource: nil))]), [])
|
||||
return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), customStableId: nil, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(period: ttlSeconds, autoSettingSource: nil))]), [])
|
||||
case .decryptedMessageActionResend:
|
||||
return nil
|
||||
case .decryptedMessageActionRequestKey:
|
||||
|
|
|
|||
|
|
@ -10,13 +10,6 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = {
|
|||
]
|
||||
}
|
||||
|
||||
var messageThreadHoles: [PeerId.Namespace: [MessageId.Namespace]] = [:]
|
||||
for peerNamespace in peerIdNamespacesWithInitialCloudMessageHoles {
|
||||
messageThreadHoles[peerNamespace] = [
|
||||
Namespaces.Message.Cloud
|
||||
]
|
||||
}
|
||||
|
||||
// To avoid upgrading the database, **new** tags can be added here
|
||||
// Uninitialized peers will fill the info using messageHoles
|
||||
var upgradedMessageHoles: [PeerId.Namespace: [MessageId.Namespace: Set<MessageTags>]] = [:]
|
||||
|
|
@ -42,7 +35,15 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = {
|
|||
),
|
||||
messageHoles: messageHoles,
|
||||
upgradedMessageHoles: upgradedMessageHoles,
|
||||
messageThreadHoles: messageThreadHoles,
|
||||
messageThreadHoles: { peerIdNamespace, threadId in
|
||||
if threadId == Message.newTopicThreadId {
|
||||
return nil
|
||||
}
|
||||
if peerIdNamespacesWithInitialCloudMessageHoles.contains(peerIdNamespace) {
|
||||
return [Namespaces.Message.Cloud]
|
||||
}
|
||||
return nil
|
||||
},
|
||||
existingMessageTags: MessageTags.all,
|
||||
messageTagsWithSummary: [.unseenPersonalMessage, .pinned, .video, .photo, .gif, .music, .voiceOrInstantVideo, .webPage, .file, .unseenReaction],
|
||||
messageTagsWithThreadSummary: [.unseenPersonalMessage, .unseenReaction],
|
||||
|
|
@ -76,10 +77,14 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = {
|
|||
peerSummaryIsThreadBased: { peer, associatedPeer in
|
||||
if let channel = peer as? TelegramChannel {
|
||||
if channel.flags.contains(.isForum) {
|
||||
if channel.flags.contains(.displayForumAsTabs) {
|
||||
return (false, false)
|
||||
} else {
|
||||
if channel.linkedBotId != nil {
|
||||
return (true, false)
|
||||
} else {
|
||||
if channel.flags.contains(.displayForumAsTabs) {
|
||||
return (false, false)
|
||||
} else {
|
||||
return (true, false)
|
||||
}
|
||||
}
|
||||
} else if channel.flags.contains(.isMonoforum) {
|
||||
if let associatedPeer = associatedPeer as? TelegramChannel, associatedPeer.hasPermission(.manageDirect) {
|
||||
|
|
@ -183,6 +188,14 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = {
|
|||
}
|
||||
return false
|
||||
},
|
||||
decodeAssociatedChatListPeerId: { cachedData in
|
||||
if let cachedData = cachedData as? CachedUserData {
|
||||
if case let .known(value) = cachedData.linkedBotChannelId {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
isPeerUpgradeMessage: { message in
|
||||
for media in message.media {
|
||||
if let action = media as? TelegramMediaAction {
|
||||
|
|
|
|||
|
|
@ -219,6 +219,8 @@ public final class TelegramChannel: Peer, Equatable {
|
|||
public var associatedPeerId: PeerId? {
|
||||
if self.flags.contains(.isMonoforum) {
|
||||
return self.linkedMonoforumId
|
||||
} else if let linkedBotId = self.linkedBotId {
|
||||
return linkedBotId
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -259,7 +261,21 @@ public final class TelegramChannel: Peer, Equatable {
|
|||
return mediaIds
|
||||
}
|
||||
|
||||
public let notificationSettingsPeerId: PeerId? = nil
|
||||
public var notificationSettingsPeerId: PeerId? {
|
||||
if let linkedBotId = self.linkedBotId {
|
||||
return linkedBotId
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public var associatedPeerOverridesIdentity: Bool {
|
||||
if self.linkedBotId != nil {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public var timeoutAttribute: UInt32? {
|
||||
if let emojiStatus = self.emojiStatus {
|
||||
|
|
|
|||
|
|
@ -3353,6 +3353,7 @@ func _internal_refreshInlineGroupCall(account: Account, messageId: MessageId) ->
|
|||
}
|
||||
return .update(StoreMessage(
|
||||
id: currentMessage.id,
|
||||
customStableId: nil,
|
||||
globallyUniqueId: currentMessage.globallyUniqueId,
|
||||
groupingKey: currentMessage.groupingKey,
|
||||
threadId: currentMessage.threadId,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ func _internal_applyMaxReadIndexInteractively(transaction: Transaction, stateMan
|
|||
return currentAttribute
|
||||
}
|
||||
})
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
break
|
||||
|
|
@ -123,7 +123,7 @@ func applySecretOutgoingMessageReadActions(transaction: Transaction, id: Message
|
|||
return currentAttribute
|
||||
}
|
||||
})
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
break
|
||||
|
|
@ -307,6 +307,12 @@ func _internal_togglePeerUnreadMarkInteractively(transaction: Transaction, netwo
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let user = peer as? TelegramUser, let botInfo = user.botInfo, botInfo.flags.contains(.hasForum) {
|
||||
if let cachedData = transaction.getPeerCachedData(peerId: user.id) as? CachedUserData, case let .known(linkedBotChannelId) = cachedData.linkedBotChannelId, let linkedBotChannelId {
|
||||
_internal_togglePeerUnreadMarkInteractively(transaction: transaction, network: network, viewTracker: viewTracker, peerId: linkedBotChannelId, setToValue: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func clearPeerUnseenPersonalMessagesInteractively(account: Account, peerId: PeerId, threadId: Int64?) -> Signal<Never, NoError> {
|
||||
|
|
|
|||
|
|
@ -532,7 +532,7 @@ extension EngineChatList.Item {
|
|||
}
|
||||
|
||||
var forumTopicDataValue: EngineChatList.ForumTopicData?
|
||||
if let forumTopicData = forumTopicData {
|
||||
if let forumTopicData {
|
||||
let id = forumTopicData.id
|
||||
if let forumTopicInfo = forumTopicData.info.data.get(MessageHistoryThreadData.self) {
|
||||
forumTopicDataValue = EngineChatList.ForumTopicData(id: id, title: forumTopicInfo.info.title, iconFileId: forumTopicInfo.info.icon, iconColor: forumTopicInfo.info.iconColor, maxOutgoingReadMessageId: MessageId(peerId: index.messageIndex.id.peerId, namespace: Namespaces.Message.Cloud, id: forumTopicInfo.maxOutgoingReadId), isUnread: forumTopicInfo.incomingUnreadCount > 0, threadPeer: forumTopicData.threadPeer.flatMap(EnginePeer.init))
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ func _internal_clearHistoryInteractively(postbox: Postbox, peerId: PeerId, threa
|
|||
}
|
||||
|
||||
if addEmptyMessage {
|
||||
let _ = transaction.addMessages([StoreMessage(id: topIndex.id, globallyUniqueId: nil, groupingKey: nil, threadId: nil, timestamp: topIndex.timestamp, flags: StoreMessageFlags(), tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: nil, text: "", attributes: [], media: [TelegramMediaAction(action: .historyCleared)])], location: .Random)
|
||||
let _ = transaction.addMessages([StoreMessage(id: topIndex.id, customStableId: nil, globallyUniqueId: nil, groupingKey: nil, threadId: nil, timestamp: topIndex.timestamp, flags: StoreMessageFlags(), tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: nil, text: "", attributes: [], media: [TelegramMediaAction(action: .historyCleared)])], location: .Random)
|
||||
}
|
||||
} else {
|
||||
updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: topIndex.timestamp, forceRootGroupIfNotExists: false)
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ func _internal_getMessagesFactCheckByPeerId(account: Account, peerId: EnginePeer
|
|||
let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init)
|
||||
var attributes = currentMessage.attributes.filter { !($0 is FactCheckMessageAttribute) }
|
||||
attributes.append(attribute)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
index += 1
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ func _internal_installInteractiveReadMessagesAction(postbox: Postbox, stateManag
|
|||
}
|
||||
tags.remove(.unseenReaction)
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
|
||||
if consumeMessageIds.contains(id) {
|
||||
|
|
@ -151,7 +151,7 @@ private final class StoreOrUpdateMessageActionImpl: StoreOrUpdateMessageAction {
|
|||
}
|
||||
var tags = currentMessage.tags
|
||||
tags.remove(.unseenReaction)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
transaction.setPendingMessageAction(type: .readReaction, id: id, action: ReadReactionAction())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ func _internal_markMessageContentAsConsumedInteractively(postbox: Postbox, messa
|
|||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -153,7 +153,7 @@ func _internal_markReactionsAsSeenInteractively(postbox: Postbox, messageId: Mes
|
|||
}
|
||||
var tags = currentMessage.tags
|
||||
tags.remove(.unseenReaction)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -244,7 +244,7 @@ func markMessageContentAsConsumedRemotely(transaction: Transaction, messageId: M
|
|||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: updatedMedia))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: updatedMedia))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import Postbox
|
||||
|
||||
public final class EngineMessage: Equatable {
|
||||
public static let newTopicThreadId: Int64 = Message.newTopicThreadId
|
||||
|
||||
public typealias Id = MessageId
|
||||
public typealias StableId = UInt32
|
||||
public typealias Index = MessageIndex
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ private class ReplyThreadHistoryContextImpl {
|
|||
)
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -400,7 +400,7 @@ private class ReplyThreadHistoryContextImpl {
|
|||
attributes[j] = updatedAttribute
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import MtProtoKit
|
|||
|
||||
|
||||
func _internal_requestStartBot(account: Account, botPeerId: PeerId, payload: String?) -> Signal<Void, NoError> {
|
||||
#if DEBUG
|
||||
if "".isEmpty {
|
||||
return account.postbox.loadedPeerWithId(botPeerId)
|
||||
|> mapToSignal { botPeer -> Signal<Void, NoError> in
|
||||
|
|
@ -34,11 +33,53 @@ func _internal_requestStartBot(account: Account, botPeerId: PeerId, payload: Str
|
|||
}
|
||||
}
|
||||
|
||||
return .complete()
|
||||
if let payload = payload, !payload.isEmpty {
|
||||
return account.postbox.loadedPeerWithId(botPeerId)
|
||||
|> mapToSignal { botPeer -> Signal<Void, NoError> in
|
||||
if let inputUser = apiInputUser(botPeer) {
|
||||
return account.network.request(Api.functions.messages.startBot(bot: inputUser, peer: .inputPeerEmpty, randomId: Int64.random(in: Int64.min ... Int64.max), startParam: payload))
|
||||
|> mapToSignal { result -> Signal<Void, MTRpcError> in
|
||||
account.stateManager.addUpdates(result)
|
||||
return .complete()
|
||||
}
|
||||
|> `catch` { _ -> Signal<Void, MTRpcError> in
|
||||
return .complete()
|
||||
}
|
||||
|> retryRequest
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|> castError(MTRpcError.self)
|
||||
} else {
|
||||
return enqueueMessages(account: account, peerId: botPeerId, messages: [.message(text: "/start", attributes: [], inlineStickers: [:], mediaReference: nil, threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])]) |> mapToSignal { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
|> castError(MTRpcError.self)
|
||||
}
|
||||
}
|
||||
|> `catch` { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|
||||
if let payload = payload, !payload.isEmpty {
|
||||
return account.postbox.loadedPeerWithId(botPeerId)
|
||||
|> mapToSignal { botPeer -> Signal<Void, NoError> in
|
||||
if let inputUser = apiInputUser(botPeer) {
|
||||
return account.network.request(Api.functions.messages.startBot(bot: inputUser, peer: .inputPeerEmpty, randomId: Int64.random(in: Int64.min ... Int64.max), startParam: payload))
|
||||
|> mapToSignal { result -> Signal<Void, MTRpcError> in
|
||||
account.stateManager.addUpdates(result)
|
||||
return .complete()
|
||||
}
|
||||
|> `catch` { _ -> Signal<Void, MTRpcError> in
|
||||
return .complete()
|
||||
}
|
||||
|> retryRequest
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return enqueueMessages(account: account, peerId: botPeerId, messages: [.message(text: "/start", attributes: [], inlineStickers: [:], mediaReference: nil, threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])]) |> mapToSignal { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
|
|
@ -46,7 +87,6 @@ func _internal_requestStartBot(account: Account, botPeerId: PeerId, payload: Str
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if let payload = payload, !payload.isEmpty {
|
||||
return account.postbox.loadedPeerWithId(botPeerId)
|
||||
|
|
|
|||
|
|
@ -476,7 +476,7 @@ public extension TelegramEngine {
|
|||
updatedMedia[i] = TelegramMediaMap(latitude: media.latitude, longitude: media.longitude, heading: media.heading, accuracyRadius: media.accuracyRadius, venue: media.venue, liveBroadcastingTimeout: max(0, timestamp - currentMessage.timestamp - 1), liveProximityNotificationRadius: nil)
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: updatedMedia))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: updatedMedia))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -616,7 +616,7 @@ public extension TelegramEngine {
|
|||
|
||||
attributes.append(AudioTranscriptionMessageAttribute(id: 0, text: text, isPending: !isFinal, didRate: false, error: error))
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
|> ignoreValues
|
||||
|
|
@ -632,7 +632,7 @@ public extension TelegramEngine {
|
|||
attributes.append(DerivedDataMessageAttribute(data: data))
|
||||
}
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
|> ignoreValues
|
||||
|
|
@ -654,7 +654,7 @@ public extension TelegramEngine {
|
|||
attributes.append(DerivedDataMessageAttribute(data: data))
|
||||
}
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
|> ignoreValues
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ func _internal_requestUpdateTodoMessageItems(account: Account, messageId: Messag
|
|||
updatedCompletions.removeAll(where: { incompletedIds.contains($0.id) })
|
||||
media = [todo.withUpdated(completions: updatedCompletions)]
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: media))
|
||||
})
|
||||
return account.network.request(Api.functions.messages.toggleTodoCompleted(peer: inputPeer, msgId: messageId.id, completed: completedIds, incompleted: incompletedIds))
|
||||
|> mapError { _ -> RequestUpdateTodoMessageError in
|
||||
|
|
@ -59,7 +59,7 @@ func _internal_appendTodoMessageItems(account: Account, messageId: MessageId, it
|
|||
updatedItems.append(contentsOf: items)
|
||||
media = [todo.withUpdated(items: updatedItems)]
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: media))
|
||||
})
|
||||
return account.network.request(Api.functions.messages.appendTodoList(peer: inputPeer, msgId: messageId.id, list: items.map { $0.apiItem }))
|
||||
|> mapError { _ -> AppendTodoMessageError in
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ func _internal_transcribeAudio(postbox: Postbox, network: Network, messageId: Me
|
|||
|
||||
attributes.append(updatedAttribute)
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
|
||||
if updatedAttribute.error == nil {
|
||||
|
|
@ -111,6 +111,7 @@ func _internal_rateAudioTranscription(postbox: Postbox, network: Network, messag
|
|||
}
|
||||
return .update(StoreMessage(
|
||||
id: currentMessage.id,
|
||||
customStableId: nil,
|
||||
globallyUniqueId: currentMessage.globallyUniqueId,
|
||||
groupingKey: currentMessage.groupingKey,
|
||||
threadId: currentMessage.threadId,
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ private func _internal_translateMessagesByPeerId(account: Account, peerId: Engin
|
|||
|
||||
attributes.append(updatedAttribute)
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
index += 1
|
||||
|
|
@ -246,7 +246,7 @@ private func _internal_translateMessagesByPeerId(account: Account, peerId: Engin
|
|||
let updatedAttribute: TranslationMessageAttribute = TranslationMessageAttribute(text: title.0, entities: title.1, additional: attrOptions, pollSolution: solution, toLang: toLang)
|
||||
attributes.append(updatedAttribute)
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ func _internal_requestUpdatePinnedMessage(account: Account, peerId: PeerId, upda
|
|||
if updatedTags == currentMessage.tags {
|
||||
return .skip
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: updatedTags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -204,7 +204,7 @@ func _internal_requestUnpinAllMessages(account: Account, peerId: PeerId, threadI
|
|||
return .skip
|
||||
}
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ func _internal_storeMessageFromSearch(transaction: Transaction, message: Message
|
|||
}
|
||||
}
|
||||
|
||||
let storeMessage = StoreMessage(id: .Id(message.id), globallyUniqueId: message.globallyUniqueId, groupingKey: message.groupingKey, threadId: message.threadId, timestamp: message.timestamp, flags: StoreMessageFlags(message.flags), tags: message.tags, globalTags: message.globalTags, localTags: message.localTags, forwardInfo: message.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: message.author?.id, text: message.text, attributes: message.attributes, media: message.media)
|
||||
let storeMessage = StoreMessage(id: .Id(message.id), customStableId: nil, globallyUniqueId: message.globallyUniqueId, groupingKey: message.groupingKey, threadId: message.threadId, timestamp: message.timestamp, flags: StoreMessageFlags(message.flags), tags: message.tags, globalTags: message.globalTags, localTags: message.localTags, forwardInfo: message.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: message.author?.id, text: message.text, attributes: message.attributes, media: message.media)
|
||||
|
||||
let _ = transaction.addMessages([storeMessage], location: .Random)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ func updateMessageMedia(transaction: Transaction, id: MediaId, media: Media?) {
|
|||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -113,7 +113,7 @@ private func updateMessageThreadStatsInternal(transaction: Transaction, threadKe
|
|||
channelThreadMessageId = attribute.messageId
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
|
||||
if let channelThreadMessageId = channelThreadMessageId {
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ public enum PresentationResourceKey: Int32 {
|
|||
|
||||
case chatListGeneralTopicIcon
|
||||
case chatListGeneralTopicTemplateIcon
|
||||
case chatListNewTopicTemplateIcon
|
||||
case chatListGeneralTopicSmallIcon
|
||||
|
||||
case searchAdIcon
|
||||
|
|
|
|||
|
|
@ -451,6 +451,23 @@ public struct PresentationResourcesChatList {
|
|||
})
|
||||
}
|
||||
|
||||
public static func newTopicTemplateIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatListNewTopicTemplateIcon.rawValue, { theme in
|
||||
guard let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: .white) else {
|
||||
return nil
|
||||
}
|
||||
let size = CGSize(width: 24.0, height: 24.0)
|
||||
return generateImage(size, rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
UIGraphicsPushContext(context)
|
||||
defer {
|
||||
UIGraphicsPopContext()
|
||||
}
|
||||
image.draw(in: CGRect(origin: CGPoint(), size: size))
|
||||
})?.withRenderingMode(.alwaysTemplate)
|
||||
})
|
||||
}
|
||||
|
||||
public static func statusAutoremoveIcon(_ theme: PresentationTheme, isActive: Bool) -> UIImage? {
|
||||
return theme.image(PresentationResourceParameterKey.statusAutoremoveIcon(isActive: isActive), { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: isActive ? "Chat List/StatusIconAutoremoveOn" : "Chat List/StatusIconAutoremoveOff"), color: isActive ? theme.list.itemAccentColor : theme.list.itemSecondaryTextColor)
|
||||
|
|
|
|||
|
|
@ -26,13 +26,13 @@ public final class ChatAvatarNavigationNode: ASDisplayNode {
|
|||
private var context: AccountContext?
|
||||
|
||||
private let containerNode: ContextControllerSourceNode
|
||||
public let avatarNode: AvatarNode
|
||||
public var avatarNode: AvatarNode
|
||||
private var avatarVideoNode: AvatarVideoNode?
|
||||
|
||||
public private(set) var avatarStoryView: ComponentView<Empty>?
|
||||
public var storyData: (hasUnseen: Bool, hasUnseenCloseFriends: Bool)?
|
||||
|
||||
public let statusView: ComponentView<Empty>
|
||||
public var statusView: ComponentView<Empty>
|
||||
private var starView: StarView?
|
||||
|
||||
private var cachedDataDisposable = MetaDisposable()
|
||||
|
|
@ -119,6 +119,13 @@ public final class ChatAvatarNavigationNode: ASDisplayNode {
|
|||
|
||||
public func setPeer(context: AccountContext, theme: PresentationTheme, peer: EnginePeer?, authorOfMessage: MessageReference? = nil, overrideImage: AvatarNodeImageOverride? = nil, emptyColor: UIColor? = nil, clipStyle: AvatarNodeClipStyle = .round, synchronousLoad: Bool = false, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), storeUnrounded: Bool = false) {
|
||||
self.context = context
|
||||
|
||||
if let statusComponentView = self.statusView.view {
|
||||
self.statusView = ComponentView()
|
||||
statusComponentView.removeFromSuperview()
|
||||
}
|
||||
|
||||
self.avatarNode.isHidden = false
|
||||
self.avatarNode.setPeer(context: context, theme: theme, peer: peer, authorOfMessage: authorOfMessage, overrideImage: overrideImage, emptyColor: emptyColor, clipStyle: clipStyle, synchronousLoad: synchronousLoad, displayDimensions: displayDimensions, storeUnrounded: storeUnrounded)
|
||||
|
||||
if let peer, peer.isSubscription {
|
||||
|
|
|
|||
|
|
@ -479,7 +479,7 @@ private final class ChatMessagePeerContentNode: ASDisplayNode {
|
|||
avatarIconContent = .topic(title: String(info.title.prefix(1)), color: info.iconColor, size: CGSize(width: 16.0, height: 16.0))
|
||||
}
|
||||
} else {
|
||||
avatarIconContent = .image(image: PresentationResourcesChatList.generalTopicIcon(presentationData.theme.theme)?.withRenderingMode(.alwaysTemplate), tintColor: bubbleVariableColor(variableColor: presentationData.theme.theme.chat.serviceMessage.dateTextColor, wallpaper: presentationData.theme.wallpaper))
|
||||
avatarIconContent = .image(image: PresentationResourcesChatList.generalTopicTemplateIcon(presentationData.theme.theme), tintColor: bubbleVariableColor(variableColor: presentationData.theme.theme.chat.serviceMessage.dateTextColor, wallpaper: presentationData.theme.wallpaper))
|
||||
}
|
||||
|
||||
let avatarIconComponent = EmojiStatusComponent(
|
||||
|
|
|
|||
|
|
@ -45,12 +45,18 @@ public final class ChatSideTopicsPanel: Component {
|
|||
case top
|
||||
}
|
||||
|
||||
public enum Kind {
|
||||
case forum
|
||||
case monoforum
|
||||
case botForum
|
||||
}
|
||||
|
||||
let context: AccountContext
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
let location: Location
|
||||
let peerId: EnginePeer.Id
|
||||
let isMonoforum: Bool
|
||||
let kind: Kind
|
||||
let topicId: Int64?
|
||||
let controller: () -> ViewController?
|
||||
let togglePanel: () -> Void
|
||||
|
|
@ -63,7 +69,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
strings: PresentationStrings,
|
||||
location: Location,
|
||||
peerId: EnginePeer.Id,
|
||||
isMonoforum: Bool,
|
||||
kind: Kind,
|
||||
topicId: Int64?,
|
||||
controller: @escaping () -> ViewController?,
|
||||
togglePanel: @escaping () -> Void,
|
||||
|
|
@ -75,7 +81,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
self.strings = strings
|
||||
self.location = location
|
||||
self.peerId = peerId
|
||||
self.isMonoforum = isMonoforum
|
||||
self.kind = kind
|
||||
self.topicId = topicId
|
||||
self.controller = controller
|
||||
self.togglePanel = togglePanel
|
||||
|
|
@ -99,7 +105,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
if lhs.peerId != rhs.peerId {
|
||||
return false
|
||||
}
|
||||
if lhs.isMonoforum != rhs.isMonoforum {
|
||||
if lhs.kind != rhs.kind {
|
||||
return false
|
||||
}
|
||||
if lhs.topicId != rhs.topicId {
|
||||
|
|
@ -386,6 +392,8 @@ public final class ChatSideTopicsPanel: Component {
|
|||
} else {
|
||||
avatarIconContent = .topic(title: String(threadData.info.title.prefix(1)), color: threadData.info.iconColor, size: iconSize)
|
||||
}
|
||||
} else if topicId == EngineMessage.newTopicThreadId {
|
||||
avatarIconContent = .image(image: PresentationResourcesChatList.newTopicTemplateIcon(component.theme), tintColor: component.isSelected ? component.theme.rootController.navigationBar.accentTextColor : component.theme.rootController.navigationBar.controlColor)
|
||||
} else {
|
||||
avatarIconContent = .image(image: PresentationResourcesChatList.generalTopicTemplateIcon(component.theme), tintColor: component.isSelected ? component.theme.rootController.navigationBar.accentTextColor : component.theme.rootController.navigationBar.controlColor)
|
||||
}
|
||||
|
|
@ -429,6 +437,9 @@ public final class ChatSideTopicsPanel: Component {
|
|||
let _ = topicId
|
||||
if let threadData = component.item.item.threadData {
|
||||
titleText = threadData.info.title
|
||||
} else if topicId == EngineMessage.newTopicThreadId {
|
||||
//TODO:localize
|
||||
titleText = "New Chat"
|
||||
} else {
|
||||
titleText = " "
|
||||
}
|
||||
|
|
@ -824,6 +835,8 @@ public final class ChatSideTopicsPanel: Component {
|
|||
} else {
|
||||
avatarIconContent = .topic(title: String(threadData.info.title.prefix(1)), color: threadData.info.iconColor, size: iconSize)
|
||||
}
|
||||
} else if topicId == EngineMessage.newTopicThreadId {
|
||||
avatarIconContent = .image(image: PresentationResourcesChatList.newTopicTemplateIcon(component.theme), tintColor: component.isSelected ? component.theme.rootController.navigationBar.accentTextColor : component.theme.rootController.navigationBar.controlColor)
|
||||
} else {
|
||||
avatarIconContent = .image(image: PresentationResourcesChatList.generalTopicTemplateIcon(component.theme), tintColor: component.isSelected ? component.theme.rootController.navigationBar.accentTextColor : component.theme.rootController.navigationBar.controlColor)
|
||||
}
|
||||
|
|
@ -861,6 +874,9 @@ public final class ChatSideTopicsPanel: Component {
|
|||
let _ = topicId
|
||||
if let threadData = component.item.item.threadData {
|
||||
titleText = threadData.info.title
|
||||
} else if topicId == EngineMessage.newTopicThreadId {
|
||||
//TODO:localize
|
||||
titleText = "New Chat"
|
||||
} else {
|
||||
titleText = " "
|
||||
}
|
||||
|
|
@ -1144,12 +1160,14 @@ public final class ChatSideTopicsPanel: Component {
|
|||
|
||||
private final class VerticalAllItemComponent: Component, AllItemComponent {
|
||||
let isSelected: Bool
|
||||
let kind: ChatSideTopicsPanel.Kind
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
let action: (() -> Void)?
|
||||
|
||||
init(isSelected: Bool, theme: PresentationTheme, strings: PresentationStrings, action: (() -> Void)?) {
|
||||
init(isSelected: Bool, kind: ChatSideTopicsPanel.Kind, theme: PresentationTheme, strings: PresentationStrings, action: (() -> Void)?) {
|
||||
self.isSelected = isSelected
|
||||
self.kind = kind
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.action = action
|
||||
|
|
@ -1162,6 +1180,9 @@ public final class ChatSideTopicsPanel: Component {
|
|||
if lhs.isSelected != rhs.isSelected {
|
||||
return false
|
||||
}
|
||||
if lhs.kind != rhs.kind {
|
||||
return false
|
||||
}
|
||||
if lhs.theme !== rhs.theme {
|
||||
return false
|
||||
}
|
||||
|
|
@ -1234,7 +1255,13 @@ public final class ChatSideTopicsPanel: Component {
|
|||
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||
)
|
||||
|
||||
let titleText: String = component.strings.Chat_InlineTopicMenu_AllTab
|
||||
let titleText: String
|
||||
if case .botForum = component.kind {
|
||||
//TODO:localize
|
||||
titleText = "General"
|
||||
} else {
|
||||
titleText = component.strings.Chat_InlineTopicMenu_AllTab
|
||||
}
|
||||
let titleSize = self.title.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
|
|
@ -1284,12 +1311,14 @@ public final class ChatSideTopicsPanel: Component {
|
|||
|
||||
private final class HorizontalAllItemComponent: Component, AllItemComponent {
|
||||
let isSelected: Bool
|
||||
let kind: ChatSideTopicsPanel.Kind
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
let action: (() -> Void)?
|
||||
|
||||
init(isSelected: Bool, theme: PresentationTheme, strings: PresentationStrings, action: (() -> Void)?) {
|
||||
init(isSelected: Bool, kind: ChatSideTopicsPanel.Kind, theme: PresentationTheme, strings: PresentationStrings, action: (() -> Void)?) {
|
||||
self.isSelected = isSelected
|
||||
self.kind = kind
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.action = action
|
||||
|
|
@ -1302,6 +1331,9 @@ public final class ChatSideTopicsPanel: Component {
|
|||
if lhs.isSelected != rhs.isSelected {
|
||||
return false
|
||||
}
|
||||
if lhs.kind != rhs.kind {
|
||||
return false
|
||||
}
|
||||
if lhs.theme !== rhs.theme {
|
||||
return false
|
||||
}
|
||||
|
|
@ -1361,7 +1393,13 @@ public final class ChatSideTopicsPanel: Component {
|
|||
let leftInset: CGFloat = 6.0
|
||||
let rightInset: CGFloat = 12.0
|
||||
|
||||
let titleText: String = component.strings.Chat_InlineTopicMenu_AllTab
|
||||
let titleText: String
|
||||
if case .botForum = component.kind {
|
||||
//TODO:localize
|
||||
titleText = "General"
|
||||
} else {
|
||||
titleText = component.strings.Chat_InlineTopicMenu_AllTab
|
||||
}
|
||||
let titleSize = self.title.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
|
|
@ -1372,7 +1410,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
containerSize: CGSize(width: 400.0, height: 200.0)
|
||||
)
|
||||
|
||||
let contentSize: CGFloat = leftInset + rightInset + titleSize.height
|
||||
let contentSize: CGFloat = leftInset + rightInset + titleSize.width
|
||||
let size = CGSize(width: contentSize, height: availableSize.height)
|
||||
|
||||
let titleFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((size.height - titleSize.height) * 0.5)), size: titleSize)
|
||||
|
|
@ -1422,6 +1460,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
|
||||
private var tabItemView: TabItemView?
|
||||
|
||||
private var peerId: EnginePeer.Id?
|
||||
private var rawItems: [Item] = []
|
||||
private var reorderingItems: [Item]?
|
||||
private var resetReorderingOnNextUpdate: Bool = false
|
||||
|
|
@ -1653,21 +1692,99 @@ public final class ChatSideTopicsPanel: Component {
|
|||
}
|
||||
|
||||
if self.component == nil {
|
||||
let threadListSignal: Signal<EngineChatList, NoError> = component.context.sharedContext.subscribeChatListData(context: component.context, location: component.isMonoforum ? .savedMessagesChats(peerId: component.peerId) : .forum(peerId: component.peerId))
|
||||
let threadListSignal: Signal<(EnginePeer.Id, EngineChatList), NoError>
|
||||
|
||||
switch component.kind {
|
||||
case .botForum:
|
||||
let forumPeerId: Signal<EnginePeer.Id?, NoError>
|
||||
if component.peerId.namespace == Namespaces.Peer.CloudUser {
|
||||
forumPeerId = component.context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.LinkedBotForumPeerId(id: component.peerId)
|
||||
)
|
||||
|> map { value -> EnginePeer.Id? in
|
||||
if case let .known(value) = value {
|
||||
return value
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
} else {
|
||||
forumPeerId = .single(component.peerId)
|
||||
}
|
||||
|
||||
let defaultPeerId = component.peerId
|
||||
threadListSignal = forumPeerId
|
||||
|> mapToSignal { forumPeerId -> Signal<(EnginePeer.Id, EngineChatList), NoError> in
|
||||
if let forumPeerId {
|
||||
return component.context.sharedContext.subscribeChatListData(context: component.context, location: .forum(peerId: forumPeerId))
|
||||
|> map { value in
|
||||
return (forumPeerId, value)
|
||||
}
|
||||
} else {
|
||||
return .single((defaultPeerId, EngineChatList(items: [], groupItems: [], additionalItems: [], hasEarlier: false, hasLater: false, isLoading: false)))
|
||||
}
|
||||
}
|
||||
default:
|
||||
let defaultPeerId = component.peerId
|
||||
threadListSignal = component.context.sharedContext.subscribeChatListData(context: component.context, location: component.kind == .monoforum ? .savedMessagesChats(peerId: component.peerId) : .forum(peerId: component.peerId))
|
||||
|> map { value in
|
||||
return (defaultPeerId, value)
|
||||
}
|
||||
}
|
||||
|
||||
self.itemsDisposable = (threadListSignal
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] chatList in
|
||||
guard let self else {
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] peerId, chatList in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
|
||||
self.peerId = peerId
|
||||
|
||||
let wasEmpty = self.rawItems.isEmpty
|
||||
|
||||
self.rawItems.removeAll()
|
||||
for item in chatList.items.reversed() {
|
||||
if case .botForum = component.kind, case let .forum(topicId) = item.id, topicId == 1 {
|
||||
#if DEBUG && false
|
||||
#else
|
||||
continue
|
||||
#endif
|
||||
}
|
||||
self.rawItems.append(Item(item: item))
|
||||
}
|
||||
|
||||
if case .botForum = component.kind, !self.rawItems.contains(where: { item in
|
||||
if case let .forum(topicId) = item.id {
|
||||
return topicId == EngineMessage.newTopicThreadId
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}) {
|
||||
self.rawItems.insert(Item(item: EngineChatList.Item(
|
||||
id: .forum(EngineMessage.newTopicThreadId),
|
||||
index: EngineChatList.Item.Index.forum(pinnedIndex: .none, timestamp: Int32.max - 1, threadId: EngineMessage.newTopicThreadId, namespace: Namespaces.Message.Local, id: 1),
|
||||
messages: [],
|
||||
readCounters: nil,
|
||||
isMuted: false,
|
||||
draft: nil,
|
||||
threadData: nil,
|
||||
renderedPeer: EngineRenderedPeer(peerId: peerId, peers: [:], associatedMedia: [:]),
|
||||
presence: nil,
|
||||
hasUnseenMentions: false,
|
||||
hasUnseenReactions: false,
|
||||
forumTopicData: nil,
|
||||
topForumTopicItems: [],
|
||||
hasFailed: false,
|
||||
isContact: false,
|
||||
autoremoveTimeout: nil,
|
||||
storyStats: nil,
|
||||
displayAsTopicList: false,
|
||||
isPremiumRequiredToMessage: false,
|
||||
mediaDraftContentType: nil
|
||||
)), at: 0)
|
||||
}
|
||||
|
||||
if self.reorderingItems != nil {
|
||||
self.reorderingItems = self.rawItems
|
||||
}
|
||||
|
|
@ -1786,7 +1903,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
itemTransition = .immediate
|
||||
animateIn = true
|
||||
itemView = TabItemView(context: component.context, action: { [weak self] in
|
||||
guard let self, let component = self.component else {
|
||||
guard let self, let peerId = self.peerId, let component = self.component else {
|
||||
return
|
||||
}
|
||||
if self.isReordering {
|
||||
|
|
@ -1806,7 +1923,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
}
|
||||
|
||||
if threadIds != currentThreadIds {
|
||||
let _ = component.context.engine.peers.setForumChannelPinnedTopics(id: component.peerId, threadIds: threadIds).startStandalone()
|
||||
let _ = component.context.engine.peers.setForumChannelPinnedTopics(id: peerId, threadIds: threadIds).startStandalone()
|
||||
self.resetReorderingOnNextUpdate = true
|
||||
} else {
|
||||
self.reorderingItems = nil
|
||||
|
|
@ -1880,6 +1997,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
id: ScrollId.all,
|
||||
component: AnyComponent(VerticalAllItemComponent(
|
||||
isSelected: component.topicId == nil,
|
||||
kind: component.kind,
|
||||
theme: component.theme,
|
||||
strings: component.strings,
|
||||
action: { [weak self] in
|
||||
|
|
@ -1895,6 +2013,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
id: ScrollId.all,
|
||||
component: AnyComponent(HorizontalAllItemComponent(
|
||||
isSelected: component.topicId == nil,
|
||||
kind: component.kind,
|
||||
theme: component.theme,
|
||||
strings: component.strings,
|
||||
action: { [weak self] in
|
||||
|
|
@ -1937,10 +2056,10 @@ public final class ChatSideTopicsPanel: Component {
|
|||
component.updateTopicId(topicId, direction)
|
||||
}
|
||||
var itemContextGesture: ((ContextGesture, ContextExtractedContentContainingNode) -> Void)?
|
||||
if !self.isReordering && component.isMonoforum {
|
||||
if !self.isReordering, case .monoforum = component.kind {
|
||||
itemContextGesture = { [weak self] gesture, sourceNode in
|
||||
Task { @MainActor in
|
||||
guard let self, let component = self.component else {
|
||||
guard let self, let peerId = self.peerId, let component = self.component else {
|
||||
return
|
||||
}
|
||||
guard let controller = component.controller() else {
|
||||
|
|
@ -1964,18 +2083,18 @@ public final class ChatSideTopicsPanel: Component {
|
|||
var items: [ContextMenuItem] = []
|
||||
|
||||
let threadInfo = await component.context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Messages.ThreadInfo(peerId: component.peerId, threadId: topicId)
|
||||
TelegramEngine.EngineData.Item.Messages.ThreadInfo(peerId: peerId, threadId: topicId)
|
||||
).get()
|
||||
|
||||
if let threadInfo, threadInfo.isMessageFeeRemoved {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ReinstatePaidMessages, textColor: .primary, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Rate"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
guard let self, let component = self.component else {
|
||||
guard let self, let peerId = self.peerId, let component = self.component else {
|
||||
return
|
||||
}
|
||||
|
||||
c?.dismiss(completion: {})
|
||||
|
||||
let _ = component.context.engine.peers.reinstateNoPaidMessagesException(scopePeerId: component.peerId, peerId: EnginePeer.Id(topicId)).startStandalone()
|
||||
let _ = component.context.engine.peers.reinstateNoPaidMessagesException(scopePeerId: peerId, peerId: EnginePeer.Id(topicId)).startStandalone()
|
||||
})))
|
||||
}
|
||||
|
||||
|
|
@ -2011,7 +2130,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
}
|
||||
} else if !self.isReordering {
|
||||
itemContextGesture = { [weak self] gesture, sourceNode in
|
||||
guard let self, let component = self.component else {
|
||||
guard let self, let peerId = self.peerId, let component = self.component else {
|
||||
return
|
||||
}
|
||||
guard let controller = component.controller() else {
|
||||
|
|
@ -2043,7 +2162,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
|
||||
let _ = (chatForumTopicMenuItems(
|
||||
context: component.context,
|
||||
peerId: component.peerId,
|
||||
peerId: peerId,
|
||||
threadId: topicId,
|
||||
isPinned: isPinned,
|
||||
isClosed: isClosed,
|
||||
|
|
@ -2052,12 +2171,12 @@ public final class ChatSideTopicsPanel: Component {
|
|||
canSelect: false,
|
||||
customEdit: { [weak self] contextController in
|
||||
contextController.dismiss(completion: {
|
||||
guard let self, let component = self.component, let threadData else {
|
||||
guard let self, let peerId = self.peerId, let component = self.component, let threadData else {
|
||||
return
|
||||
}
|
||||
let editController = component.context.sharedContext.makeEditForumTopicScreen(
|
||||
context: component.context,
|
||||
peerId: component.peerId,
|
||||
peerId: peerId,
|
||||
threadId: topicId,
|
||||
threadInfo: threadData.info,
|
||||
isHidden: threadData.isHidden
|
||||
|
|
@ -2066,7 +2185,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
})
|
||||
},
|
||||
customPinUnpin: { [weak self] contextController in
|
||||
guard let self, let component = self.component else {
|
||||
guard let self, let peerId = self.peerId, let component = self.component else {
|
||||
contextController.dismiss(completion: {})
|
||||
return
|
||||
}
|
||||
|
|
@ -2074,7 +2193,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
self.isTogglingPinnedItem = true
|
||||
self.dismissContextControllerOnNextUpdate = contextController
|
||||
|
||||
let _ = (component.context.engine.peers.toggleForumChannelTopicPinned(id: component.peerId, threadId: topicId)
|
||||
let _ = (component.context.engine.peers.toggleForumChannelTopicPinned(id: peerId, threadId: topicId)
|
||||
|> deliverOnMainQueue).startStandalone(error: { [weak self, weak contextController] error in
|
||||
guard let self, let component = self.component else {
|
||||
contextController?.dismiss(completion: {})
|
||||
|
|
@ -2099,6 +2218,12 @@ public final class ChatSideTopicsPanel: Component {
|
|||
return
|
||||
}
|
||||
self.updateIsReordering(isReordering: true)
|
||||
},
|
||||
onDeleted: { [weak self] in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
component.updateTopicId(nil, false)
|
||||
}
|
||||
)
|
||||
|> take(1)
|
||||
|
|
|
|||
|
|
@ -1263,15 +1263,18 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||
subtitleColor = UIColor.white
|
||||
|
||||
let statusText: String
|
||||
statusText = peer.debugDisplayTitle
|
||||
if let channel = peer as? TelegramChannel, channel.linkedBotId != nil {
|
||||
statusText = " "
|
||||
} else {
|
||||
statusText = peer.debugDisplayTitle
|
||||
subtitleIsButton = true
|
||||
}
|
||||
|
||||
subtitleStringText = statusText
|
||||
subtitleAttributes = MultiScaleTextState.Attributes(font: Font.semibold(16.0), color: subtitleColor)
|
||||
smallSubtitleAttributes = MultiScaleTextState.Attributes(font: Font.regular(16.0), color: .white, shadowColor: titleShadowColor)
|
||||
|
||||
usernameString = ("", MultiScaleTextState.Attributes(font: Font.regular(16.0), color: .white))
|
||||
|
||||
subtitleIsButton = true
|
||||
|
||||
let (maybePanelStatusData, _, _) = panelStatusData
|
||||
if let panelStatusData = maybePanelStatusData {
|
||||
|
|
@ -1979,7 +1982,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||
self.currentPendingStarRating = nil
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#if DEBUG && false
|
||||
if "".isEmpty {
|
||||
let starRating: TelegramStarRating
|
||||
|
||||
|
|
|
|||
|
|
@ -12680,7 +12680,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||
} else if peerInfoCanEdit(peer: self.data?.peer, chatLocation: self.chatLocation, threadData: self.data?.threadData, cachedData: self.data?.cachedData, isContact: self.data?.isContact) {
|
||||
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .edit, isForExpandedView: false))
|
||||
}
|
||||
if let data = self.data, !data.isPremiumRequiredForStoryPosting || data.accountIsPremium, let channel = data.peer as? TelegramChannel, channel.hasPermission(.postStories) {
|
||||
if let data = self.data, !data.isPremiumRequiredForStoryPosting || data.accountIsPremium, let channel = data.peer as? TelegramChannel, channel.hasPermission(.postStories), channel.linkedBotId == nil {
|
||||
rightNavigationButtons.insert(PeerInfoHeaderNavigationButtonSpec(key: .postStory, isForExpandedView: false), at: 0)
|
||||
} else if self.isMyProfile {
|
||||
rightNavigationButtons.insert(PeerInfoHeaderNavigationButtonSpec(key: .postStory, isForExpandedView: false), at: 0)
|
||||
|
|
|
|||
|
|
@ -130,6 +130,9 @@ extension ChatControllerImpl {
|
|||
|
||||
self.contentDataDisposable?.dispose()
|
||||
|
||||
self.newTopicEventsDisposable?.dispose()
|
||||
self.newTopicEventsDisposable = nil
|
||||
|
||||
let configuration: Signal<ChatControllerImpl.ContentData.Configuration, NoError> = self.presentationInterfaceStatePromise.get()
|
||||
|> map { presentationInterfaceState -> ChatControllerImpl.ContentData.Configuration in
|
||||
return ChatControllerImpl.ContentData.Configuration(
|
||||
|
|
@ -166,6 +169,10 @@ extension ChatControllerImpl {
|
|||
if let historyNodeData = contentData.state.historyNodeData {
|
||||
self.updateChatLocationToOther(chatLocation: historyNodeData.chatLocation)
|
||||
return
|
||||
} else if case let .botForumThread(linkedForumId, threadId) = self.subject {
|
||||
self.subject = nil
|
||||
self.updateInitialChatBotForumLocationThread(linkedForumId: linkedForumId, threadId: threadId)
|
||||
return
|
||||
}
|
||||
|
||||
apply({ [weak self, weak contentData] forceAnimation in
|
||||
|
|
@ -202,6 +209,25 @@ extension ChatControllerImpl {
|
|||
self.contentDataUpdated(synchronous: false, forceAnimation: false, previousState: previousState)
|
||||
}
|
||||
})
|
||||
|
||||
if self.newTopicEventsDisposable == nil, let peerId = chatLocation.peerId, chatLocation.threadId == EngineMessage.newTopicThreadId {
|
||||
self.newTopicEventsDisposable = (self.context.account.pendingMessageManager.newTopicEvents(peerId: peerId)
|
||||
|> mapToSignal { event -> Signal<Int64, NoError> in
|
||||
if case let .didMove(fromThreadId, toThreadId) = event {
|
||||
if fromThreadId == EngineMessage.newTopicThreadId {
|
||||
return .single(toThreadId)
|
||||
}
|
||||
}
|
||||
return .never()
|
||||
}
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] threadId in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.updateInitialChatBotForumLocationThread(linkedForumId: peerId, threadId: threadId)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ import ChatEmptyNode
|
|||
import ChatMediaInputStickerGridItem
|
||||
import AdsInfoScreen
|
||||
import FaceScanScreen
|
||||
import ForumCreateTopicScreen
|
||||
|
||||
extension ChatControllerImpl {
|
||||
func openPeer(peer: EnginePeer?, navigation: ChatControllerInteractionNavigateToPeer, fromMessage: MessageReference?, fromReactionMessageId: MessageId? = nil, expandAvatar: Bool = false, peerTypes: ReplyMarkupButtonAction.PeerTypes? = nil, skipAgeVerification: Bool = false) {
|
||||
|
|
@ -328,4 +329,106 @@ extension ChatControllerImpl {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func openBotForumMoreMenu(sourceView: UIView, gesture: ContextGesture?) {
|
||||
Task { @MainActor [weak self] in
|
||||
guard let self, let peerId = self.chatLocation.peerId else {
|
||||
return
|
||||
}
|
||||
guard let forumPeerId = await (self.context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.LinkedBotForumPeerId(id: peerId)
|
||||
)
|
||||
|> map { value -> EnginePeer.Id? in
|
||||
if case let .known(value) = value {
|
||||
return value
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}).get() else {
|
||||
return
|
||||
}
|
||||
|
||||
let strings = self.presentationData.strings
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
//TODO:localize
|
||||
items.append(.action(ContextMenuActionItem(text: "Open Profile", icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Info"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
guard let self, let peer = self.presentationInterfaceState.renderedPeer?.chatMainPeer else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let controller = self.context.sharedContext.makePeerInfoController(context: self.context, updatedPresentationData: nil, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) else {
|
||||
return
|
||||
}
|
||||
(self.navigationController as? NavigationController)?.pushViewController(controller)
|
||||
})))
|
||||
|
||||
items.append(.separator)
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Conversation_Search, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Search"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] action in
|
||||
action.dismissWithResult(.default)
|
||||
|
||||
self?.beginMessageSearch("")
|
||||
})))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Chat_CreateTopic, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] action in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
action.dismissWithResult(.default)
|
||||
|
||||
let controller = ForumCreateTopicScreen(context: self.context, peerId: forumPeerId, mode: .create)
|
||||
controller.navigationPresentation = .modal
|
||||
|
||||
controller.completion = { [weak self, weak controller] title, fileId, iconColor, _ in
|
||||
controller?.isInProgress = true
|
||||
controller?.view.endEditing(true)
|
||||
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
let _ = (self.context.engine.peers.createForumChannelTopic(id: forumPeerId, title: title, iconColor: iconColor, iconFileId: fileId)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self, weak controller] topicId in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.updateChatLocationThread(threadId: topicId)
|
||||
controller?.dismiss()
|
||||
}, error: { _ in
|
||||
controller?.isInProgress = false
|
||||
})
|
||||
}
|
||||
self.push(controller)
|
||||
})))
|
||||
|
||||
let presentationData = self.presentationData
|
||||
|
||||
let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: self, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
self.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class HeaderContextReferenceContentSource: ContextReferenceContentSource {
|
||||
private let controller: ViewController
|
||||
private let sourceView: UIView
|
||||
|
||||
init(controller: ViewController, sourceView: UIView) {
|
||||
self.controller = controller
|
||||
self.sourceView = sourceView
|
||||
}
|
||||
|
||||
func transitionInfo() -> ContextControllerReferenceViewInfo? {
|
||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
|
||||
let context: AccountContext
|
||||
public internal(set) var chatLocation: ChatLocation
|
||||
public let subject: ChatControllerSubject?
|
||||
public internal(set) var subject: ChatControllerSubject?
|
||||
|
||||
var botStart: ChatControllerInitialBotStart?
|
||||
var attachBotStart: ChatControllerInitialAttachBotStart?
|
||||
|
|
@ -258,6 +258,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
var contentData: ChatControllerImpl.ContentData?
|
||||
let contentDataReady = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||
var contentDataDisposable: Disposable?
|
||||
var newTopicEventsDisposable: Disposable?
|
||||
var didHandlePerformDismissAction: Bool = false
|
||||
var didInitializePersistentPeerInterfaceData: Bool = false
|
||||
|
||||
|
|
@ -703,6 +704,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
|
||||
self.stickerSettings = ChatInterfaceStickerSettings()
|
||||
|
||||
var subject = subject
|
||||
if case .botForumThread = subject {
|
||||
subject = nil
|
||||
}
|
||||
|
||||
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: context.account.peerId, mode: mode, chatLocation: chatLocation, subject: subject, peerNearbyData: peerNearbyData, greetingData: context.prefetchManager?.preloadedGreetingSticker, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil)
|
||||
|
||||
if case let .customChatContents(customChatContents) = subject {
|
||||
|
|
@ -5528,6 +5534,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
|
||||
if peerId == self.context.account.peerId {
|
||||
PeerInfoScreenImpl.openSavedMessagesMoreMenu(context: self.context, sourceController: self, isViewingAsTopics: false, sourceView: sourceNode.view, gesture: gesture)
|
||||
} else if peerId.namespace == Namespaces.Peer.CloudUser {
|
||||
self.openBotForumMoreMenu(sourceView: sourceNode.view, gesture: gesture)
|
||||
} else {
|
||||
ChatListControllerImpl.openMoreMenu(context: self.context, peerId: peerId, sourceController: self, isViewingAsTopics: false, sourceView: sourceNode.view, gesture: gesture)
|
||||
}
|
||||
|
|
@ -6179,6 +6187,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
self.updateChatLocationThreadDisposable?.dispose()
|
||||
self.accountPeerDisposable?.dispose()
|
||||
self.contentDataDisposable?.dispose()
|
||||
self.newTopicEventsDisposable?.dispose()
|
||||
self.updateMessageTodoDisposables?.dispose()
|
||||
self.preloadNextChatPeerIdDisposable.dispose()
|
||||
}
|
||||
|
|
@ -8827,7 +8836,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
return
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#if DEBUG && false
|
||||
let botForumId = await self.context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.LinkedBotForumPeerId(id: peerId)
|
||||
).get()
|
||||
|
|
@ -10144,17 +10153,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
})
|
||||
}
|
||||
|
||||
public func updateChatLocationThread(threadId: Int64?, animationDirection: ChatControllerAnimateInnerChatSwitchDirection? = nil) {
|
||||
func updateInitialChatBotForumLocationThread(linkedForumId: EnginePeer.Id, threadId: Int64) {
|
||||
if self.isUpdatingChatLocationThread {
|
||||
return
|
||||
}
|
||||
guard let peerId = self.chatLocation.peerId else {
|
||||
return
|
||||
}
|
||||
if self.chatLocation.threadId == threadId {
|
||||
return
|
||||
}
|
||||
guard let peer = self.presentationInterfaceState.renderedPeer?.chatMainPeer else {
|
||||
assertionFailure()
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -10162,34 +10163,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
|
||||
self.chatDisplayNode.dismissTextInput()
|
||||
|
||||
let updatedChatLocation: ChatLocation
|
||||
if let threadId {
|
||||
var isMonoforum = false
|
||||
if let channel = peer as? TelegramChannel, channel.flags.contains(.isMonoforum) {
|
||||
isMonoforum = true
|
||||
}
|
||||
|
||||
updatedChatLocation = .replyThread(message: ChatReplyThreadMessage(
|
||||
peerId: peerId,
|
||||
threadId: threadId,
|
||||
channelMessageId: nil,
|
||||
isChannelPost: false,
|
||||
isForumPost: true,
|
||||
isMonoforumPost: isMonoforum,
|
||||
maxMessage: nil,
|
||||
maxReadIncomingMessageId: nil,
|
||||
maxReadOutgoingMessageId: nil,
|
||||
unreadCount: 0,
|
||||
initialFilledHoles: IndexSet(),
|
||||
initialAnchor: .automatic,
|
||||
isNotAvailable: false
|
||||
))
|
||||
} else {
|
||||
updatedChatLocation = .peer(id: peerId)
|
||||
}
|
||||
|
||||
let navigationSnapshot = self.chatTitleView?.prepareSnapshotState()
|
||||
let avatarSnapshot = self.chatInfoNavigationButton?.buttonItem.customDisplayNode?.view.window != nil ? (self.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.prepareSnapshotState() : nil
|
||||
let updatedChatLocation: ChatLocation = .replyThread(message: ChatReplyThreadMessage(
|
||||
peerId: linkedForumId,
|
||||
threadId: threadId,
|
||||
channelMessageId: nil,
|
||||
isChannelPost: false,
|
||||
isForumPost: true,
|
||||
isMonoforumPost: false,
|
||||
maxMessage: nil,
|
||||
maxReadIncomingMessageId: nil,
|
||||
maxReadOutgoingMessageId: nil,
|
||||
unreadCount: 0,
|
||||
initialFilledHoles: IndexSet(),
|
||||
initialAnchor: .automatic,
|
||||
isNotAvailable: false
|
||||
))
|
||||
|
||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||
let historyNode = self.chatDisplayNode.createHistoryNodeForChatLocation(chatLocation: updatedChatLocation, chatLocationContextHolder: chatLocationContextHolder)
|
||||
|
|
@ -10199,38 +10187,139 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
return
|
||||
}
|
||||
|
||||
self.currentChatSwitchDirection = animationDirection
|
||||
self.currentChatSwitchDirection = nil
|
||||
self.chatLocation = updatedChatLocation
|
||||
historyNode.areContentAnimationsEnabled = true
|
||||
self.chatDisplayNode.prepareSwitchToChatLocation(historyNode: historyNode, animationDirection: animationDirection)
|
||||
self.chatDisplayNode.prepareSwitchToChatLocation(historyNode: historyNode, animationDirection: nil)
|
||||
|
||||
apply(true)
|
||||
|
||||
if let navigationSnapshot, let animationDirection {
|
||||
let mappedAnimationDirection: ChatTitleView.AnimateFromSnapshotDirection
|
||||
switch animationDirection {
|
||||
case .up:
|
||||
mappedAnimationDirection = .up
|
||||
case .down:
|
||||
mappedAnimationDirection = .down
|
||||
case .left:
|
||||
mappedAnimationDirection = .left
|
||||
case .right:
|
||||
mappedAnimationDirection = .right
|
||||
}
|
||||
|
||||
self.chatTitleView?.animateFromSnapshot(navigationSnapshot, direction: mappedAnimationDirection)
|
||||
}
|
||||
|
||||
if let avatarSnapshot, self.chatInfoNavigationButton?.buttonItem.customDisplayNode?.view.window != nil {
|
||||
(self.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.animateFromSnapshot(avatarSnapshot)
|
||||
}
|
||||
|
||||
self.currentChatSwitchDirection = nil
|
||||
self.isUpdatingChatLocationThread = false
|
||||
})
|
||||
}
|
||||
|
||||
public func updateChatLocationThread(threadId: Int64?, animationDirection: ChatControllerAnimateInnerChatSwitchDirection? = nil) {
|
||||
Task { @MainActor [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
if self.isUpdatingChatLocationThread {
|
||||
return
|
||||
}
|
||||
guard let peerId = self.chatLocation.peerId else {
|
||||
return
|
||||
}
|
||||
if self.chatLocation.threadId == threadId {
|
||||
return
|
||||
}
|
||||
guard let peer = self.presentationInterfaceState.renderedPeer?.chatMainPeer else {
|
||||
return
|
||||
}
|
||||
|
||||
self.saveInterfaceState()
|
||||
|
||||
self.chatDisplayNode.dismissTextInput()
|
||||
|
||||
let updatedChatLocation: ChatLocation
|
||||
if let threadId {
|
||||
if let user = peer as? TelegramUser, let botInfo = user.botInfo, botInfo.flags.contains(.hasForum) {
|
||||
guard case let .known(linkedForumId) = await self.context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.LinkedBotForumPeerId(id: user.id)
|
||||
).get(), let linkedForumId else {
|
||||
return
|
||||
}
|
||||
|
||||
updatedChatLocation = .replyThread(message: ChatReplyThreadMessage(
|
||||
peerId: linkedForumId,
|
||||
threadId: threadId,
|
||||
channelMessageId: nil,
|
||||
isChannelPost: false,
|
||||
isForumPost: true,
|
||||
isMonoforumPost: false,
|
||||
maxMessage: nil,
|
||||
maxReadIncomingMessageId: nil,
|
||||
maxReadOutgoingMessageId: nil,
|
||||
unreadCount: 0,
|
||||
initialFilledHoles: IndexSet(),
|
||||
initialAnchor: .automatic,
|
||||
isNotAvailable: false
|
||||
))
|
||||
} else {
|
||||
var isMonoforum = false
|
||||
if let channel = peer as? TelegramChannel, channel.flags.contains(.isMonoforum) {
|
||||
isMonoforum = true
|
||||
}
|
||||
|
||||
updatedChatLocation = .replyThread(message: ChatReplyThreadMessage(
|
||||
peerId: peerId,
|
||||
threadId: threadId,
|
||||
channelMessageId: nil,
|
||||
isChannelPost: false,
|
||||
isForumPost: true,
|
||||
isMonoforumPost: isMonoforum,
|
||||
maxMessage: nil,
|
||||
maxReadIncomingMessageId: nil,
|
||||
maxReadOutgoingMessageId: nil,
|
||||
unreadCount: 0,
|
||||
initialFilledHoles: IndexSet(),
|
||||
initialAnchor: .automatic,
|
||||
isNotAvailable: false
|
||||
))
|
||||
}
|
||||
} else {
|
||||
if let channel = peer as? TelegramChannel, let linkedBotId = channel.linkedBotId {
|
||||
updatedChatLocation = .peer(id: linkedBotId)
|
||||
} else {
|
||||
updatedChatLocation = .peer(id: peerId)
|
||||
}
|
||||
}
|
||||
|
||||
let navigationSnapshot = self.chatTitleView?.prepareSnapshotState()
|
||||
let avatarSnapshot = self.chatInfoNavigationButton?.buttonItem.customDisplayNode?.view.window != nil ? (self.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.prepareSnapshotState() : nil
|
||||
|
||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||
let historyNode = self.chatDisplayNode.createHistoryNodeForChatLocation(chatLocation: updatedChatLocation, chatLocationContextHolder: chatLocationContextHolder)
|
||||
self.isUpdatingChatLocationThread = true
|
||||
self.reloadChatLocation(chatLocation: updatedChatLocation, chatLocationContextHolder: chatLocationContextHolder, historyNode: historyNode, apply: { [weak self, weak historyNode] apply in
|
||||
guard let self, let historyNode else {
|
||||
return
|
||||
}
|
||||
|
||||
self.currentChatSwitchDirection = animationDirection
|
||||
self.chatLocation = updatedChatLocation
|
||||
historyNode.areContentAnimationsEnabled = true
|
||||
self.chatDisplayNode.prepareSwitchToChatLocation(historyNode: historyNode, animationDirection: animationDirection)
|
||||
|
||||
apply(true)
|
||||
|
||||
if let navigationSnapshot, let animationDirection {
|
||||
let mappedAnimationDirection: ChatTitleView.AnimateFromSnapshotDirection
|
||||
switch animationDirection {
|
||||
case .up:
|
||||
mappedAnimationDirection = .up
|
||||
case .down:
|
||||
mappedAnimationDirection = .down
|
||||
case .left:
|
||||
mappedAnimationDirection = .left
|
||||
case .right:
|
||||
mappedAnimationDirection = .right
|
||||
}
|
||||
|
||||
self.chatTitleView?.animateFromSnapshot(navigationSnapshot, direction: mappedAnimationDirection)
|
||||
}
|
||||
|
||||
if let avatarSnapshot, self.chatInfoNavigationButton?.buttonItem.customDisplayNode?.view.window != nil {
|
||||
(self.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.animateFromSnapshot(avatarSnapshot)
|
||||
}
|
||||
|
||||
self.currentChatSwitchDirection = nil
|
||||
self.isUpdatingChatLocationThread = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public var contentContainerNode: ASDisplayNode {
|
||||
return self.chatDisplayNode.contentContainerNode
|
||||
}
|
||||
|
|
|
|||
|
|
@ -811,7 +811,6 @@ extension ChatControllerImpl {
|
|||
var sendPaidMessageStars: StarsAmount?
|
||||
var alwaysShowGiftButton = false
|
||||
var disallowedGifts: TelegramDisallowedGifts?
|
||||
var switchToBotForum: EnginePeer.Id?
|
||||
if let peer = peerView.peers[peerView.peerId] {
|
||||
if let cachedData = peerView.cachedData as? CachedUserData {
|
||||
contactStatus = ChatContactStatus(canAddContact: !peerView.peerIsContact, peerStatusSettings: cachedData.peerStatusSettings, invitedBy: nil, managingBot: managingBot)
|
||||
|
|
@ -826,11 +825,6 @@ extension ChatControllerImpl {
|
|||
}
|
||||
disallowedGifts = cachedData.disallowedGifts
|
||||
}
|
||||
if case let .known(value) = cachedData.linkedBotChannelId {
|
||||
if let value {
|
||||
switchToBotForum = value
|
||||
}
|
||||
}
|
||||
} else if let cachedData = peerView.cachedData as? CachedGroupData {
|
||||
var invitedBy: Peer?
|
||||
if let invitedByPeerId = cachedData.invitedBy {
|
||||
|
|
@ -1030,15 +1024,6 @@ extension ChatControllerImpl {
|
|||
|
||||
strongSelf.state.renderedPeer = renderedPeer
|
||||
strongSelf.state.adMessage = adMessage
|
||||
|
||||
if let switchToBotForum {
|
||||
strongSelf.state.historyNodeData = HistoryNodeData(
|
||||
chatLocation: .peer(id: switchToBotForum),
|
||||
chatLocationContextHolder: Atomic(value: nil)
|
||||
)
|
||||
} else {
|
||||
strongSelf.state.historyNodeData = nil
|
||||
}
|
||||
|
||||
if case .standard(.default) = mode, let channel = renderedPeer?.chatMainPeer as? TelegramChannel, case .broadcast = channel.info {
|
||||
var isRegularChat = false
|
||||
|
|
@ -1459,12 +1444,19 @@ extension ChatControllerImpl {
|
|||
)
|
||||
|
||||
var customMessageCount: Int?
|
||||
if let peer = peerView.peers[peerView.peerId] as? TelegramChannel, peer.isMonoForum {
|
||||
var customSubtitle: String?
|
||||
if let peer = peerView.peers[peerView.peerId] as? TelegramChannel {
|
||||
if peer.isMonoForum {
|
||||
} else if peer.linkedBotId != nil {
|
||||
customSubtitle = strongSelf.presentationData.strings.Bot_GenericBotStatus
|
||||
} else {
|
||||
customMessageCount = savedMessagesPeer?.messageCount ?? 0
|
||||
}
|
||||
} else {
|
||||
customMessageCount = savedMessagesPeer?.messageCount ?? 0
|
||||
}
|
||||
|
||||
strongSelf.state.chatTitleContent = .peer(peerView: mappedPeerData, customTitle: nil, customSubtitle: nil, onlineMemberCount: (nil, nil), isScheduledMessages: false, isMuted: false, customMessageCount: customMessageCount, isEnabled: true)
|
||||
strongSelf.state.chatTitleContent = .peer(peerView: mappedPeerData, customTitle: nil, customSubtitle: customSubtitle, onlineMemberCount: (nil, nil), isScheduledMessages: false, isMuted: false, customMessageCount: customMessageCount, isEnabled: true)
|
||||
|
||||
strongSelf.state.peerView = peerView
|
||||
|
||||
|
|
@ -1551,7 +1543,15 @@ extension ChatControllerImpl {
|
|||
}
|
||||
|
||||
if let threadInfo = messageAndTopic.threadData?.info {
|
||||
strongSelf.state.chatTitleContent = .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: threadInfo.title, customSubtitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: peerIsMuted, customMessageCount: messageAndTopic.messageCount == 0 ? nil : messageAndTopic.messageCount, isEnabled: true)
|
||||
var customSubtitle: String?
|
||||
if messageAndTopic.messageCount == 0, let peer = peerView.peers[peerView.peerId] as? TelegramChannel {
|
||||
if peer.linkedBotId != nil {
|
||||
//TODO:localize
|
||||
customSubtitle = "topic"
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.state.chatTitleContent = .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: threadInfo.title, customSubtitle: customSubtitle, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: peerIsMuted, customMessageCount: messageAndTopic.messageCount == 0 ? nil : messageAndTopic.messageCount, isEnabled: true)
|
||||
|
||||
let avatarContent: EmojiStatusComponent.Content
|
||||
if chatLocation.threadId == 1 {
|
||||
|
|
@ -1569,6 +1569,10 @@ extension ChatControllerImpl {
|
|||
infoContextActionIsEnabled = true
|
||||
}
|
||||
strongSelf.state.infoAvatar = .emojiStatus(content: avatarContent, contextActionIsEnabled: infoContextActionIsEnabled)
|
||||
} else if chatLocation.threadId == EngineMessage.newTopicThreadId {
|
||||
//TODO:localize
|
||||
strongSelf.state.chatTitleContent = .custom("New Chat", nil, false)
|
||||
strongSelf.state.infoAvatar = nil
|
||||
} else {
|
||||
strongSelf.state.chatTitleContent = .replyThread(type: replyThreadType, count: count)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1381,7 +1381,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||
|
||||
let currentViewVersion = self.currentViewVersion
|
||||
|
||||
let historyViewUpdate: Signal<(ChatHistoryViewUpdate, Int, ChatHistoryLocationInput?, ClosedRange<Int32>?, Set<MessageId>), NoError>
|
||||
var historyViewUpdate: Signal<(ChatHistoryViewUpdate, Int, ChatHistoryLocationInput?, ClosedRange<Int32>?, Set<MessageId>), NoError>
|
||||
var isFirstTime = true
|
||||
var updateAllOnEachVersion = false
|
||||
if case let .custom(messages, at, quote, _) = self.source {
|
||||
|
|
@ -1746,6 +1746,33 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
let stopHistoryViewUpdates: Signal<Bool, NoError>
|
||||
if let peerId = chatLocation.peerId, chatLocation.threadId == EngineMessage.newTopicThreadId {
|
||||
stopHistoryViewUpdates = Signal<Bool, NoError>.single(false)
|
||||
|> then(
|
||||
self.context.account.pendingMessageManager.newTopicEvents(peerId: peerId)
|
||||
|> mapToSignal { event -> Signal<Bool, NoError> in
|
||||
if case .willMove(EngineMessage.newTopicThreadId, _) = event {
|
||||
return .single(true)
|
||||
} else {
|
||||
return .never()
|
||||
}
|
||||
}
|
||||
|> take(1)
|
||||
)
|
||||
} else {
|
||||
stopHistoryViewUpdates = .single(false)
|
||||
}
|
||||
|
||||
let historyViewUpdateValue = historyViewUpdate
|
||||
historyViewUpdate = stopHistoryViewUpdates |> mapToSignal { value in
|
||||
if value {
|
||||
return .never()
|
||||
} else {
|
||||
return historyViewUpdateValue
|
||||
}
|
||||
}
|
||||
|
||||
let startTime = CFAbsoluteTimeGetCurrent()
|
||||
var measure_isFirstTime = true
|
||||
let messageViewQueue = Queue.mainQueue()
|
||||
|
|
|
|||
|
|
@ -132,6 +132,13 @@ func rightNavigationButtonForChatInterfaceState(context: AccountContext, present
|
|||
}
|
||||
}
|
||||
|
||||
if let user = presentationInterfaceState.renderedPeer?.peer as? TelegramUser, let botInfo = user.botInfo, botInfo.flags.contains(.hasForum), let moreInfoNavigationButton = moreInfoNavigationButton {
|
||||
if case .pinnedMessages = presentationInterfaceState.subject {
|
||||
} else {
|
||||
return moreInfoNavigationButton
|
||||
}
|
||||
}
|
||||
|
||||
if case .messageOptions = presentationInterfaceState.subject {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ func titleTopicsPanelForChatPresentationInterfaceState(_ chatPresentationInterfa
|
|||
if let currentPanel = currentPanel as? ChatTopicListTitleAccessoryPanelNode {
|
||||
return currentPanel
|
||||
} else {
|
||||
let panel = ChatTopicListTitleAccessoryPanelNode(context: context, peerId: peerId, isMonoforum: true)
|
||||
let panel = ChatTopicListTitleAccessoryPanelNode(context: context, peerId: peerId, kind: .monoforum)
|
||||
panel.interfaceInteraction = interfaceInteraction
|
||||
return panel
|
||||
}
|
||||
|
|
@ -248,7 +248,18 @@ func titleTopicsPanelForChatPresentationInterfaceState(_ chatPresentationInterfa
|
|||
if let currentPanel = currentPanel as? ChatTopicListTitleAccessoryPanelNode {
|
||||
return currentPanel
|
||||
} else {
|
||||
let panel = ChatTopicListTitleAccessoryPanelNode(context: context, peerId: peerId, isMonoforum: false)
|
||||
let panel = ChatTopicListTitleAccessoryPanelNode(context: context, peerId: peerId, kind: channel.linkedBotId != nil ? .botForum : .forum)
|
||||
panel.interfaceInteraction = interfaceInteraction
|
||||
return panel
|
||||
}
|
||||
}
|
||||
} else if let user = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramUser, let botInfo = user.botInfo, botInfo.flags.contains(.hasForum), chatPresentationInterfaceState.search == nil {
|
||||
let topicListDisplayModeOnTheSide = chatPresentationInterfaceState.persistentData.topicListPanelLocation
|
||||
if !topicListDisplayModeOnTheSide, let peerId = chatPresentationInterfaceState.chatLocation.peerId {
|
||||
if let currentPanel = currentPanel as? ChatTopicListTitleAccessoryPanelNode {
|
||||
return currentPanel
|
||||
} else {
|
||||
let panel = ChatTopicListTitleAccessoryPanelNode(context: context, peerId: peerId, kind: .botForum)
|
||||
panel.interfaceInteraction = interfaceInteraction
|
||||
return panel
|
||||
}
|
||||
|
|
@ -279,7 +290,7 @@ func sidePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceState
|
|||
strings: chatPresentationInterfaceState.strings,
|
||||
location: .side,
|
||||
peerId: peerId,
|
||||
isMonoforum: true,
|
||||
kind: .monoforum,
|
||||
topicId: chatPresentationInterfaceState.chatLocation.threadId,
|
||||
controller: { [weak interfaceInteraction] in
|
||||
return interfaceInteraction?.chatController()
|
||||
|
|
@ -310,7 +321,38 @@ func sidePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceState
|
|||
strings: chatPresentationInterfaceState.strings,
|
||||
location: .side,
|
||||
peerId: peerId,
|
||||
isMonoforum: false,
|
||||
kind: channel.linkedBotId != nil ? .botForum : .forum,
|
||||
topicId: chatPresentationInterfaceState.chatLocation.threadId,
|
||||
controller: { [weak interfaceInteraction] in
|
||||
return interfaceInteraction?.chatController()
|
||||
},
|
||||
togglePanel: { [weak interfaceInteraction] in
|
||||
interfaceInteraction?.toggleChatSidebarMode()
|
||||
},
|
||||
updateTopicId: { [weak interfaceInteraction] topicId, direction in
|
||||
interfaceInteraction?.updateChatLocationThread(topicId, direction ? .down : .up)
|
||||
},
|
||||
openDeletePeer: { [weak interfaceInteraction] threadId in
|
||||
guard let controller = interfaceInteraction?.chatController() as? ChatControllerImpl else {
|
||||
return
|
||||
}
|
||||
controller.openDeleteMonoforumPeer(peerId: EnginePeer.Id(threadId))
|
||||
}
|
||||
))
|
||||
)
|
||||
}
|
||||
} else if let user = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramUser, let botInfo = user.botInfo, botInfo.flags.contains(.hasForum), chatPresentationInterfaceState.search == nil {
|
||||
let topicListDisplayModeOnTheSide = chatPresentationInterfaceState.persistentData.topicListPanelLocation
|
||||
if topicListDisplayModeOnTheSide {
|
||||
return AnyComponentWithIdentity(
|
||||
id: "topics",
|
||||
component: AnyComponent(ChatSideTopicsPanel(
|
||||
context: context,
|
||||
theme: chatPresentationInterfaceState.theme,
|
||||
strings: chatPresentationInterfaceState.strings,
|
||||
location: .side,
|
||||
peerId: peerId,
|
||||
kind: .botForum,
|
||||
topicId: chatPresentationInterfaceState.chatLocation.threadId,
|
||||
controller: { [weak interfaceInteraction] in
|
||||
return interfaceInteraction?.chatController()
|
||||
|
|
|
|||
|
|
@ -53,17 +53,15 @@ final class ChatTopicListTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, C
|
|||
|
||||
private let context: AccountContext
|
||||
private let peerId: EnginePeer.Id
|
||||
private let isMonoforum: Bool
|
||||
private let kind: ChatSideTopicsPanel.Kind
|
||||
private let panel = ComponentView<ChatSidePanelEnvironment>()
|
||||
|
||||
init(context: AccountContext, peerId: EnginePeer.Id, isMonoforum: Bool) {
|
||||
init(context: AccountContext, peerId: EnginePeer.Id, kind: ChatSideTopicsPanel.Kind) {
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
self.isMonoforum = isMonoforum
|
||||
self.kind = kind
|
||||
|
||||
super.init()
|
||||
|
||||
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
@ -103,7 +101,7 @@ final class ChatTopicListTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, C
|
|||
strings: params.interfaceState.strings,
|
||||
location: .top,
|
||||
peerId: self.peerId,
|
||||
isMonoforum: self.isMonoforum,
|
||||
kind: self.kind,
|
||||
topicId: params.interfaceState.chatLocation.threadId,
|
||||
controller: { [weak self] in
|
||||
return self?.interfaceInteraction?.chatController()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue