Various fixes

This commit is contained in:
Ilya Laktyushin 2024-06-26 13:54:54 +04:00
parent 29e31bdf8b
commit 022d626000
9 changed files with 232 additions and 195 deletions

View File

@ -1061,35 +1061,30 @@ public class AttachmentController: ViewController {
return self.buttons.contains(.standalone)
}
private var snapshotView: UIView?
public override var isMinimized: Bool {
didSet {
guard self.isMinimized != oldValue else {
return
}
if self.isMinimized {
if self.snapshotView == nil, let lastController = self.node.container.container.controllers.last, let snapshotView = lastController.view.snapshotView(afterScreenUpdates: false) {
snapshotView.isUserInteractionEnabled = false
self.snapshotView = snapshotView
lastController.view.addSubview(snapshotView)
}
} else {
if let snapshotView = self.snapshotView {
self.snapshotView = nil
Queue.mainQueue().after(0.5) {
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
snapshotView.removeFromSuperview()
})
}
}
}
if !self.node.isDismissing {
let transition: ContainedViewLayoutTransition = self.isMinimized ? .immediate : .animated(duration: 0.2, curve: .easeInOut)
transition.updateAlpha(node: self.node.dim, alpha: self.isMinimized ? 0.0 : 1.0)
}
}
}
// private var snapshotView: UIView?
// public override var isMinimized: Bool {
// didSet {
// guard self.isMinimized != oldValue else {
// return
// }
// if self.isMinimized {
// if self.snapshotView == nil, let lastController = self.node.container.container.controllers.last, let snapshotView = lastController.view.snapshotView(afterScreenUpdates: false) {
// snapshotView.isUserInteractionEnabled = false
// self.snapshotView = snapshotView
// lastController.view.addSubview(snapshotView)
// }
// } else {
// if let snapshotView = self.snapshotView {
// self.snapshotView = nil
// Queue.mainQueue().after(0.15) {
// snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
// snapshotView.removeFromSuperview()
// })
// }
// }
// }
// }
// }
public func updateSelectionCount(_ count: Int) {
self.node.updateSelectionCount(count, animated: false)

View File

@ -1567,6 +1567,7 @@ open class NavigationController: UINavigationController, ContainableController,
self.updateContainersNonReentrant(transition: transition)
}
viewController.isMinimized = true
self.filterController(viewController, animated: true)
minimizedContainer?.addController(viewController, transition: transition)
}
@ -1587,6 +1588,9 @@ open class NavigationController: UINavigationController, ContainableController,
var viewControllers = self.viewControllers
viewControllers.append(viewController)
self.setViewControllers(viewControllers, animated: false)
viewController.isMinimized = false
self.isMaximizing = false
if dismissed, let minimizedContainer = self.minimizedContainer {

View File

@ -723,15 +723,7 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
transition.updateTransformScale(layer: backgroundNode.layer, scale: 1.0)
}
}
for (_, priceNode) in strongSelf.priceNodes {
priceNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: 0.1)
if strongSelf.isExternalPreview {
ComponentTransition.immediate.setScale(layer: priceNode.layer, scale: 0.001)
transition.updateTransformScale(layer: priceNode.layer, scale: 1.0)
}
}
for (identifier, itemNode) in strongSelf.itemNodes {
if !strongSelf.isObscuredExternalPreview, let (transitionView, _, _) = strongSelf.getTransitionView(identifier) {
itemNode.animateFrom(transitionView, transition: transition)
@ -746,6 +738,15 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
}
}
for (_, priceNode) in strongSelf.priceNodes {
strongSelf.scrollNode.addSubnode(priceNode)
priceNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: 0.1)
if strongSelf.isExternalPreview {
ComponentTransition.immediate.setScale(layer: priceNode.layer, scale: 0.001)
transition.updateTransformScale(layer: priceNode.layer, scale: 1.0)
}
}
if let topNode = strongSelf.messageNodes?.first, !topNode.alpha.isZero {
topNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: 0.1)
transition.animatePositionAdditive(layer: topNode.layer, offset: CGPoint(x: 0.0, y: -30.0))

View File

@ -234,7 +234,7 @@ public class ChatMessageStarsMediaInfoNode: ASDisplayNode {
let textFont = Font.regular(fontSize)
let text: NSMutableAttributedString
if let peer = arguments.message.peers[arguments.message.id.peerId] as? TelegramChannel, peer.flags.contains(.isCreator) || peer.adminRights != nil {
if let peer = arguments.message.peers[arguments.message.id.peerId] as? TelegramChannel, peer.flags.contains(.isCreator) || peer.adminRights != nil, arguments.message.forwardInfo == nil {
let amountString = presentationStringsFormattedNumber(Int32(arguments.media.amount), arguments.presentationData.dateTimeFormat.groupingSeparator)
text = NSMutableAttributedString(string: "⭐️\(amountString)", font: textFont, textColor: .white)
} else {

View File

@ -48,6 +48,8 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
private let dimCoverNode: ASDisplayNode
private let shadowNode: ASImageNode
private var controllerView: UIView?
var tapped: (() -> Void)?
var highlighted: ((Bool) -> Void)?
var closeTapped: (() -> Void)?
@ -58,9 +60,8 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
transition.updateAlpha(node: self.dimCoverNode, alpha: self.isCovered ? 0.25 : 0.0)
}
}
var isExpanded = false
private var validLayout: (CGSize, UIEdgeInsets)?
private var validLayout: (CGSize, UIEdgeInsets, Bool)?
init(theme: PresentationTheme, strings: PresentationStrings, item: Item) {
self.theme = theme
@ -94,9 +95,15 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
applySmoothRoundedCorners(self.containerNode.layer)
self.shadowNode.image = shadowImage
self.addSubnode(self.containerNode)
self.containerNode.addSubnode(self.item.controller.displayNode)
if let snapshotView = self.item.controller.displayNode.view.snapshotView(afterScreenUpdates: false) {
self.controllerView = snapshotView
self.containerNode.view.addSubview(snapshotView)
} else {
self.controllerView = self.item.controller.displayNode.view
self.containerNode.view.addSubview(self.item.controller.displayNode.view)
}
self.addSubnode(self.headerNode)
self.addSubnode(self.dimCoverNode)
self.addSubnode(self.shadowNode)
@ -152,7 +159,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
}
@objc func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
guard let (_, insets) = self.validLayout else {
guard let (_, insets, _) = self.validLayout else {
return
}
switch recognizer.state {
@ -174,8 +181,8 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
}
}
func updateLayout(size: CGSize, insets: UIEdgeInsets, transition: ContainedViewLayoutTransition) {
self.validLayout = (size, insets)
func updateLayout(size: CGSize, insets: UIEdgeInsets, isExpanded: Bool, transition: ContainedViewLayoutTransition) {
self.validLayout = (size, insets, isExpanded)
var topInset = insets.top
if size.width < size.height {
@ -187,17 +194,22 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
self.shadowNode.frame = CGRect(origin: .zero, size: CGSize(width: size.width, height: size.height - topInset))
var navigationHeight: CGFloat = minimizedNavigationHeight
if !self.isExpanded {
if !isExpanded {
navigationHeight += insets.bottom
}
let headerFrame = CGRect(origin: .zero, size: CGSize(width: size.width, height: navigationHeight))
self.headerNode.update(size: size, insets: insets, transition: transition)
self.headerNode.update(size: size, insets: insets, isExpanded: isExpanded, transition: transition)
transition.updateFrame(node: self.headerNode, frame: headerFrame)
transition.updateFrame(node: self.dimCoverNode, frame: CGRect(origin: .zero, size: size))
if let controllerView = self.controllerView {
let controllerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - controllerView.bounds.size.width) / 2.0), y: 0.0), size: controllerView.bounds.size)
transition.updateFrame(view: controllerView, frame: controllerFrame)
}
if !self.isDismissed {
transition.updateAlpha(node: self.shadowNode, alpha: self.isExpanded ? 1.0 : 0.0)
transition.updateAlpha(node: self.shadowNode, alpha: isExpanded ? 1.0 : 0.0)
}
}
}
@ -225,6 +237,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
private var dismissingItemOffset: CGFloat?
private var currentTransition: Transition?
private var isApplyingTransition = false
private var validLayout: ContainerViewLayout?
public init(context: AccountContext, navigationController: NavigationController) {
@ -299,7 +312,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
let insets = layout.insets(options: [.statusBar])
let itemCount = self.items.count
let spacing = interitemSpacing(itemCount: itemCount, boundingSize: self.scrollView.bounds.size, insets: insets)
return max(0, min(Int(floor((y - additionalInsetTop) / spacing)), itemCount - 1))
return max(0, min(Int(floor((y - additionalInsetTop - insets.top) / spacing)), itemCount - 1))
}
public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
@ -463,7 +476,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
}
self.validLayout = layout
let bounds = CGRect(origin: .zero, size: layout.size)
containerTransition.updateFrame(view: self.blurView, frame: bounds)
@ -494,6 +507,10 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
transition.animatePosition(layer: self.bottomEdgeView.layer, from: self.bottomEdgeView.layer.position.offsetBy(dx: 0.0, dy: minimizedNavigationHeight + minimizedTopMargin), to: self.bottomEdgeView.layer.position)
}
if self.isApplyingTransition {
return
}
let insets = layout.insets(options: [.statusBar])
let itemInsets = UIEdgeInsets(top: insets.top, left: layout.safeInsets.left, bottom: insets.bottom, right: layout.safeInsets.right)
var topInset = insets.top
@ -569,7 +586,6 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
} else {
itemNode.layer.zPosition = 0.0
}
itemNode.isExpanded = self.isExpanded
if self.isExpanded {
let currentItemFrame = frameForIndex(index: index, size: layout.size, insets: itemInsets, itemCount: self.items.count, boundingSize: layout.size)
@ -652,7 +668,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
}
itemNode.bounds = CGRect(origin: .zero, size: itemFrame.size)
itemNode.updateLayout(size: layout.size, insets: itemInsets, transition: itemTransition)
itemNode.updateLayout(size: itemFrame.size, insets: itemInsets, isExpanded: self.isExpanded, transition: itemTransition)
if index == self.items.count - 1 && !self.isExpanded {
itemNode.setTitleControllers(self.items.map { $0.controller })
@ -677,6 +693,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
self.scrollView.isScrollEnabled = self.isExpanded
if let currentTransition = self.currentTransition {
self.isApplyingTransition = true
switch self.currentTransition {
case let .minimize(itemId):
guard let itemNode = self.itemNodes[itemId] else {
@ -692,7 +709,6 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
dimView.removeFromSuperview()
})
itemNode.animateIn()
var initialOffset = insets.top + itemNode.item.controller.minimizedTopEdgeOffset
@ -704,6 +720,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
}
transition.animatePosition(node: itemNode, from: CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0 + initialOffset), completion: { _ in
self.isApplyingTransition = false
if self.currentTransition == currentTransition {
self.currentTransition = nil
}
@ -724,6 +741,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
itemNode.animateOut()
transition.updateTransform(node: itemNode, transform: CATransform3DIdentity)
transition.updatePosition(node: itemNode, position: CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0 + topInset + self.scrollView.contentOffset.y), completion: { _ in
self.isApplyingTransition = false
if self.currentTransition == currentTransition {
self.currentTransition = nil
}
@ -750,6 +768,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
itemNode.animateOut()
transition.updateTransform(node: itemNode, transform: CATransform3DIdentity)
transition.updatePosition(node: itemNode, position: CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0 + topInset + self.scrollView.contentOffset.y), completion: { _ in
self.isApplyingTransition = false
if self.currentTransition == currentTransition {
self.currentTransition = nil
}
@ -766,6 +785,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
transition.updatePosition(node: dismissedItemNode, position: CGPoint(x: -layout.size.width, y: dismissedItemNode.position.y))
} else {
transition.updatePosition(node: dismissedItemNode, position: CGPoint(x: -layout.size.width, y: dismissedItemNode.position.y), completion: { _ in
self.isApplyingTransition = false
if self.currentTransition == currentTransition {
self.currentTransition = nil
}
@ -778,6 +798,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
case .dismissAll:
let dismissOffset = collapsedHeight(layout: layout)
transition.updatePosition(layer: self.bottomEdgeView.layer, position: self.bottomEdgeView.layer.position.offsetBy(dx: 0.0, dy: dismissOffset), completion: { _ in
self.isApplyingTransition = false
if self.currentTransition == currentTransition {
self.currentTransition = nil
}
@ -794,133 +815,3 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
return minimizedNavigationHeight + minimizedTopMargin + layout.intrinsicInsets.bottom
}
}
private let maxInteritemSpacing: CGFloat = 240.0
private let additionalInsetTop: CGFloat = 16.0
private let additionalInsetBottom: CGFloat = 0.0
private let zOffset: CGFloat = -60.0
private let perspectiveCorrection: CGFloat = -1.0 / 1000.0
private let maxRotationAngle: CGFloat = -CGFloat.pi / 2.2
private func angle(for origin: CGFloat, itemCount: Int, scrollBounds: CGRect, contentHeight: CGFloat?, insets: UIEdgeInsets) -> CGFloat {
var rotationAngle = rotationAngleAt0(itemCount: itemCount)
var contentOffset = scrollBounds.origin.y
if contentOffset < 0.0 {
contentOffset *= 2.0
}
var yOnScreen = origin - contentOffset - additionalInsetTop - insets.top
if yOnScreen < 0 {
yOnScreen = 0
} else if yOnScreen > scrollBounds.height {
yOnScreen = scrollBounds.height
}
let maxRotationVariance = maxRotationAngle - rotationAngleAt0(itemCount: itemCount)
rotationAngle += (maxRotationVariance / scrollBounds.height) * yOnScreen
return rotationAngle
}
private func final3dTransform(for origin: CGFloat, size: CGSize, contentHeight: CGFloat?, itemCount: Int, forcedAngle: CGFloat? = nil, additionalAngle: CGFloat? = nil, scrollBounds: CGRect, insets: UIEdgeInsets) -> CATransform3D {
var transform = CATransform3DIdentity
transform.m34 = perspectiveCorrection
let rotationAngle = forcedAngle ?? angle(for: origin, itemCount: itemCount, scrollBounds: scrollBounds, contentHeight: contentHeight, insets: insets)
var effectiveRotationAngle = rotationAngle
if let additionalAngle = additionalAngle {
effectiveRotationAngle += additionalAngle
}
let r = size.height / 2.0 + abs(zOffset / sin(rotationAngle))
let zTranslation = r * sin(rotationAngle)
let yTranslation: CGFloat = r * (1 - cos(rotationAngle))
let zTranslateTransform = CATransform3DTranslate(transform, 0.0, -yTranslation, zTranslation)
let rotateTransform = CATransform3DRotate(zTranslateTransform, effectiveRotationAngle, 1.0, 0.0, 0.0)
return rotateTransform
}
private func interitemSpacing(itemCount: Int, boundingSize: CGSize, insets: UIEdgeInsets) -> CGFloat {
var interitemSpacing = maxInteritemSpacing
if itemCount > 0 {
interitemSpacing = (boundingSize.height - additionalInsetTop - additionalInsetBottom - insets.top) / CGFloat(min(itemCount, 5))
}
return interitemSpacing
}
private func frameForIndex(index: Int, size: CGSize, insets: UIEdgeInsets, itemCount: Int, boundingSize: CGSize) -> CGRect {
let spacing = interitemSpacing(itemCount: itemCount, boundingSize: boundingSize, insets: insets)
let y = additionalInsetTop + insets.top + spacing * CGFloat(index)
let origin = CGPoint(x: insets.left, y: y)
return CGRect(origin: origin, size: CGSize(width: size.width - insets.left - insets.right, height: size.height))
}
private func rotationAngleAt0(itemCount: Int) -> CGFloat {
let multiplier: CGFloat = min(CGFloat(itemCount), 5.0) - 1.0
return -CGFloat.pi / 7.0 - CGFloat.pi / 7.0 * multiplier / 4.0
}
private class BlurView: UIVisualEffectView {
private func setup() {
for subview in self.subviews {
if subview.description.contains("VisualEffectSubview") {
subview.isHidden = true
}
}
if let sublayer = self.layer.sublayers?[0], let filters = sublayer.filters {
sublayer.backgroundColor = nil
sublayer.isOpaque = false
let allowedKeys: [String] = [
"gaussianBlur",
"colorSaturate"
]
sublayer.filters = filters.filter { filter in
guard let filter = filter as? NSObject else {
return true
}
let filterName = String(describing: filter)
if !allowedKeys.contains(filterName) {
return false
}
return true
}
}
}
override var effect: UIVisualEffect? {
get {
return super.effect
}
set {
super.effect = newValue
self.setup()
}
}
override func didAddSubview(_ subview: UIView) {
super.didAddSubview(subview)
self.setup()
}
}
private let shadowImage: UIImage? = {
return generateImage(CGSize(width: 1.0, height: 480.0), rotatedContext: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
let gradientColors = [UIColor.black.withAlphaComponent(0.0).cgColor, UIColor.black.withAlphaComponent(0.55).cgColor, UIColor.black.withAlphaComponent(0.55).cgColor] as CFArray
var locations: [CGFloat] = [0.0, 0.65, 1.0]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: bounds.height), options: [])
})
}()

View File

@ -57,8 +57,8 @@ final class MinimizedHeaderNode: ASDisplayNode {
var title: String? {
didSet {
if let (size, insets) = self.validLayout {
self.update(size: size, insets: insets, transition: .immediate)
if let (size, insets, isExpanded) = self.validLayout {
self.update(size: size, insets: insets, isExpanded: isExpanded, transition: .immediate)
}
}
}
@ -66,7 +66,7 @@ final class MinimizedHeaderNode: ASDisplayNode {
var requestClose: () -> Void = {}
var requestMaximize: () -> Void = {}
private var validLayout: (CGSize, UIEdgeInsets)?
private var validLayout: (CGSize, UIEdgeInsets, Bool)?
init(theme: NavigationControllerTheme, strings: PresentationStrings) {
self.theme = theme
@ -123,19 +123,22 @@ final class MinimizedHeaderNode: ASDisplayNode {
}
}
func update(size: CGSize, insets: UIEdgeInsets, transition: ContainedViewLayoutTransition) {
self.validLayout = (size, insets)
func update(size: CGSize, insets: UIEdgeInsets, isExpanded: Bool, transition: ContainedViewLayoutTransition) {
self.validLayout = (size, insets, isExpanded)
let headerHeight: CGFloat = 44.0
let titleSideInset: CGFloat = 56.0 + insets.left
var titleSideInset: CGFloat = 56.0
if !isExpanded {
titleSideInset += insets.left
}
self.minimizedTitleNode.attributedText = NSAttributedString(string: title ?? "", font: Font.bold(17.0), textColor: self.theme.navigationBar.primaryTextColor)
self.minimizedTitleNode.attributedText = NSAttributedString(string: self.title ?? "", font: Font.bold(17.0), textColor: self.theme.navigationBar.primaryTextColor)
let titleSize = self.minimizedTitleNode.updateLayout(CGSize(width: size.width - titleSideInset * 2.0, height: headerHeight))
let titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - titleSize.width) / 2.0), y: floorToScreenPixels((headerHeight - titleSize.height) / 2.0)), size: titleSize)
self.minimizedTitleNode.bounds = CGRect(origin: .zero, size: titleFrame.size)
transition.updatePosition(node: self.minimizedTitleNode, position: titleFrame.center)
transition.updateFrame(node: self.minimizedCloseButton, frame: CGRect(origin: CGPoint(x: insets.left, y: 0.0), size: CGSize(width: 44.0, height: 44.0)))
transition.updateFrame(node: self.minimizedCloseButton, frame: CGRect(origin: CGPoint(x: isExpanded ? 0.0 : insets.left, y: 0.0), size: CGSize(width: 44.0, height: 44.0)))
transition.updateFrame(node: self.minimizedBackgroundNode, frame: CGRect(origin: .zero, size: CGSize(width: size.width, height: 243.0)))
}

View File

@ -1,5 +1,6 @@
import Foundation
import UIKit
import Display
extension CATransform3D {
func interpolate(with other: CATransform3D, fraction: CGFloat) -> CATransform3D {
@ -50,3 +51,133 @@ extension CGRect {
return CGRect(origin: self.origin.interpolate(with: other.origin, fraction: fraction), size: self.size.interpolate(with: other.size, fraction: fraction))
}
}
private let maxInteritemSpacing: CGFloat = 240.0
let additionalInsetTop: CGFloat = 16.0
private let additionalInsetBottom: CGFloat = 0.0
private let zOffset: CGFloat = -60.0
private let perspectiveCorrection: CGFloat = -1.0 / 1000.0
private let maxRotationAngle: CGFloat = -CGFloat.pi / 2.2
func angle(for origin: CGFloat, itemCount: Int, scrollBounds: CGRect, contentHeight: CGFloat?, insets: UIEdgeInsets) -> CGFloat {
var rotationAngle = rotationAngleAt0(itemCount: itemCount)
var contentOffset = scrollBounds.origin.y
if contentOffset < 0.0 {
contentOffset *= 2.0
}
var yOnScreen = origin - contentOffset - additionalInsetTop - insets.top
if yOnScreen < 0 {
yOnScreen = 0
} else if yOnScreen > scrollBounds.height {
yOnScreen = scrollBounds.height
}
let maxRotationVariance = maxRotationAngle - rotationAngleAt0(itemCount: itemCount)
rotationAngle += (maxRotationVariance / scrollBounds.height) * yOnScreen
return rotationAngle
}
func final3dTransform(for origin: CGFloat, size: CGSize, contentHeight: CGFloat?, itemCount: Int, forcedAngle: CGFloat? = nil, additionalAngle: CGFloat? = nil, scrollBounds: CGRect, insets: UIEdgeInsets) -> CATransform3D {
var transform = CATransform3DIdentity
transform.m34 = perspectiveCorrection
let rotationAngle = forcedAngle ?? angle(for: origin, itemCount: itemCount, scrollBounds: scrollBounds, contentHeight: contentHeight, insets: insets)
var effectiveRotationAngle = rotationAngle
if let additionalAngle = additionalAngle {
effectiveRotationAngle += additionalAngle
}
let r = size.height / 2.0 + abs(zOffset / sin(rotationAngle))
let zTranslation = r * sin(rotationAngle)
let yTranslation: CGFloat = r * (1 - cos(rotationAngle))
let zTranslateTransform = CATransform3DTranslate(transform, 0.0, -yTranslation, zTranslation)
let rotateTransform = CATransform3DRotate(zTranslateTransform, effectiveRotationAngle, 1.0, 0.0, 0.0)
return rotateTransform
}
func interitemSpacing(itemCount: Int, boundingSize: CGSize, insets: UIEdgeInsets) -> CGFloat {
var interitemSpacing = maxInteritemSpacing
if itemCount > 0 {
interitemSpacing = (boundingSize.height - additionalInsetTop - additionalInsetBottom - insets.top) / CGFloat(min(itemCount, 5))
}
return interitemSpacing
}
func frameForIndex(index: Int, size: CGSize, insets: UIEdgeInsets, itemCount: Int, boundingSize: CGSize) -> CGRect {
let spacing = interitemSpacing(itemCount: itemCount, boundingSize: boundingSize, insets: insets)
let y = additionalInsetTop + insets.top + spacing * CGFloat(index)
let origin = CGPoint(x: insets.left, y: y)
return CGRect(origin: origin, size: CGSize(width: size.width - insets.left - insets.right, height: size.height))
}
func rotationAngleAt0(itemCount: Int) -> CGFloat {
let multiplier: CGFloat = min(CGFloat(itemCount), 5.0) - 1.0
return -CGFloat.pi / 7.0 - CGFloat.pi / 7.0 * multiplier / 4.0
}
final class BlurView: UIVisualEffectView {
private func setup() {
for subview in self.subviews {
if subview.description.contains("VisualEffectSubview") {
subview.isHidden = true
}
}
if let sublayer = self.layer.sublayers?[0], let filters = sublayer.filters {
sublayer.backgroundColor = nil
sublayer.isOpaque = false
let allowedKeys: [String] = [
"gaussianBlur",
"colorSaturate"
]
sublayer.filters = filters.filter { filter in
guard let filter = filter as? NSObject else {
return true
}
let filterName = String(describing: filter)
if !allowedKeys.contains(filterName) {
return false
}
return true
}
}
}
override var effect: UIVisualEffect? {
get {
return super.effect
}
set {
super.effect = newValue
self.setup()
}
}
override func didAddSubview(_ subview: UIView) {
super.didAddSubview(subview)
self.setup()
}
}
let shadowImage: UIImage? = {
return generateImage(CGSize(width: 1.0, height: 480.0), rotatedContext: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
let gradientColors = [UIColor.black.withAlphaComponent(0.0).cgColor, UIColor.black.withAlphaComponent(0.55).cgColor, UIColor.black.withAlphaComponent(0.55).cgColor] as CFArray
var locations: [CGFloat] = [0.0, 0.65, 1.0]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: bounds.height), options: [])
})
}()

View File

@ -519,6 +519,8 @@ public final class StarsWithdrawScreen: ViewControllerComponentContainer {
}
}
private let invalidAmountCharacters = CharacterSet.decimalDigits.inverted
private final class AmountFieldComponent: Component {
typealias EnvironmentType = Empty
@ -623,7 +625,16 @@ private final class AmountFieldComponent: Component {
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let newText = ((textField.text ?? "") as NSString).replacingCharacters(in: range, with: string)
if string.rangeOfCharacter(from: invalidAmountCharacters) != nil {
return false
}
var newText = ((textField.text ?? "") as NSString).replacingCharacters(in: range, with: string)
if newText == "0" || (newText.count > 1 && newText.hasPrefix("0")) {
newText.removeFirst()
textField.text = newText
self.textChanged(self.textField)
return false
}
if let component = self.component {
let amount: Int64?

View File

@ -2134,6 +2134,7 @@ func chatAvailableMessageActionsImpl(engine: TelegramEngine, accountPeerId: Peer
var disableDelete = false
var isCopyProtected = false
var isShareProtected = false
var isExternalShareProtected = false
var setTag = false
var commonTags: Set<MessageReaction.Reaction>?
@ -2191,7 +2192,7 @@ func chatAvailableMessageActionsImpl(engine: TelegramEngine, accountPeerId: Peer
if let invoice = media as? TelegramMediaInvoice, let _ = invoice.extendedMedia {
isShareProtected = true
} else if let _ = media as? TelegramMediaPaidContent {
isShareProtected = true
isExternalShareProtected = true
} else if let file = media as? TelegramMediaFile, file.isSticker {
for case let .Sticker(_, packReference, _) in file.attributes {
if let _ = packReference {
@ -2394,7 +2395,7 @@ func chatAvailableMessageActionsImpl(engine: TelegramEngine, accountPeerId: Peer
}
}
if !isShareProtected {
if !isShareProtected && !isExternalShareProtected {
optionsMap[id]!.insert(.externalShare)
}
}