diff --git a/submodules/Display/Display/ImmediateTextNode.swift b/submodules/Display/Display/ImmediateTextNode.swift index add3df7e25..a8e4154c15 100644 --- a/submodules/Display/Display/ImmediateTextNode.swift +++ b/submodules/Display/Display/ImmediateTextNode.swift @@ -13,6 +13,7 @@ public class ImmediateTextNode: TextNode { public var maximumNumberOfLines: Int = 1 public var lineSpacing: CGFloat = 0.0 public var insets: UIEdgeInsets = UIEdgeInsets() + public var textShadowColor: UIColor? private var tapRecognizer: TapLongTapOrDoubleTapGestureRecognizer? private var linkHighlightingNode: LinkHighlightingNode? @@ -34,7 +35,7 @@ public class ImmediateTextNode: TextNode { public func updateLayout(_ constrainedSize: CGSize) -> CGSize { let makeLayout = TextNode.asyncLayout(self) - let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, lineSpacing: self.lineSpacing, cutout: nil, insets: self.insets)) + let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, lineSpacing: self.lineSpacing, cutout: nil, insets: self.insets, textShadowColor: self.textShadowColor)) let _ = apply() if layout.numberOfLines > 1 { self.trailingLineWidth = layout.trailingLineWidth diff --git a/submodules/Display/Display/TextNode.swift b/submodules/Display/Display/TextNode.swift index a00c22c472..b1650c4eba 100644 --- a/submodules/Display/Display/TextNode.swift +++ b/submodules/Display/Display/TextNode.swift @@ -92,8 +92,9 @@ public final class TextNodeLayoutArguments { public let cutout: TextNodeCutout? public let insets: UIEdgeInsets public let lineColor: UIColor? + public let textShadowColor: UIColor? - public init(attributedString: NSAttributedString?, backgroundColor: UIColor? = nil, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, constrainedSize: CGSize, alignment: NSTextAlignment = .natural, lineSpacing: CGFloat = 0.12, cutout: TextNodeCutout? = nil, insets: UIEdgeInsets = UIEdgeInsets(), lineColor: UIColor? = nil) { + public init(attributedString: NSAttributedString?, backgroundColor: UIColor? = nil, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, constrainedSize: CGSize, alignment: NSTextAlignment = .natural, lineSpacing: CGFloat = 0.12, cutout: TextNodeCutout? = nil, insets: UIEdgeInsets = UIEdgeInsets(), lineColor: UIColor? = nil, textShadowColor: UIColor? = nil) { self.attributedString = attributedString self.backgroundColor = backgroundColor self.maximumNumberOfLines = maximumNumberOfLines @@ -104,6 +105,7 @@ public final class TextNodeLayoutArguments { self.cutout = cutout self.insets = insets self.lineColor = lineColor + self.textShadowColor = textShadowColor } } @@ -123,9 +125,10 @@ public final class TextNodeLayout: NSObject { fileprivate let lines: [TextNodeLine] fileprivate let blockQuotes: [TextNodeBlockQuote] fileprivate let lineColor: UIColor? + fileprivate let textShadowColor: UIColor? public let hasRTL: Bool - fileprivate init(attributedString: NSAttributedString?, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, constrainedSize: CGSize, alignment: NSTextAlignment, lineSpacing: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, size: CGSize, truncated: Bool, firstLineOffset: CGFloat, lines: [TextNodeLine], blockQuotes: [TextNodeBlockQuote], backgroundColor: UIColor?, lineColor: UIColor?) { + fileprivate init(attributedString: NSAttributedString?, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, constrainedSize: CGSize, alignment: NSTextAlignment, lineSpacing: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, size: CGSize, truncated: Bool, firstLineOffset: CGFloat, lines: [TextNodeLine], blockQuotes: [TextNodeBlockQuote], backgroundColor: UIColor?, lineColor: UIColor?, textShadowColor: UIColor?) { self.attributedString = attributedString self.maximumNumberOfLines = maximumNumberOfLines self.truncationType = truncationType @@ -141,6 +144,7 @@ public final class TextNodeLayout: NSObject { self.blockQuotes = blockQuotes self.backgroundColor = backgroundColor self.lineColor = lineColor + self.textShadowColor = textShadowColor var hasRTL = false for line in lines { if line.isRTL { @@ -575,7 +579,7 @@ public class TextNode: ASDisplayNode { } } - private class func calculateLayout(attributedString: NSAttributedString?, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, backgroundColor: UIColor?, constrainedSize: CGSize, alignment: NSTextAlignment, lineSpacingFactor: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, lineColor: UIColor?) -> TextNodeLayout { + private class func calculateLayout(attributedString: NSAttributedString?, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, backgroundColor: UIColor?, constrainedSize: CGSize, alignment: NSTextAlignment, lineSpacingFactor: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, lineColor: UIColor?, textShadowColor: UIColor?) -> TextNodeLayout { if let attributedString = attributedString { let stringLength = attributedString.length @@ -601,7 +605,7 @@ public class TextNode: ASDisplayNode { var maybeTypesetter: CTTypesetter? maybeTypesetter = CTTypesetterCreateWithAttributedString(attributedString as CFAttributedString) if maybeTypesetter == nil { - return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, alignment: alignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor) + return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, alignment: alignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor) } let typesetter = maybeTypesetter! @@ -793,9 +797,9 @@ public class TextNode: ASDisplayNode { } } - return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, alignment: alignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(width: ceil(layoutSize.width) + insets.left + insets.right, height: ceil(layoutSize.height) + insets.top + insets.bottom), truncated: truncated, firstLineOffset: firstLineOffset, lines: lines, blockQuotes: blockQuotes, backgroundColor: backgroundColor, lineColor: lineColor) + return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, alignment: alignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(width: ceil(layoutSize.width) + insets.left + insets.right, height: ceil(layoutSize.height) + insets.top + insets.bottom), truncated: truncated, firstLineOffset: firstLineOffset, lines: lines, blockQuotes: blockQuotes, backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor) } else { - return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, alignment: alignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor) + return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, alignment: alignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor) } } @@ -828,11 +832,15 @@ public class TextNode: ASDisplayNode { context.fill(bounds) } + if let textShadowColor = layout.textShadowColor { + context.setTextDrawingMode(.fill) + context.setShadow(offset: CGSize(width: 0.0, height: 1.0), blur: 0.0, color: textShadowColor.cgColor) + } + let textMatrix = context.textMatrix let textPosition = context.textPosition context.textMatrix = CGAffineTransform(scaleX: 1.0, y: -1.0) - let alignment = layout.alignment let offset = CGPoint(x: layout.insets.left, y: layout.insets.top) @@ -927,11 +935,11 @@ public class TextNode: ASDisplayNode { if stringMatch { layout = existingLayout } else { - layout = TextNode.calculateLayout(attributedString: arguments.attributedString, maximumNumberOfLines: arguments.maximumNumberOfLines, truncationType: arguments.truncationType, backgroundColor: arguments.backgroundColor, constrainedSize: arguments.constrainedSize, alignment: arguments.alignment, lineSpacingFactor: arguments.lineSpacing, cutout: arguments.cutout, insets: arguments.insets, lineColor: arguments.lineColor) + layout = TextNode.calculateLayout(attributedString: arguments.attributedString, maximumNumberOfLines: arguments.maximumNumberOfLines, truncationType: arguments.truncationType, backgroundColor: arguments.backgroundColor, constrainedSize: arguments.constrainedSize, alignment: arguments.alignment, lineSpacingFactor: arguments.lineSpacing, cutout: arguments.cutout, insets: arguments.insets, lineColor: arguments.lineColor, textShadowColor: arguments.textShadowColor) updated = true } } else { - layout = TextNode.calculateLayout(attributedString: arguments.attributedString, maximumNumberOfLines: arguments.maximumNumberOfLines, truncationType: arguments.truncationType, backgroundColor: arguments.backgroundColor, constrainedSize: arguments.constrainedSize, alignment: arguments.alignment, lineSpacingFactor: arguments.lineSpacing, cutout: arguments.cutout, insets: arguments.insets, lineColor: arguments.lineColor) + layout = TextNode.calculateLayout(attributedString: arguments.attributedString, maximumNumberOfLines: arguments.maximumNumberOfLines, truncationType: arguments.truncationType, backgroundColor: arguments.backgroundColor, constrainedSize: arguments.constrainedSize, alignment: arguments.alignment, lineSpacingFactor: arguments.lineSpacing, cutout: arguments.cutout, insets: arguments.insets, lineColor: arguments.lineColor, textShadowColor: arguments.textShadowColor) updated = true } diff --git a/submodules/MtProtoKit/MtProtoKit_Xcode.xcodeproj/project.pbxproj b/submodules/MtProtoKit/MtProtoKit_Xcode.xcodeproj/project.pbxproj index b321ed0361..60b6cfeae6 100644 --- a/submodules/MtProtoKit/MtProtoKit_Xcode.xcodeproj/project.pbxproj +++ b/submodules/MtProtoKit/MtProtoKit_Xcode.xcodeproj/project.pbxproj @@ -1929,6 +1929,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, ); mainGroup = D05A830918AFB3F9007F1076; @@ -2492,7 +2493,7 @@ ); GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; - GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl"; INFOPLIST_FILE = MtProtoKitDynamic/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -2770,7 +2771,7 @@ "DEBUG=1", "$(inherited)", ); - GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl"; INFOPLIST_FILE = MtProtoKitDynamic/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -3018,7 +3019,7 @@ "DEBUG=1", "$(inherited)", ); - GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl"; INFOPLIST_FILE = MtProtoKitDynamic/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -3266,7 +3267,7 @@ "DEBUG=1", "$(inherited)", ); - GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl"; INFOPLIST_FILE = MtProtoKitDynamic/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -3675,7 +3676,7 @@ "DEBUG=1", "$(inherited)", ); - GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl"; INFOPLIST_FILE = MtProtoKitDynamic/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -3902,7 +3903,7 @@ "$(PROJECT_DIR)/thirdparty", ); GCC_NO_COMMON_BLOCKS = YES; - GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl"; INFOPLIST_FILE = MtProtoKitDynamic/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4122,7 +4123,7 @@ "$(PROJECT_DIR)/thirdparty", ); GCC_NO_COMMON_BLOCKS = YES; - GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl"; INFOPLIST_FILE = MtProtoKitDynamic/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4341,7 +4342,7 @@ "$(PROJECT_DIR)/thirdparty", ); GCC_NO_COMMON_BLOCKS = YES; - GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl"; INFOPLIST_FILE = MtProtoKitDynamic/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4560,7 +4561,7 @@ "$(PROJECT_DIR)/thirdparty", ); GCC_NO_COMMON_BLOCKS = YES; - GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl"; INFOPLIST_FILE = MtProtoKitDynamic/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4801,7 +4802,7 @@ "DEBUG=1", "$(inherited)", ); - GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl"; INFOPLIST_FILE = MtProtoKitDynamic/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5139,7 +5140,7 @@ "$(PROJECT_DIR)/thirdparty", ); GCC_NO_COMMON_BLOCKS = YES; - GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl"; INFOPLIST_FILE = MtProtoKitDynamic/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5233,7 +5234,7 @@ "DEBUG=1", "$(inherited)", ); - GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl"; INFOPLIST_FILE = MtProtoKitDynamic/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5285,7 +5286,7 @@ "$(PROJECT_DIR)/thirdparty", ); GCC_NO_COMMON_BLOCKS = YES; - GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl"; INFOPLIST_FILE = MtProtoKitDynamic/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5534,7 +5535,7 @@ "DEBUG=1", "$(inherited)", ); - GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl"; INFOPLIST_FILE = MtProtoKitDynamic/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; diff --git a/submodules/TelegramUI/TelegramUI/ChatItemGalleryFooterContentNode.swift b/submodules/TelegramUI/TelegramUI/ChatItemGalleryFooterContentNode.swift index c09b73d672..ed2d2d9549 100644 --- a/submodules/TelegramUI/TelegramUI/ChatItemGalleryFooterContentNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatItemGalleryFooterContentNode.swift @@ -167,7 +167,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll private let messageContextDisposable = MetaDisposable() - private var videoFramePreviewNode: ASImageNode? + private var videoFramePreviewNode: (ASImageNode, ImmediateTextNode)? private var validLayout: (CGSize, LayoutMetrics, CGFloat, CGFloat, CGFloat, CGFloat)? @@ -230,6 +230,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll } private var scrubbingHandleRelativePosition: CGFloat = 0.0 + private var scrubbingVisualTimestamp: Double? var scrubberView: ChatVideoGalleryItemScrubberView? = nil { willSet { @@ -240,6 +241,23 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll didSet { if let scrubberView = self.scrubberView { self.view.addSubview(scrubberView) + scrubberView.updateScrubbingVisual = { [weak self] value in + guard let strongSelf = self else { + return + } + if let value = value { + strongSelf.scrubbingVisualTimestamp = value + if let (videoFramePreviewNode, videoFrameTextNode) = strongSelf.videoFramePreviewNode { + videoFrameTextNode.attributedText = NSAttributedString(string: stringForDuration(Int32(value)), font: Font.regular(13.0), textColor: .white) + let textSize = videoFrameTextNode.updateLayout(CGSize(width: 100.0, height: 100.0)) + let imageFrame = videoFramePreviewNode.frame + let textOffset = (Int((imageFrame.size.width - videoFrameTextNode.bounds.width) / 2) / 2) * 2 + videoFrameTextNode.frame = CGRect(origin: CGPoint(x: CGFloat(textOffset), y: imageFrame.size.height - videoFrameTextNode.bounds.height - 5.0), size: textSize) + } + } else { + strongSelf.scrubbingVisualTimestamp = nil + } + } scrubberView.updateScrubbingHandlePosition = { [weak self] value in guard let strongSelf = self else { return @@ -638,15 +656,31 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll self.dateNode.frame = CGRect(origin: CGPoint(x: floor((width - dateSize.width) / 2.0), y: panelHeight - bottomInset - 44.0 + floor((44.0 - dateSize.height - authorNameSize.height - labelsSpacing) / 2.0) + authorNameSize.height + labelsSpacing), size: dateSize) } - if let videoFramePreviewNode = self.videoFramePreviewNode { + if let (videoFramePreviewNode, videoFrameTextNode) = self.videoFramePreviewNode { let intrinsicImageSize = videoFramePreviewNode.image?.size ?? CGSize(width: 320.0, height: 240.0) - let imageSize = intrinsicImageSize.aspectFitted(CGSize(width: 200.0, height: 200.0)) - var imageFrame = CGRect(origin: CGPoint(x: leftInset + floor(self.scrubbingHandleRelativePosition * (width - leftInset - rightInset) - imageSize.width / 2.0), y: self.scrollNode.frame.minY - 10.0 - imageSize.height), size: imageSize) + let fitSize: CGSize + if intrinsicImageSize.width < intrinsicImageSize.height { + fitSize = CGSize(width: 90.0, height: 160.0) + } else { + fitSize = CGSize(width: 160.0, height: 90.0) + } + let scrubberInset: CGFloat + if size.width > size.height { + scrubberInset = 58.0 + } else { + scrubberInset = 13.0 + } + + let imageSize = intrinsicImageSize.aspectFitted(fitSize) + var imageFrame = CGRect(origin: CGPoint(x: leftInset + scrubberInset + floor(self.scrubbingHandleRelativePosition * (width - leftInset - rightInset - scrubberInset * 2.0) - imageSize.width / 2.0), y: self.scrollNode.frame.minY - 6.0 - imageSize.height), size: imageSize) imageFrame.origin.x = min(imageFrame.origin.x, width - rightInset - 10.0 - imageSize.width) imageFrame.origin.x = max(imageFrame.origin.x, leftInset + 10.0) videoFramePreviewNode.frame = imageFrame videoFramePreviewNode.subnodes?.first?.frame = CGRect(origin: CGPoint(), size: imageFrame.size) + + let textOffset = (Int((imageFrame.size.width - videoFrameTextNode.bounds.width) / 2) / 2) * 2 + videoFrameTextNode.frame = CGRect(origin: CGPoint(x: CGFloat(textOffset), y: imageFrame.size.height - videoFrameTextNode.bounds.height - 5.0), size: videoFrameTextNode.bounds.size) } return panelHeight @@ -1023,7 +1057,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll } func setFramePreviewImageIsLoading() { - if self.videoFramePreviewNode?.image != nil { + if self.videoFramePreviewNode?.0.image != nil { //self.videoFramePreviewNode?.subnodes?.first?.alpha = 1.0 } } @@ -1031,17 +1065,34 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll func setFramePreviewImage(image: UIImage?) { if let image = image { let videoFramePreviewNode: ASImageNode + let videoFrameTextNode: ImmediateTextNode var animateIn = false if let current = self.videoFramePreviewNode { - videoFramePreviewNode = current + videoFramePreviewNode = current.0 + videoFrameTextNode = current.1 } else { videoFramePreviewNode = ASImageNode() videoFramePreviewNode.displaysAsynchronously = false videoFramePreviewNode.displayWithoutProcessing = true + videoFramePreviewNode.clipsToBounds = true + videoFramePreviewNode.cornerRadius = 6.0 + let dimNode = ASDisplayNode() dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5) videoFramePreviewNode.addSubnode(dimNode) - self.videoFramePreviewNode = videoFramePreviewNode + + videoFrameTextNode = ImmediateTextNode() + videoFrameTextNode.displaysAsynchronously = false + videoFrameTextNode.maximumNumberOfLines = 1 + videoFrameTextNode.textShadowColor = .black + if let scrubbingVisualTimestamp = self.scrubbingVisualTimestamp { + videoFrameTextNode.attributedText = NSAttributedString(string: stringForDuration(Int32(scrubbingVisualTimestamp)), font: Font.regular(13.0), textColor: .white) + } + let textSize = videoFrameTextNode.updateLayout(CGSize(width: 100.0, height: 100.0)) + videoFrameTextNode.frame = CGRect(origin: CGPoint(), size: textSize) + videoFramePreviewNode.addSubnode(videoFrameTextNode) + + self.videoFramePreviewNode = (videoFramePreviewNode, videoFrameTextNode) self.addSubnode(videoFramePreviewNode) animateIn = true } @@ -1054,7 +1105,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll if animateIn { videoFramePreviewNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) } - } else if let videoFramePreviewNode = self.videoFramePreviewNode { + } else if let (videoFramePreviewNode, _) = self.videoFramePreviewNode { self.videoFramePreviewNode = nil videoFramePreviewNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak videoFramePreviewNode] _ in videoFramePreviewNode?.removeFromSupernode() diff --git a/submodules/TelegramUI/TelegramUI/ChatVideoGalleryItemScrubberView.swift b/submodules/TelegramUI/TelegramUI/ChatVideoGalleryItemScrubberView.swift index ab588236ca..9efbcc2e9a 100644 --- a/submodules/TelegramUI/TelegramUI/ChatVideoGalleryItemScrubberView.swift +++ b/submodules/TelegramUI/TelegramUI/ChatVideoGalleryItemScrubberView.swift @@ -43,6 +43,7 @@ final class ChatVideoGalleryItemScrubberView: UIView { } var updateScrubbing: (Double?) -> Void = { _ in } + var updateScrubbingVisual: (Double?) -> Void = { _ in } var updateScrubbingHandlePosition: (CGFloat) -> Void = { _ in } var seek: (Double) -> Void = { _ in } @@ -67,6 +68,7 @@ final class ChatVideoGalleryItemScrubberView: UIView { self.scrubberNode.update = { [weak self] timestamp, position in self?.updateScrubbing(timestamp) + self?.updateScrubbingVisual(timestamp) self?.updateScrubbingHandlePosition(position) }