Various improvements

This commit is contained in:
Isaac 2024-01-29 22:23:50 +01:00
parent 9a791da77b
commit 27c5ca7474
15 changed files with 99 additions and 34 deletions

View File

@ -764,6 +764,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
self.interfaceInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in self.interfaceInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in
}, setupEditMessage: { _, _ in }, setupEditMessage: { _, _ in
}, beginMessageSelection: { _, _ in }, beginMessageSelection: { _, _ in
}, cancelMessageSelection: { _ in
}, deleteSelectedMessages: { }, deleteSelectedMessages: {
}, reportSelectedMessages: { }, reportSelectedMessages: {
}, reportMessages: { _, _ in }, reportMessages: { _, _ in

View File

@ -72,6 +72,7 @@ public final class ChatPanelInterfaceInteraction {
public let setupReplyMessage: (MessageId?, @escaping (ContainedViewLayoutTransition, @escaping () -> Void) -> Void) -> Void public let setupReplyMessage: (MessageId?, @escaping (ContainedViewLayoutTransition, @escaping () -> Void) -> Void) -> Void
public let setupEditMessage: (MessageId?, @escaping (ContainedViewLayoutTransition) -> Void) -> Void public let setupEditMessage: (MessageId?, @escaping (ContainedViewLayoutTransition) -> Void) -> Void
public let beginMessageSelection: ([MessageId], @escaping (ContainedViewLayoutTransition) -> Void) -> Void public let beginMessageSelection: ([MessageId], @escaping (ContainedViewLayoutTransition) -> Void) -> Void
public let cancelMessageSelection: (ContainedViewLayoutTransition) -> Void
public let deleteSelectedMessages: () -> Void public let deleteSelectedMessages: () -> Void
public let reportSelectedMessages: () -> Void public let reportSelectedMessages: () -> Void
public let reportMessages: ([Message], ContextControllerProtocol?) -> Void public let reportMessages: ([Message], ContextControllerProtocol?) -> Void
@ -182,6 +183,7 @@ public final class ChatPanelInterfaceInteraction {
setupReplyMessage: @escaping (MessageId?, @escaping (ContainedViewLayoutTransition, @escaping () -> Void) -> Void) -> Void, setupReplyMessage: @escaping (MessageId?, @escaping (ContainedViewLayoutTransition, @escaping () -> Void) -> Void) -> Void,
setupEditMessage: @escaping (MessageId?, @escaping (ContainedViewLayoutTransition) -> Void) -> Void, setupEditMessage: @escaping (MessageId?, @escaping (ContainedViewLayoutTransition) -> Void) -> Void,
beginMessageSelection: @escaping ([MessageId], @escaping (ContainedViewLayoutTransition) -> Void) -> Void, beginMessageSelection: @escaping ([MessageId], @escaping (ContainedViewLayoutTransition) -> Void) -> Void,
cancelMessageSelection: @escaping (ContainedViewLayoutTransition) -> Void,
deleteSelectedMessages: @escaping () -> Void, deleteSelectedMessages: @escaping () -> Void,
reportSelectedMessages: @escaping () -> Void, reportSelectedMessages: @escaping () -> Void,
reportMessages: @escaping ([Message], ContextControllerProtocol?) -> Void, reportMessages: @escaping ([Message], ContextControllerProtocol?) -> Void,
@ -291,6 +293,7 @@ public final class ChatPanelInterfaceInteraction {
self.setupReplyMessage = setupReplyMessage self.setupReplyMessage = setupReplyMessage
self.setupEditMessage = setupEditMessage self.setupEditMessage = setupEditMessage
self.beginMessageSelection = beginMessageSelection self.beginMessageSelection = beginMessageSelection
self.cancelMessageSelection = cancelMessageSelection
self.deleteSelectedMessages = deleteSelectedMessages self.deleteSelectedMessages = deleteSelectedMessages
self.reportSelectedMessages = reportSelectedMessages self.reportSelectedMessages = reportSelectedMessages
self.reportMessages = reportMessages self.reportMessages = reportMessages
@ -407,6 +410,7 @@ public final class ChatPanelInterfaceInteraction {
self.init(setupReplyMessage: { _, _ in self.init(setupReplyMessage: { _, _ in
}, setupEditMessage: { _, _ in }, setupEditMessage: { _, _ in
}, beginMessageSelection: { _, _ in }, beginMessageSelection: { _, _ in
}, cancelMessageSelection: { _ in
}, deleteSelectedMessages: { }, deleteSelectedMessages: {
}, reportSelectedMessages: { }, reportSelectedMessages: {
}, reportMessages: { _, _ in }, reportMessages: { _, _ in

View File

@ -377,10 +377,7 @@ final class ContextSourceContainer: ASDisplayNode {
super.init() super.init()
#if DEBUG
#else
self.addSubnode(self.backgroundNode) self.addSubnode(self.backgroundNode)
#endif
for i in 0 ..< configuration.sources.count { for i in 0 ..< configuration.sources.count {
let source = configuration.sources[i] let source = configuration.sources[i]

View File

@ -65,6 +65,8 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
public private(set) var accessoryPanelContainerHeight: CGFloat = 0.0 public private(set) var accessoryPanelContainerHeight: CGFloat = 0.0
public let mediaAccessoryPanelVisibility: MediaAccessoryPanelVisibility public let mediaAccessoryPanelVisibility: MediaAccessoryPanelVisibility
public var tempHideAccessoryPanels: Bool = false
public let locationBroadcastPanelSource: LocationBroadcastPanelSource public let locationBroadcastPanelSource: LocationBroadcastPanelSource
public let groupCallPanelSource: GroupCallPanelSource public let groupCallPanelSource: GroupCallPanelSource
@ -408,13 +410,17 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
let navigationHeight = super.navigationLayout(layout: layout).navigationFrame.height - self.additionalNavigationBarHeight let navigationHeight = super.navigationLayout(layout: layout).navigationFrame.height - self.additionalNavigationBarHeight
let mediaAccessoryPanelHidden: Bool let mediaAccessoryPanelHidden: Bool
switch self.mediaAccessoryPanelVisibility { if self.tempHideAccessoryPanels {
case .always:
mediaAccessoryPanelHidden = false
case .none:
mediaAccessoryPanelHidden = true mediaAccessoryPanelHidden = true
case let .specific(size): } else {
mediaAccessoryPanelHidden = size != layout.metrics.widthClass switch self.mediaAccessoryPanelVisibility {
case .always:
mediaAccessoryPanelHidden = false
case .none:
mediaAccessoryPanelHidden = true
case let .specific(size):
mediaAccessoryPanelHidden = size != layout.metrics.widthClass
}
} }
var additionalHeight: CGFloat = 0.0 var additionalHeight: CGFloat = 0.0

View File

@ -18,7 +18,7 @@ public enum UpdateMessageReaction {
} }
} }
public func updateMessageReactionsInteractively(account: Account, messageId: MessageId, reactions: [UpdateMessageReaction], isLarge: Bool, storeAsRecentlyUsed: Bool) -> Signal<Never, NoError> { public func updateMessageReactionsInteractively(account: Account, messageId: MessageId, reactions: [UpdateMessageReaction], isLarge: Bool, storeAsRecentlyUsed: Bool, add: Bool = false) -> Signal<Never, NoError> {
return account.postbox.transaction { transaction -> Void in return account.postbox.transaction { transaction -> Void in
var sendAsPeerId = account.peerId var sendAsPeerId = account.peerId
if let cachedData = transaction.getPeerCachedData(peerId: messageId.peerId) { if let cachedData = transaction.getPeerCachedData(peerId: messageId.peerId) {
@ -40,6 +40,25 @@ public func updateMessageReactionsInteractively(account: Account, messageId: Mes
} }
var mappedReactions: [PendingReactionsMessageAttribute.PendingReaction] = [] var mappedReactions: [PendingReactionsMessageAttribute.PendingReaction] = []
var reactions: [UpdateMessageReaction] = reactions
if add {
if let message = transaction.getMessage(messageId), let effectiveReactions = message.effectiveReactions(isTags: message.areReactionsTags(accountPeerId: account.peerId)) {
for reaction in effectiveReactions {
if !reactions.contains(where: { $0.reaction == reaction.value }) {
let mappedValue: UpdateMessageReaction
switch reaction.value {
case let .builtin(value):
mappedValue = .builtin(value)
case let .custom(fileId):
mappedValue = .custom(fileId: fileId, file: nil)
}
reactions.append(mappedValue)
}
}
}
}
for reaction in reactions { for reaction in reactions {
switch reaction { switch reaction {
case let .custom(fileId, file): case let .custom(fileId, file):

View File

@ -307,7 +307,22 @@ public extension TelegramEngine {
messageId: id, messageId: id,
reactions: reactions, reactions: reactions,
isLarge: false, isLarge: false,
storeAsRecentlyUsed: false storeAsRecentlyUsed: false,
add: false
).start()
}
public func addMessageReactions(
id: EngineMessage.Id,
reactions: [UpdateMessageReaction]
) {
let _ = updateMessageReactionsInteractively(
account: self.account,
messageId: id,
reactions: reactions,
isLarge: false,
storeAsRecentlyUsed: false,
add: true
).start() ).start()
} }

View File

@ -310,24 +310,29 @@ public final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
return return
} }
var reactions = actions.editTags self.interfaceInteraction?.cancelMessageSelection(.animated(duration: 0.4, curve: .spring))
if reactions.contains(updateReaction.reaction) {
reactions.remove(updateReaction.reaction)
} else {
reactions.insert(updateReaction.reaction)
}
let mappedUpdatedReactions = reactions.map { reaction -> UpdateMessageReaction in
switch reaction {
case let .builtin(value):
return .builtin(value)
case let .custom(fileId):
return .custom(fileId: fileId, file: nil)
}
}
if let selectionState = presentationInterfaceState.interfaceState.selectionState { if actions.editTags.contains(updateReaction.reaction) {
for id in selectionState.selectedIds { var reactions = actions.editTags
context.engine.messages.setMessageReactions(id: id, reactions: mappedUpdatedReactions) reactions.remove(updateReaction.reaction)
let mappedUpdatedReactions = reactions.map { reaction -> UpdateMessageReaction in
switch reaction {
case let .builtin(value):
return .builtin(value)
case let .custom(fileId):
return .custom(fileId: fileId, file: nil)
}
}
if let selectionState = presentationInterfaceState.interfaceState.selectionState {
for id in selectionState.selectedIds {
context.engine.messages.setMessageReactions(id: id, reactions: mappedUpdatedReactions)
}
}
} else {
if let selectionState = presentationInterfaceState.interfaceState.selectionState {
for id in selectionState.selectedIds {
context.engine.messages.addMessageReactions(id: id, reactions: [updateReaction])
}
} }
} }

View File

@ -63,6 +63,7 @@ public final class ChatRecentActionsController: TelegramBaseController {
self.panelInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in self.panelInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in
}, setupEditMessage: { _, _ in }, setupEditMessage: { _, _ in
}, beginMessageSelection: { _, _ in }, beginMessageSelection: { _, _ in
}, cancelMessageSelection: { _ in
}, deleteSelectedMessages: { }, deleteSelectedMessages: {
}, reportSelectedMessages: { }, reportSelectedMessages: {
}, reportMessages: { _, _ in }, reportMessages: { _, _ in

View File

@ -305,6 +305,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
let interfaceInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in let interfaceInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in
}, setupEditMessage: { _, _ in }, setupEditMessage: { _, _ in
}, beginMessageSelection: { _, _ in }, beginMessageSelection: { _, _ in
}, cancelMessageSelection: { _ in
}, deleteSelectedMessages: { }, deleteSelectedMessages: {
deleteMessages() deleteMessages()
}, reportSelectedMessages: { }, reportSelectedMessages: {
@ -11301,7 +11302,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
//TODO:localize //TODO:localize
items.append(.action(ContextMenuActionItem(text: "View as Chats", icon: { theme in items.append(.action(ContextMenuActionItem(text: "View as Chats", icon: { theme in
if !isViewingAsTopics { if !isViewingAsTopics {
return nil return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: .clear)
} }
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
}, iconPosition: .left, action: { [weak sourceController] _, a in }, iconPosition: .left, action: { [weak sourceController] _, a in
@ -11319,7 +11320,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
}))) })))
items.append(.action(ContextMenuActionItem(text: strings.Chat_ContextViewAsMessages, icon: { theme in items.append(.action(ContextMenuActionItem(text: strings.Chat_ContextViewAsMessages, icon: { theme in
if isViewingAsTopics { if isViewingAsTopics {
return nil return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: .clear)
} }
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
}, iconPosition: .left, action: { [weak sourceController] _, a in }, iconPosition: .left, action: { [weak sourceController] _, a in

View File

@ -337,6 +337,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
self.interfaceInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in self.interfaceInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in
}, setupEditMessage: { _, _ in }, setupEditMessage: { _, _ in
}, beginMessageSelection: { _, _ in }, beginMessageSelection: { _, _ in
}, cancelMessageSelection: { _ in
}, deleteSelectedMessages: { }, deleteSelectedMessages: {
}, reportSelectedMessages: { }, reportSelectedMessages: {
}, reportMessages: { _, _ in }, reportMessages: { _, _ in

View File

@ -414,6 +414,8 @@ func updateChatPresentationInterfaceStateImpl(
selfController.chatDisplayNode.collapseInput() selfController.chatDisplayNode.collapseInput()
} }
selfController.tempHideAccessoryPanels = selfController.presentationInterfaceState.search != nil
if selfController.isNodeLoaded { if selfController.isNodeLoaded {
selfController.chatDisplayNode.updateChatPresentationInterfaceState(updatedChatPresentationInterfaceState, transition: transition, interactive: interactive, completion: completion) selfController.chatDisplayNode.updateChatPresentationInterfaceState(updatedChatPresentationInterfaceState, transition: transition, interactive: interactive, completion: completion)
} else { } else {

View File

@ -8639,6 +8639,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} else { } else {
completion(.immediate) completion(.immediate)
} }
}, cancelMessageSelection: { [weak self] transition in
guard let self else {
return
}
self.updateChatPresentationInterfaceState(transition: transition, interactive: true, { $0.updatedInterfaceState { $0.withoutSelectionState() } })
}, deleteSelectedMessages: { [weak self] in }, deleteSelectedMessages: { [weak self] in
if let strongSelf = self { if let strongSelf = self {
if let messageIds = strongSelf.presentationInterfaceState.interfaceState.selectionState?.selectedIds, !messageIds.isEmpty { if let messageIds = strongSelf.presentationInterfaceState.interfaceState.selectionState?.selectedIds, !messageIds.isEmpty {

View File

@ -1656,7 +1656,12 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
isSending = true isSending = true
title = chatPresentationInterfaceState.strings.Conversation_ContextMenuCancelSending title = chatPresentationInterfaceState.strings.Conversation_ContextMenuCancelSending
} else { } else {
title = chatPresentationInterfaceState.strings.Conversation_ContextMenuDelete if case .peer(context.account.peerId) = chatPresentationInterfaceState.chatLocation, message.effectivelyIncoming(context.account.peerId) {
//TODO:localize
title = "Remove"
} else {
title = chatPresentationInterfaceState.strings.Conversation_ContextMenuDelete
}
} }
if let autoremoveDeadline = autoremoveDeadline, !isEditing, !isSending { if let autoremoveDeadline = autoremoveDeadline, !isEditing, !isSending {

View File

@ -184,6 +184,9 @@ func rightNavigationButtonForChatInterfaceState(context: AccountContext, present
} }
func secondaryRightNavigationButtonForChatInterfaceState(context: AccountContext, presentationInterfaceState: ChatPresentationInterfaceState, strings: PresentationStrings, currentButton: ChatNavigationButton?, target: Any?, selector: Selector?, chatInfoNavigationButton: ChatNavigationButton?, moreInfoNavigationButton: ChatNavigationButton?) -> ChatNavigationButton? { func secondaryRightNavigationButtonForChatInterfaceState(context: AccountContext, presentationInterfaceState: ChatPresentationInterfaceState, strings: PresentationStrings, currentButton: ChatNavigationButton?, target: Any?, selector: Selector?, chatInfoNavigationButton: ChatNavigationButton?, moreInfoNavigationButton: ChatNavigationButton?) -> ChatNavigationButton? {
if presentationInterfaceState.interfaceState.selectionState != nil {
return nil
}
if case .peer(context.account.peerId) = presentationInterfaceState.chatLocation { if case .peer(context.account.peerId) = presentationInterfaceState.chatLocation {
return moreInfoNavigationButton return moreInfoNavigationButton
} }

View File

@ -262,7 +262,7 @@ final class ChatTagSearchInputPanelNode: ChatInputPanelNode {
} }
} }
var nextLeftX: CGFloat = 11.0 var nextLeftX: CGFloat = 12.0
let calendarButtonSize = self.calendarButton.update( let calendarButtonSize = self.calendarButton.update(
transition: .immediate, transition: .immediate,
@ -372,7 +372,7 @@ final class ChatTagSearchInputPanelNode: ChatInputPanelNode {
environment: {}, environment: {},
containerSize: size containerSize: size
) )
let resultsTextFrame = CGRect(origin: CGPoint(x: nextLeftX, y: floor((size.height - resultsTextSize.height) * 0.5)), size: resultsTextSize) let resultsTextFrame = CGRect(origin: CGPoint(x: nextLeftX - 3.0, y: floor((size.height - resultsTextSize.height) * 0.5)), size: resultsTextSize)
if let resultsTextView = resultsText.view { if let resultsTextView = resultsText.view {
if resultsTextView.superview == nil { if resultsTextView.superview == nil {
resultsTextView.alpha = 0.0 resultsTextView.alpha = 0.0
@ -381,7 +381,7 @@ final class ChatTagSearchInputPanelNode: ChatInputPanelNode {
resultsTextTransition.setFrame(view: resultsTextView, frame: resultsTextFrame) resultsTextTransition.setFrame(view: resultsTextView, frame: resultsTextFrame)
transition.setAlpha(view: resultsTextView, alpha: 1.0) transition.setAlpha(view: resultsTextView, alpha: 1.0)
} }
nextLeftX += resultsTextSize.width nextLeftX += -3.0 + resultsTextSize.width
} else { } else {
if let resultsText = self.resultsText { if let resultsText = self.resultsText {
self.resultsText = nil self.resultsText = nil