Various improvements

This commit is contained in:
Isaac 2024-01-30 13:21:18 +01:00
parent 83c7c54616
commit 8a0fbe7f21
8 changed files with 191 additions and 159 deletions

View File

@ -10860,6 +10860,7 @@ Sorry for the inconvenience.";
"Chat.PanelStatusAuthorHidden" = "Senders of these messages restricted to link\ntheir name when forwarding."; "Chat.PanelStatusAuthorHidden" = "Senders of these messages restricted to link\ntheir name when forwarding.";
"Chat.SavedMessagesChatsTooltip" = "Tap to view your Saved Messages organized by type or source"; "Chat.SavedMessagesChatsTooltip" = "Tap to view your Saved Messages organized by type or source";
"Chat.ConfirmationDeleteFromSavedMessages" = "Delete from Saved Messages";
"Chat.ConfirmationRemoveFromSavedMessages" = "Remove from Saved Messages"; "Chat.ConfirmationRemoveFromSavedMessages" = "Remove from Saved Messages";
"Premium.MaxSavedPinsText" = "Sorry, you can't pin more than **%1$@** chats to the top. Unpin some that are currently pinned or subscribe to **Telegram Premium** to double the limit to **%2$@** chats."; "Premium.MaxSavedPinsText" = "Sorry, you can't pin more than **%1$@** chats to the top. Unpin some that are currently pinned or subscribe to **Telegram Premium** to double the limit to **%2$@** chats.";
@ -10964,6 +10965,7 @@ Sorry for the inconvenience.";
"PrivacyInfo.ShowReadTime.AlwaysToast.Text" = "Set **Last Seen** privacy to 'Nobody' or 'My Contacts.'"; "PrivacyInfo.ShowReadTime.AlwaysToast.Text" = "Set **Last Seen** privacy to 'Nobody' or 'My Contacts.'";
"Chat.ToastMessageTagged.Text" = "Message tagged with %@"; "Chat.ToastMessageTagged.Text" = "Message tagged with %@";
"Chat.ToastMessagesTagged.Text" = "Messages tagged with %@";
"Chat.ToastMessageTagged.Action" = "View"; "Chat.ToastMessageTagged.Action" = "View";
"Chat.PrivateMessageSeenTimestamp.Date" = "read %@"; "Chat.PrivateMessageSeenTimestamp.Date" = "read %@";

View File

@ -24,16 +24,17 @@ public final class ChatShareMessageTagView: UIView, UndoOverlayControllerAdditio
private var reactionContextNode: ReactionContextNode? private var reactionContextNode: ReactionContextNode?
private var params: Params? private var params: Params?
public init(context: AccountContext, presentationData: PresentationData, reactionItems: [ReactionItem], completion: @escaping (TelegramMediaFile, UpdateMessageReaction) -> Void) { public init(context: AccountContext, presentationData: PresentationData, isSingleMessage: Bool, reactionItems: [ReactionItem], completion: @escaping (TelegramMediaFile, UpdateMessageReaction) -> Void) {
super.init(frame: CGRect()) super.init(frame: CGRect())
//TODO:localize
let reactionContextNode = ReactionContextNode( let reactionContextNode = ReactionContextNode(
context: context, context: context,
animationCache: context.animationCache, animationCache: context.animationCache,
presentationData: presentationData, presentationData: presentationData,
items: reactionItems.map(ReactionContextItem.reaction), items: reactionItems.map(ReactionContextItem.reaction),
selectedItems: Set(), selectedItems: Set(),
title: presentationData.strings.Chat_ContextMenuTagsTitle, title: isSingleMessage ? presentationData.strings.Chat_ContextMenuTagsTitle : "You can add a tag to messages",
reactionsLocked: false, reactionsLocked: false,
alwaysAllowPremiumReactions: false, alwaysAllowPremiumReactions: false,
allPresetReactionsAreAvailable: true, allPresetReactionsAreAvailable: true,

View File

@ -16649,6 +16649,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
func presentDeleteMessageOptions(messageIds: Set<MessageId>, options: ChatAvailableMessageActionOptions, contextController: ContextControllerProtocol?, completion: @escaping (ContextMenuActionResult) -> Void) { func presentDeleteMessageOptions(messageIds: Set<MessageId>, options: ChatAvailableMessageActionOptions, contextController: ContextControllerProtocol?, completion: @escaping (ContextMenuActionResult) -> Void) {
let _ = (self.context.engine.data.get(
EngineDataMap(messageIds.map(TelegramEngine.EngineData.Item.Messages.Message.init(id:)))
)
|> deliverOnMainQueue).start(next: { [weak self] messages in
guard let self else {
return
}
let actionSheet = ActionSheetController(presentationData: self.presentationData) let actionSheet = ActionSheetController(presentationData: self.presentationData)
var items: [ActionSheetItem] = [] var items: [ActionSheetItem] = []
var personalPeerName: String? var personalPeerName: String?
@ -16739,7 +16747,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if options.contains(.deleteLocally) { if options.contains(.deleteLocally) {
var localOptionText = self.presentationData.strings.Conversation_DeleteMessagesForMe var localOptionText = self.presentationData.strings.Conversation_DeleteMessagesForMe
if self.chatLocation.peerId == self.context.account.peerId { if self.chatLocation.peerId == self.context.account.peerId {
if case .peer(self.context.account.peerId) = self.chatLocation, messages.values.allSatisfy({ message in message?._asMessage().effectivelyIncoming(self.context.account.peerId) ?? false }) {
localOptionText = self.presentationData.strings.Chat_ConfirmationRemoveFromSavedMessages localOptionText = self.presentationData.strings.Chat_ConfirmationRemoveFromSavedMessages
} else {
localOptionText = self.presentationData.strings.Chat_ConfirmationDeleteFromSavedMessages
}
} else if case .scheduledMessages = self.presentationInterfaceState.subject { } else if case .scheduledMessages = self.presentationInterfaceState.subject {
localOptionText = messageIds.count > 1 ? self.presentationData.strings.ScheduledMessages_DeleteMany : self.presentationData.strings.ScheduledMessages_Delete localOptionText = messageIds.count > 1 ? self.presentationData.strings.ScheduledMessages_DeleteMany : self.presentationData.strings.ScheduledMessages_Delete
} else { } else {
@ -16805,6 +16817,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
completion(.default) completion(.default)
} }
} }
})
} }
func presentClearCacheSuggestion() { func presentClearCacheSuggestion() {

View File

@ -186,7 +186,7 @@ extension ChatControllerImpl {
} }
let reactionItems: Signal<[ReactionItem], NoError> let reactionItems: Signal<[ReactionItem], NoError>
if savedMessages && messages.count == 1 { if savedMessages && messages.count > 0 {
reactionItems = tagMessageReactions(context: strongSelf.context) reactionItems = tagMessageReactions(context: strongSelf.context)
} else { } else {
reactionItems = .single([]) reactionItems = .single([])
@ -198,7 +198,7 @@ extension ChatControllerImpl {
return return
} }
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, position: savedMessages && messages.count == 1 ? .top : .bottom, animateInAsReplacement: true, action: { action in strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, position: savedMessages && messages.count > 0 ? .top : .bottom, animateInAsReplacement: true, action: { action in
if savedMessages, let self, action == .info { if savedMessages, let self, action == .info {
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId)) let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId))
|> deliverOnMainQueue).start(next: { [weak self] peer in |> deliverOnMainQueue).start(next: { [weak self] peer in
@ -212,7 +212,7 @@ extension ChatControllerImpl {
}) })
} }
return false return false
}, additionalView: (savedMessages && messages.count == 1) ? chatShareToSavedMessagesAdditionalView(strongSelf, reactionItems: reactionItems, correlationId: correlationIds.first) : nil), in: .current) }, additionalView: (savedMessages && messages.count > 0) ? chatShareToSavedMessagesAdditionalView(strongSelf, reactionItems: reactionItems, correlationIds: correlationIds) : nil), in: .current)
}) })
} }
@ -269,7 +269,7 @@ extension ChatControllerImpl {
} }
let reactionItems: Signal<[ReactionItem], NoError> let reactionItems: Signal<[ReactionItem], NoError>
if messages.count == 1 { if messages.count > 0 {
reactionItems = tagMessageReactions(context: strongSelf.context) reactionItems = tagMessageReactions(context: strongSelf.context)
} else { } else {
reactionItems = .single([]) reactionItems = .single([])
@ -289,7 +289,7 @@ extension ChatControllerImpl {
} }
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: true, text: messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many), elevatedLayout: false, position: messages.count == 1 ? .top : .bottom, animateInAsReplacement: true, action: { [weak self] value in strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: true, text: messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many), elevatedLayout: false, position: .top, animateInAsReplacement: true, action: { [weak self] value in
if case .info = value, let strongSelf = self { if case .info = value, let strongSelf = self {
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: strongSelf.context.account.peerId)) let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: strongSelf.context.account.peerId))
|> deliverOnMainQueue).startStandalone(next: { peer in |> deliverOnMainQueue).startStandalone(next: { peer in
@ -302,7 +302,7 @@ extension ChatControllerImpl {
return true return true
} }
return false return false
}, additionalView: messages.count == 1 ? chatShareToSavedMessagesAdditionalView(strongSelf, reactionItems: reactionItems, correlationId: correlationIds.first) : nil), in: .current) }, additionalView: messages.count > 0 ? chatShareToSavedMessagesAdditionalView(strongSelf, reactionItems: reactionItems, correlationIds: correlationIds) : nil), in: .current)
}) })
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: mappedMessages) let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: mappedMessages)

View File

@ -15,30 +15,33 @@ import ChatShareMessageTagView
import ReactionSelectionNode import ReactionSelectionNode
import TopMessageReactions import TopMessageReactions
func chatShareToSavedMessagesAdditionalView(_ chatController: ChatControllerImpl, reactionItems: [ReactionItem], correlationId: Int64?) -> (() -> UndoOverlayControllerAdditionalView?)? { func chatShareToSavedMessagesAdditionalView(_ chatController: ChatControllerImpl, reactionItems: [ReactionItem], correlationIds: [Int64]) -> (() -> UndoOverlayControllerAdditionalView?)? {
if !chatController.presentationInterfaceState.isPremium { if !chatController.presentationInterfaceState.isPremium {
return nil return nil
} }
guard let correlationId else { if correlationIds.count < 1 {
return nil return nil
} }
return { [weak chatController] () -> UndoOverlayControllerAdditionalView? in return { [weak chatController] () -> UndoOverlayControllerAdditionalView? in
guard let chatController else { guard let chatController else {
return nil return nil
} }
return ChatShareMessageTagView(context: chatController.context, presentationData: chatController.presentationData, reactionItems: reactionItems, completion: { [weak chatController] file, updateReaction in return ChatShareMessageTagView(context: chatController.context, presentationData: chatController.presentationData, isSingleMessage: correlationIds.count == 1, reactionItems: reactionItems, completion: { [weak chatController] file, updateReaction in
guard let chatController else { guard let chatController else {
return return
} }
let _ = (chatController.context.account.postbox.aroundMessageHistoryViewForLocation(.peer(peerId: chatController.context.account.peerId, threadId: nil), anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: 45, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: Set(), tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: []) let _ = (chatController.context.account.postbox.aroundMessageHistoryViewForLocation(.peer(peerId: chatController.context.account.peerId, threadId: nil), anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: 45, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: Set(), tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: [])
|> map { view, _, _ -> [EngineMessage.Id] in |> map { view, _, _ -> [EngineMessage.Id] in
guard let messageId = chatController.context.engine.messages.synchronouslyLookupCorrelationId(correlationId: correlationId) else { let messageIds = correlationIds.compactMap { correlationId in
return chatController.context.engine.messages.synchronouslyLookupCorrelationId(correlationId: correlationId)
}
if messageIds.isEmpty {
return [] return []
} }
let exactResult = view.entries.compactMap { entry -> EngineMessage.Id? in let exactResult = view.entries.compactMap { entry -> EngineMessage.Id? in
if entry.message.id == messageId { if messageIds.contains(entry.message.id) {
return entry.message.id return entry.message.id
} else { } else {
return nil return nil
@ -57,15 +60,17 @@ func chatShareToSavedMessagesAdditionalView(_ chatController: ChatControllerImpl
guard let chatController else { guard let chatController else {
return return
} }
if let messageId = messageIds.first { if !messageIds.isEmpty {
for messageId in messageIds {
let _ = chatController.context.engine.messages.setMessageReactions(id: messageId, reactions: [updateReaction]) let _ = chatController.context.engine.messages.setMessageReactions(id: messageId, reactions: [updateReaction])
}
var isBuiltinReaction = false var isBuiltinReaction = false
if case .builtin = updateReaction { if case .builtin = updateReaction {
isBuiltinReaction = true isBuiltinReaction = true
} }
let presentationData = chatController.context.sharedContext.currentPresentationData.with { $0 } let presentationData = chatController.context.sharedContext.currentPresentationData.with { $0 }
chatController.present(UndoOverlayController(presentationData: presentationData, content: .messageTagged(context: chatController.context, customEmoji: file, isBuiltinReaction: isBuiltinReaction, customUndoText: presentationData.strings.Chat_ToastMessageTagged_Action), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { [weak chatController] action in chatController.present(UndoOverlayController(presentationData: presentationData, content: .messageTagged(context: chatController.context, isSingleMessage: messageIds.count == 1, customEmoji: file, isBuiltinReaction: isBuiltinReaction, customUndoText: presentationData.strings.Chat_ToastMessageTagged_Action), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { [weak chatController] action in
if (action == .info || action == .undo), let chatController { if (action == .info || action == .undo), let chatController {
let _ = (chatController.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: chatController.context.account.peerId)) let _ = (chatController.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: chatController.context.account.peerId))
|> deliverOnMainQueue).start(next: { [weak chatController] peer in |> deliverOnMainQueue).start(next: { [weak chatController] peer in
@ -226,7 +231,7 @@ extension ChatControllerImpl {
}) })
} }
return false return false
}, additionalView: savedMessages ? chatShareToSavedMessagesAdditionalView(self, reactionItems: reactionItems, correlationId: correlationIds.first) : nil), in: .current) }, additionalView: savedMessages ? chatShareToSavedMessagesAdditionalView(self, reactionItems: reactionItems, correlationIds: correlationIds) : nil), in: .current)
}) })
}) })
} }

View File

@ -82,8 +82,19 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, ignoreMess
var preloaded = false var preloaded = false
var fadeIn = false var fadeIn = false
let signal: Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> let signal: Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError>
if let tag {
signal = account.viewTracker.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, index: .upperBound, anchorIndex: .upperBound, count: count, ignoreRelatedChats: ignoreRelatedChats, fixedCombinedReadStates: nil, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics) var requestAroundId = false
var preFixedReadState: MessageHistoryViewReadState?
if tag != nil {
requestAroundId = true
}
if case let .replyThread(message) = chatLocation, message.peerId == context.account.peerId {
requestAroundId = true
preFixedReadState = .peer([:])
}
if requestAroundId {
signal = account.viewTracker.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, index: .upperBound, anchorIndex: .upperBound, count: count, ignoreRelatedChats: ignoreRelatedChats, fixedCombinedReadStates: preFixedReadState, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics)
} else { } else {
signal = account.viewTracker.aroundMessageOfInterestHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics, additionalData: additionalData) signal = account.viewTracker.aroundMessageOfInterestHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics, additionalData: additionalData)
} }

View File

@ -45,7 +45,7 @@ public enum UndoOverlayContent {
case universal(animation: String, scale: CGFloat, colors: [String: UIColor], title: String?, text: String, customUndoText: String?, timeout: Double?) case universal(animation: String, scale: CGFloat, colors: [String: UIColor], title: String?, text: String, customUndoText: String?, timeout: Double?)
case premiumPaywall(title: String?, text: String, customUndoText: String?, timeout: Double?, linkAction: ((String) -> Void)?) case premiumPaywall(title: String?, text: String, customUndoText: String?, timeout: Double?, linkAction: ((String) -> Void)?)
case peers(context: AccountContext, peers: [EnginePeer], title: String?, text: String, customUndoText: String?) case peers(context: AccountContext, peers: [EnginePeer], title: String?, text: String, customUndoText: String?)
case messageTagged(context: AccountContext, customEmoji: TelegramMediaFile, isBuiltinReaction: Bool, customUndoText: String?) case messageTagged(context: AccountContext, isSingleMessage: Bool, customEmoji: TelegramMediaFile, isBuiltinReaction: Bool, customUndoText: String?)
} }
public enum UndoOverlayAction { public enum UndoOverlayAction {

View File

@ -1159,14 +1159,14 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
} else { } else {
displayUndo = false displayUndo = false
} }
case let .messageTagged(context, customEmoji, isBuiltinReaction, customUndoText): case let .messageTagged(context, isSingleMessage, customEmoji, isBuiltinReaction, customUndoText):
self.avatarNode = nil self.avatarNode = nil
self.iconNode = nil self.iconNode = nil
self.iconCheckNode = nil self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_savedmessages", colors: [:], scale: 0.066) self.animationNode = AnimationNode(animation: "anim_savedmessages", colors: [:], scale: 0.066)
self.animatedStickerNode = nil self.animatedStickerNode = nil
let rawText = presentationData.strings.Chat_ToastMessageTagged_Text(".") let rawText = isSingleMessage ? presentationData.strings.Chat_ToastMessageTagged_Text(".") : presentationData.strings.Chat_ToastMessagesTagged_Text(".")
let attributedText = NSMutableAttributedString(string: rawText.string, font: Font.regular(14.0), textColor: .white) let attributedText = NSMutableAttributedString(string: rawText.string, font: Font.regular(14.0), textColor: .white)
for range in rawText.ranges { for range in rawText.ranges {
attributedText.addAttributes([ChatTextInputAttributes.customEmoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: customEmoji.fileId.id, file: customEmoji, custom: nil)], range: range.range) attributedText.addAttributes([ChatTextInputAttributes.customEmoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: customEmoji.fileId.id, file: customEmoji, custom: nil)], range: range.range)