From bed8d20213d0093b8ac6608e0427d9779c1ab94f Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Fri, 26 Apr 2024 23:15:21 +0400 Subject: [PATCH 1/6] Add translate --- .../Sources/PeerInfoScreen.swift | 160 +++++++++++------- 1 file changed, 98 insertions(+), 62 deletions(-) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 3abe8d18e5..0331394318 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -6967,82 +6967,118 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } private func openBioContextMenu(node: ASDisplayNode, gesture: ContextGesture?) { - guard let sourceNode = node as? ContextExtractedContentContainingNode else { - return - } - guard let cachedData = self.data?.cachedData else { - return - } - - var bioText: String? - if let cachedData = cachedData as? CachedUserData { - bioText = cachedData.about - } else if let cachedData = cachedData as? CachedChannelData { - bioText = cachedData.about - } else if let cachedData = cachedData as? CachedGroupData { - bioText = cachedData.about - } - - guard let bioText, !bioText.isEmpty else { - return - } - - let copyAction = { [weak self] in + let _ = (self.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings]) + |> take(1) + |> deliverOnMainQueue).startStandalone(next: { [weak self] sharedData in guard let self else { return } - UIPasteboard.general.string = bioText - let toastText: String - if let _ = self.data?.peer as? TelegramUser { - toastText = self.presentationData.strings.MyProfile_ToastBioCopied + let translationSettings: TranslationSettings + if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.translationSettings]?.get(TranslationSettings.self) { + translationSettings = current } else { - toastText = self.presentationData.strings.ChannelProfile_ToastAboutCopied + translationSettings = TranslationSettings.defaultSettings } - self.controller?.present(UndoOverlayController(presentationData: self.presentationData, content: .copy(text: toastText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current) - } - - var items: [ContextMenuItem] = [] - - if self.isMyProfile { - items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_BioActionEdit, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in - c.dismiss { - guard let self else { - return - } - self.headerNode.navigationButtonContainer.performAction?(.edit, nil, nil) - - for (_, section) in self.editingSections { - for (id, itemNode) in section.itemNodes { - if id == AnyHashable("bio_edit") { - if let itemNode = itemNode as? PeerInfoScreenMultilineInputItemNode { - itemNode.focus() + guard let sourceNode = node as? ContextExtractedContentContainingNode else { + return + } + guard let cachedData = self.data?.cachedData else { + return + } + + var bioText: String? + if let cachedData = cachedData as? CachedUserData { + bioText = cachedData.about + } else if let cachedData = cachedData as? CachedChannelData { + bioText = cachedData.about + } else if let cachedData = cachedData as? CachedGroupData { + bioText = cachedData.about + } + + guard let bioText, !bioText.isEmpty else { + return + } + + let copyAction = { [weak self] in + guard let self else { + return + } + UIPasteboard.general.string = bioText + + let toastText: String + if let _ = self.data?.peer as? TelegramUser { + toastText = self.presentationData.strings.MyProfile_ToastBioCopied + } else { + toastText = self.presentationData.strings.ChannelProfile_ToastAboutCopied + } + + self.controller?.present(UndoOverlayController(presentationData: self.presentationData, content: .copy(text: toastText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current) + } + + var items: [ContextMenuItem] = [] + + if self.isMyProfile { + items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_BioActionEdit, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in + c.dismiss { + guard let self else { + return + } + self.headerNode.navigationButtonContainer.performAction?(.edit, nil, nil) + + for (_, section) in self.editingSections { + for (id, itemNode) in section.itemNodes { + if id == AnyHashable("bio_edit") { + if let itemNode = itemNode as? PeerInfoScreenMultilineInputItemNode { + itemNode.focus() + } + break } - break } } } + }))) + } + + let copyText: String + if let _ = self.data?.peer as? TelegramUser { + copyText = self.presentationData.strings.MyProfile_BioActionCopy + } else { + copyText = self.presentationData.strings.ChannelProfile_AboutActionCopy + } + items.append(.action(ContextMenuActionItem(text: copyText, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in + c.dismiss { + copyAction() } }))) - } - - let copyText: String - if let _ = self.data?.peer as? TelegramUser { - copyText = self.presentationData.strings.MyProfile_BioActionCopy - } else { - copyText = self.presentationData.strings.ChannelProfile_AboutActionCopy - } - items.append(.action(ContextMenuActionItem(text: copyText, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in - c.dismiss { - copyAction() + + let (canTranslate, language) = canTranslateText(context: self.context, text: bioText, showTranslate: translationSettings.showTranslate, showTranslateIfTopical: false, ignoredLanguages: translationSettings.ignoredLanguages) + if canTranslate { + items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuTranslate, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in + c.dismiss { + guard let self else { + return + } + + let controller = TranslateScreen(context: self.context, text: bioText, canCopy: true, fromLanguage: language, ignoredLanguages: translationSettings.ignoredLanguages) + controller.pushController = { [weak self] c in + (self?.controller?.navigationController as? NavigationController)?._keepModalDismissProgress = true + self?.controller?.push(c) + } + controller.presentController = { [weak self] c in + self?.controller?.present(c, in: .window(.root)) + } + self.controller?.present(controller, in: .window(.root)) + } + }))) } - }))) - - let actions = ContextController.Items(content: .list(items)) - - let contextController = ContextController(presentationData: self.presentationData, source: .extracted(PeerInfoContextExtractedContentSource(sourceNode: sourceNode)), items: .single(actions), gesture: gesture) - self.controller?.present(contextController, in: .window(.root)) + + let actions = ContextController.Items(content: .list(items)) + + let contextController = ContextController(presentationData: self.presentationData, source: .extracted(PeerInfoContextExtractedContentSource(sourceNode: sourceNode)), items: .single(actions), gesture: gesture) + self.controller?.present(contextController, in: .window(.root)) + }) } private func openWorkingHoursContextMenu(node: ASDisplayNode, gesture: ContextGesture?) { From dc9138e4355fc0e1e235bf322e6cefaf964be59c Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Fri, 26 Apr 2024 23:51:57 +0400 Subject: [PATCH 2/6] Update localization [skip ci] --- Telegram/Telegram-iOS/en.lproj/Localizable.strings | 1 + .../AdminUserActionsSheet/Sources/AdminUserActionsSheet.swift | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index b5d1141306..15eb844b4e 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -12158,6 +12158,7 @@ Sorry for the inconvenience."; "Chat.AdminActionSheet.BanFooterMultiple" = "Fully ban users"; "Chat.AdminActionSheet.RestrictFooterMultiple" = "Partially restrict users"; "Chat.AdminActionSheet.PermissionsSectionHeader" = "WHAT CAN THIS USER DO?"; +"Chat.AdminActionSheet.PermissionsSectionHeaderMultiple" = "WHAT CAN THESE USERS DO?"; "Chat.AdminActionSheet.ActionButton" = "Proceed"; "Chat.AdminAction.ToastMessagesDeletedTitleSingle" = "Message Deleted"; diff --git a/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsSheet.swift b/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsSheet.swift index 584b12f197..150c207776 100644 --- a/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsSheet.swift +++ b/submodules/TelegramUI/Components/AdminUserActionsSheet/Sources/AdminUserActionsSheet.swift @@ -1247,7 +1247,7 @@ private final class AdminUserActionsSheetComponent: Component { theme: environment.theme, header: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( - string: environment.strings.Chat_AdminActionSheet_PermissionsSectionHeader, + string: component.peers.count == 1 ? environment.strings.Chat_AdminActionSheet_PermissionsSectionHeader : environment.strings.Chat_AdminActionSheet_PermissionsSectionHeaderMultiple, font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), textColor: environment.theme.list.freeTextColor )), From 1ff9ffcb02a86cb193a5ea2f9a74cb720bc571ef Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 22 May 2024 19:16:58 +0400 Subject: [PATCH 3/6] Bump version --- versions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions.json b/versions.json index f069c6c557..5f83936904 100644 --- a/versions.json +++ b/versions.json @@ -1,5 +1,5 @@ { - "app": "10.12", + "app": "10.13", "xcode": "15.2", "bazel": "7.1.1", "macos": "13.0" From 41eb7e224e117ebc91f8ae6ac5258d08c1f74447 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 22 May 2024 19:40:31 +0400 Subject: [PATCH 4/6] Fix build --- .../PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift | 9 --------- 1 file changed, 9 deletions(-) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index cbf147e1d4..b8becd4489 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -7078,24 +7078,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro copyText = self.presentationData.strings.ChannelProfile_AboutActionCopy } items.append(.action(ContextMenuActionItem(text: copyText, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in -<<<<<<< HEAD - c.dismiss { -======= c?.dismiss { ->>>>>>> master copyAction() } }))) let (canTranslate, language) = canTranslateText(context: self.context, text: bioText, showTranslate: translationSettings.showTranslate, showTranslateIfTopical: false, ignoredLanguages: translationSettings.ignoredLanguages) if canTranslate { -<<<<<<< HEAD - items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuTranslate, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in - c.dismiss { -======= items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuTranslate, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Translate"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in c?.dismiss { ->>>>>>> master guard let self else { return } From 17d9d6caf374d5776ce862680e026d67f10ad1ef Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Fri, 24 May 2024 18:10:30 +0400 Subject: [PATCH 5/6] Quote improvements --- .../Sources/ChatController.swift | 24 +++++--- .../Sources/ChatInterfaceState.swift | 3 +- .../Components/Chat/ChatInputTextNode/BUILD | 1 + .../Sources/ChatInputTextNode.swift | 55 +++++++++++++------ .../Sources/InteractiveTextComponent.swift | 2 +- .../Sources/ChatTextInputPanelNode.swift | 25 ++++++++- .../Sources/ChatTextInputAttributes.swift | 2 +- 7 files changed, 82 insertions(+), 30 deletions(-) diff --git a/submodules/AccountContext/Sources/ChatController.swift b/submodules/AccountContext/Sources/ChatController.swift index f8cacc148f..d0db28a125 100644 --- a/submodules/AccountContext/Sources/ChatController.swift +++ b/submodules/AccountContext/Sources/ChatController.swift @@ -550,18 +550,24 @@ public struct ChatTextInputStateText: Codable, Equatable { parsedAttributes.append(ChatTextInputStateTextAttribute(type: .underline, range: range.location ..< (range.location + range.length))) } else if key == ChatTextInputAttributes.spoiler { parsedAttributes.append(ChatTextInputStateTextAttribute(type: .spoiler, range: range.location ..< (range.location + range.length))) - } else if key == ChatTextInputAttributes.block, let value = value as? ChatTextInputTextQuoteAttribute { - switch value.kind { - case .quote: - parsedAttributes.append(ChatTextInputStateTextAttribute(type: .quote(isCollapsed: value.isCollapsed), range: range.location ..< (range.location + range.length))) - case let .code(language): - parsedAttributes.append(ChatTextInputStateTextAttribute(type: .codeBlock(language: language), range: range.location ..< (range.location + range.length))) - } - } else if key == ChatTextInputAttributes.collapsedBlock, let value = value as? NSAttributedString { - parsedAttributes.append(ChatTextInputStateTextAttribute(type: .collapsedQuote(text: ChatTextInputStateText(attributedText: value)), range: range.location ..< (range.location + range.length))) } } }) + attributedText.enumerateAttribute(ChatTextInputAttributes.block, in: NSRange(location: 0, length: attributedText.length), options: [], using: { value, range, _ in + if let value = value as? ChatTextInputTextQuoteAttribute { + switch value.kind { + case .quote: + parsedAttributes.append(ChatTextInputStateTextAttribute(type: .quote(isCollapsed: value.isCollapsed), range: range.location ..< (range.location + range.length))) + case let .code(language): + parsedAttributes.append(ChatTextInputStateTextAttribute(type: .codeBlock(language: language), range: range.location ..< (range.location + range.length))) + } + } + }) + attributedText.enumerateAttribute(ChatTextInputAttributes.collapsedBlock, in: NSRange(location: 0, length: attributedText.length), options: [], using: { value, range, _ in + if let value = value as? NSAttributedString { + parsedAttributes.append(ChatTextInputStateTextAttribute(type: .collapsedQuote(text: ChatTextInputStateText(attributedText: value)), range: range.location ..< (range.location + range.length))) + } + }) self.attributes = parsedAttributes } diff --git a/submodules/ChatInterfaceState/Sources/ChatInterfaceState.swift b/submodules/ChatInterfaceState/Sources/ChatInterfaceState.swift index 1c94d2519d..8e3ab429af 100644 --- a/submodules/ChatInterfaceState/Sources/ChatInterfaceState.swift +++ b/submodules/ChatInterfaceState/Sources/ChatInterfaceState.swift @@ -470,7 +470,8 @@ public final class ChatInterfaceState: Codable, Equatable { if self.composeInputState.inputText.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && self.replyMessageSubject == nil { return nil } else { - return SynchronizeableChatInputState(replySubject: self.replyMessageSubject?.subjectModel, text: self.composeInputState.inputText.string, entities: generateChatInputTextEntities(self.composeInputState.inputText), timestamp: self.timestamp, textSelection: self.composeInputState.selectionRange) + let sourceText = expandedInputStateAttributedString(self.composeInputState.inputText) + return SynchronizeableChatInputState(replySubject: self.replyMessageSubject?.subjectModel, text: sourceText.string, entities: generateChatInputTextEntities(sourceText), timestamp: self.timestamp, textSelection: self.composeInputState.selectionRange) } } diff --git a/submodules/TelegramUI/Components/Chat/ChatInputTextNode/BUILD b/submodules/TelegramUI/Components/Chat/ChatInputTextNode/BUILD index 5b069f65cd..9efb6c1ba2 100644 --- a/submodules/TelegramUI/Components/Chat/ChatInputTextNode/BUILD +++ b/submodules/TelegramUI/Components/Chat/ChatInputTextNode/BUILD @@ -16,6 +16,7 @@ swift_library( "//submodules/TelegramUI/Components/Chat/ChatInputTextNode/ChatInputTextViewImpl", "//submodules/TelegramUI/Components/Chat/MessageInlineBlockBackgroundView", "//submodules/AccountContext", + "//submodules/TelegramUI/Components/TextNodeWithEntities", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Chat/ChatInputTextNode/Sources/ChatInputTextNode.swift b/submodules/TelegramUI/Components/Chat/ChatInputTextNode/Sources/ChatInputTextNode.swift index 2348bde696..f98a704e0d 100644 --- a/submodules/TelegramUI/Components/Chat/ChatInputTextNode/Sources/ChatInputTextNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatInputTextNode/Sources/ChatInputTextNode.swift @@ -7,6 +7,7 @@ import ChatInputTextViewImpl import MessageInlineBlockBackgroundView import TextFormat import AccountContext +import TextNodeWithEntities public protocol ChatInputTextNodeDelegate: AnyObject { func chatInputTextNodeDidUpdateText() @@ -540,7 +541,19 @@ private final class ChatInputTextLegacyInternal: NSObject, ChatInputTextInternal var startIndex = glyphRange.lowerBound while startIndex < glyphRange.upperBound { var effectiveRange = NSRange(location: NSNotFound, length: 0) - let rect = self.customLayoutManager.lineFragmentUsedRect(forGlyphAt: startIndex, effectiveRange: &effectiveRange) + var rect = self.customLayoutManager.lineFragmentUsedRect(forGlyphAt: startIndex, effectiveRange: &effectiveRange) + + let characterRange = self.customLayoutManager.characterRange(forGlyphRange: NSRange(location: startIndex, length: 1), actualGlyphRange: nil) + if characterRange.location != NSNotFound { + if let attribute = self.customTextStorage.attribute(NSAttributedString.Key("Attribute__Blockquote"), at: characterRange.location, effectiveRange: nil) { + let _ = attribute + rect.size.width += 13.0 + } else if let attribute = self.customTextStorage.attribute(.attachment, at: characterRange.location, effectiveRange: nil) as? ChatInputTextCollapsedQuoteAttachment { + let _ = attribute + rect.size.width += 8.0 + } + } + if boundingRect.isEmpty { boundingRect = rect } else { @@ -552,6 +565,7 @@ private final class ChatInputTextLegacyInternal: NSObject, ChatInputTextInternal break } } + return boundingRect } @@ -804,11 +818,12 @@ private let registeredViewProvider: Void = { public final class ChatInputTextCollapsedQuoteAttachmentImpl: NSTextAttachment, ChatInputTextCollapsedQuoteAttachment { final class View: UIView { let attachment: ChatInputTextCollapsedQuoteAttachmentImpl - let textNode: ImmediateTextNode + let textNode: ImmediateTextNodeWithEntities init(attachment: ChatInputTextCollapsedQuoteAttachmentImpl) { self.attachment = attachment - self.textNode = ImmediateTextNode() + self.textNode = ImmediateTextNodeWithEntities() + self.textNode.displaysAsynchronously = false self.textNode.maximumNumberOfLines = 3 super.init(frame: CGRect()) @@ -825,10 +840,6 @@ public final class ChatInputTextCollapsedQuoteAttachmentImpl: NSTextAttachment, return CGSize(width: 10.0, height: 10.0) } - /*let renderingText = NSMutableAttributedString(attributedString: attachment.text) - renderingText.addAttribute(.font, value: attachment.attributes.font, range: NSRange(location: 0, length: renderingText.length)) - renderingText.addAttribute(.foregroundColor, value: attachment.attributes.textColor, range: NSRange(location: 0, length: renderingText.length))*/ - let renderingText = textAttributedStringForStateText( context: context, stateText: attachment.text, @@ -846,11 +857,11 @@ public final class ChatInputTextCollapsedQuoteAttachmentImpl: NSTextAttachment, textNode.maximumNumberOfLines = 3 textNode.attributedText = renderingText - textNode.cutout = TextNodeCutout(topRight: CGSize(width: 40.0, height: 10.0)) + textNode.cutout = TextNodeCutout(topRight: CGSize(width: 30.0, height: 10.0)) - let layoutInfo = textNode.updateLayoutFullInfo(CGSize(width: constrainedSize.width - 9.0, height: constrainedSize.height)) + let layoutSize = textNode.updateLayout(CGSize(width: constrainedSize.width - 9.0, height: constrainedSize.height)) - return CGSize(width: constrainedSize.width, height: 8.0 + layoutInfo.size.height + 8.0) + return CGSize(width: constrainedSize.width, height: 8.0 + layoutSize.height + 8.0) } override func layoutSubviews() { @@ -876,13 +887,24 @@ public final class ChatInputTextCollapsedQuoteAttachmentImpl: NSTextAttachment, renderingText.addAttribute(.font, value: attachment.attributes.font, range: NSRange(location: 0, length: renderingText.length)) renderingText.addAttribute(.foregroundColor, value: attachment.attributes.textColor, range: NSRange(location: 0, length: renderingText.length))*/ + self.textNode.arguments = TextNodeWithEntities.Arguments( + context: context, + cache: context.animationCache, + renderer: context.animationRenderer, + placeholderColor: .gray, + attemptSynchronous: true + ) + self.textNode.attributedText = renderingText - self.textNode.cutout = TextNodeCutout(topRight: CGSize(width: 10.0, height: 8.0)) + self.textNode.cutout = TextNodeCutout(topRight: CGSize(width: 30.0, height: 10.0)) + + self.textNode.displaySpoilerEffect = true + self.textNode.visibility = true let maxTextSize = CGSize(width: self.bounds.size.width - 9.0, height: self.bounds.size.height) - let layoutInfo = self.textNode.updateLayoutFullInfo(maxTextSize) + let layoutSize = self.textNode.updateLayout(maxTextSize) - self.textNode.frame = CGRect(origin: CGPoint(x: 9.0, y: 8.0), size: layoutInfo.size) + self.textNode.frame = CGRect(origin: CGPoint(x: 9.0, y: 8.0), size: layoutSize) } } @@ -1450,16 +1472,17 @@ private final class QuoteBackgroundView: UIView { self.iconView.frame = CGRect(origin: CGPoint(x: size.width - 4.0 - quoteIcon.size.width, y: 4.0), size: quoteIcon.size) let collapseButtonSize = CGSize(width: 18.0, height: 18.0) - self.collapseButton.frame = CGRect(origin: CGPoint(x: size.width - 2.0 - collapseButtonSize.width, y: 2.0), size: collapseButtonSize) if isCollapsed { self.collapseButtonIconView.image = quoteExpandImage + self.collapseButton.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size) } else { self.collapseButtonIconView.image = quoteCollapseImage + self.collapseButton.frame = CGRect(origin: CGPoint(x: size.width - 2.0 - collapseButtonSize.width, y: 2.0), size: collapseButtonSize) } if let image = self.collapseButtonIconView.image { let iconSize = image.size.aspectFitted(collapseButtonSize) - self.collapseButtonIconView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((collapseButtonSize.width - iconSize.width) * 0.5), y: floorToScreenPixels((collapseButtonSize.height - iconSize.height) * 0.5)), size: iconSize) + self.collapseButtonIconView.frame = CGRect(origin: CGPoint(x: self.collapseButton.bounds.width - 2.0 - collapseButtonSize.width + floorToScreenPixels((collapseButtonSize.width - iconSize.width) * 0.5), y: 2.0 + floorToScreenPixels((collapseButtonSize.height - iconSize.height) * 0.5)), size: iconSize) } var primaryColor: UIColor @@ -1469,7 +1492,7 @@ private final class QuoteBackgroundView: UIView { switch kind { case .quote: - if size.height >= 100.0 || isCollapsed { + if size.height >= 60.0 || isCollapsed { self.iconView.isHidden = true self.collapseButton.isHidden = false } else { diff --git a/submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift b/submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift index 7340cfbc37..ffc6c7d3a7 100644 --- a/submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift +++ b/submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift @@ -45,7 +45,7 @@ private func generateBlockMaskImage() -> UIImage { gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)! context.setBlendMode(.destinationIn) - context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: size.height), end: CGPoint(x: 0.0, y: size.height - 7.0), options: CGGradientDrawingOptions()) + context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: size.height), end: CGPoint(x: 0.0, y: size.height - 18.0), options: CGGradientDrawingOptions()) })!.resizableImage(withCapInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: size.height - 1.0, right: size.width - 1.0), resizingMode: .stretch) } diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index a11c432d40..7d3da90cdd 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -1212,13 +1212,23 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in let result = NSMutableAttributedString(attributedString: current.inputText) + var selectionRange = current.selectionRange if let _ = result.attribute(ChatTextInputAttributes.block, at: range.lowerBound, effectiveRange: nil) as? ChatTextInputTextQuoteAttribute { - let blockString = result.attributedSubstring(from: range) + let blockString = NSMutableAttributedString(attributedString: result.attributedSubstring(from: range)) + blockString.removeAttribute(ChatTextInputAttributes.block, range: NSRange(location: 0, length: blockString.length)) + result.replaceCharacters(in: range, with: "") result.insert(NSAttributedString(string: " ", attributes: [ ChatTextInputAttributes.collapsedBlock: blockString ]), at: range.lowerBound) + + if selectionRange.lowerBound >= range.lowerBound && selectionRange.upperBound < range.upperBound { + selectionRange = range.lowerBound ..< range.lowerBound + } else if selectionRange.lowerBound >= range.upperBound { + let deltaLength = 1 - range.length + selectionRange = (selectionRange.lowerBound + deltaLength) ..< (selectionRange.lowerBound + deltaLength) + } } else if let current = result.attribute(ChatTextInputAttributes.collapsedBlock, at: range.lowerBound, effectiveRange: nil) as? NSAttributedString { result.replaceCharacters(in: range, with: "") @@ -1226,13 +1236,24 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch updatedBlockString.addAttribute(ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .quote, isCollapsed: false), range: NSRange(location: 0, length: updatedBlockString.length)) result.insert(updatedBlockString, at: range.lowerBound) + + if selectionRange.lowerBound >= range.upperBound { + let deltaLength = updatedBlockString.length - 1 + selectionRange = (selectionRange.lowerBound + deltaLength) ..< (selectionRange.lowerBound + deltaLength) + } } let stateResult = stateAttributedStringForText(result) + if selectionRange.lowerBound < 0 { + selectionRange = 0 ..< selectionRange.upperBound + } + if selectionRange.upperBound > stateResult.length { + selectionRange = selectionRange.lowerBound ..< stateResult.length + } return (ChatTextInputState( inputText: stateResult, - selectionRange: current.selectionRange + selectionRange: selectionRange ), inputMode) } } diff --git a/submodules/TextFormat/Sources/ChatTextInputAttributes.swift b/submodules/TextFormat/Sources/ChatTextInputAttributes.swift index f15e284ace..52dc6e7292 100644 --- a/submodules/TextFormat/Sources/ChatTextInputAttributes.swift +++ b/submodules/TextFormat/Sources/ChatTextInputAttributes.swift @@ -179,7 +179,7 @@ public struct ChatTextFontAttributes: OptionSet, Hashable, Sequence { public func textAttributedStringForStateText(context: AnyObject, stateText: NSAttributedString, fontSize: CGFloat, textColor: UIColor, accentTextColor: UIColor, writingDirection: NSWritingDirection?, spoilersRevealed: Bool, availableEmojis: Set, emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?, makeCollapsedQuoteAttachment: ((NSAttributedString, ChatInputTextCollapsedQuoteAttributes) -> ChatInputTextCollapsedQuoteAttachment)?) -> NSAttributedString { let quoteAttributes = ChatInputTextCollapsedQuoteAttributes( context: context, - fontSize: fontSize, + fontSize: round(fontSize * 0.8235294117647058), textColor: textColor, accentTextColor: accentTextColor ) From 211000d019ecc1c70004ce8b33ca85b5a8a81415 Mon Sep 17 00:00:00 2001 From: Mikhail Filimonov Date: Fri, 24 May 2024 18:13:36 +0400 Subject: [PATCH 6/6] struct visibility --- .../TelegramCore/Sources/TelegramEngine/Payments/Stars.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift index f25ea03474..e08737230f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift @@ -260,7 +260,7 @@ public final class StarsContext { public let description: String? public let photo: TelegramMediaWebFile? - init( + public init( id: String, count: Int64, date: Int32,