diff --git a/submodules/TelegramStringFormatting/Sources/MessageContentKind.swift b/submodules/TelegramStringFormatting/Sources/MessageContentKind.swift index e289c562b6..809a6d3369 100644 --- a/submodules/TelegramStringFormatting/Sources/MessageContentKind.swift +++ b/submodules/TelegramStringFormatting/Sources/MessageContentKind.swift @@ -24,6 +24,7 @@ public enum MessageContentKindKey { case expiredVoiceMessage case expiredVideoMessage case poll + case todo case restricted case dice case invoice @@ -50,6 +51,7 @@ public enum MessageContentKind: Equatable { case expiredVoiceMessage case expiredVideoMessage case poll(String) + case todo(String) case restricted(String) case dice(String) case invoice(String) @@ -160,6 +162,12 @@ public enum MessageContentKind: Equatable { } else { return false } + case .todo: + if case .todo = other { + return true + } else { + return false + } case .restricted: if case .restricted = other { return true @@ -229,6 +237,8 @@ public enum MessageContentKind: Equatable { return .expiredVideoMessage case .poll: return .poll + case .todo: + return .todo case .restricted: return .restricted case .dice: @@ -369,6 +379,8 @@ public func mediaContentKind(_ media: EngineMedia, message: EngineMessage? = nil } case let .poll(poll): return .poll(poll.text) + case let .todo(todo): + return .todo(todo.text) case let .dice(dice): return .dice(dice.emoji) case let .invoice(invoice): @@ -455,6 +467,8 @@ public func stringForMediaKind(_ kind: MessageContentKind, strings: Presentation return (NSAttributedString(string: strings.Message_VideoMessageExpired), true) case let .poll(text): return (NSAttributedString(string: "📊 \(text)"), false) + case let .todo(text): + return (NSAttributedString(string: "☑️ \(text)"), false) case let .restricted(text): return (NSAttributedString(string: text), false) case let .dice(emoji): diff --git a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift index 529f802938..6d4e5c83b2 100644 --- a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift @@ -1297,38 +1297,47 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, } } } + + var taskTitle = "DELETED" if let todo { - if message.author?.id == accountPeerId { - let resultString: PresentationStrings.FormattedString - if let completedTaskId = completed.first, let completedTask = todo.items.first(where: { $0.id == completedTaskId }) { - resultString = strings.Notification_TodoCompletedYou(completedTask.text) - } else if let incompletedTaskId = incompleted.first, let incompletedTask = todo.items.first(where: { $0.id == incompletedTaskId }) { - resultString = strings.Notification_TodoIncompletedYou(incompletedTask.text) - } else { - fatalError() - } - attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes]) - } else { - let peerName = message.author?.compactDisplayTitle ?? "" - - var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]) - attributes[1] = boldAttributes - - let resultString: PresentationStrings.FormattedString - if let completedTaskId = completed.first, let completedTask = todo.items.first(where: { $0.id == completedTaskId }) { - resultString = strings.Notification_TodoCompleted(peerName, completedTask.text) - } else if let incompletedTaskId = incompleted.first, let incompletedTask = todo.items.first(where: { $0.id == incompletedTaskId }) { - resultString = strings.Notification_TodoIncompleted(peerName, incompletedTask.text) - } else { - fatalError() - } - attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: attributes) + if let completedTaskId = completed.first, let completedTask = todo.items.first(where: { $0.id == completedTaskId }) { + taskTitle = completedTask.text + } else if let incompletedTaskId = incompleted.first, let incompletedTask = todo.items.first(where: { $0.id == incompletedTaskId }) { + taskTitle = incompletedTask.text } + } + if taskTitle.count > 20 { + taskTitle = taskTitle.prefix(20) + "…" + } + + if message.author?.id == accountPeerId { + let resultString: PresentationStrings.FormattedString + if let _ = completed.first { + resultString = strings.Notification_TodoCompletedYou(taskTitle) + } else if let _ = incompleted.first { + resultString = strings.Notification_TodoIncompletedYou(taskTitle) + } else { + resultString = strings.Notification_TodoCompletedYou("") + } + attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes]) } else { - attributedString = NSAttributedString(string: ".") + let peerName = message.author?.compactDisplayTitle ?? "" + + var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]) + attributes[1] = boldAttributes + + let resultString: PresentationStrings.FormattedString + if let _ = completed.first { + resultString = strings.Notification_TodoCompleted(peerName, taskTitle) + } else if let _ = incompleted.first { + resultString = strings.Notification_TodoIncompleted(peerName, taskTitle) + } else { + resultString = strings.Notification_TodoCompleted(peerName, "") + } + attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: attributes) } case let .todoAppendTasks(tasks): - var todoTitle = "" + var todoTitle = "DELETED" for attribute in message.attributes { if let attribute = attribute as? ReplyMessageAttribute, let message = message.associatedMessages[attribute.messageId] { for media in message.media { @@ -1338,10 +1347,17 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, } } } + if todoTitle.count > 20 { + todoTitle = todoTitle.prefix(20) + "…" + } if message.author?.id == accountPeerId { let resultString: PresentationStrings.FormattedString if tasks.count == 1, let task = tasks.first { - resultString = strings.Notification_TodoAddedTaskYou(task.text, todoTitle) + var taskTitle = task.text + if taskTitle.count > 20 { + taskTitle = taskTitle.prefix(20) + "…" + } + resultString = strings.Notification_TodoAddedTaskYou(taskTitle, todoTitle) } else { resultString = strings.Notification_TodoAddedMultipleTasksYou(strings.Notification_TodoTasks(Int32(tasks.count)), todoTitle) } @@ -1354,7 +1370,11 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, let resultString: PresentationStrings.FormattedString if tasks.count == 1, let task = tasks.first { - resultString = strings.Notification_TodoAddedTask(peerName, task.text, todoTitle) + var taskTitle = task.text + if taskTitle.count > 20 { + taskTitle = taskTitle.prefix(20) + "…" + } + resultString = strings.Notification_TodoAddedTask(peerName, taskTitle, todoTitle) } else { resultString = strings.Notification_TodoAddedMultipleTasks(peerName, strings.Notification_TodoTasks(Int32(tasks.count)), todoTitle) } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift index 51ac8db26c..b81a7cac0d 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift @@ -414,6 +414,7 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([ if result.last?.1 == ChatMessageTextBubbleContentNode.self { } else { if result.last?.1 == ChatMessagePollBubbleContentNode.self || + result.last?.1 == ChatMessageTodoBubbleContentNode.self || result.last?.1 == ChatMessageContactBubbleContentNode.self || result.last?.1 == ChatMessageGameBubbleContentNode.self || result.last?.1 == ChatMessageInvoiceBubbleContentNode.self || @@ -423,8 +424,9 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([ } else if result.last?.1 == ChatMessageCommentFooterContentNode.self { if result.count >= 2 { if result[result.count - 2].1 == ChatMessagePollBubbleContentNode.self || - result[result.count - 2].1 == ChatMessageContactBubbleContentNode.self || - result[result.count - 2].1 == ChatMessageGiveawayBubbleContentNode.self { + result[result.count - 2].1 == ChatMessageTodoBubbleContentNode.self || + result[result.count - 2].1 == ChatMessageContactBubbleContentNode.self || + result[result.count - 2].1 == ChatMessageGiveawayBubbleContentNode.self { result.insert((firstMessage, ChatMessageReactionsFooterContentNode.self, ChatMessageEntryAttributes(), BubbleItemAttributes(isAttachment: true, neighborType: .reactions, neighborSpacing: .default)), at: result.count - 1) } } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift index 3c0945ed07..e71506cdcd 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift @@ -1092,7 +1092,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { }) } backgroundContent.view.mask = strongSelf.mediaBackgroundMaskNode.view - strongSelf.mediaBackgroundMaskNode.frame = CGRect(origin: .zero, size: backgroundMaskFrame.size) + animation.animator.updateFrame(layer: strongSelf.mediaBackgroundMaskNode.layer, frame: CGRect(origin: .zero, size: backgroundMaskFrame.size), completion: nil) } else { animation.animator.updateFrame(layer: backgroundContent.layer, frame: mediaBackgroundFrame, completion: nil) backgroundContent.clipsToBounds = true @@ -1153,7 +1153,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { } if let backgroundNode = strongSelf.backgroundNode { - backgroundNode.frame = CGRect(origin: CGPoint(x: baseBackgroundFrame.minX + offset.x, y: baseBackgroundFrame.minY + offset.y), size: image.size) + animation.animator.updateFrame(layer: backgroundNode.layer, frame: CGRect(origin: CGPoint(x: baseBackgroundFrame.minX + offset.x, y: baseBackgroundFrame.minY + offset.y), size: image.size), completion: nil) } strongSelf.backgroundMaskNode.image = image strongSelf.backgroundMaskNode.frame = CGRect(origin: CGPoint(), size: image.size) diff --git a/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift b/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift index 04714e2e0e..dec2bc59ab 100644 --- a/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift +++ b/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift @@ -625,6 +625,7 @@ final class ComposeTodoScreenComponent: Component { }, assumeIsEditing: self.inputMediaNodeTargetTag === self.todoTextFieldTag, characterLimit: component.initialData.maxTodoTextLength, + canReorder: canEdit, emptyLineHandling: .allowed, returnKeyAction: { [weak self] in guard let self else { diff --git a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/ChatGiftPreviewItem.swift b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/ChatGiftPreviewItem.swift index 860b495783..ed635f4557 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/ChatGiftPreviewItem.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/ChatGiftPreviewItem.swift @@ -257,18 +257,17 @@ final class ChatGiftPreviewItemNode: ListViewItemNode { currentNodes = nil } + let transition = ControlledTransition(duration: 0.2, curve: .spring, interactive: false) if let messageNodes = currentNodes { nodes = messageNodes for i in 0 ..< items.count { let itemNode = messageNodes[i] items[i].updateNode(async: { $0() }, node: { return itemNode - }, params: params, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], animation: .System(duration: 0.2, transition: ControlledTransition(duration: 0.2, curve: .spring, interactive: false)), completion: { (layout, apply) in - let nodeFrame = CGRect(origin: itemNode.frame.origin, size: CGSize(width: layout.size.width, height: layout.size.height)) - + }, params: params, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], animation: .System(duration: 0.2, transition: transition), completion: { (layout, apply) in + itemNode.bounds = CGRect(origin: .zero, size: layout.size) itemNode.contentSize = layout.contentSize itemNode.insets = layout.insets - itemNode.frame = nodeFrame itemNode.isUserInteractionEnabled = false itemNode.visibility = .visible(1.0, .infinite) @@ -333,12 +332,14 @@ final class ChatGiftPreviewItemNode: ListViewItemNode { strongSelf.containerNode.addSubnode(node) } let bubbleHeight: CGFloat - if node.frame.height > 44.0, let initialBubbleHeight = strongSelf.initialBubbleHeight { - bubbleHeight = max(node.frame.height, initialBubbleHeight) - } else { +// if node.frame.height > 44.0, let initialBubbleHeight = strongSelf.initialBubbleHeight { +// bubbleHeight = max(node.frame.height, initialBubbleHeight) +// } else { bubbleHeight = node.frame.height - } - node.updateFrame(CGRect(origin: CGPoint(x: 0.0, y: originY), size: node.frame.size), within: layoutSize) +// } + transition.legacyAnimator.transition.updateFrame(node: node, frame: CGRect(origin: CGPoint(x: 0.0, y: originY), size: node.frame.size)) + + //node.updateFrame(CGRect(origin: CGPoint(x: 0.0, y: originY), size: node.frame.size), within: layoutSize, transition: transition) originY += bubbleHeight } diff --git a/submodules/TelegramUI/Components/ListComposePollOptionComponent/Sources/ListComposePollOptionComponent.swift b/submodules/TelegramUI/Components/ListComposePollOptionComponent/Sources/ListComposePollOptionComponent.swift index 83b11d55bf..3989ee04fe 100644 --- a/submodules/TelegramUI/Components/ListComposePollOptionComponent/Sources/ListComposePollOptionComponent.swift +++ b/submodules/TelegramUI/Components/ListComposePollOptionComponent/Sources/ListComposePollOptionComponent.swift @@ -78,6 +78,7 @@ public final class ListComposePollOptionComponent: Component { public let assumeIsEditing: Bool public let characterLimit: Int? public let enableInlineAnimations: Bool + public let canReorder: Bool public let emptyLineHandling: TextFieldComponent.EmptyLineHandling public let returnKeyAction: (() -> Void)? public let backspaceKeyAction: (() -> Void)? @@ -98,6 +99,7 @@ public final class ListComposePollOptionComponent: Component { assumeIsEditing: Bool = false, characterLimit: Int, enableInlineAnimations: Bool = true, + canReorder: Bool = false, emptyLineHandling: TextFieldComponent.EmptyLineHandling, returnKeyAction: (() -> Void)?, backspaceKeyAction: (() -> Void)?, @@ -117,6 +119,7 @@ public final class ListComposePollOptionComponent: Component { self.assumeIsEditing = assumeIsEditing self.characterLimit = characterLimit self.enableInlineAnimations = enableInlineAnimations + self.canReorder = canReorder self.emptyLineHandling = emptyLineHandling self.returnKeyAction = returnKeyAction self.backspaceKeyAction = backspaceKeyAction @@ -158,6 +161,9 @@ public final class ListComposePollOptionComponent: Component { if lhs.enableInlineAnimations != rhs.enableInlineAnimations { return false } + if lhs.canReorder != rhs.canReorder { + return false + } if lhs.emptyLineHandling != rhs.emptyLineHandling { return false } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index c24cbaae0c..cbfebb5004 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -967,7 +967,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return false } switch action.action { - case .pinnedMessageUpdated, .gameScore, .setSameChatWallpaper, .giveawayResults, .customText: + case .pinnedMessageUpdated, .gameScore, .setSameChatWallpaper, .giveawayResults, .customText, .todoCompletions, .todoAppendTasks: for attribute in message.attributes { if let attribute = attribute as? ReplyMessageAttribute { self.navigateToMessage(from: message.id, to: .id(attribute.messageId, NavigateToMessageParams(timestamp: nil, quote: attribute.isQuote ? attribute.quote.flatMap { quote in NavigateToMessageParams.Quote(string: quote.text, offset: quote.offset) } : nil)))