Various improvements

This commit is contained in:
Ali 2023-09-15 21:12:01 +02:00
parent b7e4fb3d57
commit 3453137463
20 changed files with 235 additions and 19 deletions

View File

@ -32,7 +32,11 @@ public final class AnimationNode: ASDisplayNode {
super.init()
self.setViewBlock({
self.setViewBlock({ [weak self] in
guard let self else {
return UIView()
}
var animation: Animation?
if let animationName {
if let url = getAppBundle().url(forResource: animationName, withExtension: "json"), let maybeAnimation = Animation.filepath(url.path) {

View File

@ -448,7 +448,9 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
let textSelectionNode = TextSelectionNode(theme: TextSelectionTheme(selection: presentationData.theme.contextMenu.primaryColor.withAlphaComponent(0.15), knob: presentationData.theme.contextMenu.primaryColor, knobDiameter: 8.0), strings: presentationData.strings, textNode: self.textNode.textNode, updateIsActive: { _ in
}, present: { _, _ in
}, rootNode: self, performAction: { _, _ in
}, rootNode: { [weak self] in
return self
}, performAction: { _, _ in
})
self.textSelectionNode = textSelectionNode

View File

@ -48,6 +48,7 @@ swift_library(
"//submodules/TelegramUI/Components/SliderContextItem:SliderContextItem",
"//submodules/TooltipUI",
"//submodules/TelegramNotices",
"//submodules/Pasteboard",
],
visibility = [
"//visibility:public",

View File

@ -25,6 +25,10 @@ import InvisibleInkDustNode
import TextNodeWithEntities
import AnimationCache
import MultiAnimationRenderer
import Pasteboard
import Speak
import TranslateUI
import TelegramNotices
private let deleteImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: .white)
private let actionImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: .white)
@ -133,6 +137,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
private let actionButton: UIButton
private let editButton: UIButton
private let maskNode: ASDisplayNode
private let textSelectionKnobContainer: UIView
private let textSelectionKnobSurface: UIView
private let scrollWrapperNode: CaptionScrollWrapperNode
private let scrollNode: ASScrollNode
@ -140,6 +146,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
private var spoilerTextNode: ImmediateTextNodeWithEntities?
private var dustNode: InvisibleInkDustNode?
private var textSelectionNode: TextSelectionNode?
private let animationCache: AnimationCache
private let animationRenderer: MultiAnimationRenderer
@ -178,6 +186,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
private var currentIsPaused: Bool = true
private var seekRate: Double = 1.0
private var currentSpeechHolder: SpeechSynthesizerHolder?
var performAction: ((GalleryControllerInteractionTapAction) -> Void)?
var openActionOptions: ((GalleryControllerInteractionTapAction, Message) -> Void)?
@ -325,6 +335,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.actionButton.setImage(actionImage, for: [.normal])
self.editButton.setImage(editImage, for: [.normal])
self.textSelectionKnobContainer = UIView()
self.textSelectionKnobSurface = UIView()
self.textSelectionKnobContainer.addSubview(self.textSelectionKnobSurface)
self.scrollWrapperNode = CaptionScrollWrapperNode()
self.scrollWrapperNode.clipsToBounds = true
@ -398,6 +412,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.textNode.longTapAttributeAction = { [weak self] attributes, index in
if let strongSelf = self, let action = strongSelf.actionForAttributes(attributes, index), let message = strongSelf.currentMessage {
strongSelf.openActionOptions?(action, message)
} else {
}
}
@ -410,13 +426,159 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
)
self.textNode.visibility = true
let textSelectionNode = TextSelectionNode(theme: TextSelectionTheme(selection: defaultDarkPresentationTheme.list.itemAccentColor.withMultipliedAlpha(0.5), knob: defaultDarkPresentationTheme.list.itemAccentColor), strings: presentationData.strings, textNode: self.textNode, updateIsActive: { [weak self] value in
guard let self else {
return
}
let _ = self
}, present: { c, a in
present(c, a)
}, rootNode: { [weak self] in
guard let self else {
return nil
}
return self.controllerInteraction?.controller()?.displayNode
}, externalKnobSurface: self.textSelectionKnobSurface, performAction: { [weak self] text, action in
guard let self else {
return
}
switch action {
case .copy:
storeAttributedTextInPasteboard(text)
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
let undoController = UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Conversation_TextCopied), elevatedLayout: false, animateInAsReplacement: false, blurred: true, action: { _ in true })
self.controllerInteraction?.presentController(undoController, nil)
case .share:
let theme = defaultDarkPresentationTheme
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (self.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), self.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) })
let shareController = ShareController(context: self.context, subject: .text(text.string), externalShare: true, immediateExternalShare: false, updatedPresentationData: updatedPresentationData)
self.controllerInteraction?.presentController(shareController, nil)
case .lookup:
let controller = UIReferenceLibraryViewController(term: text.string)
if let window = self.controllerInteraction?.controller()?.view.window {
controller.popoverPresentationController?.sourceView = window
controller.popoverPresentationController?.sourceRect = CGRect(origin: CGPoint(x: window.bounds.width / 2.0, y: window.bounds.size.height - 1.0), size: CGSize(width: 1.0, height: 1.0))
window.rootViewController?.present(controller, animated: true)
}
case .speak:
if let speechHolder = speakText(context: self.context, text: text.string) {
speechHolder.completion = { [weak self, weak speechHolder] in
guard let self else {
return
}
if self.currentSpeechHolder === speechHolder {
self.currentSpeechHolder = nil
}
}
self.currentSpeechHolder = speechHolder
}
case .translate:
let _ = (self.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings])
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] sharedData in
guard let self else {
return
}
//let peer = component.slice.peer
let translationSettings: TranslationSettings
if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.translationSettings]?.get(TranslationSettings.self) {
translationSettings = current
} else {
translationSettings = TranslationSettings.defaultSettings
}
/*var showTranslateIfTopical = false
if case let .channel(channel) = peer, !(channel.addressName ?? "").isEmpty {
showTranslateIfTopical = true
}*/
let showTranslateIfTopical = false
let (_, language) = canTranslateText(context: self.context, text: text.string, showTranslate: translationSettings.showTranslate, showTranslateIfTopical: showTranslateIfTopical, ignoredLanguages: translationSettings.ignoredLanguages)
let _ = ApplicationSpecificNotice.incrementTranslationSuggestion(accountManager: self.context.sharedContext.accountManager, timestamp: Int32(Date().timeIntervalSince1970)).start()
let translateController = TranslateScreen(context: self.context, forceTheme: defaultDarkPresentationTheme, text: text.string, canCopy: true, fromLanguage: language, ignoredLanguages: translationSettings.ignoredLanguages)
translateController.pushController = { [weak self] c in
guard let self else {
return
}
self.controllerInteraction?.pushController(c)
}
translateController.presentController = { [weak self] c in
guard let self else {
return
}
self.controllerInteraction?.presentController(c, nil)
}
//self.actionSheet = translateController
//view.updateIsProgressPaused()
/*translateController.wasDismissed = { [weak self, weak view] in
guard let self, let view else {
return
}
self.actionSheet = nil
view.updateIsProgressPaused()
}*/
//component.controller()?.present(translateController, in: .window(.root))
self.controllerInteraction?.presentController(translateController, nil)
})
}
})
textSelectionNode.enableLookup = true
textSelectionNode.canBeginSelection = { [weak self] location in
guard let self else {
return false
}
let textNode = self.textNode
let titleFrame = textNode.view.bounds
if let (index, attributes) = textNode.attributesAtPoint(CGPoint(x: location.x - titleFrame.minX, y: location.y - titleFrame.minY)) {
let _ = index
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler)] {
return false
} else if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
return false
} else if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerMention)] as? TelegramPeerMention {
return false
} else if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerTextMention)] as? String {
return false
} else if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Hashtag)] as? TelegramHashtag {
return false
} else if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.BankCard)] as? String {
return false
} else if let emoji = attributes[NSAttributedString.Key(rawValue: ChatTextInputAttributes.customEmoji.rawValue)] as? ChatTextInputTextCustomEmojiAttribute, let _ = emoji.file {
return false
}
}
return true
}
self.textSelectionNode = textSelectionNode
self.contentNode.view.addSubview(self.deleteButton)
self.contentNode.view.addSubview(self.fullscreenButton)
self.contentNode.view.addSubview(self.actionButton)
self.contentNode.view.addSubview(self.editButton)
self.contentNode.addSubnode(self.scrollWrapperNode)
self.scrollWrapperNode.addSubnode(self.scrollNode)
self.contentNode.view.addSubview(self.textSelectionKnobContainer)
self.scrollNode.addSubnode(textSelectionNode.highlightAreaNode)
self.scrollNode.addSubnode(self.textNode)
self.scrollNode.addSubnode(textSelectionNode)
self.contentNode.addSubnode(self.authorNameNode)
self.contentNode.addSubnode(self.dateNode)
@ -602,6 +764,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.textNode.isHidden = false
self.textNode.attributedText = caption
}
self.textSelectionNode?.isHidden = self.textNode.isHidden
if let titleText = titleText {
self.authorNameNode.attributedText = NSAttributedString(string: titleText, font: titleFont, textColor: .white)
@ -778,6 +941,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.textNode.attributedText = messageText
}
self.textSelectionNode?.isHidden = self.textNode.isHidden
if let authorNameText = authorNameText {
self.authorNameNode.attributedText = NSAttributedString(string: authorNameText, font: titleFont, textColor: .white)
} else {
@ -845,6 +1010,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.textSelectionKnobContainer.frame = CGRect(origin: CGPoint(x: 0.0, y: -scrollView.bounds.origin.y), size: CGSize())
self.requestLayout?(.immediate)
}
@ -950,6 +1117,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
if self.textNode.frame != textFrame {
self.textNode.frame = textFrame
self.spoilerTextNode?.frame = textFrame
self.textSelectionNode?.frame = textFrame
self.textSelectionNode?.highlightAreaNode.frame = textFrame
self.textSelectionKnobSurface.frame = textFrame
}
}

View File

@ -1213,6 +1213,8 @@ public class GalleryController: ViewController, StandalonePresentableController,
self?.dismiss(forceAway: true)
})
}
}, controller: { [weak self] in
return self
})
let disableTapNavigation = !(self.context.sharedContext.currentMediaDisplaySettings.with { $0 }.showNextMediaOnTap)

View File

@ -11,13 +11,15 @@ public final class GalleryControllerInteraction {
public let dismissController: () -> Void
public let replaceRootController: (ViewController, Promise<Bool>?) -> Void
public let editMedia: (MessageId) -> Void
public let controller: () -> ViewController?
public init(presentController: @escaping (ViewController, ViewControllerPresentationArguments?) -> Void, pushController: @escaping (ViewController) -> Void, dismissController: @escaping () -> Void, replaceRootController: @escaping (ViewController, Promise<Bool>?) -> Void, editMedia: @escaping (MessageId) -> Void) {
public init(presentController: @escaping (ViewController, ViewControllerPresentationArguments?) -> Void, pushController: @escaping (ViewController) -> Void, dismissController: @escaping () -> Void, replaceRootController: @escaping (ViewController, Promise<Bool>?) -> Void, editMedia: @escaping (MessageId) -> Void, controller: @escaping () -> ViewController?) {
self.presentController = presentController
self.pushController = pushController
self.dismissController = dismissController
self.replaceRootController = replaceRootController
self.editMedia = editMedia
self.controller = controller
}
}

View File

@ -251,6 +251,8 @@ public final class SecretMediaPreviewController: ViewController {
self?.dismiss(forceAway: true)
}, replaceRootController: { _, _ in
}, editMedia: { _ in
}, controller: { [weak self] in
return self
})
self.displayNode = SecretMediaPreviewControllerNode(controllerInteraction: controllerInteraction)
self.displayNodeDidLoad()

View File

@ -372,6 +372,8 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable
strongSelf.replaceRootController(controller, ready)
}
}, editMedia: { _ in
}, controller: { [weak self] in
return self
})
self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction)
self.displayNodeDidLoad()

View File

@ -566,11 +566,13 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
node.containerNode.addSubnode(node.bufferingNode)
node.foregroundNode.addSubnode(node.foregroundContentNode)
node.containerNode.addSubnode(node.foregroundNode)
let highlightedHandleNode = node.highlightedHandleNode
if let handleNodeContainer = node.handleNodeContainer {
self.addSubnode(handleNodeContainer)
handleNodeContainer.highlighted = { [weak self] highlighted in
if let strongSelf = self, let highlightedHandleNode = node.highlightedHandleNode, let statusValue = strongSelf.statusValue, Double(0.0).isLess(than: statusValue.duration) {
if let strongSelf = self, let highlightedHandleNode, let statusValue = strongSelf.statusValue, Double(0.0).isLess(than: statusValue.duration) {
if highlighted {
strongSelf.displayLink?.isPaused = true

View File

@ -184,6 +184,8 @@ class SecureIdDocumentGalleryController: ViewController, StandalonePresentableCo
strongSelf.replaceRootController(controller, ready)
}
}, editMedia: { _ in
}, controller: { [weak self] in
return self
})
self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction)
self.displayNodeDidLoad()

View File

@ -630,6 +630,8 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr
strongSelf.replaceRootController(controller, ready)
}
}, editMedia: { _ in
}, controller: { [weak self] in
return self
})
self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction)
self.displayNodeDidLoad()

View File

@ -441,6 +441,8 @@ public class WallpaperGalleryController: ViewController {
self?.dismiss(forceAway: true)
}, replaceRootController: { controller, ready in
}, editMedia: { _ in
}, controller: { [weak self] in
return self
})
self.displayNode = WallpaperGalleryControllerNode(controllerInteraction: controllerInteraction, pageGap: 0.0, disableTapNavigation: true)
self.displayNodeDidLoad()

View File

@ -93,19 +93,22 @@ public final class ButtonTextContentComponent: Component {
public let textColor: UIColor
public let badgeBackground: UIColor
public let badgeForeground: UIColor
public let combinedAlignment: Bool
public init(
text: String,
badge: Int,
textColor: UIColor,
badgeBackground: UIColor,
badgeForeground: UIColor
badgeForeground: UIColor,
combinedAlignment: Bool = false
) {
self.text = text
self.badge = badge
self.textColor = textColor
self.badgeBackground = badgeBackground
self.badgeForeground = badgeForeground
self.combinedAlignment = combinedAlignment
}
public static func ==(lhs: ButtonTextContentComponent, rhs: ButtonTextContentComponent) -> Bool {
@ -124,6 +127,9 @@ public final class ButtonTextContentComponent: Component {
if lhs.badgeForeground != rhs.badgeForeground {
return false
}
if lhs.combinedAlignment != rhs.combinedAlignment {
return false
}
return true
}
@ -194,23 +200,26 @@ public final class ButtonTextContentComponent: Component {
}
var size = contentSize
var measurementSize = size
if let badgeSize {
//size.width += badgeSpacing
//size.width += badgeSize.width
if component.combinedAlignment {
measurementSize.width += badgeSpacing
measurementSize.width += badgeSize.width
}
size.height = max(size.height, badgeSize.height)
}
let contentFrame = CGRect(origin: CGPoint(x: floor((size.width - contentSize.width) * 0.5), y: floor((size.height - contentSize.height) * 0.5)), size: contentSize)
let contentFrame = CGRect(origin: CGPoint(x: floor((size.width - measurementSize.width) * 0.5), y: floor((size.height - measurementSize.height) * 0.5)), size: measurementSize)
if let contentView = self.content.view {
if contentView.superview == nil {
self.addSubview(contentView)
}
transition.setFrame(view: contentView, frame: contentFrame)
transition.setFrame(view: contentView, frame: CGRect(origin: contentFrame.origin, size: contentSize))
}
if let badgeSize, let badge = self.badge {
let badgeFrame = CGRect(origin: CGPoint(x: contentFrame.maxX + badgeSpacing, y: floor((size.height - badgeSize.height) * 0.5) + 1.0), size: badgeSize)
let badgeFrame = CGRect(origin: CGPoint(x: contentFrame.minX + contentSize.width + badgeSpacing, y: floor((size.height - badgeSize.height) * 0.5) + 1.0), size: badgeSize)
if let badgeView = badge.view {
var animateIn = false

View File

@ -2288,7 +2288,8 @@ final class ShareWithPeersScreenComponent: Component {
badge: badge,
textColor: environment.theme.list.itemCheckColors.foregroundColor,
badgeBackground: environment.theme.list.itemCheckColors.foregroundColor,
badgeForeground: environment.theme.list.itemCheckColors.fillColor
badgeForeground: environment.theme.list.itemCheckColors.fillColor,
combinedAlignment: true
))
),
isEnabled: true,

View File

@ -744,7 +744,9 @@ final class StoryContentCaptionComponent: Component {
return
}
component.controller()?.presentInGlobalOverlay(c, with: a)
}, rootNode: controller.displayNode, externalKnobSurface: self.textSelectionKnobSurface, performAction: { [weak self] text, action in
}, rootNode: { [weak controller] in
return controller?.displayNode
}, externalKnobSurface: self.textSelectionKnobSurface, performAction: { [weak self] text, action in
guard let self, let component = self.component else {
return
}

View File

@ -1484,8 +1484,12 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
Logger.shared.log("App \(self.episodeId)", "Memory consumption: \(value / (1024 * 1024)) MB")
if !buildConfig.isAppStoreBuild {
if value >= 1 * 1024 * 1024 * 1024 {
if value >= 800 * 1024 * 1024 {
#if targetEnvironment(simulator)
print("Debug memory")
#else
preconditionFailure()
#endif
}
}
}

View File

@ -1794,7 +1794,9 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
self?.updateIsTextSelectionActive?(value)
}, present: { [weak self] c, a in
self?.arguments?.controllerInteraction.presentGlobalOverlayController(c, a)
}, rootNode: rootNode, performAction: { [weak self] text, action in
}, rootNode: { [weak rootNode] in
return rootNode
}, performAction: { [weak self] text, action in
guard let strongSelf = self, let item = strongSelf.arguments else {
return
}

View File

@ -798,7 +798,9 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
self?.updateIsTextSelectionActive?(value)
}, present: { [weak self] c, a in
self?.item?.controllerInteraction.presentGlobalOverlayController(c, a)
}, rootNode: rootNode, performAction: { [weak self] text, action in
}, rootNode: { [weak rootNode] in
return rootNode
}, performAction: { [weak self] text, action in
guard let strongSelf = self, let item = strongSelf.item else {
return
}

View File

@ -220,7 +220,7 @@ public final class TextSelectionNode: ASDisplayNode {
public var canBeginSelection: (CGPoint) -> Bool = { _ in true }
public var updateRange: ((NSRange?) -> Void)?
private let present: (ViewController, Any?) -> Void
private weak var rootNode: ASDisplayNode?
private let rootNode: () -> ASDisplayNode?
private let performAction: (NSAttributedString, TextSelectionAction) -> Void
private var highlightOverlay: LinkHighlightingNode?
private let leftKnob: ASImageNode
@ -240,7 +240,7 @@ public final class TextSelectionNode: ASDisplayNode {
return self.recognizer?.didRecognizeTap ?? false
}
public init(theme: TextSelectionTheme, strings: PresentationStrings, textNode: TextNode, updateIsActive: @escaping (Bool) -> Void, present: @escaping (ViewController, Any?) -> Void, rootNode: ASDisplayNode, externalKnobSurface: UIView? = nil, performAction: @escaping (NSAttributedString, TextSelectionAction) -> Void) {
public init(theme: TextSelectionTheme, strings: PresentationStrings, textNode: TextNode, updateIsActive: @escaping (Bool) -> Void, present: @escaping (ViewController, Any?) -> Void, rootNode: @escaping () -> ASDisplayNode?, externalKnobSurface: UIView? = nil, performAction: @escaping (NSAttributedString, TextSelectionAction) -> Void) {
self.theme = theme
self.strings = strings
self.textNode = textNode
@ -312,7 +312,7 @@ public final class TextSelectionNode: ASDisplayNode {
if let scrollView = findScrollView(view: strongSelf.view) {
let scrollPoint = strongSelf.view.convert(point, to: scrollView)
scrollView.scrollRectToVisible(CGRect(origin: CGPoint(x: scrollPoint.x, y: scrollPoint.y - 30.0), size: CGSize(width: 1.0, height: 60.0)), animated: false)
scrollView.scrollRectToVisible(CGRect(origin: CGPoint(x: scrollPoint.x, y: scrollPoint.y - 50.0), size: CGSize(width: 1.0, height: 100.0)), animated: false)
}
}
}
@ -596,7 +596,7 @@ public final class TextSelectionNode: ASDisplayNode {
}))
self.present(ContextMenuController(actions: actions, catchTapsOutside: false, hasHapticFeedback: false), ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self] in
guard let strongSelf = self, let rootNode = strongSelf.rootNode else {
guard let strongSelf = self, let rootNode = strongSelf.rootNode() else {
return nil
}
return (strongSelf, completeRect, rootNode, rootNode.bounds)

View File

@ -227,6 +227,8 @@ class WebSearchGalleryController: ViewController {
strongSelf.replaceRootController(controller, ready)
}
}, editMedia: { _ in
}, controller: { [weak self] in
return self
})
self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction)
self.displayNodeDidLoad()