mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Various improvements
This commit is contained in:
parent
d36b6b0b7f
commit
70ae305e99
@ -7542,3 +7542,5 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Premium.Reactions.Description" = "Unlock additional reactions by subscribing to Telegram Premium.";
|
||||
"Premium.Reactions.Proceed" = "Unlock Additional Reactions";
|
||||
|
||||
"AccessDenied.LocationPreciseDenied" = "To share your specific location in this chat, please go to Settings > Privacy > Location Services > Telegram and set Precise Location to On.";
|
||||
|
@ -1379,6 +1379,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
} else if peer.isVerified {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||
credibilityIconOffset = 3.0
|
||||
} else if peer.isPremium {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.premiumIcon(item.presentationData.theme)
|
||||
credibilityIconOffset = 2.0
|
||||
}
|
||||
}
|
||||
default:
|
||||
@ -1394,6 +1397,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
} else if peer.isVerified {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||
credibilityIconOffset = 3.0
|
||||
} else if peer.isPremium {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.premiumIcon(item.presentationData.theme)
|
||||
credibilityIconOffset = 2.0
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1762,7 +1768,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
if let currentMutedIconImage = currentMutedIconImage {
|
||||
strongSelf.mutedIconNode.image = currentMutedIconImage
|
||||
strongSelf.mutedIconNode.isHidden = false
|
||||
transition.updateFrame(node: strongSelf.mutedIconNode, frame: CGRect(origin: CGPoint(x: nextTitleIconOrigin - 4.0, y: contentRect.origin.y - 2.0), size: currentMutedIconImage.size))
|
||||
transition.updateFrame(node: strongSelf.mutedIconNode, frame: CGRect(origin: CGPoint(x: nextTitleIconOrigin - 5.0, y: contentRect.origin.y - 3.0 + UIScreenPixel), size: currentMutedIconImage.size))
|
||||
nextTitleIconOrigin += currentMutedIconImage.size.width + 1.0
|
||||
} else {
|
||||
strongSelf.mutedIconNode.image = nil
|
||||
|
@ -14,6 +14,7 @@ private let animationDurationFactor: Double = 1.0
|
||||
public protocol ContextControllerProtocol: AnyObject {
|
||||
var useComplexItemsTransitionAnimation: Bool { get set }
|
||||
var immediateItemsTransitionAnimation: Bool { get set }
|
||||
var getOverlayViews: (() -> [UIView])? { get set }
|
||||
|
||||
func getActionsMinHeight() -> ContextController.ActionsHeight?
|
||||
func setItems(_ items: Signal<ContextController.Items, NoError>, minHeight: ContextController.ActionsHeight?)
|
||||
@ -1238,7 +1239,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
}
|
||||
|
||||
if animateOutToItem, let originalProjectedContentViewFrame = self.originalProjectedContentViewFrame {
|
||||
|
||||
let localSourceFrame = self.view.convert(CGRect(origin: CGPoint(x: originalProjectedContentViewFrame.1.minX, y: originalProjectedContentViewFrame.1.minY), size: CGSize(width: originalProjectedContentViewFrame.1.width, height: originalProjectedContentViewFrame.1.height)), to: self.scrollNode.view)
|
||||
|
||||
self.actionsContainerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: localSourceFrame.center.x - self.actionsContainerNode.position.x, y: localSourceFrame.center.y - self.actionsContainerNode.position.y), duration: transitionDuration * animationDurationFactor, timingFunction: transitionCurve.timingFunction, removeOnCompletion: false, additive: true)
|
||||
@ -2267,6 +2267,8 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
||||
|
||||
public var reactionSelected: ((ReactionContextItem, Bool) -> Void)?
|
||||
|
||||
public var getOverlayViews: (() -> [UIView])?
|
||||
|
||||
public init(account: Account, presentationData: PresentationData, source: ContextContentSource, items: Signal<ContextController.Items, NoError>, recognizer: TapLongTapOrDoubleTapGestureRecognizer? = nil, gesture: ContextGesture? = nil, workaroundUseLegacyImplementation: Bool = false) {
|
||||
self.account = account
|
||||
self.presentationData = presentationData
|
||||
|
@ -638,6 +638,18 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let overlayViews = self.getController()?.getOverlayViews?(), !overlayViews.isEmpty {
|
||||
for view in overlayViews {
|
||||
if let snapshotView = view.snapshotView(afterScreenUpdates: false) {
|
||||
snapshotView.frame = view.convert(view.bounds, to: nil)
|
||||
self.view.addSubview(snapshotView)
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .animateOut(result, completion):
|
||||
let duration: Double
|
||||
let timingFunction: String
|
||||
@ -785,6 +797,18 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
||||
if let reactionContextNode = self.reactionContextNode {
|
||||
reactionContextNode.animateOut(to: currentContentScreenFrame, animatingOutToReaction: self.reactionContextNodeIsAnimatingOut)
|
||||
}
|
||||
|
||||
if let overlayViews = self.getController()?.getOverlayViews?(), !overlayViews.isEmpty {
|
||||
for view in overlayViews {
|
||||
if let snapshotView = view.snapshotView(afterScreenUpdates: false) {
|
||||
snapshotView.frame = view.convert(view.bounds, to: nil)
|
||||
self.view.addSubview(snapshotView)
|
||||
snapshotView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
case .none:
|
||||
if animateReactionsIn, let reactionContextNode = self.reactionContextNode {
|
||||
reactionContextNode.animateIn(from: contentRect)
|
||||
|
@ -64,6 +64,8 @@ public final class PeekController: ViewController, ContextControllerProtocol {
|
||||
|
||||
public var visibilityUpdated: ((Bool) -> Void)?
|
||||
|
||||
public var getOverlayViews: (() -> [UIView])?
|
||||
|
||||
private var animatedIn = false
|
||||
|
||||
public init(presentationData: PresentationData, content: PeekControllerContent, sourceNode: @escaping () -> ASDisplayNode?) {
|
||||
|
@ -378,9 +378,29 @@ public final class DeviceAccess {
|
||||
}
|
||||
case let .location(locationSubject):
|
||||
let status = CLLocationManager.authorizationStatus()
|
||||
let hasPreciseLocation: Bool
|
||||
if #available(iOS 14.0, *) {
|
||||
if case .fullAccuracy = CLLocationManager().accuracyAuthorization {
|
||||
hasPreciseLocation = true
|
||||
} else {
|
||||
hasPreciseLocation = false
|
||||
}
|
||||
} else {
|
||||
hasPreciseLocation = true
|
||||
}
|
||||
switch status {
|
||||
case .authorizedAlways:
|
||||
completion(true)
|
||||
if case .live = locationSubject, !hasPreciseLocation {
|
||||
completion(false)
|
||||
if let presentationData = presentationData {
|
||||
let text = presentationData.strings.AccessDenied_LocationPreciseDenied
|
||||
present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: presentationData.strings.AccessDenied_Title, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_NotNow, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.AccessDenied_Settings, action: {
|
||||
openSettings()
|
||||
})]), nil)
|
||||
}
|
||||
} else {
|
||||
completion(true)
|
||||
}
|
||||
case .authorizedWhenInUse:
|
||||
switch locationSubject {
|
||||
case .send, .tracking:
|
||||
|
@ -4,6 +4,7 @@ import UIKit
|
||||
public struct ImmediateTextNodeLayoutInfo {
|
||||
public let size: CGSize
|
||||
public let truncated: Bool
|
||||
public let numberOfLines: Int
|
||||
}
|
||||
|
||||
public class ImmediateTextNode: TextNode {
|
||||
@ -18,8 +19,7 @@ public class ImmediateTextNode: TextNode {
|
||||
public var textStroke: (UIColor, CGFloat)?
|
||||
public var cutout: TextNodeCutout?
|
||||
public var displaySpoilers = false
|
||||
public var countIfMoreThanOneLineOverMaximum = false
|
||||
|
||||
|
||||
public var truncationMode: NSLineBreakMode {
|
||||
get {
|
||||
switch self.truncationType {
|
||||
@ -91,7 +91,7 @@ public class ImmediateTextNode: TextNode {
|
||||
self.constrainedSize = constrainedSize
|
||||
|
||||
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, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, textShadowColor: self.textShadowColor, textStroke: self.textStroke, displaySpoilers: self.displaySpoilers, countIfMoreThanOneLineOverMaximum: self.countIfMoreThanOneLineOverMaximum))
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, textShadowColor: self.textShadowColor, textStroke: self.textStroke, displaySpoilers: self.displaySpoilers))
|
||||
let _ = apply()
|
||||
if layout.numberOfLines > 1 {
|
||||
self.trailingLineWidth = layout.trailingLineWidth
|
||||
@ -105,16 +105,16 @@ public class ImmediateTextNode: TextNode {
|
||||
self.constrainedSize = constrainedSize
|
||||
|
||||
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, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, displaySpoilers: self.displaySpoilers, countIfMoreThanOneLineOverMaximum: self.countIfMoreThanOneLineOverMaximum))
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, displaySpoilers: self.displaySpoilers))
|
||||
let _ = apply()
|
||||
return ImmediateTextNodeLayoutInfo(size: layout.size, truncated: layout.truncated)
|
||||
return ImmediateTextNodeLayoutInfo(size: layout.size, truncated: layout.truncated, numberOfLines: layout.numberOfLines)
|
||||
}
|
||||
|
||||
public func updateLayoutFullInfo(_ constrainedSize: CGSize) -> TextNodeLayout {
|
||||
self.constrainedSize = constrainedSize
|
||||
|
||||
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, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, displaySpoilers: self.displaySpoilers, countIfMoreThanOneLineOverMaximum: self.countIfMoreThanOneLineOverMaximum))
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, displaySpoilers: self.displaySpoilers))
|
||||
let _ = apply()
|
||||
return layout
|
||||
}
|
||||
@ -287,7 +287,7 @@ public class ImmediateTextView: TextView {
|
||||
self.constrainedSize = constrainedSize
|
||||
|
||||
let makeLayout = TextView.asyncLayout(self)
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, textShadowColor: self.textShadowColor, textStroke: self.textStroke, displaySpoilers: self.displaySpoilers, countIfMoreThanOneLineOverMaximum: false))
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, textShadowColor: self.textShadowColor, textStroke: self.textStroke, displaySpoilers: self.displaySpoilers))
|
||||
let _ = apply()
|
||||
if layout.numberOfLines > 1 {
|
||||
self.trailingLineWidth = layout.trailingLineWidth
|
||||
@ -301,16 +301,16 @@ public class ImmediateTextView: TextView {
|
||||
self.constrainedSize = constrainedSize
|
||||
|
||||
let makeLayout = TextView.asyncLayout(self)
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, displaySpoilers: self.displaySpoilers, countIfMoreThanOneLineOverMaximum: false))
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, displaySpoilers: self.displaySpoilers))
|
||||
let _ = apply()
|
||||
return ImmediateTextNodeLayoutInfo(size: layout.size, truncated: layout.truncated)
|
||||
return ImmediateTextNodeLayoutInfo(size: layout.size, truncated: layout.truncated, numberOfLines: layout.numberOfLines)
|
||||
}
|
||||
|
||||
public func updateLayoutFullInfo(_ constrainedSize: CGSize) -> TextNodeLayout {
|
||||
self.constrainedSize = constrainedSize
|
||||
|
||||
let makeLayout = TextView.asyncLayout(self)
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, displaySpoilers: self.displaySpoilers, countIfMoreThanOneLineOverMaximum: false))
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, displaySpoilers: self.displaySpoilers))
|
||||
let _ = apply()
|
||||
return layout
|
||||
}
|
||||
|
@ -123,6 +123,14 @@ public final class NavigationBackgroundNode: ASDisplayNode {
|
||||
private let backgroundNode: ASDisplayNode
|
||||
|
||||
private var validLayout: (CGSize, CGFloat)?
|
||||
|
||||
public var backgroundCornerRadius: CGFloat {
|
||||
if let (_, cornerRadius) = self.validLayout {
|
||||
return cornerRadius
|
||||
} else {
|
||||
return 0.0
|
||||
}
|
||||
}
|
||||
|
||||
public init(color: UIColor, enableBlur: Bool = true) {
|
||||
self._color = .clear
|
||||
|
@ -132,9 +132,8 @@ public final class TextNodeLayoutArguments {
|
||||
public let textShadowColor: UIColor?
|
||||
public let textStroke: (UIColor, CGFloat)?
|
||||
public let displaySpoilers: Bool
|
||||
public let countIfMoreThanOneLineOverMaximum: Bool
|
||||
|
||||
public init(attributedString: NSAttributedString?, backgroundColor: UIColor? = nil, minimumNumberOfLines: Int = 0, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, constrainedSize: CGSize, alignment: NSTextAlignment = .natural, verticalAlignment: TextVerticalAlignment = .top, lineSpacing: CGFloat = 0.12, cutout: TextNodeCutout? = nil, insets: UIEdgeInsets = UIEdgeInsets(), lineColor: UIColor? = nil, textShadowColor: UIColor? = nil, textStroke: (UIColor, CGFloat)? = nil, displaySpoilers: Bool = false, countIfMoreThanOneLineOverMaximum: Bool = false) {
|
||||
public init(attributedString: NSAttributedString?, backgroundColor: UIColor? = nil, minimumNumberOfLines: Int = 0, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, constrainedSize: CGSize, alignment: NSTextAlignment = .natural, verticalAlignment: TextVerticalAlignment = .top, lineSpacing: CGFloat = 0.12, cutout: TextNodeCutout? = nil, insets: UIEdgeInsets = UIEdgeInsets(), lineColor: UIColor? = nil, textShadowColor: UIColor? = nil, textStroke: (UIColor, CGFloat)? = nil, displaySpoilers: Bool = false) {
|
||||
self.attributedString = attributedString
|
||||
self.backgroundColor = backgroundColor
|
||||
self.minimumNumberOfLines = minimumNumberOfLines
|
||||
@ -150,7 +149,6 @@ public final class TextNodeLayoutArguments {
|
||||
self.textShadowColor = textShadowColor
|
||||
self.textStroke = textStroke
|
||||
self.displaySpoilers = displaySpoilers
|
||||
self.countIfMoreThanOneLineOverMaximum = countIfMoreThanOneLineOverMaximum
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,9 +177,8 @@ public final class TextNodeLayout: NSObject {
|
||||
public let hasRTL: Bool
|
||||
public let spoilers: [(NSRange, CGRect)]
|
||||
public let spoilerWords: [(NSRange, CGRect)]
|
||||
public let hasMoreThanOneLineOverMaximum: Bool?
|
||||
|
||||
fileprivate init(attributedString: NSAttributedString?, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, constrainedSize: CGSize, explicitAlignment: NSTextAlignment, resolvedAlignment: NSTextAlignment, verticalAlignment: TextVerticalAlignment, lineSpacing: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, size: CGSize, rawTextSize: CGSize, truncated: Bool, firstLineOffset: CGFloat, lines: [TextNodeLine], blockQuotes: [TextNodeBlockQuote], backgroundColor: UIColor?, lineColor: UIColor?, textShadowColor: UIColor?, textStroke: (UIColor, CGFloat)?, displaySpoilers: Bool, hasMoreThanOneLineOverMaximum: Bool?) {
|
||||
fileprivate init(attributedString: NSAttributedString?, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, constrainedSize: CGSize, explicitAlignment: NSTextAlignment, resolvedAlignment: NSTextAlignment, verticalAlignment: TextVerticalAlignment, lineSpacing: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, size: CGSize, rawTextSize: CGSize, truncated: Bool, firstLineOffset: CGFloat, lines: [TextNodeLine], blockQuotes: [TextNodeBlockQuote], backgroundColor: UIColor?, lineColor: UIColor?, textShadowColor: UIColor?, textStroke: (UIColor, CGFloat)?, displaySpoilers: Bool) {
|
||||
self.attributedString = attributedString
|
||||
self.maximumNumberOfLines = maximumNumberOfLines
|
||||
self.truncationType = truncationType
|
||||
@ -225,7 +222,6 @@ public final class TextNodeLayout: NSObject {
|
||||
self.hasRTL = hasRTL
|
||||
self.spoilers = spoilers
|
||||
self.spoilerWords = spoilerWords
|
||||
self.hasMoreThanOneLineOverMaximum = hasMoreThanOneLineOverMaximum
|
||||
}
|
||||
|
||||
public func areLinesEqual(to other: TextNodeLayout) -> Bool {
|
||||
@ -896,9 +892,6 @@ public class TextNode: ASDisplayNode {
|
||||
|
||||
static func calculateLayout(attributedString: NSAttributedString?, minimumNumberOfLines: Int, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, backgroundColor: UIColor?, constrainedSize: CGSize, alignment: NSTextAlignment, verticalAlignment: TextVerticalAlignment, lineSpacingFactor: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, lineColor: UIColor?, textShadowColor: UIColor?, textStroke: (UIColor, CGFloat)?, displaySpoilers: Bool) -> TextNodeLayout {
|
||||
if let attributedString = attributedString {
|
||||
if attributedString.string.hasPrefix("Д") {
|
||||
print()
|
||||
}
|
||||
let stringLength = attributedString.length
|
||||
|
||||
let font: CTFont
|
||||
@ -935,7 +928,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, explicitAlignment: alignment, resolvedAlignment: resolvedAlignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), rawTextSize: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textStroke: textStroke, displaySpoilers: displaySpoilers, hasMoreThanOneLineOverMaximum: nil)
|
||||
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, explicitAlignment: alignment, resolvedAlignment: resolvedAlignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), rawTextSize: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textStroke: textStroke, displaySpoilers: displaySpoilers)
|
||||
}
|
||||
|
||||
let typesetter = maybeTypesetter!
|
||||
@ -951,9 +944,7 @@ public class TextNode: ASDisplayNode {
|
||||
|
||||
var bottomCutoutEnabled = false
|
||||
var bottomCutoutSize = CGSize()
|
||||
|
||||
let hasMoreThanOneLineOverMaximum: Bool? = nil
|
||||
|
||||
|
||||
if let topLeft = cutout?.topLeft {
|
||||
cutoutMinY = -fontLineSpacing
|
||||
cutoutMaxY = topLeft.height + fontLineSpacing
|
||||
@ -1268,9 +1259,9 @@ public class TextNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, explicitAlignment: alignment, resolvedAlignment: resolvedAlignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(width: ceil(layoutSize.width) + insets.left + insets.right, height: ceil(layoutSize.height) + insets.top + insets.bottom), rawTextSize: CGSize(width: ceil(rawLayoutSize.width) + insets.left + insets.right, height: ceil(rawLayoutSize.height) + insets.top + insets.bottom), truncated: truncated, firstLineOffset: firstLineOffset, lines: lines, blockQuotes: blockQuotes, backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textStroke: textStroke, displaySpoilers: displaySpoilers, hasMoreThanOneLineOverMaximum: hasMoreThanOneLineOverMaximum)
|
||||
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, explicitAlignment: alignment, resolvedAlignment: resolvedAlignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(width: ceil(layoutSize.width) + insets.left + insets.right, height: ceil(layoutSize.height) + insets.top + insets.bottom), rawTextSize: CGSize(width: ceil(rawLayoutSize.width) + insets.left + insets.right, height: ceil(rawLayoutSize.height) + insets.top + insets.bottom), truncated: truncated, firstLineOffset: firstLineOffset, lines: lines, blockQuotes: blockQuotes, backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textStroke: textStroke, displaySpoilers: displaySpoilers)
|
||||
} else {
|
||||
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, explicitAlignment: alignment, resolvedAlignment: alignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), rawTextSize: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textStroke: textStroke, displaySpoilers: displaySpoilers, hasMoreThanOneLineOverMaximum: nil)
|
||||
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, explicitAlignment: alignment, resolvedAlignment: alignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), rawTextSize: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textStroke: textStroke, displaySpoilers: displaySpoilers)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1594,7 +1585,7 @@ open class TextView: UIView {
|
||||
var maybeTypesetter: CTTypesetter?
|
||||
maybeTypesetter = CTTypesetterCreateWithAttributedString(attributedString as CFAttributedString)
|
||||
if maybeTypesetter == nil {
|
||||
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, explicitAlignment: alignment, resolvedAlignment: resolvedAlignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), rawTextSize: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textStroke: textStroke, displaySpoilers: displaySpoilers, hasMoreThanOneLineOverMaximum: nil)
|
||||
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, explicitAlignment: alignment, resolvedAlignment: resolvedAlignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), rawTextSize: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textStroke: textStroke, displaySpoilers: displaySpoilers)
|
||||
}
|
||||
|
||||
let typesetter = maybeTypesetter!
|
||||
@ -1925,9 +1916,9 @@ open class TextView: UIView {
|
||||
}
|
||||
}
|
||||
|
||||
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, explicitAlignment: alignment, resolvedAlignment: resolvedAlignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(width: ceil(layoutSize.width) + insets.left + insets.right, height: ceil(layoutSize.height) + insets.top + insets.bottom), rawTextSize: CGSize(width: ceil(rawLayoutSize.width) + insets.left + insets.right, height: ceil(rawLayoutSize.height) + insets.top + insets.bottom), truncated: truncated, firstLineOffset: firstLineOffset, lines: lines, blockQuotes: blockQuotes, backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textStroke: textStroke, displaySpoilers: displaySpoilers, hasMoreThanOneLineOverMaximum: nil)
|
||||
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, explicitAlignment: alignment, resolvedAlignment: resolvedAlignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(width: ceil(layoutSize.width) + insets.left + insets.right, height: ceil(layoutSize.height) + insets.top + insets.bottom), rawTextSize: CGSize(width: ceil(rawLayoutSize.width) + insets.left + insets.right, height: ceil(rawLayoutSize.height) + insets.top + insets.bottom), truncated: truncated, firstLineOffset: firstLineOffset, lines: lines, blockQuotes: blockQuotes, backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textStroke: textStroke, displaySpoilers: displaySpoilers)
|
||||
} else {
|
||||
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, explicitAlignment: alignment, resolvedAlignment: alignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), rawTextSize: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textStroke: textStroke, displaySpoilers: displaySpoilers, hasMoreThanOneLineOverMaximum: nil)
|
||||
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, explicitAlignment: alignment, resolvedAlignment: alignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), rawTextSize: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textStroke: textStroke, displaySpoilers: displaySpoilers)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -316,9 +316,9 @@ final class PremiumReactionsNode: ASDisplayNode, ReactionItemNode {
|
||||
self.addSubnode(self.imageNode)
|
||||
|
||||
if theme.overallDarkAppearance {
|
||||
self.imageNode.image = generateTintedImage(image: UIImage(bundleImageName: "Premium/ReactionIcon"), color: .white)
|
||||
self.imageNode.image = generateTintedImage(image: UIImage(bundleImageName: "Premium/BackgroundIcon"), color: .white)
|
||||
} else {
|
||||
self.imageNode.image = UIImage(bundleImageName: "Premium/ReactionIcon")
|
||||
self.imageNode.image = UIImage(bundleImageName: "Premium/BackgroundIcon")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,7 +204,7 @@ final class StickerPackPreviewControllerNode: ViewControllerTracingNode, UIScrol
|
||||
return strongSelf.context.account.postbox.transaction { transaction -> (Bool, Bool) in
|
||||
let isStarred = getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
|
||||
var hasPremium = false
|
||||
if let peer = transaction.getPeer(accountPeerId) as? TelegramUser, peer.flags.contains(.isPremium) {
|
||||
if let peer = transaction.getPeer(accountPeerId) as? TelegramUser, peer.isPremium {
|
||||
hasPremium = true
|
||||
}
|
||||
return (isStarred, hasPremium)
|
||||
|
@ -174,7 +174,7 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||
lockBackground = UIImageView()
|
||||
lockBackground.clipsToBounds = true
|
||||
lockBackground.isUserInteractionEnabled = false
|
||||
lockBackground.image = UIImage(bundleImageName: "Premium/StickerIcon")
|
||||
lockBackground.image = PresentationResourcesChat.chatInputMediaStickerGridPremiumIcon(theme)
|
||||
self.lockBackground = lockBackground
|
||||
|
||||
self.view.addSubview(lockBackground)
|
||||
|
@ -177,8 +177,8 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.gridNode)
|
||||
self.addSubnode(self.actionAreaBackgroundNode)
|
||||
self.addSubnode(self.actionAreaSeparatorNode)
|
||||
// self.addSubnode(self.actionAreaBackgroundNode)
|
||||
// self.addSubnode(self.actionAreaSeparatorNode)
|
||||
self.addSubnode(self.buttonNode)
|
||||
|
||||
self.addSubnode(self.titleBackgroundnode)
|
||||
@ -294,7 +294,7 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
return
|
||||
}
|
||||
var hasPremium = false
|
||||
if case let .user(user) = peer, user.flags.contains(.isPremium) {
|
||||
if let peer = peer, peer.isPremium {
|
||||
hasPremium = true
|
||||
}
|
||||
strongSelf.updateStickerPackContents(contents, hasPremium: hasPremium)
|
||||
@ -337,7 +337,7 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
return strongSelf.context.account.postbox.transaction { transaction -> (Bool, Bool) in
|
||||
let isStarred = getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
|
||||
var hasPremium = false
|
||||
if let peer = transaction.getPeer(accountPeerId) as? TelegramUser, peer.flags.contains(.isPremium) {
|
||||
if let peer = transaction.getPeer(accountPeerId) as? TelegramUser, peer.isPremium {
|
||||
hasPremium = true
|
||||
}
|
||||
return (isStarred, hasPremium)
|
||||
|
@ -17,6 +17,7 @@ private final class CallRatingAlertContentNode: AlertContentNode {
|
||||
var rating: Int?
|
||||
|
||||
private let titleNode: ASTextNode
|
||||
private var starContainerNode: ASDisplayNode
|
||||
private let starNodes: [ASButtonNode]
|
||||
|
||||
private let actionNodesSeparator: ASDisplayNode
|
||||
@ -38,6 +39,8 @@ private final class CallRatingAlertContentNode: AlertContentNode {
|
||||
self.titleNode = ASTextNode()
|
||||
self.titleNode.maximumNumberOfLines = 3
|
||||
|
||||
self.starContainerNode = ASDisplayNode()
|
||||
|
||||
var starNodes: [ASButtonNode] = []
|
||||
for _ in 0 ..< 5 {
|
||||
starNodes.append(ASButtonNode())
|
||||
@ -65,10 +68,12 @@ private final class CallRatingAlertContentNode: AlertContentNode {
|
||||
|
||||
self.addSubnode(self.titleNode)
|
||||
|
||||
self.addSubnode(self.starContainerNode)
|
||||
|
||||
for node in self.starNodes {
|
||||
node.addTarget(self, action: #selector(self.starPressed(_:)), forControlEvents: .touchDown)
|
||||
node.addTarget(self, action: #selector(self.starReleased(_:)), forControlEvents: .touchUpInside)
|
||||
self.addSubnode(node)
|
||||
self.starContainerNode.addSubnode(node)
|
||||
}
|
||||
|
||||
self.addSubnode(self.actionNodesSeparator)
|
||||
@ -88,6 +93,44 @@ private final class CallRatingAlertContentNode: AlertContentNode {
|
||||
self.disposable.dispose()
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.starContainerNode.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:))))
|
||||
}
|
||||
|
||||
@objc func panGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
|
||||
let location = gestureRecognizer.location(in: self.starContainerNode.view)
|
||||
var selectedNode: ASButtonNode?
|
||||
for node in self.starNodes {
|
||||
if node.frame.contains(location) {
|
||||
selectedNode = node
|
||||
break
|
||||
}
|
||||
}
|
||||
if let selectedNode = selectedNode {
|
||||
switch gestureRecognizer.state {
|
||||
case .began, .changed:
|
||||
self.starPressed(selectedNode)
|
||||
case .ended:
|
||||
self.starReleased(selectedNode)
|
||||
case .cancelled:
|
||||
self.resetStars()
|
||||
default:
|
||||
break
|
||||
}
|
||||
} else {
|
||||
self.resetStars()
|
||||
}
|
||||
}
|
||||
|
||||
private func resetStars() {
|
||||
for i in 0 ..< self.starNodes.count {
|
||||
let node = self.starNodes[i]
|
||||
node.isSelected = false
|
||||
}
|
||||
}
|
||||
|
||||
@objc func starPressed(_ sender: ASButtonNode) {
|
||||
if let index = self.starNodes.firstIndex(of: sender) {
|
||||
self.rating = index + 1
|
||||
@ -182,9 +225,10 @@ private final class CallRatingAlertContentNode: AlertContentNode {
|
||||
|
||||
let starSize = CGSize(width: 42.0, height: 38.0)
|
||||
let starsOrigin = floorToScreenPixels((resultWidth - starSize.width * 5.0) / 2.0)
|
||||
self.starContainerNode.frame = CGRect(origin: CGPoint(x: starsOrigin, y: origin.y), size: CGSize(width: starSize.width * CGFloat(self.starNodes.count), height: starSize.height))
|
||||
for i in 0 ..< self.starNodes.count {
|
||||
let node = self.starNodes[i]
|
||||
transition.updateFrame(node: node, frame: CGRect(x: starsOrigin + 42.0 * CGFloat(i), y: origin.y, width: starSize.width, height: starSize.height))
|
||||
transition.updateFrame(node: node, frame: CGRect(x: starSize.width * CGFloat(i), y: 0.0, width: starSize.width, height: starSize.height))
|
||||
}
|
||||
origin.y += titleSize.height
|
||||
|
||||
|
@ -155,7 +155,7 @@ public final class AvailableReactions: Equatable, Codable {
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case hash
|
||||
case newHash
|
||||
case reactions
|
||||
}
|
||||
|
||||
@ -183,14 +183,14 @@ public final class AvailableReactions: Equatable, Codable {
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
self.hash = try container.decode(Int32.self, forKey: .hash)
|
||||
self.hash = try container.decodeIfPresent(Int32.self, forKey: .newHash) ?? 0
|
||||
self.reactions = try container.decode([Reaction].self, forKey: .reactions)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(self.hash, forKey: .hash)
|
||||
try container.encode(self.hash, forKey: .newHash)
|
||||
try container.encode(self.reactions, forKey: .reactions)
|
||||
}
|
||||
}
|
||||
|
@ -395,6 +395,10 @@ public extension EnginePeer {
|
||||
var isVerified: Bool {
|
||||
return self._asPeer().isVerified
|
||||
}
|
||||
|
||||
var isPremium: Bool {
|
||||
return self._asPeer().isPremium
|
||||
}
|
||||
|
||||
var isService: Bool {
|
||||
if case let .user(peer) = self {
|
||||
|
@ -154,6 +154,15 @@ public extension Peer {
|
||||
}
|
||||
}
|
||||
|
||||
var isPremium: Bool {
|
||||
switch self {
|
||||
case let user as TelegramUser:
|
||||
return user.flags.contains(.isPremium)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var isCopyProtectionEnabled: Bool {
|
||||
switch self {
|
||||
case let group as TelegramGroup:
|
||||
|
@ -85,6 +85,7 @@ public enum PresentationResourceKey: Int32 {
|
||||
case chatListBadgeBackgroundPinned
|
||||
case chatListMutedIcon
|
||||
case chatListVerifiedIcon
|
||||
case chatListPremiumIcon
|
||||
case chatListScamRegularIcon
|
||||
case chatListScamOutgoingIcon
|
||||
case chatListScamServiceIcon
|
||||
@ -165,6 +166,7 @@ public enum PresentationResourceKey: Int32 {
|
||||
case chatInputMediaPanelTrendingGifsIcon
|
||||
case chatInputMediaPanelStickersModeIcon
|
||||
case chatInputMediaPanelPremiumIcon
|
||||
case chatInputMediaStickerGridPremiumIcon
|
||||
|
||||
case chatInputButtonPanelButtonImage
|
||||
case chatInputButtonPanelButtonHighlightedImage
|
||||
|
@ -294,13 +294,59 @@ public struct PresentationResourcesChat {
|
||||
return theme.image(PresentationResourceKey.chatInputMediaPanelPremiumIcon.rawValue, { theme in
|
||||
return generateImage(CGSize(width: 44.0, height: 42.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/PremiumIcon"), color: theme.chat.inputMediaPanel.panelIconColor) {
|
||||
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size))
|
||||
if let image = UIImage(bundleImageName: "Peer Info/PremiumIcon") {
|
||||
if let cgImage = image.cgImage {
|
||||
context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage)
|
||||
}
|
||||
|
||||
let colorsArray: [CGColor] = [
|
||||
UIColor(rgb: 0x418eff).cgColor,
|
||||
UIColor(rgb: 0x418eff).cgColor,
|
||||
UIColor(rgb: 0xfc7ebd).cgColor,
|
||||
UIColor(rgb: 0xfc7ebd).cgColor
|
||||
]
|
||||
var locations: [CGFloat] = [0.0, 0.35, 0.65, 1.0]
|
||||
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
||||
|
||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatInputMediaStickerGridPremiumIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputMediaStickerGridPremiumIcon.rawValue, { theme in
|
||||
return generateImage(CGSize(width: 32.0, height: 32.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
if let backgroundImage = UIImage(bundleImageName: "Premium/BackgroundIcon"), let foregroundImage = UIImage(bundleImageName: "Premium/ForegroundIcon") {
|
||||
context.saveGState()
|
||||
if let cgImage = backgroundImage.cgImage {
|
||||
context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage)
|
||||
}
|
||||
|
||||
let colorsArray: [CGColor] = [
|
||||
UIColor(rgb: 0x418eff).cgColor,
|
||||
UIColor(rgb: 0x418eff).cgColor,
|
||||
UIColor(rgb: 0xfc7ebd).cgColor,
|
||||
UIColor(rgb: 0xfc7ebd).cgColor
|
||||
]
|
||||
var locations: [CGFloat] = [0.0, 0.35, 0.65, 1.0]
|
||||
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
||||
|
||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
||||
|
||||
context.restoreGState()
|
||||
|
||||
if let cgImage = foregroundImage.cgImage {
|
||||
context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage)
|
||||
}
|
||||
context.setFillColor(UIColor.white.cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(), size: size))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatInputMediaPanelRecentStickersIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputMediaPanelRecentStickersIconImage.rawValue, { theme in
|
||||
return generateImage(CGSize(width: 42.0, height: 42.0), contextGenerator: { size, context in
|
||||
|
@ -228,6 +228,32 @@ public struct PresentationResourcesChatList {
|
||||
return UIImage(bundleImageName: "Chat List/PeerVerifiedIcon")?.precomposed()
|
||||
})
|
||||
}
|
||||
|
||||
public static func premiumIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatListPremiumIcon.rawValue, { theme in
|
||||
if let image = UIImage(bundleImageName: "Chat List/PeerPremiumIcon") {
|
||||
return generateImage(image.size, contextGenerator: { size, context in
|
||||
if let cgImage = image.cgImage {
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage)
|
||||
|
||||
let colorsArray: [CGColor] = [
|
||||
UIColor(rgb: 0x418eff).cgColor,
|
||||
UIColor(rgb: 0x418eff).cgColor,
|
||||
UIColor(rgb: 0xfc7ebd).cgColor,
|
||||
UIColor(rgb: 0xfc7ebd).cgColor
|
||||
]
|
||||
var locations: [CGFloat] = [0.0, 0.35, 0.65, 1.0]
|
||||
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
||||
|
||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
||||
}
|
||||
}, opaque: false)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public static func scamIcon(_ theme: PresentationTheme, strings: PresentationStrings, type: ScamIconType) -> UIImage? {
|
||||
let key: PresentationResourceKey
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "premiumbadge_20.pdf",
|
||||
"filename" : "premium_24 (2).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
97
submodules/TelegramUI/Images.xcassets/Peer Info/PremiumIcon.imageset/premium_24 (2).pdf
vendored
Normal file
97
submodules/TelegramUI/Images.xcassets/Peer Info/PremiumIcon.imageset/premium_24 (2).pdf
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 1.565002 2.396484 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
9.882594 3.317978 m
|
||||
5.183870 0.439518 l
|
||||
4.695292 0.140213 4.056584 0.293650 3.757278 0.782228 c
|
||||
3.611097 1.020851 3.567514 1.308409 3.636422 1.579630 c
|
||||
4.363782 4.442544 l
|
||||
4.626348 5.476007 5.333546 6.339901 6.294793 6.801413 c
|
||||
11.420867 9.262531 l
|
||||
11.659847 9.377270 11.760565 9.664015 11.645826 9.902994 c
|
||||
11.552906 10.096530 11.342772 10.204829 11.131232 10.168206 c
|
||||
5.425254 9.180357 l
|
||||
4.265362 8.979550 3.075904 9.299845 2.173681 10.055932 c
|
||||
0.371115 11.566533 l
|
||||
-0.068036 11.934555 -0.125698 12.588898 0.242323 13.028049 c
|
||||
0.421316 13.241636 0.678710 13.374235 0.956533 13.395977 c
|
||||
6.463908 13.826983 l
|
||||
6.852989 13.857433 7.192064 14.103661 7.341429 14.464218 c
|
||||
9.466071 19.592974 l
|
||||
9.685358 20.122318 10.292244 20.373671 10.821589 20.154385 c
|
||||
11.075764 20.049089 11.277705 19.847147 11.382999 19.592974 c
|
||||
13.507642 14.464218 l
|
||||
13.657006 14.103661 13.996081 13.857433 14.385162 13.826983 c
|
||||
19.922798 13.393608 l
|
||||
20.494020 13.348906 20.920849 12.849598 20.876144 12.278376 c
|
||||
20.854639 12.003585 20.724667 11.748647 20.514914 11.569828 c
|
||||
16.291594 7.969350 l
|
||||
15.994287 7.715888 15.864580 7.316894 15.956014 6.937058 c
|
||||
17.254391 1.543314 l
|
||||
17.388485 0.986258 17.045605 0.425970 16.488548 0.291876 c
|
||||
16.220879 0.227442 15.938575 0.272047 15.703809 0.415865 c
|
||||
10.966476 3.317978 l
|
||||
10.633904 3.521713 10.215167 3.521713 9.882594 3.317978 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1468
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000001558 00000 n
|
||||
0000001581 00000 n
|
||||
0000001754 00000 n
|
||||
0000001828 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
1887
|
||||
%%EOF
|
@ -1,97 +0,0 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 1.312988 1.997192 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
8.235496 2.764818 m
|
||||
4.319892 0.366102 l
|
||||
3.912743 0.116680 3.380487 0.244545 3.131065 0.651693 c
|
||||
3.009248 0.850546 2.972928 1.090177 3.030351 1.316196 c
|
||||
3.636486 3.701958 l
|
||||
3.855290 4.563177 4.444622 5.283089 5.245661 5.667681 c
|
||||
9.517389 7.718613 l
|
||||
9.716539 7.814228 9.800470 8.053183 9.704855 8.252333 c
|
||||
9.627422 8.413612 9.452311 8.503861 9.276028 8.473343 c
|
||||
4.521046 7.650135 l
|
||||
3.554468 7.482796 2.563253 7.749707 1.811401 8.379781 c
|
||||
0.309263 9.638615 l
|
||||
-0.056697 9.945299 -0.104749 10.490585 0.201936 10.856544 c
|
||||
0.351096 11.034534 0.565592 11.145033 0.797111 11.163151 c
|
||||
5.386590 11.522324 l
|
||||
5.710824 11.547698 5.993387 11.752888 6.117858 12.053352 c
|
||||
7.888392 16.327314 l
|
||||
8.071132 16.768436 8.576871 16.977896 9.017992 16.795156 c
|
||||
9.229803 16.707413 9.398088 16.539127 9.485833 16.327314 c
|
||||
11.256369 12.053352 l
|
||||
11.380839 11.752888 11.663401 11.547698 11.987636 11.522324 c
|
||||
16.602333 11.161178 l
|
||||
17.078350 11.123924 17.434040 10.707836 17.396788 10.231817 c
|
||||
17.378866 10.002825 17.270555 9.790377 17.095762 9.641360 c
|
||||
13.576328 6.640962 l
|
||||
13.328572 6.429744 13.220484 6.097248 13.296679 5.780720 c
|
||||
14.378658 1.285933 l
|
||||
14.490404 0.821718 14.204671 0.354813 13.740458 0.243067 c
|
||||
13.517399 0.189373 13.282146 0.226543 13.086508 0.346392 c
|
||||
9.138731 2.764818 l
|
||||
8.861588 2.934598 8.512639 2.934598 8.235496 2.764818 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1445
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 20.000000 20.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000001535 00000 n
|
||||
0000001558 00000 n
|
||||
0000001731 00000 n
|
||||
0000001805 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
1864
|
||||
%%EOF
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "addreactions_32.pdf",
|
||||
"filename" : "addreactions2_32.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
BIN
submodules/TelegramUI/Images.xcassets/Premium/ForegroundIcon.imageset/addreactions2_32.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Premium/ForegroundIcon.imageset/addreactions2_32.pdf
vendored
Normal file
Binary file not shown.
@ -1,201 +0,0 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< /Length 2 0 R
|
||||
/Range [ 0.000000 1.000000 0.000000 1.000000 0.000000 1.000000 ]
|
||||
/Domain [ 0.000000 1.000000 ]
|
||||
/FunctionType 4
|
||||
>>
|
||||
stream
|
||||
{ 0.000000 exch 0.721569 exch 1.000000 exch dup 0.000000 gt { exch pop exch pop exch pop dup 0.000000 sub 0.000000 mul 0.000000 add exch dup 0.000000 sub -0.243137 mul 0.721569 add exch dup 0.000000 sub 0.000000 mul 1.000000 add exch } if dup 1.000000 gt { exch pop exch pop exch pop 0.000000 exch 0.478431 exch 1.000000 exch } if pop }
|
||||
endstream
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
337
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
<< /Pattern << /P1 << /Matrix [ 0.000000 -32.000000 32.000000 0.000000 -32.000000 32.000000 ]
|
||||
/Shading << /Coords [ 0.000000 0.000000 1.000000 0.000000 ]
|
||||
/ColorSpace /DeviceRGB
|
||||
/Function 1 0 R
|
||||
/Domain [ 0.000000 1.000000 ]
|
||||
/ShadingType 2
|
||||
/Extend [ true true ]
|
||||
>>
|
||||
/PatternType 2
|
||||
/Type /Pattern
|
||||
>> >> >>
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Length 5 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
0.000000 16.000000 m
|
||||
0.000000 24.836555 7.163444 32.000000 16.000000 32.000000 c
|
||||
16.000000 32.000000 l
|
||||
24.836555 32.000000 32.000000 24.836555 32.000000 16.000000 c
|
||||
32.000000 16.000000 l
|
||||
32.000000 7.163445 24.836555 0.000000 16.000000 0.000000 c
|
||||
16.000000 0.000000 l
|
||||
7.163444 0.000000 0.000000 7.163445 0.000000 16.000000 c
|
||||
0.000000 16.000000 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||
/Pattern cs
|
||||
/P1 scn
|
||||
16.000000 0.000000 m
|
||||
17.874004 0.000000 19.672758 0.322180 21.343897 0.914169 c
|
||||
21.572962 0.677401 21.840872 0.478514 22.138031 0.327103 c
|
||||
22.516409 0.134308 22.909628 0.062992 23.304974 0.030691 c
|
||||
23.679550 0.000088 24.134321 0.000103 24.661480 0.000122 c
|
||||
27.338524 0.000122 l
|
||||
27.865683 0.000103 28.320454 0.000088 28.695030 0.030691 c
|
||||
29.090376 0.062992 29.483595 0.134308 29.861973 0.327103 c
|
||||
30.426460 0.614723 30.885403 1.073666 31.173021 1.638149 c
|
||||
31.365814 2.016529 31.437132 2.409748 31.469433 2.805094 c
|
||||
31.500034 3.179638 31.500019 3.634357 31.500002 4.161457 c
|
||||
31.500002 4.161480 l
|
||||
31.500002 4.161600 l
|
||||
31.500002 4.838646 l
|
||||
31.500002 4.838766 l
|
||||
31.500002 4.838789 l
|
||||
31.500019 5.365887 31.500034 5.820606 31.469433 6.195150 c
|
||||
31.437132 6.590496 31.365814 6.983715 31.173021 7.362093 c
|
||||
30.938610 7.822155 30.590397 8.212109 30.163998 8.496347 c
|
||||
30.163998 8.551201 l
|
||||
31.336399 10.775940 32.000000 13.310474 32.000000 16.000000 c
|
||||
32.000000 24.836555 24.836555 32.000000 16.000000 32.000000 c
|
||||
7.163444 32.000000 0.000000 24.836555 0.000000 16.000000 c
|
||||
0.000000 7.163445 7.163444 0.000000 16.000000 0.000000 c
|
||||
h
|
||||
16.562183 8.757324 m
|
||||
20.546453 6.359240 l
|
||||
20.584953 6.699120 20.660887 7.036112 20.826982 7.362093 c
|
||||
21.061394 7.822151 21.409601 8.212103 21.835997 8.496340 c
|
||||
21.835997 9.500063 l
|
||||
21.835997 10.039848 21.938705 10.555647 22.125647 11.028978 c
|
||||
21.774387 12.530510 l
|
||||
21.686312 12.907011 21.814457 13.301291 22.107056 13.554068 c
|
||||
26.503191 17.351892 l
|
||||
27.199739 17.953642 26.828377 19.096992 25.911175 19.174591 c
|
||||
20.119438 19.664600 l
|
||||
19.735479 19.697086 19.400976 19.939270 19.250256 20.293901 c
|
||||
16.982876 25.628805 l
|
||||
16.624168 26.472807 15.427922 26.472807 15.069214 25.628805 c
|
||||
12.801836 20.293903 l
|
||||
12.651114 19.939270 12.316612 19.697086 11.932652 19.664600 c
|
||||
6.140916 19.174591 l
|
||||
5.223714 19.096992 4.852351 17.953640 5.548900 17.351891 c
|
||||
7.200050 15.925461 l
|
||||
7.880803 15.337358 8.782333 15.071831 9.673182 15.197048 c
|
||||
19.282505 16.547745 l
|
||||
19.848860 16.627354 20.083559 15.847515 19.567341 15.601313 c
|
||||
11.272570 11.645247 l
|
||||
10.417443 11.237408 9.794044 10.463003 9.578240 9.540506 c
|
||||
8.956986 6.884823 l
|
||||
8.747575 5.989647 9.717782 5.283152 10.505456 5.757242 c
|
||||
15.489906 8.757324 l
|
||||
15.819762 8.955860 16.232327 8.955860 16.562183 8.757324 c
|
||||
h
|
||||
22.579525 1.224531 m
|
||||
22.517185 1.256849 22.456810 1.292316 22.398592 1.330725 c
|
||||
22.110716 1.520653 21.875710 1.782589 21.717987 2.092140 c
|
||||
21.500000 2.519964 21.500000 3.080017 21.500000 4.200123 c
|
||||
21.500000 4.800121 l
|
||||
21.500000 5.187914 21.500002 5.508577 21.509048 5.779865 c
|
||||
21.523994 6.228132 21.563643 6.541590 21.668795 6.800331 c
|
||||
21.683817 6.837294 21.700174 6.873140 21.717989 6.908104 c
|
||||
21.909735 7.284428 22.215696 7.590389 22.592020 7.782135 c
|
||||
22.663559 7.818586 22.738798 7.848942 22.819733 7.874222 c
|
||||
22.825129 7.875908 22.830549 7.877571 22.835997 7.879211 c
|
||||
22.835997 7.992439 l
|
||||
22.835995 9.500063 l
|
||||
22.835995 11.247492 24.252565 12.664062 25.999994 12.664062 c
|
||||
27.747423 12.664062 29.163994 11.247492 29.163994 9.500063 c
|
||||
29.163994 7.879215 l
|
||||
29.251150 7.852966 29.331669 7.821018 29.407982 7.782135 c
|
||||
29.490490 7.740095 29.569614 7.692564 29.644896 7.640007 c
|
||||
29.912977 7.452845 30.132307 7.201921 30.282015 6.908104 c
|
||||
30.500002 6.480280 30.500002 5.920227 30.500002 4.800121 c
|
||||
30.500002 4.200123 l
|
||||
30.500002 3.080017 30.500002 2.519964 30.282015 2.092140 c
|
||||
30.258047 2.045099 30.232294 1.999159 30.204842 1.954403 c
|
||||
30.012678 1.641111 29.737267 1.385887 29.407982 1.218109 c
|
||||
28.980160 1.000122 28.420107 1.000122 27.300003 1.000122 c
|
||||
24.700001 1.000122 l
|
||||
23.579897 1.000122 23.019844 1.000122 22.592020 1.218109 c
|
||||
22.587847 1.220236 22.583681 1.222376 22.579525 1.224531 c
|
||||
h
|
||||
25.999994 11.336063 m
|
||||
24.986000 11.336063 24.163994 10.514057 24.163994 9.500063 c
|
||||
24.163994 7.998974 l
|
||||
24.327213 8.000122 24.505131 8.000122 24.700001 8.000122 c
|
||||
27.299999 8.000122 l
|
||||
27.494865 8.000122 27.672779 8.000122 27.835995 7.998974 c
|
||||
27.835995 9.500063 l
|
||||
27.835995 10.514057 27.013988 11.336063 25.999994 11.336063 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
4545
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 32.000000 32.000000 ]
|
||||
/Resources 3 0 R
|
||||
/Contents 4 0 R
|
||||
/Parent 7 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
7 0 obj
|
||||
<< /Kids [ 6 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
8 0 obj
|
||||
<< /Pages 7 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 9
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000531 00000 n
|
||||
0000000553 00000 n
|
||||
0000001179 00000 n
|
||||
0000005780 00000 n
|
||||
0000005803 00000 n
|
||||
0000005976 00000 n
|
||||
0000006050 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 8 0 R
|
||||
/Size 9
|
||||
>>
|
||||
startxref
|
||||
6109
|
||||
%%EOF
|
@ -982,7 +982,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
var hasPremium = false
|
||||
if case let .user(user) = peer, user.flags.contains(.isPremium) {
|
||||
if case let .user(user) = peer, user.isPremium {
|
||||
hasPremium = true
|
||||
}
|
||||
|
||||
@ -1079,6 +1079,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts()
|
||||
|
||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, postbox: strongSelf.context.account.postbox, message: message, selectAll: selectAll)), items: .single(actions), recognizer: recognizer, gesture: gesture)
|
||||
controller.getOverlayViews = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return []
|
||||
}
|
||||
return [strongSelf.chatDisplayNode.navigateButtons.view]
|
||||
}
|
||||
strongSelf.currentContextController = controller
|
||||
|
||||
controller.reactionSelected = { [weak controller] value, isLarge in
|
||||
@ -2347,15 +2353,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let message = message else {
|
||||
return
|
||||
}
|
||||
|
||||
let context = strongSelf.context
|
||||
let chatPresentationInterfaceState = strongSelf.presentationInterfaceState
|
||||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
|
||||
|
||||
let isCopyLink: Bool
|
||||
var isCopyLink = false
|
||||
var isForward = false
|
||||
if message.id.namespace == Namespaces.Message.Cloud, let _ = message.peers[message.id.peerId] as? TelegramChannel, !(message.media.first is TelegramMediaAction) {
|
||||
isCopyLink = true
|
||||
} else {
|
||||
isCopyLink = false
|
||||
} else if let forwardInfo = message.forwardInfo, let _ = forwardInfo.author as? TelegramChannel {
|
||||
isCopyLink = true
|
||||
isForward = true
|
||||
}
|
||||
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
|
||||
@ -2368,13 +2377,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}),
|
||||
ActionSheetButtonItem(title: isCopyLink ? strongSelf.presentationData.strings.Conversation_ContextMenuCopyLink : strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if isCopyLink, let channel = message.peers[message.id.peerId] as? TelegramChannel {
|
||||
|
||||
var messageId = message.id
|
||||
var channel = message.peers[message.id.peerId]
|
||||
if isForward, let forwardMessageId = message.forwardInfo?.sourceMessageId, let forwardAuthor = message.forwardInfo?.author as? TelegramChannel {
|
||||
messageId = forwardMessageId
|
||||
channel = forwardAuthor
|
||||
}
|
||||
|
||||
if isCopyLink, let channel = channel as? TelegramChannel {
|
||||
var threadMessageId: MessageId?
|
||||
|
||||
if case let .replyThread(replyThreadMessage) = chatPresentationInterfaceState.chatLocation {
|
||||
threadMessageId = replyThreadMessage.messageId
|
||||
}
|
||||
let _ = (context.engine.messages.exportMessageLink(peerId: message.id.peerId, messageId: message.id, isThread: threadMessageId != nil)
|
||||
let _ = (context.engine.messages.exportMessageLink(peerId: messageId.peerId, messageId: messageId, isThread: threadMessageId != nil)
|
||||
|> map { result -> String? in
|
||||
return result
|
||||
}
|
||||
|
@ -202,6 +202,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.isLoadingValue = isLoading
|
||||
if isLoading {
|
||||
self.historyNodeContainer.supernode?.insertSubnode(self.loadingNode, belowSubnode: self.historyNodeContainer)
|
||||
self.loadingNode.isHidden = false
|
||||
self.loadingNode.layer.removeAllAnimations()
|
||||
self.loadingNode.alpha = 1.0
|
||||
if animated {
|
||||
@ -215,12 +216,12 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
if let strongSelf = self {
|
||||
strongSelf.loadingNode.layer.removeAllAnimations()
|
||||
if completed {
|
||||
strongSelf.loadingNode.removeFromSupernode()
|
||||
strongSelf.loadingNode.isHidden = true
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
self.loadingNode.removeFromSupernode()
|
||||
self.loadingNode.isHidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -651,12 +652,12 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.emptyType = emptyType
|
||||
if let emptyType = emptyType, self.emptyNode == nil {
|
||||
let emptyNode = ChatEmptyNode(context: self.context, interaction: self.interfaceInteraction)
|
||||
if let (size, insets) = self.validEmptyNodeLayout {
|
||||
emptyNode.updateLayout(interfaceState: self.chatPresentationInterfaceState, emptyType: emptyType, size: size, insets: insets, transition: .immediate)
|
||||
}
|
||||
emptyNode.isHidden = self.restrictedNode != nil
|
||||
self.emptyNode = emptyNode
|
||||
self.historyNodeContainer.supernode?.insertSubnode(emptyNode, aboveSubnode: self.historyNodeContainer)
|
||||
if let (size, insets) = self.validEmptyNodeLayout {
|
||||
emptyNode.updateLayout(interfaceState: self.chatPresentationInterfaceState, emptyType: emptyType, loadingNode: wasLoading && self.loadingNode.supernode != nil ? self.loadingNode : nil, size: size, insets: insets, transition: .immediate)
|
||||
}
|
||||
if animated {
|
||||
emptyNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
@ -1211,7 +1212,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
emptyNodeInsets.bottom += inputPanelsHeight
|
||||
self.validEmptyNodeLayout = (contentBounds.size, emptyNodeInsets)
|
||||
if let emptyNode = self.emptyNode, let emptyType = self.emptyType {
|
||||
emptyNode.updateLayout(interfaceState: self.chatPresentationInterfaceState, emptyType: emptyType, size: contentBounds.size, insets: emptyNodeInsets, transition: transition)
|
||||
emptyNode.updateLayout(interfaceState: self.chatPresentationInterfaceState, emptyType: emptyType, loadingNode: nil, size: contentBounds.size, insets: emptyNodeInsets, transition: transition)
|
||||
transition.updateFrame(node: emptyNode, frame: contentBounds)
|
||||
}
|
||||
|
||||
|
@ -807,7 +807,25 @@ final class ChatEmptyNode: ASDisplayNode {
|
||||
self.addSubnode(self.backgroundNode)
|
||||
}
|
||||
|
||||
func updateLayout(interfaceState: ChatPresentationInterfaceState, emptyType: ChatHistoryNodeLoadState.EmptyType, size: CGSize, insets: UIEdgeInsets, transition: ContainedViewLayoutTransition) {
|
||||
func animateFromLoadingNode(_ loadingNode: ChatLoadingNode) {
|
||||
guard let (_, node) = content else {
|
||||
return
|
||||
}
|
||||
|
||||
let duration: Double = 0.2
|
||||
node.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||
node.layer.animateScale(from: 0.0, to: 1.0, duration: duration, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
|
||||
|
||||
let targetCornerRadius = self.backgroundNode.backgroundCornerRadius
|
||||
let targetFrame = self.backgroundNode.frame
|
||||
let initialFrame = loadingNode.convert(loadingNode.progressFrame, to: self)
|
||||
|
||||
self.backgroundNode.layer.animateFrame(from: initialFrame, to: targetFrame, duration: duration)
|
||||
self.backgroundNode.update(size: initialFrame.size, cornerRadius: initialFrame.size.width / 2.0, transition: .immediate)
|
||||
self.backgroundNode.update(size: targetFrame.size, cornerRadius: targetCornerRadius, transition: .animated(duration: duration, curve: .easeInOut))
|
||||
}
|
||||
|
||||
func updateLayout(interfaceState: ChatPresentationInterfaceState, emptyType: ChatHistoryNodeLoadState.EmptyType, loadingNode: ChatLoadingNode?, size: CGSize, insets: UIEdgeInsets, transition: ContainedViewLayoutTransition) {
|
||||
if self.currentTheme !== interfaceState.theme || self.currentStrings !== interfaceState.strings {
|
||||
self.currentTheme = interfaceState.theme
|
||||
self.currentStrings = interfaceState.strings
|
||||
@ -904,5 +922,9 @@ final class ChatEmptyNode: ASDisplayNode {
|
||||
|
||||
transition.updateFrame(node: self.backgroundNode, frame: contentFrame)
|
||||
self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: min(20.0, self.backgroundNode.bounds.height / 2.0), transition: transition)
|
||||
|
||||
if let loadingNode = loadingNode {
|
||||
self.animateFromLoadingNode(loadingNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,5 +38,9 @@ final class ChatLoadingNode: ASDisplayNode {
|
||||
let activitySize = self.activityIndicator.measure(size)
|
||||
transition.updateFrame(node: self.activityIndicator, frame: CGRect(origin: CGPoint(x: displayRect.minX + floor((displayRect.width - activitySize.width) / 2.0) + self.offset.x, y: displayRect.minY + floor((displayRect.height - activitySize.height) / 2.0) + self.offset.y), size: activitySize))
|
||||
}
|
||||
|
||||
var progressFrame: CGRect {
|
||||
return self.backgroundNode.frame
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1659,7 +1659,7 @@ final class ChatMediaInputNode: ChatInputNode {
|
||||
return strongSelf.context.account.postbox.transaction { transaction -> (Bool, Bool) in
|
||||
let isStarred = getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
|
||||
var hasPremium = false
|
||||
if let peer = transaction.getPeer(accountPeerId) as? TelegramUser, peer.flags.contains(.isPremium) {
|
||||
if let peer = transaction.getPeer(accountPeerId) as? TelegramUser, peer.isPremium {
|
||||
hasPremium = true
|
||||
}
|
||||
return (isStarred, hasPremium)
|
||||
|
@ -320,7 +320,7 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
|
||||
lockBackground = UIImageView()
|
||||
lockBackground.clipsToBounds = true
|
||||
lockBackground.isUserInteractionEnabled = false
|
||||
lockBackground.image = UIImage(bundleImageName: "Premium/StickerIcon")
|
||||
lockBackground.image = PresentationResourcesChat.chatInputMediaStickerGridPremiumIcon(item.theme)
|
||||
self.lockBackground = lockBackground
|
||||
|
||||
self.view.addSubview(lockBackground)
|
||||
|
@ -37,6 +37,14 @@ private enum ChatTitleIcon {
|
||||
case mute
|
||||
}
|
||||
|
||||
private enum ChatTitleCredibilityIcon {
|
||||
case none
|
||||
case fake
|
||||
case scam
|
||||
case verified
|
||||
case premium
|
||||
}
|
||||
|
||||
final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
private let account: Account
|
||||
|
||||
@ -59,8 +67,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
|
||||
private var titleLeftIcon: ChatTitleIcon = .none
|
||||
private var titleRightIcon: ChatTitleIcon = .none
|
||||
private var titleFakeIcon = false
|
||||
private var titleScamIcon = false
|
||||
private var titleCredibilityIcon: ChatTitleCredibilityIcon = .none
|
||||
|
||||
//private var networkStatusNode: ChatTitleNetworkStatusNode?
|
||||
|
||||
@ -106,8 +113,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
var segments: [AnimatedCountLabelNode.Segment] = []
|
||||
var titleLeftIcon: ChatTitleIcon = .none
|
||||
var titleRightIcon: ChatTitleIcon = .none
|
||||
var titleScamIcon = false
|
||||
var titleFakeIcon = false
|
||||
var titleCredibilityIcon: ChatTitleCredibilityIcon = .none
|
||||
var isEnabled = true
|
||||
switch titleContent {
|
||||
case let .peer(peerView, _, isScheduledMessages):
|
||||
@ -134,9 +140,13 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
}
|
||||
}
|
||||
if peer.isFake {
|
||||
titleFakeIcon = true
|
||||
titleCredibilityIcon = .fake
|
||||
} else if peer.isScam {
|
||||
titleScamIcon = true
|
||||
titleCredibilityIcon = .scam
|
||||
} else if peer.isVerified {
|
||||
titleCredibilityIcon = .verified
|
||||
} else if peer.isPremium {
|
||||
titleCredibilityIcon = .premium
|
||||
}
|
||||
}
|
||||
if peerView.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
@ -243,15 +253,20 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
updated = true
|
||||
}
|
||||
|
||||
if titleFakeIcon != self.titleFakeIcon {
|
||||
self.titleFakeIcon = titleFakeIcon
|
||||
self.titleCredibilityIconNode.image = titleFakeIcon ? PresentationResourcesChatList.fakeIcon(titleTheme, strings: self.strings, type: .regular) : nil
|
||||
updated = true
|
||||
}
|
||||
|
||||
if titleScamIcon != self.titleScamIcon {
|
||||
self.titleScamIcon = titleScamIcon
|
||||
self.titleCredibilityIconNode.image = titleScamIcon ? PresentationResourcesChatList.scamIcon(titleTheme, strings: self.strings, type: .regular) : nil
|
||||
if titleCredibilityIcon != self.titleCredibilityIcon {
|
||||
self.titleCredibilityIcon = titleCredibilityIcon
|
||||
switch titleCredibilityIcon {
|
||||
case .none:
|
||||
self.titleCredibilityIconNode.image = nil
|
||||
case .fake:
|
||||
self.titleCredibilityIconNode.image = PresentationResourcesChatList.fakeIcon(titleTheme, strings: self.strings, type: .regular)
|
||||
case .scam:
|
||||
self.titleCredibilityIconNode.image = PresentationResourcesChatList.scamIcon(titleTheme, strings: self.strings, type: .regular)
|
||||
case .verified:
|
||||
self.titleCredibilityIconNode.image = PresentationResourcesChatList.verifiedIcon(titleTheme)
|
||||
case .premium:
|
||||
self.titleCredibilityIconNode.image = PresentationResourcesChatList.premiumIcon(titleTheme)
|
||||
}
|
||||
updated = true
|
||||
}
|
||||
|
||||
@ -685,10 +700,14 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
self.titleLeftIconNode.frame = CGRect(origin: CGPoint(x: -image.size.width - 3.0 - UIScreenPixel, y: 4.0), size: image.size)
|
||||
}
|
||||
if let image = self.titleCredibilityIconNode.image {
|
||||
self.titleCredibilityIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.width - image.size.width - 1.0, y: 2.0), size: image.size)
|
||||
var originY: CGFloat = 3.0
|
||||
if [.fake, .scam].contains(self.titleCredibilityIcon) {
|
||||
originY = 2.0
|
||||
}
|
||||
self.titleCredibilityIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.width - image.size.width, y: originY), size: image.size)
|
||||
}
|
||||
if let image = self.titleRightIconNode.image {
|
||||
self.titleRightIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.width + 3.0, y: 6.0), size: image.size)
|
||||
self.titleRightIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.width + 3.0 + UIScreenPixel, y: 6.0), size: image.size)
|
||||
}
|
||||
} else {
|
||||
let titleSize = self.titleNode.updateLayout(size: CGSize(width: floor(clearBounds.width / 2.0 - leftIconWidth - credibilityIconWidth - rightIconWidth - titleSideInset * 2.0), height: size.height), animated: transition.isAnimated)
|
||||
@ -705,10 +724,14 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
self.titleLeftIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.minX, y: titleFrame.minY + 4.0), size: image.size)
|
||||
}
|
||||
if let image = self.titleCredibilityIconNode.image {
|
||||
self.titleCredibilityIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.maxX - image.size.width - 1.0, y: titleFrame.minY + 6.0), size: image.size)
|
||||
var originY: CGFloat = titleFrame.minY + 7.0
|
||||
if [.fake, .scam].contains(self.titleCredibilityIcon) {
|
||||
originY = titleFrame.minY + 6.0
|
||||
}
|
||||
self.titleCredibilityIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.maxX - image.size.width, y: originY), size: image.size)
|
||||
}
|
||||
if let image = self.titleRightIconNode.image {
|
||||
self.titleRightIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.maxX - image.size.width - 1.0, y: titleFrame.minY + 6.0), size: image.size)
|
||||
self.titleRightIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.maxX - image.size.width, y: titleFrame.minY + 6.0), size: image.size)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
||||
private let maskNode: ASImageNode
|
||||
private let labelNode: ImmediateTextNode
|
||||
private let textNode: ImmediateTextNode
|
||||
private let measureTextNode: ImmediateTextNode
|
||||
private let bottomSeparatorNode: ASDisplayNode
|
||||
|
||||
private let expandBackgroundNode: ASImageNode
|
||||
@ -120,6 +121,10 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
||||
self.textNode.displaysAsynchronously = false
|
||||
self.textNode.isUserInteractionEnabled = false
|
||||
|
||||
self.measureTextNode = ImmediateTextNode()
|
||||
self.measureTextNode.displaysAsynchronously = false
|
||||
self.measureTextNode.isUserInteractionEnabled = false
|
||||
|
||||
self.bottomSeparatorNode = ASDisplayNode()
|
||||
self.bottomSeparatorNode.isLayerBacked = true
|
||||
|
||||
@ -285,38 +290,6 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
||||
|
||||
self.labelNode.attributedText = NSAttributedString(string: item.label, font: Font.regular(14.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
|
||||
|
||||
var text = item.text
|
||||
let maxNumberOfLines: Int
|
||||
switch item.textBehavior {
|
||||
case .singleLine:
|
||||
maxNumberOfLines = 1
|
||||
self.textNode.maximumNumberOfLines = maxNumberOfLines
|
||||
self.textNode.cutout = nil
|
||||
self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue)
|
||||
case let .multiLine(maxLines, enabledEntities):
|
||||
if !self.isExpanded {
|
||||
text = trimToLineCount(text, lineCount: 3)
|
||||
}
|
||||
|
||||
maxNumberOfLines = self.isExpanded ? maxLines : 3
|
||||
self.textNode.maximumNumberOfLines = maxNumberOfLines
|
||||
if enabledEntities.isEmpty {
|
||||
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(17.0), textColor: textColorValue)
|
||||
} else {
|
||||
let fontSize: CGFloat = 17.0
|
||||
|
||||
let baseFont = Font.regular(fontSize)
|
||||
let linkFont = baseFont
|
||||
let boldFont = Font.medium(fontSize)
|
||||
let italicFont = Font.italic(fontSize)
|
||||
let boldItalicFont = Font.semiboldItalic(fontSize)
|
||||
let titleFixedFont = Font.monospace(fontSize)
|
||||
|
||||
let entities = generateTextEntities(text, enabledTypes: enabledEntities)
|
||||
self.textNode.attributedText = stringWithAppliedEntities(text, entities: entities, baseColor: textColorValue, linkColor: presentationData.theme.list.itemAccentColor, baseFont: baseFont, linkFont: linkFont, boldFont: boldFont, italicFont: italicFont, boldItalicFont: boldItalicFont, fixedFont: titleFixedFont, blockQuoteFont: baseFont)
|
||||
}
|
||||
}
|
||||
|
||||
if let icon = item.icon {
|
||||
let iconImage: UIImage?
|
||||
switch icon {
|
||||
@ -332,6 +305,55 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
||||
}
|
||||
|
||||
let additionalSideInset: CGFloat = !self.iconNode.isHidden ? 32.0 : 0.0
|
||||
|
||||
var text = item.text
|
||||
let maxNumberOfLines: Int
|
||||
switch item.textBehavior {
|
||||
case .singleLine:
|
||||
maxNumberOfLines = 1
|
||||
self.textNode.maximumNumberOfLines = maxNumberOfLines
|
||||
self.textNode.cutout = nil
|
||||
self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue)
|
||||
case let .multiLine(maxLines, enabledEntities):
|
||||
let originalText = text
|
||||
if !self.isExpanded {
|
||||
text = trimToLineCount(text, lineCount: 3)
|
||||
}
|
||||
|
||||
func createAttributedText(_ text: String) -> NSAttributedString {
|
||||
if enabledEntities.isEmpty {
|
||||
return NSAttributedString(string: text, font: Font.regular(17.0), textColor: textColorValue)
|
||||
} else {
|
||||
let fontSize: CGFloat = 17.0
|
||||
|
||||
let baseFont = Font.regular(fontSize)
|
||||
let linkFont = baseFont
|
||||
let boldFont = Font.medium(fontSize)
|
||||
let italicFont = Font.italic(fontSize)
|
||||
let boldItalicFont = Font.semiboldItalic(fontSize)
|
||||
let titleFixedFont = Font.monospace(fontSize)
|
||||
|
||||
let entities = generateTextEntities(text, enabledTypes: enabledEntities)
|
||||
return stringWithAppliedEntities(text, entities: entities, baseColor: textColorValue, linkColor: presentationData.theme.list.itemAccentColor, baseFont: baseFont, linkFont: linkFont, boldFont: boldFont, italicFont: italicFont, boldItalicFont: boldItalicFont, fixedFont: titleFixedFont, blockQuoteFont: baseFont)
|
||||
}
|
||||
}
|
||||
|
||||
self.measureTextNode.maximumNumberOfLines = 0
|
||||
self.measureTextNode.attributedText = createAttributedText(originalText)
|
||||
|
||||
let textLayout = self.measureTextNode.updateLayoutInfo(CGSize(width: width - sideInset * 2.0 - additionalSideInset, height: .greatestFiniteMagnitude))
|
||||
var collapsedNumberOfLines = 3
|
||||
if textLayout.numberOfLines == 4 {
|
||||
collapsedNumberOfLines = 4
|
||||
}
|
||||
|
||||
self.textNode.attributedText = createAttributedText(text)
|
||||
|
||||
maxNumberOfLines = self.isExpanded ? maxLines : collapsedNumberOfLines
|
||||
self.textNode.maximumNumberOfLines = maxNumberOfLines
|
||||
}
|
||||
|
||||
|
||||
let labelSize = self.labelNode.updateLayout(CGSize(width: width - sideInset * 2.0, height: .greatestFiniteMagnitude))
|
||||
let textLayout = self.textNode.updateLayoutInfo(CGSize(width: width - sideInset * 2.0 - additionalSideInset, height: .greatestFiniteMagnitude))
|
||||
let textSize = textLayout.size
|
||||
|
@ -2278,6 +2278,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
|
||||
if themeUpdated || !initializedCredibilityIcon {
|
||||
let image: UIImage?
|
||||
var expandedImage: UIImage?
|
||||
if let peer = peer {
|
||||
self.initializedCredibilityIcon = true
|
||||
if peer.isFake {
|
||||
@ -2297,6 +2298,36 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
} else {
|
||||
image = nil
|
||||
}
|
||||
} else if peer.isPremium {
|
||||
if let sourceImage = UIImage(bundleImageName: "Peer Info/PremiumIcon") {
|
||||
image = generateImage(sourceImage.size, contextGenerator: { size, context in
|
||||
if let cgImage = sourceImage.cgImage {
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage)
|
||||
|
||||
let colorsArray: [CGColor] = [
|
||||
UIColor(rgb: 0x418eff).cgColor,
|
||||
UIColor(rgb: 0x418eff).cgColor,
|
||||
UIColor(rgb: 0xfc7ebd).cgColor,
|
||||
UIColor(rgb: 0xfc7ebd).cgColor
|
||||
]
|
||||
var locations: [CGFloat] = [0.0, 0.35, 0.65, 1.0]
|
||||
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
||||
|
||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
||||
}
|
||||
}, opaque: false)
|
||||
expandedImage = generateImage(sourceImage.size, contextGenerator: { size, context in
|
||||
if let cgImage = sourceImage.cgImage {
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage)
|
||||
context.setFillColor(UIColor(rgb: 0xffffff, alpha: 0.75).cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(), size: size))
|
||||
}
|
||||
}, opaque: false)
|
||||
} else {
|
||||
image = nil
|
||||
}
|
||||
} else {
|
||||
image = nil
|
||||
}
|
||||
@ -2304,7 +2335,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
image = nil
|
||||
}
|
||||
self.titleCredibilityIconNode.image = image
|
||||
self.titleExpandedCredibilityIconNode.image = image
|
||||
self.titleExpandedCredibilityIconNode.image = expandedImage ?? image
|
||||
}
|
||||
|
||||
self.regularContentNode.alpha = state.isEditing ? 0.0 : 1.0
|
||||
@ -2524,7 +2555,6 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
|
||||
if let image = self.titleCredibilityIconNode.image {
|
||||
transition.updateFrame(node: self.titleCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleSize.width + 4.0, y: floor((titleSize.height - image.size.height) / 2.0) + 1.0), size: image.size))
|
||||
|
||||
transition.updateFrame(node: self.titleExpandedCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleExpandedSize.width + 4.0, y: floor((titleExpandedSize.height - image.size.height) / 2.0) + 1.0), size: image.size))
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@ import DatePickerNode
|
||||
import DebugSettingsUI
|
||||
import TabBarUI
|
||||
|
||||
import TelegramCallsUI
|
||||
|
||||
public final class TelegramRootController: NavigationController {
|
||||
private let context: AccountContext
|
||||
|
||||
|
@ -445,7 +445,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
self.handleSendData(data: eventData)
|
||||
}
|
||||
case "web_app_setup_main_button":
|
||||
if let webView = self.webView, !webView.didTouchOnce {
|
||||
if let webView = self.webView, !webView.didTouchOnce && controller.url == nil {
|
||||
self.delayedScriptMessage = message
|
||||
} else if let eventData = (body["eventData"] as? String)?.data(using: .utf8), let json = try? JSONSerialization.jsonObject(with: eventData, options: []) as? [String: Any] {
|
||||
if var isVisible = json["is_visible"] as? Bool {
|
||||
|
Loading…
x
Reference in New Issue
Block a user