mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-29 19:35:08 +00:00
Improve scrubbing
This commit is contained in:
parent
11ab388fc0
commit
8fbaf8d1a6
@ -13,6 +13,7 @@ public class ImmediateTextNode: TextNode {
|
|||||||
public var maximumNumberOfLines: Int = 1
|
public var maximumNumberOfLines: Int = 1
|
||||||
public var lineSpacing: CGFloat = 0.0
|
public var lineSpacing: CGFloat = 0.0
|
||||||
public var insets: UIEdgeInsets = UIEdgeInsets()
|
public var insets: UIEdgeInsets = UIEdgeInsets()
|
||||||
|
public var textShadowColor: UIColor?
|
||||||
|
|
||||||
private var tapRecognizer: TapLongTapOrDoubleTapGestureRecognizer?
|
private var tapRecognizer: TapLongTapOrDoubleTapGestureRecognizer?
|
||||||
private var linkHighlightingNode: LinkHighlightingNode?
|
private var linkHighlightingNode: LinkHighlightingNode?
|
||||||
@ -34,7 +35,7 @@ public class ImmediateTextNode: TextNode {
|
|||||||
|
|
||||||
public func updateLayout(_ constrainedSize: CGSize) -> CGSize {
|
public func updateLayout(_ constrainedSize: CGSize) -> CGSize {
|
||||||
let makeLayout = TextNode.asyncLayout(self)
|
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()
|
let _ = apply()
|
||||||
if layout.numberOfLines > 1 {
|
if layout.numberOfLines > 1 {
|
||||||
self.trailingLineWidth = layout.trailingLineWidth
|
self.trailingLineWidth = layout.trailingLineWidth
|
||||||
|
|||||||
@ -92,8 +92,9 @@ public final class TextNodeLayoutArguments {
|
|||||||
public let cutout: TextNodeCutout?
|
public let cutout: TextNodeCutout?
|
||||||
public let insets: UIEdgeInsets
|
public let insets: UIEdgeInsets
|
||||||
public let lineColor: UIColor?
|
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.attributedString = attributedString
|
||||||
self.backgroundColor = backgroundColor
|
self.backgroundColor = backgroundColor
|
||||||
self.maximumNumberOfLines = maximumNumberOfLines
|
self.maximumNumberOfLines = maximumNumberOfLines
|
||||||
@ -104,6 +105,7 @@ public final class TextNodeLayoutArguments {
|
|||||||
self.cutout = cutout
|
self.cutout = cutout
|
||||||
self.insets = insets
|
self.insets = insets
|
||||||
self.lineColor = lineColor
|
self.lineColor = lineColor
|
||||||
|
self.textShadowColor = textShadowColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,9 +125,10 @@ public final class TextNodeLayout: NSObject {
|
|||||||
fileprivate let lines: [TextNodeLine]
|
fileprivate let lines: [TextNodeLine]
|
||||||
fileprivate let blockQuotes: [TextNodeBlockQuote]
|
fileprivate let blockQuotes: [TextNodeBlockQuote]
|
||||||
fileprivate let lineColor: UIColor?
|
fileprivate let lineColor: UIColor?
|
||||||
|
fileprivate let textShadowColor: UIColor?
|
||||||
public let hasRTL: Bool
|
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.attributedString = attributedString
|
||||||
self.maximumNumberOfLines = maximumNumberOfLines
|
self.maximumNumberOfLines = maximumNumberOfLines
|
||||||
self.truncationType = truncationType
|
self.truncationType = truncationType
|
||||||
@ -141,6 +144,7 @@ public final class TextNodeLayout: NSObject {
|
|||||||
self.blockQuotes = blockQuotes
|
self.blockQuotes = blockQuotes
|
||||||
self.backgroundColor = backgroundColor
|
self.backgroundColor = backgroundColor
|
||||||
self.lineColor = lineColor
|
self.lineColor = lineColor
|
||||||
|
self.textShadowColor = textShadowColor
|
||||||
var hasRTL = false
|
var hasRTL = false
|
||||||
for line in lines {
|
for line in lines {
|
||||||
if line.isRTL {
|
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 {
|
if let attributedString = attributedString {
|
||||||
let stringLength = attributedString.length
|
let stringLength = attributedString.length
|
||||||
|
|
||||||
@ -601,7 +605,7 @@ public class TextNode: ASDisplayNode {
|
|||||||
var maybeTypesetter: CTTypesetter?
|
var maybeTypesetter: CTTypesetter?
|
||||||
maybeTypesetter = CTTypesetterCreateWithAttributedString(attributedString as CFAttributedString)
|
maybeTypesetter = CTTypesetterCreateWithAttributedString(attributedString as CFAttributedString)
|
||||||
if maybeTypesetter == nil {
|
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!
|
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 {
|
} 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)
|
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 textMatrix = context.textMatrix
|
||||||
let textPosition = context.textPosition
|
let textPosition = context.textPosition
|
||||||
context.textMatrix = CGAffineTransform(scaleX: 1.0, y: -1.0)
|
context.textMatrix = CGAffineTransform(scaleX: 1.0, y: -1.0)
|
||||||
|
|
||||||
|
|
||||||
let alignment = layout.alignment
|
let alignment = layout.alignment
|
||||||
let offset = CGPoint(x: layout.insets.left, y: layout.insets.top)
|
let offset = CGPoint(x: layout.insets.left, y: layout.insets.top)
|
||||||
|
|
||||||
@ -927,11 +935,11 @@ public class TextNode: ASDisplayNode {
|
|||||||
if stringMatch {
|
if stringMatch {
|
||||||
layout = existingLayout
|
layout = existingLayout
|
||||||
} else {
|
} 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
|
updated = true
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
updated = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1929,6 +1929,7 @@
|
|||||||
developmentRegion = English;
|
developmentRegion = English;
|
||||||
hasScannedForEncodings = 0;
|
hasScannedForEncodings = 0;
|
||||||
knownRegions = (
|
knownRegions = (
|
||||||
|
English,
|
||||||
en,
|
en,
|
||||||
);
|
);
|
||||||
mainGroup = D05A830918AFB3F9007F1076;
|
mainGroup = D05A830918AFB3F9007F1076;
|
||||||
@ -2492,7 +2493,7 @@
|
|||||||
);
|
);
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
||||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -2770,7 +2771,7 @@
|
|||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
||||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -3018,7 +3019,7 @@
|
|||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
||||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -3266,7 +3267,7 @@
|
|||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
||||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -3675,7 +3676,7 @@
|
|||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
||||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -3902,7 +3903,7 @@
|
|||||||
"$(PROJECT_DIR)/thirdparty",
|
"$(PROJECT_DIR)/thirdparty",
|
||||||
);
|
);
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
||||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -4122,7 +4123,7 @@
|
|||||||
"$(PROJECT_DIR)/thirdparty",
|
"$(PROJECT_DIR)/thirdparty",
|
||||||
);
|
);
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
||||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -4341,7 +4342,7 @@
|
|||||||
"$(PROJECT_DIR)/thirdparty",
|
"$(PROJECT_DIR)/thirdparty",
|
||||||
);
|
);
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
||||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -4560,7 +4561,7 @@
|
|||||||
"$(PROJECT_DIR)/thirdparty",
|
"$(PROJECT_DIR)/thirdparty",
|
||||||
);
|
);
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
||||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -4801,7 +4802,7 @@
|
|||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
||||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -5139,7 +5140,7 @@
|
|||||||
"$(PROJECT_DIR)/thirdparty",
|
"$(PROJECT_DIR)/thirdparty",
|
||||||
);
|
);
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
||||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -5233,7 +5234,7 @@
|
|||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
||||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -5285,7 +5286,7 @@
|
|||||||
"$(PROJECT_DIR)/thirdparty",
|
"$(PROJECT_DIR)/thirdparty",
|
||||||
);
|
);
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
||||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -5534,7 +5535,7 @@
|
|||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
);
|
);
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||||
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/openssl";
|
||||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
|
|||||||
@ -167,7 +167,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
|
|
||||||
private let messageContextDisposable = MetaDisposable()
|
private let messageContextDisposable = MetaDisposable()
|
||||||
|
|
||||||
private var videoFramePreviewNode: ASImageNode?
|
private var videoFramePreviewNode: (ASImageNode, ImmediateTextNode)?
|
||||||
|
|
||||||
private var validLayout: (CGSize, LayoutMetrics, CGFloat, CGFloat, CGFloat, CGFloat)?
|
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 scrubbingHandleRelativePosition: CGFloat = 0.0
|
||||||
|
private var scrubbingVisualTimestamp: Double?
|
||||||
|
|
||||||
var scrubberView: ChatVideoGalleryItemScrubberView? = nil {
|
var scrubberView: ChatVideoGalleryItemScrubberView? = nil {
|
||||||
willSet {
|
willSet {
|
||||||
@ -240,6 +241,23 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
didSet {
|
didSet {
|
||||||
if let scrubberView = self.scrubberView {
|
if let scrubberView = self.scrubberView {
|
||||||
self.view.addSubview(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
|
scrubberView.updateScrubbingHandlePosition = { [weak self] value in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
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)
|
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 intrinsicImageSize = videoFramePreviewNode.image?.size ?? CGSize(width: 320.0, height: 240.0)
|
||||||
let imageSize = intrinsicImageSize.aspectFitted(CGSize(width: 200.0, height: 200.0))
|
let fitSize: CGSize
|
||||||
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)
|
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 = min(imageFrame.origin.x, width - rightInset - 10.0 - imageSize.width)
|
||||||
imageFrame.origin.x = max(imageFrame.origin.x, leftInset + 10.0)
|
imageFrame.origin.x = max(imageFrame.origin.x, leftInset + 10.0)
|
||||||
|
|
||||||
videoFramePreviewNode.frame = imageFrame
|
videoFramePreviewNode.frame = imageFrame
|
||||||
videoFramePreviewNode.subnodes?.first?.frame = CGRect(origin: CGPoint(), size: imageFrame.size)
|
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
|
return panelHeight
|
||||||
@ -1023,7 +1057,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setFramePreviewImageIsLoading() {
|
func setFramePreviewImageIsLoading() {
|
||||||
if self.videoFramePreviewNode?.image != nil {
|
if self.videoFramePreviewNode?.0.image != nil {
|
||||||
//self.videoFramePreviewNode?.subnodes?.first?.alpha = 1.0
|
//self.videoFramePreviewNode?.subnodes?.first?.alpha = 1.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1031,17 +1065,34 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
func setFramePreviewImage(image: UIImage?) {
|
func setFramePreviewImage(image: UIImage?) {
|
||||||
if let image = image {
|
if let image = image {
|
||||||
let videoFramePreviewNode: ASImageNode
|
let videoFramePreviewNode: ASImageNode
|
||||||
|
let videoFrameTextNode: ImmediateTextNode
|
||||||
var animateIn = false
|
var animateIn = false
|
||||||
if let current = self.videoFramePreviewNode {
|
if let current = self.videoFramePreviewNode {
|
||||||
videoFramePreviewNode = current
|
videoFramePreviewNode = current.0
|
||||||
|
videoFrameTextNode = current.1
|
||||||
} else {
|
} else {
|
||||||
videoFramePreviewNode = ASImageNode()
|
videoFramePreviewNode = ASImageNode()
|
||||||
videoFramePreviewNode.displaysAsynchronously = false
|
videoFramePreviewNode.displaysAsynchronously = false
|
||||||
videoFramePreviewNode.displayWithoutProcessing = true
|
videoFramePreviewNode.displayWithoutProcessing = true
|
||||||
|
videoFramePreviewNode.clipsToBounds = true
|
||||||
|
videoFramePreviewNode.cornerRadius = 6.0
|
||||||
|
|
||||||
let dimNode = ASDisplayNode()
|
let dimNode = ASDisplayNode()
|
||||||
dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
|
dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
|
||||||
videoFramePreviewNode.addSubnode(dimNode)
|
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)
|
self.addSubnode(videoFramePreviewNode)
|
||||||
animateIn = true
|
animateIn = true
|
||||||
}
|
}
|
||||||
@ -1054,7 +1105,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
if animateIn {
|
if animateIn {
|
||||||
videoFramePreviewNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
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
|
self.videoFramePreviewNode = nil
|
||||||
videoFramePreviewNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak videoFramePreviewNode] _ in
|
videoFramePreviewNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak videoFramePreviewNode] _ in
|
||||||
videoFramePreviewNode?.removeFromSupernode()
|
videoFramePreviewNode?.removeFromSupernode()
|
||||||
|
|||||||
@ -43,6 +43,7 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var updateScrubbing: (Double?) -> Void = { _ in }
|
var updateScrubbing: (Double?) -> Void = { _ in }
|
||||||
|
var updateScrubbingVisual: (Double?) -> Void = { _ in }
|
||||||
var updateScrubbingHandlePosition: (CGFloat) -> Void = { _ in }
|
var updateScrubbingHandlePosition: (CGFloat) -> Void = { _ in }
|
||||||
var seek: (Double) -> Void = { _ in }
|
var seek: (Double) -> Void = { _ in }
|
||||||
|
|
||||||
@ -67,6 +68,7 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||||||
|
|
||||||
self.scrubberNode.update = { [weak self] timestamp, position in
|
self.scrubberNode.update = { [weak self] timestamp, position in
|
||||||
self?.updateScrubbing(timestamp)
|
self?.updateScrubbing(timestamp)
|
||||||
|
self?.updateScrubbingVisual(timestamp)
|
||||||
self?.updateScrubbingHandlePosition(position)
|
self?.updateScrubbingHandlePosition(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user