mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +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.Description" = "Unlock additional reactions by subscribing to Telegram Premium.";
|
||||||
"Premium.Reactions.Proceed" = "Unlock Additional Reactions";
|
"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 {
|
} else if peer.isVerified {
|
||||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||||
credibilityIconOffset = 3.0
|
credibilityIconOffset = 3.0
|
||||||
|
} else if peer.isPremium {
|
||||||
|
currentCredibilityIconImage = PresentationResourcesChatList.premiumIcon(item.presentationData.theme)
|
||||||
|
credibilityIconOffset = 2.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -1394,6 +1397,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
} else if peer.isVerified {
|
} else if peer.isVerified {
|
||||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||||
credibilityIconOffset = 3.0
|
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 {
|
if let currentMutedIconImage = currentMutedIconImage {
|
||||||
strongSelf.mutedIconNode.image = currentMutedIconImage
|
strongSelf.mutedIconNode.image = currentMutedIconImage
|
||||||
strongSelf.mutedIconNode.isHidden = false
|
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
|
nextTitleIconOrigin += currentMutedIconImage.size.width + 1.0
|
||||||
} else {
|
} else {
|
||||||
strongSelf.mutedIconNode.image = nil
|
strongSelf.mutedIconNode.image = nil
|
||||||
|
@ -14,6 +14,7 @@ private let animationDurationFactor: Double = 1.0
|
|||||||
public protocol ContextControllerProtocol: AnyObject {
|
public protocol ContextControllerProtocol: AnyObject {
|
||||||
var useComplexItemsTransitionAnimation: Bool { get set }
|
var useComplexItemsTransitionAnimation: Bool { get set }
|
||||||
var immediateItemsTransitionAnimation: Bool { get set }
|
var immediateItemsTransitionAnimation: Bool { get set }
|
||||||
|
var getOverlayViews: (() -> [UIView])? { get set }
|
||||||
|
|
||||||
func getActionsMinHeight() -> ContextController.ActionsHeight?
|
func getActionsMinHeight() -> ContextController.ActionsHeight?
|
||||||
func setItems(_ items: Signal<ContextController.Items, NoError>, minHeight: 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 {
|
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)
|
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)
|
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 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) {
|
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.account = account
|
||||||
self.presentationData = presentationData
|
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):
|
case let .animateOut(result, completion):
|
||||||
let duration: Double
|
let duration: Double
|
||||||
let timingFunction: String
|
let timingFunction: String
|
||||||
@ -785,6 +797,18 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
|||||||
if let reactionContextNode = self.reactionContextNode {
|
if let reactionContextNode = self.reactionContextNode {
|
||||||
reactionContextNode.animateOut(to: currentContentScreenFrame, animatingOutToReaction: self.reactionContextNodeIsAnimatingOut)
|
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:
|
case .none:
|
||||||
if animateReactionsIn, let reactionContextNode = self.reactionContextNode {
|
if animateReactionsIn, let reactionContextNode = self.reactionContextNode {
|
||||||
reactionContextNode.animateIn(from: contentRect)
|
reactionContextNode.animateIn(from: contentRect)
|
||||||
|
@ -64,6 +64,8 @@ public final class PeekController: ViewController, ContextControllerProtocol {
|
|||||||
|
|
||||||
public var visibilityUpdated: ((Bool) -> Void)?
|
public var visibilityUpdated: ((Bool) -> Void)?
|
||||||
|
|
||||||
|
public var getOverlayViews: (() -> [UIView])?
|
||||||
|
|
||||||
private var animatedIn = false
|
private var animatedIn = false
|
||||||
|
|
||||||
public init(presentationData: PresentationData, content: PeekControllerContent, sourceNode: @escaping () -> ASDisplayNode?) {
|
public init(presentationData: PresentationData, content: PeekControllerContent, sourceNode: @escaping () -> ASDisplayNode?) {
|
||||||
|
@ -378,9 +378,29 @@ public final class DeviceAccess {
|
|||||||
}
|
}
|
||||||
case let .location(locationSubject):
|
case let .location(locationSubject):
|
||||||
let status = CLLocationManager.authorizationStatus()
|
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 {
|
switch status {
|
||||||
case .authorizedAlways:
|
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:
|
case .authorizedWhenInUse:
|
||||||
switch locationSubject {
|
switch locationSubject {
|
||||||
case .send, .tracking:
|
case .send, .tracking:
|
||||||
|
@ -4,6 +4,7 @@ import UIKit
|
|||||||
public struct ImmediateTextNodeLayoutInfo {
|
public struct ImmediateTextNodeLayoutInfo {
|
||||||
public let size: CGSize
|
public let size: CGSize
|
||||||
public let truncated: Bool
|
public let truncated: Bool
|
||||||
|
public let numberOfLines: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ImmediateTextNode: TextNode {
|
public class ImmediateTextNode: TextNode {
|
||||||
@ -18,8 +19,7 @@ public class ImmediateTextNode: TextNode {
|
|||||||
public var textStroke: (UIColor, CGFloat)?
|
public var textStroke: (UIColor, CGFloat)?
|
||||||
public var cutout: TextNodeCutout?
|
public var cutout: TextNodeCutout?
|
||||||
public var displaySpoilers = false
|
public var displaySpoilers = false
|
||||||
public var countIfMoreThanOneLineOverMaximum = false
|
|
||||||
|
|
||||||
public var truncationMode: NSLineBreakMode {
|
public var truncationMode: NSLineBreakMode {
|
||||||
get {
|
get {
|
||||||
switch self.truncationType {
|
switch self.truncationType {
|
||||||
@ -91,7 +91,7 @@ public class ImmediateTextNode: TextNode {
|
|||||||
self.constrainedSize = constrainedSize
|
self.constrainedSize = constrainedSize
|
||||||
|
|
||||||
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, 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()
|
let _ = apply()
|
||||||
if layout.numberOfLines > 1 {
|
if layout.numberOfLines > 1 {
|
||||||
self.trailingLineWidth = layout.trailingLineWidth
|
self.trailingLineWidth = layout.trailingLineWidth
|
||||||
@ -105,16 +105,16 @@ public class ImmediateTextNode: TextNode {
|
|||||||
self.constrainedSize = constrainedSize
|
self.constrainedSize = constrainedSize
|
||||||
|
|
||||||
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, 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()
|
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 {
|
public func updateLayoutFullInfo(_ constrainedSize: CGSize) -> TextNodeLayout {
|
||||||
self.constrainedSize = constrainedSize
|
self.constrainedSize = constrainedSize
|
||||||
|
|
||||||
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, 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()
|
let _ = apply()
|
||||||
return layout
|
return layout
|
||||||
}
|
}
|
||||||
@ -287,7 +287,7 @@ public class ImmediateTextView: TextView {
|
|||||||
self.constrainedSize = constrainedSize
|
self.constrainedSize = constrainedSize
|
||||||
|
|
||||||
let makeLayout = TextView.asyncLayout(self)
|
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()
|
let _ = apply()
|
||||||
if layout.numberOfLines > 1 {
|
if layout.numberOfLines > 1 {
|
||||||
self.trailingLineWidth = layout.trailingLineWidth
|
self.trailingLineWidth = layout.trailingLineWidth
|
||||||
@ -301,16 +301,16 @@ public class ImmediateTextView: TextView {
|
|||||||
self.constrainedSize = constrainedSize
|
self.constrainedSize = constrainedSize
|
||||||
|
|
||||||
let makeLayout = TextView.asyncLayout(self)
|
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()
|
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 {
|
public func updateLayoutFullInfo(_ constrainedSize: CGSize) -> TextNodeLayout {
|
||||||
self.constrainedSize = constrainedSize
|
self.constrainedSize = constrainedSize
|
||||||
|
|
||||||
let makeLayout = TextView.asyncLayout(self)
|
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()
|
let _ = apply()
|
||||||
return layout
|
return layout
|
||||||
}
|
}
|
||||||
|
@ -123,6 +123,14 @@ public final class NavigationBackgroundNode: ASDisplayNode {
|
|||||||
private let backgroundNode: ASDisplayNode
|
private let backgroundNode: ASDisplayNode
|
||||||
|
|
||||||
private var validLayout: (CGSize, CGFloat)?
|
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) {
|
public init(color: UIColor, enableBlur: Bool = true) {
|
||||||
self._color = .clear
|
self._color = .clear
|
||||||
|
@ -132,9 +132,8 @@ public final class TextNodeLayoutArguments {
|
|||||||
public let textShadowColor: UIColor?
|
public let textShadowColor: UIColor?
|
||||||
public let textStroke: (UIColor, CGFloat)?
|
public let textStroke: (UIColor, CGFloat)?
|
||||||
public let displaySpoilers: Bool
|
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.attributedString = attributedString
|
||||||
self.backgroundColor = backgroundColor
|
self.backgroundColor = backgroundColor
|
||||||
self.minimumNumberOfLines = minimumNumberOfLines
|
self.minimumNumberOfLines = minimumNumberOfLines
|
||||||
@ -150,7 +149,6 @@ public final class TextNodeLayoutArguments {
|
|||||||
self.textShadowColor = textShadowColor
|
self.textShadowColor = textShadowColor
|
||||||
self.textStroke = textStroke
|
self.textStroke = textStroke
|
||||||
self.displaySpoilers = displaySpoilers
|
self.displaySpoilers = displaySpoilers
|
||||||
self.countIfMoreThanOneLineOverMaximum = countIfMoreThanOneLineOverMaximum
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,9 +177,8 @@ public final class TextNodeLayout: NSObject {
|
|||||||
public let hasRTL: Bool
|
public let hasRTL: Bool
|
||||||
public let spoilers: [(NSRange, CGRect)]
|
public let spoilers: [(NSRange, CGRect)]
|
||||||
public let spoilerWords: [(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.attributedString = attributedString
|
||||||
self.maximumNumberOfLines = maximumNumberOfLines
|
self.maximumNumberOfLines = maximumNumberOfLines
|
||||||
self.truncationType = truncationType
|
self.truncationType = truncationType
|
||||||
@ -225,7 +222,6 @@ public final class TextNodeLayout: NSObject {
|
|||||||
self.hasRTL = hasRTL
|
self.hasRTL = hasRTL
|
||||||
self.spoilers = spoilers
|
self.spoilers = spoilers
|
||||||
self.spoilerWords = spoilerWords
|
self.spoilerWords = spoilerWords
|
||||||
self.hasMoreThanOneLineOverMaximum = hasMoreThanOneLineOverMaximum
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func areLinesEqual(to other: TextNodeLayout) -> Bool {
|
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 {
|
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 let attributedString = attributedString {
|
||||||
if attributedString.string.hasPrefix("Д") {
|
|
||||||
print()
|
|
||||||
}
|
|
||||||
let stringLength = attributedString.length
|
let stringLength = attributedString.length
|
||||||
|
|
||||||
let font: CTFont
|
let font: CTFont
|
||||||
@ -935,7 +928,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, 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!
|
let typesetter = maybeTypesetter!
|
||||||
@ -951,9 +944,7 @@ public class TextNode: ASDisplayNode {
|
|||||||
|
|
||||||
var bottomCutoutEnabled = false
|
var bottomCutoutEnabled = false
|
||||||
var bottomCutoutSize = CGSize()
|
var bottomCutoutSize = CGSize()
|
||||||
|
|
||||||
let hasMoreThanOneLineOverMaximum: Bool? = nil
|
|
||||||
|
|
||||||
if let topLeft = cutout?.topLeft {
|
if let topLeft = cutout?.topLeft {
|
||||||
cutoutMinY = -fontLineSpacing
|
cutoutMinY = -fontLineSpacing
|
||||||
cutoutMaxY = topLeft.height + 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 {
|
} 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?
|
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, 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!
|
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 {
|
} 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)
|
self.addSubnode(self.imageNode)
|
||||||
|
|
||||||
if theme.overallDarkAppearance {
|
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 {
|
} 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
|
return strongSelf.context.account.postbox.transaction { transaction -> (Bool, Bool) in
|
||||||
let isStarred = getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
|
let isStarred = getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
|
||||||
var hasPremium = false
|
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
|
hasPremium = true
|
||||||
}
|
}
|
||||||
return (isStarred, hasPremium)
|
return (isStarred, hasPremium)
|
||||||
|
@ -174,7 +174,7 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
|||||||
lockBackground = UIImageView()
|
lockBackground = UIImageView()
|
||||||
lockBackground.clipsToBounds = true
|
lockBackground.clipsToBounds = true
|
||||||
lockBackground.isUserInteractionEnabled = false
|
lockBackground.isUserInteractionEnabled = false
|
||||||
lockBackground.image = UIImage(bundleImageName: "Premium/StickerIcon")
|
lockBackground.image = PresentationResourcesChat.chatInputMediaStickerGridPremiumIcon(theme)
|
||||||
self.lockBackground = lockBackground
|
self.lockBackground = lockBackground
|
||||||
|
|
||||||
self.view.addSubview(lockBackground)
|
self.view.addSubview(lockBackground)
|
||||||
|
@ -177,8 +177,8 @@ private final class StickerPackContainer: ASDisplayNode {
|
|||||||
|
|
||||||
self.addSubnode(self.backgroundNode)
|
self.addSubnode(self.backgroundNode)
|
||||||
self.addSubnode(self.gridNode)
|
self.addSubnode(self.gridNode)
|
||||||
self.addSubnode(self.actionAreaBackgroundNode)
|
// self.addSubnode(self.actionAreaBackgroundNode)
|
||||||
self.addSubnode(self.actionAreaSeparatorNode)
|
// self.addSubnode(self.actionAreaSeparatorNode)
|
||||||
self.addSubnode(self.buttonNode)
|
self.addSubnode(self.buttonNode)
|
||||||
|
|
||||||
self.addSubnode(self.titleBackgroundnode)
|
self.addSubnode(self.titleBackgroundnode)
|
||||||
@ -294,7 +294,7 @@ private final class StickerPackContainer: ASDisplayNode {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var hasPremium = false
|
var hasPremium = false
|
||||||
if case let .user(user) = peer, user.flags.contains(.isPremium) {
|
if let peer = peer, peer.isPremium {
|
||||||
hasPremium = true
|
hasPremium = true
|
||||||
}
|
}
|
||||||
strongSelf.updateStickerPackContents(contents, hasPremium: hasPremium)
|
strongSelf.updateStickerPackContents(contents, hasPremium: hasPremium)
|
||||||
@ -337,7 +337,7 @@ private final class StickerPackContainer: ASDisplayNode {
|
|||||||
return strongSelf.context.account.postbox.transaction { transaction -> (Bool, Bool) in
|
return strongSelf.context.account.postbox.transaction { transaction -> (Bool, Bool) in
|
||||||
let isStarred = getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
|
let isStarred = getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
|
||||||
var hasPremium = false
|
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
|
hasPremium = true
|
||||||
}
|
}
|
||||||
return (isStarred, hasPremium)
|
return (isStarred, hasPremium)
|
||||||
|
@ -17,6 +17,7 @@ private final class CallRatingAlertContentNode: AlertContentNode {
|
|||||||
var rating: Int?
|
var rating: Int?
|
||||||
|
|
||||||
private let titleNode: ASTextNode
|
private let titleNode: ASTextNode
|
||||||
|
private var starContainerNode: ASDisplayNode
|
||||||
private let starNodes: [ASButtonNode]
|
private let starNodes: [ASButtonNode]
|
||||||
|
|
||||||
private let actionNodesSeparator: ASDisplayNode
|
private let actionNodesSeparator: ASDisplayNode
|
||||||
@ -38,6 +39,8 @@ private final class CallRatingAlertContentNode: AlertContentNode {
|
|||||||
self.titleNode = ASTextNode()
|
self.titleNode = ASTextNode()
|
||||||
self.titleNode.maximumNumberOfLines = 3
|
self.titleNode.maximumNumberOfLines = 3
|
||||||
|
|
||||||
|
self.starContainerNode = ASDisplayNode()
|
||||||
|
|
||||||
var starNodes: [ASButtonNode] = []
|
var starNodes: [ASButtonNode] = []
|
||||||
for _ in 0 ..< 5 {
|
for _ in 0 ..< 5 {
|
||||||
starNodes.append(ASButtonNode())
|
starNodes.append(ASButtonNode())
|
||||||
@ -65,10 +68,12 @@ private final class CallRatingAlertContentNode: AlertContentNode {
|
|||||||
|
|
||||||
self.addSubnode(self.titleNode)
|
self.addSubnode(self.titleNode)
|
||||||
|
|
||||||
|
self.addSubnode(self.starContainerNode)
|
||||||
|
|
||||||
for node in self.starNodes {
|
for node in self.starNodes {
|
||||||
node.addTarget(self, action: #selector(self.starPressed(_:)), forControlEvents: .touchDown)
|
node.addTarget(self, action: #selector(self.starPressed(_:)), forControlEvents: .touchDown)
|
||||||
node.addTarget(self, action: #selector(self.starReleased(_:)), forControlEvents: .touchUpInside)
|
node.addTarget(self, action: #selector(self.starReleased(_:)), forControlEvents: .touchUpInside)
|
||||||
self.addSubnode(node)
|
self.starContainerNode.addSubnode(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.addSubnode(self.actionNodesSeparator)
|
self.addSubnode(self.actionNodesSeparator)
|
||||||
@ -88,6 +93,44 @@ private final class CallRatingAlertContentNode: AlertContentNode {
|
|||||||
self.disposable.dispose()
|
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) {
|
@objc func starPressed(_ sender: ASButtonNode) {
|
||||||
if let index = self.starNodes.firstIndex(of: sender) {
|
if let index = self.starNodes.firstIndex(of: sender) {
|
||||||
self.rating = index + 1
|
self.rating = index + 1
|
||||||
@ -182,9 +225,10 @@ private final class CallRatingAlertContentNode: AlertContentNode {
|
|||||||
|
|
||||||
let starSize = CGSize(width: 42.0, height: 38.0)
|
let starSize = CGSize(width: 42.0, height: 38.0)
|
||||||
let starsOrigin = floorToScreenPixels((resultWidth - starSize.width * 5.0) / 2.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 {
|
for i in 0 ..< self.starNodes.count {
|
||||||
let node = self.starNodes[i]
|
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
|
origin.y += titleSize.height
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ public final class AvailableReactions: Equatable, Codable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case hash
|
case newHash
|
||||||
case reactions
|
case reactions
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,14 +183,14 @@ public final class AvailableReactions: Equatable, Codable {
|
|||||||
public init(from decoder: Decoder) throws {
|
public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
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)
|
self.reactions = try container.decode([Reaction].self, forKey: .reactions)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
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)
|
try container.encode(self.reactions, forKey: .reactions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,6 +395,10 @@ public extension EnginePeer {
|
|||||||
var isVerified: Bool {
|
var isVerified: Bool {
|
||||||
return self._asPeer().isVerified
|
return self._asPeer().isVerified
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isPremium: Bool {
|
||||||
|
return self._asPeer().isPremium
|
||||||
|
}
|
||||||
|
|
||||||
var isService: Bool {
|
var isService: Bool {
|
||||||
if case let .user(peer) = self {
|
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 {
|
var isCopyProtectionEnabled: Bool {
|
||||||
switch self {
|
switch self {
|
||||||
case let group as TelegramGroup:
|
case let group as TelegramGroup:
|
||||||
|
@ -85,6 +85,7 @@ public enum PresentationResourceKey: Int32 {
|
|||||||
case chatListBadgeBackgroundPinned
|
case chatListBadgeBackgroundPinned
|
||||||
case chatListMutedIcon
|
case chatListMutedIcon
|
||||||
case chatListVerifiedIcon
|
case chatListVerifiedIcon
|
||||||
|
case chatListPremiumIcon
|
||||||
case chatListScamRegularIcon
|
case chatListScamRegularIcon
|
||||||
case chatListScamOutgoingIcon
|
case chatListScamOutgoingIcon
|
||||||
case chatListScamServiceIcon
|
case chatListScamServiceIcon
|
||||||
@ -165,6 +166,7 @@ public enum PresentationResourceKey: Int32 {
|
|||||||
case chatInputMediaPanelTrendingGifsIcon
|
case chatInputMediaPanelTrendingGifsIcon
|
||||||
case chatInputMediaPanelStickersModeIcon
|
case chatInputMediaPanelStickersModeIcon
|
||||||
case chatInputMediaPanelPremiumIcon
|
case chatInputMediaPanelPremiumIcon
|
||||||
|
case chatInputMediaStickerGridPremiumIcon
|
||||||
|
|
||||||
case chatInputButtonPanelButtonImage
|
case chatInputButtonPanelButtonImage
|
||||||
case chatInputButtonPanelButtonHighlightedImage
|
case chatInputButtonPanelButtonHighlightedImage
|
||||||
|
@ -294,13 +294,59 @@ public struct PresentationResourcesChat {
|
|||||||
return theme.image(PresentationResourceKey.chatInputMediaPanelPremiumIcon.rawValue, { theme in
|
return theme.image(PresentationResourceKey.chatInputMediaPanelPremiumIcon.rawValue, { theme in
|
||||||
return generateImage(CGSize(width: 44.0, height: 42.0), contextGenerator: { size, context in
|
return generateImage(CGSize(width: 44.0, height: 42.0), contextGenerator: { size, context in
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/PremiumIcon"), color: theme.chat.inputMediaPanel.panelIconColor) {
|
if let image = UIImage(bundleImageName: "Peer Info/PremiumIcon") {
|
||||||
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 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? {
|
public static func chatInputMediaPanelRecentStickersIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||||
return theme.image(PresentationResourceKey.chatInputMediaPanelRecentStickersIconImage.rawValue, { theme in
|
return theme.image(PresentationResourceKey.chatInputMediaPanelRecentStickersIconImage.rawValue, { theme in
|
||||||
return generateImage(CGSize(width: 42.0, height: 42.0), contextGenerator: { size, context 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()
|
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? {
|
public static func scamIcon(_ theme: PresentationTheme, strings: PresentationStrings, type: ScamIconType) -> UIImage? {
|
||||||
let key: PresentationResourceKey
|
let key: PresentationResourceKey
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"filename" : "premiumbadge_20.pdf",
|
"filename" : "premium_24 (2).pdf",
|
||||||
"idiom" : "universal"
|
"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" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"filename" : "addreactions_32.pdf",
|
"filename" : "addreactions2_32.pdf",
|
||||||
"idiom" : "universal"
|
"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
|
var hasPremium = false
|
||||||
if case let .user(user) = peer, user.flags.contains(.isPremium) {
|
if case let .user(user) = peer, user.isPremium {
|
||||||
hasPremium = true
|
hasPremium = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1079,6 +1079,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
strongSelf.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts()
|
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)
|
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
|
strongSelf.currentContextController = controller
|
||||||
|
|
||||||
controller.reactionSelected = { [weak controller] value, isLarge in
|
controller.reactionSelected = { [weak controller] value, isLarge in
|
||||||
@ -2347,15 +2353,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
guard let message = message else {
|
guard let message = message else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let context = strongSelf.context
|
let context = strongSelf.context
|
||||||
let chatPresentationInterfaceState = strongSelf.presentationInterfaceState
|
let chatPresentationInterfaceState = strongSelf.presentationInterfaceState
|
||||||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
|
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) {
|
if message.id.namespace == Namespaces.Message.Cloud, let _ = message.peers[message.id.peerId] as? TelegramChannel, !(message.media.first is TelegramMediaAction) {
|
||||||
isCopyLink = true
|
isCopyLink = true
|
||||||
} else {
|
} else if let forwardInfo = message.forwardInfo, let _ = forwardInfo.author as? TelegramChannel {
|
||||||
isCopyLink = false
|
isCopyLink = true
|
||||||
|
isForward = true
|
||||||
}
|
}
|
||||||
|
|
||||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
|
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
|
ActionSheetButtonItem(title: isCopyLink ? strongSelf.presentationData.strings.Conversation_ContextMenuCopyLink : strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
|
||||||
actionSheet?.dismissAnimated()
|
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?
|
var threadMessageId: MessageId?
|
||||||
|
|
||||||
if case let .replyThread(replyThreadMessage) = chatPresentationInterfaceState.chatLocation {
|
if case let .replyThread(replyThreadMessage) = chatPresentationInterfaceState.chatLocation {
|
||||||
threadMessageId = replyThreadMessage.messageId
|
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
|
|> map { result -> String? in
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -202,6 +202,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.isLoadingValue = isLoading
|
self.isLoadingValue = isLoading
|
||||||
if isLoading {
|
if isLoading {
|
||||||
self.historyNodeContainer.supernode?.insertSubnode(self.loadingNode, belowSubnode: self.historyNodeContainer)
|
self.historyNodeContainer.supernode?.insertSubnode(self.loadingNode, belowSubnode: self.historyNodeContainer)
|
||||||
|
self.loadingNode.isHidden = false
|
||||||
self.loadingNode.layer.removeAllAnimations()
|
self.loadingNode.layer.removeAllAnimations()
|
||||||
self.loadingNode.alpha = 1.0
|
self.loadingNode.alpha = 1.0
|
||||||
if animated {
|
if animated {
|
||||||
@ -215,12 +216,12 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.loadingNode.layer.removeAllAnimations()
|
strongSelf.loadingNode.layer.removeAllAnimations()
|
||||||
if completed {
|
if completed {
|
||||||
strongSelf.loadingNode.removeFromSupernode()
|
strongSelf.loadingNode.isHidden = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
self.loadingNode.removeFromSupernode()
|
self.loadingNode.isHidden = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -651,12 +652,12 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.emptyType = emptyType
|
self.emptyType = emptyType
|
||||||
if let emptyType = emptyType, self.emptyNode == nil {
|
if let emptyType = emptyType, self.emptyNode == nil {
|
||||||
let emptyNode = ChatEmptyNode(context: self.context, interaction: self.interfaceInteraction)
|
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
|
emptyNode.isHidden = self.restrictedNode != nil
|
||||||
self.emptyNode = emptyNode
|
self.emptyNode = emptyNode
|
||||||
self.historyNodeContainer.supernode?.insertSubnode(emptyNode, aboveSubnode: self.historyNodeContainer)
|
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 {
|
if animated {
|
||||||
emptyNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
emptyNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
}
|
}
|
||||||
@ -1211,7 +1212,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
emptyNodeInsets.bottom += inputPanelsHeight
|
emptyNodeInsets.bottom += inputPanelsHeight
|
||||||
self.validEmptyNodeLayout = (contentBounds.size, emptyNodeInsets)
|
self.validEmptyNodeLayout = (contentBounds.size, emptyNodeInsets)
|
||||||
if let emptyNode = self.emptyNode, let emptyType = self.emptyType {
|
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)
|
transition.updateFrame(node: emptyNode, frame: contentBounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -807,7 +807,25 @@ final class ChatEmptyNode: ASDisplayNode {
|
|||||||
self.addSubnode(self.backgroundNode)
|
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 {
|
if self.currentTheme !== interfaceState.theme || self.currentStrings !== interfaceState.strings {
|
||||||
self.currentTheme = interfaceState.theme
|
self.currentTheme = interfaceState.theme
|
||||||
self.currentStrings = interfaceState.strings
|
self.currentStrings = interfaceState.strings
|
||||||
@ -904,5 +922,9 @@ final class ChatEmptyNode: ASDisplayNode {
|
|||||||
|
|
||||||
transition.updateFrame(node: self.backgroundNode, frame: contentFrame)
|
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)
|
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)
|
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))
|
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
|
return strongSelf.context.account.postbox.transaction { transaction -> (Bool, Bool) in
|
||||||
let isStarred = getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
|
let isStarred = getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
|
||||||
var hasPremium = false
|
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
|
hasPremium = true
|
||||||
}
|
}
|
||||||
return (isStarred, hasPremium)
|
return (isStarred, hasPremium)
|
||||||
|
@ -320,7 +320,7 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
|
|||||||
lockBackground = UIImageView()
|
lockBackground = UIImageView()
|
||||||
lockBackground.clipsToBounds = true
|
lockBackground.clipsToBounds = true
|
||||||
lockBackground.isUserInteractionEnabled = false
|
lockBackground.isUserInteractionEnabled = false
|
||||||
lockBackground.image = UIImage(bundleImageName: "Premium/StickerIcon")
|
lockBackground.image = PresentationResourcesChat.chatInputMediaStickerGridPremiumIcon(item.theme)
|
||||||
self.lockBackground = lockBackground
|
self.lockBackground = lockBackground
|
||||||
|
|
||||||
self.view.addSubview(lockBackground)
|
self.view.addSubview(lockBackground)
|
||||||
|
@ -37,6 +37,14 @@ private enum ChatTitleIcon {
|
|||||||
case mute
|
case mute
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum ChatTitleCredibilityIcon {
|
||||||
|
case none
|
||||||
|
case fake
|
||||||
|
case scam
|
||||||
|
case verified
|
||||||
|
case premium
|
||||||
|
}
|
||||||
|
|
||||||
final class ChatTitleView: UIView, NavigationBarTitleView {
|
final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||||
private let account: Account
|
private let account: Account
|
||||||
|
|
||||||
@ -59,8 +67,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||||||
|
|
||||||
private var titleLeftIcon: ChatTitleIcon = .none
|
private var titleLeftIcon: ChatTitleIcon = .none
|
||||||
private var titleRightIcon: ChatTitleIcon = .none
|
private var titleRightIcon: ChatTitleIcon = .none
|
||||||
private var titleFakeIcon = false
|
private var titleCredibilityIcon: ChatTitleCredibilityIcon = .none
|
||||||
private var titleScamIcon = false
|
|
||||||
|
|
||||||
//private var networkStatusNode: ChatTitleNetworkStatusNode?
|
//private var networkStatusNode: ChatTitleNetworkStatusNode?
|
||||||
|
|
||||||
@ -106,8 +113,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||||||
var segments: [AnimatedCountLabelNode.Segment] = []
|
var segments: [AnimatedCountLabelNode.Segment] = []
|
||||||
var titleLeftIcon: ChatTitleIcon = .none
|
var titleLeftIcon: ChatTitleIcon = .none
|
||||||
var titleRightIcon: ChatTitleIcon = .none
|
var titleRightIcon: ChatTitleIcon = .none
|
||||||
var titleScamIcon = false
|
var titleCredibilityIcon: ChatTitleCredibilityIcon = .none
|
||||||
var titleFakeIcon = false
|
|
||||||
var isEnabled = true
|
var isEnabled = true
|
||||||
switch titleContent {
|
switch titleContent {
|
||||||
case let .peer(peerView, _, isScheduledMessages):
|
case let .peer(peerView, _, isScheduledMessages):
|
||||||
@ -134,9 +140,13 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if peer.isFake {
|
if peer.isFake {
|
||||||
titleFakeIcon = true
|
titleCredibilityIcon = .fake
|
||||||
} else if peer.isScam {
|
} 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 {
|
if peerView.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
@ -243,15 +253,20 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||||||
updated = true
|
updated = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if titleFakeIcon != self.titleFakeIcon {
|
if titleCredibilityIcon != self.titleCredibilityIcon {
|
||||||
self.titleFakeIcon = titleFakeIcon
|
self.titleCredibilityIcon = titleCredibilityIcon
|
||||||
self.titleCredibilityIconNode.image = titleFakeIcon ? PresentationResourcesChatList.fakeIcon(titleTheme, strings: self.strings, type: .regular) : nil
|
switch titleCredibilityIcon {
|
||||||
updated = true
|
case .none:
|
||||||
}
|
self.titleCredibilityIconNode.image = nil
|
||||||
|
case .fake:
|
||||||
if titleScamIcon != self.titleScamIcon {
|
self.titleCredibilityIconNode.image = PresentationResourcesChatList.fakeIcon(titleTheme, strings: self.strings, type: .regular)
|
||||||
self.titleScamIcon = titleScamIcon
|
case .scam:
|
||||||
self.titleCredibilityIconNode.image = titleScamIcon ? PresentationResourcesChatList.scamIcon(titleTheme, strings: self.strings, type: .regular) : nil
|
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
|
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)
|
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 {
|
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 {
|
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 {
|
} 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)
|
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)
|
self.titleLeftIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.minX, y: titleFrame.minY + 4.0), size: image.size)
|
||||||
}
|
}
|
||||||
if let image = self.titleCredibilityIconNode.image {
|
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 {
|
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 maskNode: ASImageNode
|
||||||
private let labelNode: ImmediateTextNode
|
private let labelNode: ImmediateTextNode
|
||||||
private let textNode: ImmediateTextNode
|
private let textNode: ImmediateTextNode
|
||||||
|
private let measureTextNode: ImmediateTextNode
|
||||||
private let bottomSeparatorNode: ASDisplayNode
|
private let bottomSeparatorNode: ASDisplayNode
|
||||||
|
|
||||||
private let expandBackgroundNode: ASImageNode
|
private let expandBackgroundNode: ASImageNode
|
||||||
@ -120,6 +121,10 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
|||||||
self.textNode.displaysAsynchronously = false
|
self.textNode.displaysAsynchronously = false
|
||||||
self.textNode.isUserInteractionEnabled = false
|
self.textNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
self.measureTextNode = ImmediateTextNode()
|
||||||
|
self.measureTextNode.displaysAsynchronously = false
|
||||||
|
self.measureTextNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
self.bottomSeparatorNode = ASDisplayNode()
|
self.bottomSeparatorNode = ASDisplayNode()
|
||||||
self.bottomSeparatorNode.isLayerBacked = true
|
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)
|
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 {
|
if let icon = item.icon {
|
||||||
let iconImage: UIImage?
|
let iconImage: UIImage?
|
||||||
switch icon {
|
switch icon {
|
||||||
@ -332,6 +305,55 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let additionalSideInset: CGFloat = !self.iconNode.isHidden ? 32.0 : 0.0
|
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 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 textLayout = self.textNode.updateLayoutInfo(CGSize(width: width - sideInset * 2.0 - additionalSideInset, height: .greatestFiniteMagnitude))
|
||||||
let textSize = textLayout.size
|
let textSize = textLayout.size
|
||||||
|
@ -2278,6 +2278,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
|
|
||||||
if themeUpdated || !initializedCredibilityIcon {
|
if themeUpdated || !initializedCredibilityIcon {
|
||||||
let image: UIImage?
|
let image: UIImage?
|
||||||
|
var expandedImage: UIImage?
|
||||||
if let peer = peer {
|
if let peer = peer {
|
||||||
self.initializedCredibilityIcon = true
|
self.initializedCredibilityIcon = true
|
||||||
if peer.isFake {
|
if peer.isFake {
|
||||||
@ -2297,6 +2298,36 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
} else {
|
} else {
|
||||||
image = nil
|
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 {
|
} else {
|
||||||
image = nil
|
image = nil
|
||||||
}
|
}
|
||||||
@ -2304,7 +2335,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
image = nil
|
image = nil
|
||||||
}
|
}
|
||||||
self.titleCredibilityIconNode.image = image
|
self.titleCredibilityIconNode.image = image
|
||||||
self.titleExpandedCredibilityIconNode.image = image
|
self.titleExpandedCredibilityIconNode.image = expandedImage ?? image
|
||||||
}
|
}
|
||||||
|
|
||||||
self.regularContentNode.alpha = state.isEditing ? 0.0 : 1.0
|
self.regularContentNode.alpha = state.isEditing ? 0.0 : 1.0
|
||||||
@ -2524,7 +2555,6 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
|
|
||||||
if let image = self.titleCredibilityIconNode.image {
|
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.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))
|
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 DebugSettingsUI
|
||||||
import TabBarUI
|
import TabBarUI
|
||||||
|
|
||||||
|
import TelegramCallsUI
|
||||||
|
|
||||||
public final class TelegramRootController: NavigationController {
|
public final class TelegramRootController: NavigationController {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
|
|
||||||
|
@ -445,7 +445,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
self.handleSendData(data: eventData)
|
self.handleSendData(data: eventData)
|
||||||
}
|
}
|
||||||
case "web_app_setup_main_button":
|
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
|
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] {
|
} 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 {
|
if var isVisible = json["is_visible"] as? Bool {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user