Various fixes

This commit is contained in:
Ilya Laktyushin 2021-02-14 12:01:17 +04:00
parent f1d322a717
commit 3b155f9d52
32 changed files with 260 additions and 269 deletions

View File

@ -136,14 +136,8 @@ public class ActionSheetPeerItemNode: ActionSheetItemNode {
self.setNeedsLayout() self.setNeedsLayout()
} }
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0) let size = CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
self.button.frame = CGRect(origin: CGPoint(), size: size) self.button.frame = CGRect(origin: CGPoint(), size: size)
@ -160,8 +154,12 @@ public class ActionSheetPeerItemNode: ActionSheetItemNode {
} }
self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size) self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size)
self.updateInternalLayout(size)
return size
} }
@objc private func buttonPressed() { @objc private func buttonPressed() {
if let item = self.item { if let item = self.item {
item.action() item.action()

View File

@ -213,14 +213,8 @@ public class BotCheckoutPaymentMethodItemNode: ActionSheetItemNode {
self.setNeedsLayout() self.setNeedsLayout()
} }
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0) let size = CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
self.button.frame = CGRect(origin: CGPoint(), size: size) self.button.frame = CGRect(origin: CGPoint(), size: size)
@ -242,6 +236,9 @@ public class BotCheckoutPaymentMethodItemNode: ActionSheetItemNode {
if let image = self.checkNode.image { if let image = self.checkNode.image {
self.checkNode.frame = CGRect(origin: CGPoint(x: floor((44.0 - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size) self.checkNode.frame = CGRect(origin: CGPoint(x: floor((44.0 - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size)
} }
self.updateInternalLayout(size)
return size
} }
@objc func buttonPressed() { @objc func buttonPressed() {

View File

@ -190,15 +190,9 @@ public class BotCheckoutPaymentShippingOptionItemNode: ActionSheetItemNode {
self.setNeedsLayout() self.setNeedsLayout()
} }
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0) let size = CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
self.button.frame = CGRect(origin: CGPoint(), size: size) self.button.frame = CGRect(origin: CGPoint(), size: size)
var checkInset: CGFloat = 15.0 var checkInset: CGFloat = 15.0
@ -214,6 +208,9 @@ public class BotCheckoutPaymentShippingOptionItemNode: ActionSheetItemNode {
if let image = self.checkNode.image { if let image = self.checkNode.image {
self.checkNode.frame = CGRect(origin: CGPoint(x: floor((44.0 - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size) self.checkNode.frame = CGRect(origin: CGPoint(x: floor((44.0 - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size)
} }
self.updateInternalLayout(size)
return size
} }
@objc func buttonPressed() { @objc func buttonPressed() {

View File

@ -128,14 +128,13 @@ private final class DateSelectionActionSheetItemNode: ActionSheetItemNode {
self.pickerView.addTarget(self, action: #selector(self.datePickerUpdated), for: .valueChanged) self.pickerView.addTarget(self, action: #selector(self.datePickerUpdated), for: .valueChanged)
} }
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 216.0) let size = CGSize(width: constrainedSize.width, height: 216.0)
}
self.pickerView.frame = CGRect(origin: CGPoint(), size: size)
override func layout() {
super.layout()
self.pickerView.frame = CGRect(origin: CGPoint(), size: CGSize(width: self.bounds.size.width, height: 216.0)) self.updateInternalLayout(size)
return size
} }
@objc private func datePickerUpdated() { @objc private func datePickerUpdated() {

View File

@ -152,7 +152,7 @@ private final class DeleteChatPeerActionSheetItemNode: ActionSheetItemNode {
} }
} }
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let textSize = self.textNode.updateLayout(CGSize(width: constrainedSize.width - 20.0, height: .greatestFiniteMagnitude)) let textSize = self.textNode.updateLayout(CGSize(width: constrainedSize.width - 20.0, height: .greatestFiniteMagnitude))
let topInset: CGFloat = 16.0 let topInset: CGFloat = 16.0
@ -166,10 +166,7 @@ private final class DeleteChatPeerActionSheetItemNode: ActionSheetItemNode {
let size = CGSize(width: constrainedSize.width, height: topInset + avatarSize + textSpacing + textSize.height + bottomInset) let size = CGSize(width: constrainedSize.width, height: topInset + avatarSize + textSpacing + textSize.height + bottomInset)
self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size) self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size)
self.updateInternalLayout(size)
return size return size
} }
override func layout() {
super.layout()
}
} }

View File

@ -152,20 +152,17 @@ public class ActionSheetButtonNode: ActionSheetItemNode {
self.setNeedsLayout() self.setNeedsLayout()
} }
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0) let size = CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
self.button.frame = CGRect(origin: CGPoint(), size: size) self.button.frame = CGRect(origin: CGPoint(), size: size)
let labelSize = self.label.updateLayout(CGSize(width: max(1.0, size.width - 10.0), height: size.height)) let labelSize = self.label.updateLayout(CGSize(width: max(1.0, size.width - 10.0), height: size.height))
self.label.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - labelSize.width) / 2.0), y: floorToScreenPixels((size.height - labelSize.height) / 2.0)), size: labelSize) self.label.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - labelSize.width) / 2.0), y: floorToScreenPixels((size.height - labelSize.height) / 2.0)), size: labelSize)
self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size) self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size)
self.updateInternalLayout(size)
return size
} }
@objc func buttonPressed() { @objc func buttonPressed() {

View File

@ -136,15 +136,9 @@ public class ActionSheetCheckboxItemNode: ActionSheetItemNode {
self.setNeedsLayout() self.setNeedsLayout()
} }
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0) let size = CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
self.button.frame = CGRect(origin: CGPoint(), size: size) self.button.frame = CGRect(origin: CGPoint(), size: size)
var titleOrigin: CGFloat = 50.0 var titleOrigin: CGFloat = 50.0
@ -164,6 +158,9 @@ public class ActionSheetCheckboxItemNode: ActionSheetItemNode {
} }
self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size) self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size)
self.updateInternalLayout(size)
return size
} }
@objc func buttonPressed() { @objc func buttonPressed() {

View File

@ -61,7 +61,7 @@ final class ActionSheetControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.itemGroupsContainerNode = ActionSheetItemGroupsContainerNode(theme: self.theme) self.itemGroupsContainerNode = ActionSheetItemGroupsContainerNode(theme: self.theme)
super.init() super.init()
self.scrollView.delegate = self self.scrollView.delegate = self
self.addSubnode(self.scrollNode) self.addSubnode(self.scrollNode)
@ -78,6 +78,12 @@ final class ActionSheetControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.scrollNode.addSubnode(self.itemGroupsContainerNode) self.scrollNode.addSubnode(self.itemGroupsContainerNode)
self.updateTheme() self.updateTheme()
self.itemGroupsContainerNode.requestLayout = { [weak self] in
if let strongSelf = self, let layout = strongSelf.validLayout {
strongSelf.containerLayoutUpdated(layout, transition: .animated(duration: 0.2, curve: .easeInOut))
}
}
} }
func updateTheme() { func updateTheme() {
@ -107,9 +113,9 @@ final class ActionSheetControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.scrollView.frame = CGRect(origin: CGPoint(), size: layout.size) self.scrollView.frame = CGRect(origin: CGPoint(), size: layout.size)
self.dismissTapView.frame = CGRect(origin: CGPoint(), size: layout.size) self.dismissTapView.frame = CGRect(origin: CGPoint(), size: layout.size)
self.itemGroupsContainerNode.measure(CGSize(width: layout.size.width - containerInsets.left - containerInsets.right - insets.left - insets.right, height: layout.size.height - containerInsets.top - containerInsets.bottom - insets.top - insets.bottom)) let itemGroupsContainerSize = self.itemGroupsContainerNode.updateLayout(constrainedSize: CGSize(width: layout.size.width - containerInsets.left - containerInsets.right - insets.left - insets.right, height: layout.size.height - containerInsets.top - containerInsets.bottom - insets.top - insets.bottom), transition: transition)
if self.allowInputInset, let inputHeight = layout.inputHeight, inputHeight > 0.0, self.itemGroupsContainerNode.groupNodes.count > 1, let lastGroupHeight = self.itemGroupsContainerNode.groupNodes.last?.calculatedSize.height { if self.allowInputInset, let inputHeight = layout.inputHeight, inputHeight > 0.0, self.itemGroupsContainerNode.groupNodes.count > 1, let lastGroupHeight = self.itemGroupsContainerNode.groupNodes.last?.frame.height {
insets.bottom -= lastGroupHeight + containerInsets.bottom insets.bottom -= lastGroupHeight + containerInsets.bottom
} }
@ -117,8 +123,7 @@ final class ActionSheetControllerNode: ASDisplayNode, UIScrollViewDelegate {
if !self.allowInputInset { if !self.allowInputInset {
transition = .immediate transition = .immediate
} }
transition.updateFrame(node: self.itemGroupsContainerNode, frame: CGRect(origin: CGPoint(x: insets.left + containerInsets.left, y: layout.size.height - insets.bottom - containerInsets.bottom - self.itemGroupsContainerNode.calculatedSize.height), size: self.itemGroupsContainerNode.calculatedSize)) transition.updateFrame(node: self.itemGroupsContainerNode, frame: CGRect(origin: CGPoint(x: insets.left + containerInsets.left, y: layout.size.height - insets.bottom - containerInsets.bottom - itemGroupsContainerSize.height), size: itemGroupsContainerSize))
self.itemGroupsContainerNode.updateLayout(transition: transition)
self.updateScrollDimViews(size: layout.size, insets: insets, transition: transition) self.updateScrollDimViews(size: layout.size, insets: insets, transition: transition)
} }

View File

@ -15,7 +15,9 @@ final class ActionSheetItemGroupNode: ASDisplayNode, UIScrollViewDelegate {
private var itemNodes: [ActionSheetItemNode] = [] private var itemNodes: [ActionSheetItemNode] = []
private var leadingVisibleNodeCount: CGFloat = 100.0 private var leadingVisibleNodeCount: CGFloat = 100.0
private var validLayout: CGSize?
init(theme: ActionSheetControllerTheme) { init(theme: ActionSheetControllerTheme) {
self.theme = theme self.theme = theme
@ -81,45 +83,8 @@ final class ActionSheetItemGroupNode: ASDisplayNode, UIScrollViewDelegate {
self.leadingVisibleNodeCount = leadingVisibleNodeCount self.leadingVisibleNodeCount = leadingVisibleNodeCount
self.invalidateCalculatedLayout() self.invalidateCalculatedLayout()
} }
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
var itemNodesHeight: CGFloat = 0.0
var leadingVisibleNodeSize: CGFloat = 0.0
var i = 0
for node in self.itemNodes {
if CGFloat(0.0).isLess(than: itemNodesHeight), node.hasSeparator {
itemNodesHeight += UIScreenPixel
}
let size = node.measure(constrainedSize)
itemNodesHeight += size.height
if ceil(CGFloat(i)).isLessThanOrEqualTo(leadingVisibleNodeCount) {
if CGFloat(0.0).isLess(than: leadingVisibleNodeSize), node.hasSeparator {
leadingVisibleNodeSize += UIScreenPixel
}
let factor: CGFloat = min(1.0, leadingVisibleNodeCount - CGFloat(i))
leadingVisibleNodeSize += size.height * factor
}
i += 1
}
return CGSize(width: constrainedSize.width, height: min(floorToScreenPixels(itemNodesHeight), constrainedSize.height))
}
func updateLayout(transition: ContainedViewLayoutTransition) {
let scrollViewFrame = CGRect(origin: CGPoint(), size: self.calculatedSize)
var updateOffset = false
if !self.scrollNode.frame.equalTo(scrollViewFrame) {
self.scrollNode.frame = scrollViewFrame
updateOffset = true
}
let backgroundEffectViewFrame = CGRect(origin: CGPoint(), size: self.calculatedSize)
if !self.backgroundEffectView.frame.equalTo(backgroundEffectViewFrame) {
transition.updateFrame(view: self.backgroundEffectView, frame: backgroundEffectViewFrame)
}
func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
var itemNodesHeight: CGFloat = 0.0 var itemNodesHeight: CGFloat = 0.0
var leadingVisibleNodeSize: CGFloat = 0.0 var leadingVisibleNodeSize: CGFloat = 0.0
@ -130,24 +95,42 @@ final class ActionSheetItemGroupNode: ASDisplayNode, UIScrollViewDelegate {
itemNodesHeight += UIScreenPixel itemNodesHeight += UIScreenPixel
} }
previousHadSeparator = node.hasSeparator previousHadSeparator = node.hasSeparator
node.frame = CGRect(origin: CGPoint(x: 0.0, y: itemNodesHeight), size: node.calculatedSize)
itemNodesHeight += node.calculatedSize.height let nodeSize = node.updateLayout(constrainedSize: CGSize(width: constrainedSize.width, height: constrainedSize.height - itemNodesHeight), transition: transition)
node.frame = CGRect(origin: CGPoint(x: 0.0, y: itemNodesHeight), size: nodeSize)
itemNodesHeight += nodeSize.height
if CGFloat(i).isLessThanOrEqualTo(leadingVisibleNodeCount) { if CGFloat(i).isLessThanOrEqualTo(leadingVisibleNodeCount) {
if CGFloat(0.0).isLess(than: leadingVisibleNodeSize), node.hasSeparator { if CGFloat(0.0).isLess(than: leadingVisibleNodeSize), node.hasSeparator {
leadingVisibleNodeSize += UIScreenPixel leadingVisibleNodeSize += UIScreenPixel
} }
let factor: CGFloat = min(1.0, leadingVisibleNodeCount - CGFloat(i)) let factor: CGFloat = min(1.0, leadingVisibleNodeCount - CGFloat(i))
leadingVisibleNodeSize += node.calculatedSize.height * factor leadingVisibleNodeSize += nodeSize.height * factor
} }
i += 1 i += 1
} }
let scrollViewContentSize = CGSize(width: self.calculatedSize.width, height: itemNodesHeight) let size = CGSize(width: constrainedSize.width, height: min(floorToScreenPixels(itemNodesHeight), constrainedSize.height))
self.validLayout = size
let scrollViewFrame = CGRect(origin: CGPoint(), size: size)
var updateOffset = false
if !self.scrollNode.frame.equalTo(scrollViewFrame) {
self.scrollNode.frame = scrollViewFrame
updateOffset = true
}
let backgroundEffectViewFrame = CGRect(origin: CGPoint(), size: size)
if !self.backgroundEffectView.frame.equalTo(backgroundEffectViewFrame) {
transition.updateFrame(view: self.backgroundEffectView, frame: backgroundEffectViewFrame)
}
let scrollViewContentSize = CGSize(width: size.width, height: itemNodesHeight)
if !self.scrollNode.view.contentSize.equalTo(scrollViewContentSize) { if !self.scrollNode.view.contentSize.equalTo(scrollViewContentSize) {
self.scrollNode.view.contentSize = scrollViewContentSize self.scrollNode.view.contentSize = scrollViewContentSize
} }
let scrollViewContentInsets = UIEdgeInsets(top: max(0.0, self.calculatedSize.height - leadingVisibleNodeSize), left: 0.0, bottom: 0.0, right: 0.0) let scrollViewContentInsets = UIEdgeInsets(top: max(0.0, size.height - leadingVisibleNodeSize), left: 0.0, bottom: 0.0, right: 0.0)
if self.scrollNode.view.contentInset != scrollViewContentInsets { if self.scrollNode.view.contentInset != scrollViewContentInsets {
self.scrollNode.view.contentInset = scrollViewContentInsets self.scrollNode.view.contentInset = scrollViewContentInsets
@ -157,7 +140,9 @@ final class ActionSheetItemGroupNode: ASDisplayNode, UIScrollViewDelegate {
self.scrollNode.view.contentOffset = CGPoint(x: 0.0, y: -scrollViewContentInsets.top) self.scrollNode.view.contentOffset = CGPoint(x: 0.0, y: -scrollViewContentInsets.top)
} }
self.updateOverscroll(transition: transition) self.updateOverscroll(size: size, transition: transition)
return size
} }
private func currentVerticalOverscroll() -> CGFloat { private func currentVerticalOverscroll() -> CGFloat {
@ -180,11 +165,11 @@ final class ActionSheetItemGroupNode: ASDisplayNode, UIScrollViewDelegate {
return verticalOverscroll return verticalOverscroll
} }
private func updateOverscroll(transition: ContainedViewLayoutTransition) { private func updateOverscroll(size: CGSize, transition: ContainedViewLayoutTransition) {
let verticalOverscroll = self.currentVerticalOverscroll() let verticalOverscroll = self.currentVerticalOverscroll()
self.clippingNode.layer.sublayerTransform = CATransform3DMakeTranslation(0.0, min(0.0, verticalOverscroll), 0.0) self.clippingNode.layer.sublayerTransform = CATransform3DMakeTranslation(0.0, min(0.0, verticalOverscroll), 0.0)
let clippingNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: max(0.0, -verticalOverscroll)), size: CGSize(width: self.calculatedSize.width, height: self.calculatedSize.height - abs(verticalOverscroll))) let clippingNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: max(0.0, -verticalOverscroll)), size: CGSize(width: size.width, height: size.height - abs(verticalOverscroll)))
if !self.clippingNode.frame.equalTo(clippingNodeFrame) { if !self.clippingNode.frame.equalTo(clippingNodeFrame) {
transition.updateFrame(node: self.clippingNode, frame: clippingNodeFrame) transition.updateFrame(node: self.clippingNode, frame: clippingNodeFrame)
@ -195,7 +180,9 @@ final class ActionSheetItemGroupNode: ASDisplayNode, UIScrollViewDelegate {
} }
func scrollViewDidScroll(_ scrollView: UIScrollView) { func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.updateOverscroll(transition: .immediate) if let size = self.validLayout {
self.updateOverscroll(size: size, transition: .immediate)
}
} }
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

View File

@ -14,6 +14,8 @@ final class ActionSheetItemGroupsContainerNode: ASDisplayNode {
private var groups: [ActionSheetItemGroup] = [] private var groups: [ActionSheetItemGroup] = []
var groupNodes: [ActionSheetItemGroupNode] = [] var groupNodes: [ActionSheetItemGroupNode] = []
var requestLayout: (() -> Void)?
init(theme: ActionSheetControllerTheme) { init(theme: ActionSheetControllerTheme) {
self.theme = theme self.theme = theme
@ -30,46 +32,49 @@ final class ActionSheetItemGroupsContainerNode: ASDisplayNode {
for group in groups { for group in groups {
let groupNode = ActionSheetItemGroupNode(theme: self.theme) let groupNode = ActionSheetItemGroupNode(theme: self.theme)
groupNode.updateItemNodes(group.items.map({ $0.node(theme: self.theme) }), leadingVisibleNodeCount: group.leadingVisibleNodeCount ?? 1000.0) let itemNodes = group.items.map({ $0.node(theme: self.theme) })
for node in itemNodes {
node.requestLayout = { [weak self] in
self?.requestLayout?()
}
}
groupNode.updateItemNodes(itemNodes, leadingVisibleNodeCount: group.leadingVisibleNodeCount ?? 1000.0)
self.groupNodes.append(groupNode) self.groupNodes.append(groupNode)
self.addSubnode(groupNode) self.addSubnode(groupNode)
} }
} }
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
var groupsHeight: CGFloat = 0.0 var groupsHeight: CGFloat = 0.0
var calculatedSizes: [CGSize] = []
for groupNode in self.groupNodes.reversed() { for groupNode in self.groupNodes.reversed() {
if CGFloat(0.0).isLess(than: groupsHeight) { if CGFloat(0.0).isLess(than: groupsHeight) {
groupsHeight += groupSpacing groupsHeight += groupSpacing
} }
let size = groupNode.measure(CGSize(width: constrainedSize.width, height: max(0.0, constrainedSize.height - groupsHeight))) let size = groupNode.updateLayout(constrainedSize: CGSize(width: constrainedSize.width, height: max(0.0, constrainedSize.height - groupsHeight)), transition: transition)
calculatedSizes.insert(size, at: 0)
groupsHeight += size.height groupsHeight += size.height
} }
return CGSize(width: constrainedSize.width, height: min(groupsHeight, constrainedSize.height)) var itemGroupsHeight: CGFloat = 0.0
}
func updateLayout(transition: ContainedViewLayoutTransition) {
var groupsHeight: CGFloat = 0.0
for i in 0 ..< self.groupNodes.count { for i in 0 ..< self.groupNodes.count {
let groupNode = self.groupNodes[i] let groupNode = self.groupNodes[i]
let size = groupNode.calculatedSize let size = calculatedSizes[i]
if i != 0 { if i != 0 {
groupsHeight += groupSpacing itemGroupsHeight += groupSpacing
transition.updateFrame(view: self.groupNodes[i - 1].trailingDimView, frame: CGRect(x: 0.0, y: groupNodes[i - 1].bounds.size.height, width: size.width, height: groupSpacing)) transition.updateFrame(view: self.groupNodes[i - 1].trailingDimView, frame: CGRect(x: 0.0, y: groupNodes[i - 1].bounds.size.height, width: size.width, height: groupSpacing))
} }
transition.updateFrame(node: groupNode, frame: CGRect(origin: CGPoint(x: 0.0, y: itemGroupsHeight), size: size))
groupNode.updateLayout(transition: transition)
transition.updateFrame(node: groupNode, frame: CGRect(origin: CGPoint(x: 0.0, y: groupsHeight), size: size))
transition.updateFrame(view: groupNode.trailingDimView, frame: CGRect()) transition.updateFrame(view: groupNode.trailingDimView, frame: CGRect())
groupsHeight += size.height itemGroupsHeight += size.height
} }
return CGSize(width: constrainedSize.width, height: min(groupsHeight, constrainedSize.height))
} }
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

View File

@ -26,13 +26,15 @@ open class ActionSheetItemNode: ASDisplayNode {
self.addSubnode(self.overflowSeparatorNode) self.addSubnode(self.overflowSeparatorNode)
} }
open override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { open func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0) let size = CGSize(width: constrainedSize.width, height: 57.0)
self.updateInternalLayout(size)
return size
} }
open override func layout() { public func updateInternalLayout(_ calculatedSize: CGSize) {
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: self.calculatedSize) self.backgroundNode.frame = CGRect(origin: CGPoint(), size: calculatedSize)
self.overflowSeparatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: self.calculatedSize.height), size: CGSize(width: self.calculatedSize.width, height: UIScreenPixel)) self.overflowSeparatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: calculatedSize.height), size: CGSize(width: calculatedSize.width, height: UIScreenPixel))
self.overflowSeparatorNode.isHidden = !self.hasSeparator self.overflowSeparatorNode.isHidden = !self.hasSeparator
} }
} }

View File

@ -103,15 +103,9 @@ public class ActionSheetSwitchNode: ActionSheetItemNode {
self.setNeedsLayout() self.setNeedsLayout()
} }
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0) let size = CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
self.button.frame = CGRect(origin: CGPoint(), size: size) self.button.frame = CGRect(origin: CGPoint(), size: size)
let labelSize = self.label.updateLayout(CGSize(width: max(1.0, size.width - 51.0 - 16.0 * 2.0), height: size.height)) let labelSize = self.label.updateLayout(CGSize(width: max(1.0, size.width - 51.0 - 16.0 * 2.0), height: size.height))
@ -121,6 +115,9 @@ public class ActionSheetSwitchNode: ActionSheetItemNode {
self.switchNode.frame = CGRect(origin: CGPoint(x: size.width - 16.0 - switchSize.width, y: floor((size.height - switchSize.height) / 2.0)), size: switchSize) self.switchNode.frame = CGRect(origin: CGPoint(x: size.width - 16.0 - switchSize.width, y: floor((size.height - switchSize.height) / 2.0)), size: switchSize)
self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size) self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size)
self.updateInternalLayout(size)
return size
} }
@objc func buttonPressed() { @objc func buttonPressed() {

View File

@ -69,19 +69,15 @@ public class ActionSheetTextNode: ActionSheetItemNode {
self.setNeedsLayout() self.setNeedsLayout()
} }
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let labelSize = self.label.updateLayout(CGSize(width: max(1.0, constrainedSize.width - 20.0), height: constrainedSize.height)) let labelSize = self.label.updateLayout(CGSize(width: max(1.0, constrainedSize.width - 20.0), height: constrainedSize.height))
return CGSize(width: constrainedSize.width, height: max(57.0, labelSize.height + 32.0)) let size = CGSize(width: constrainedSize.width, height: max(57.0, labelSize.height + 32.0))
}
public override func layout() {
super.layout()
let size = self.bounds.size
let labelSize = self.label.updateLayout(CGSize(width: max(1.0, size.width - 20.0), height: size.height))
self.label.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - labelSize.width) / 2.0), y: floorToScreenPixels((size.height - labelSize.height) / 2.0)), size: labelSize) self.label.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - labelSize.width) / 2.0), y: floorToScreenPixels((size.height - labelSize.height) / 2.0)), size: labelSize)
self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size) self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size)
self.updateInternalLayout(size)
return size
} }
} }

View File

@ -585,8 +585,10 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId, ad
} else { } else {
isGroup = true isGroup = true
} }
let controller = InviteLinkQRCodeController(context: context, invite: invite, isGroup: isGroup) Queue.mainQueue().after(0.2) {
presentControllerImpl?(controller, nil) let controller = InviteLinkQRCodeController(context: context, invite: invite, isGroup: isGroup)
presentControllerImpl?(controller, nil)
}
}) })
}))) })))
@ -727,15 +729,21 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId, ad
timer.start() timer.start()
let previousRevokedInvites = Atomic<PeerExportedInvitationsState?>(value: nil) let previousRevokedInvites = Atomic<PeerExportedInvitationsState?>(value: nil)
let previousCreators = Atomic<[ExportedInvitationCreator]?>(value: nil)
let signal = combineLatest(context.sharedContext.presentationData, peerView, importersContext, importersState.get(), invitesContext.state, revokedInvitesContext.state, creators, timerPromise.get()) let signal = combineLatest(context.sharedContext.presentationData, peerView, importersContext, importersState.get(), invitesContext.state, revokedInvitesContext.state, creators, timerPromise.get())
|> deliverOnMainQueue |> deliverOnMainQueue
|> map { presentationData, view, importersContext, importers, invites, revokedInvites, creators, tick -> (ItemListControllerState, (ItemListNodeState, Any)) in |> map { presentationData, view, importersContext, importers, invites, revokedInvites, creators, tick -> (ItemListControllerState, (ItemListNodeState, Any)) in
let previousRevokedInvites = previousRevokedInvites.swap(invites) let previousRevokedInvites = previousRevokedInvites.swap(invites)
let previousCreators = previousCreators.swap(creators)
var crossfade = false var crossfade = false
if (previousRevokedInvites?.hasLoadedOnce ?? false) != (revokedInvites.hasLoadedOnce) { if (previousRevokedInvites?.hasLoadedOnce ?? false) != (revokedInvites.hasLoadedOnce) {
crossfade = true crossfade = true
} }
if (previousCreators?.count ?? 0) != creators.count {
crossfade = true
}
let title: ItemListControllerTitle let title: ItemListControllerTitle
if let admin = admin, let peer = admin.peer.peer { if let admin = admin, let peer = admin.peer.peer {

View File

@ -45,6 +45,8 @@ private struct InviteLinkViewTransaction {
let insertions: [ListViewInsertItem] let insertions: [ListViewInsertItem]
let updates: [ListViewUpdateItem] let updates: [ListViewUpdateItem]
let isLoading: Bool let isLoading: Bool
let animated: Bool
let crossfade: Bool
} }
private enum InviteLinkViewEntryId: Hashable { private enum InviteLinkViewEntryId: Hashable {
@ -195,14 +197,14 @@ private enum InviteLinkViewEntry: Comparable, Identifiable {
} }
} }
private func preparedTransition(from fromEntries: [InviteLinkViewEntry], to toEntries: [InviteLinkViewEntry], isLoading: Bool, account: Account, presentationData: PresentationData, interaction: InviteLinkViewInteraction) -> InviteLinkViewTransaction { private func preparedTransition(from fromEntries: [InviteLinkViewEntry], to toEntries: [InviteLinkViewEntry], isLoading: Bool, animated: Bool, crossfade: Bool, account: Account, presentationData: PresentationData, interaction: InviteLinkViewInteraction) -> InviteLinkViewTransaction {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData, interaction: interaction), directionHint: nil) } let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData, interaction: interaction), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData, interaction: interaction), directionHint: nil) } let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData, interaction: interaction), directionHint: nil) }
return InviteLinkViewTransaction(deletions: deletions, insertions: insertions, updates: updates, isLoading: isLoading) return InviteLinkViewTransaction(deletions: deletions, insertions: insertions, updates: updates, isLoading: isLoading, animated: animated, crossfade: crossfade)
} }
private let titleFont = Font.bold(17.0) private let titleFont = Font.bold(17.0)
@ -535,6 +537,8 @@ public final class InviteLinkViewController: ViewController {
}) })
let previousEntries = Atomic<[InviteLinkViewEntry]?>(value: nil) let previousEntries = Atomic<[InviteLinkViewEntry]?>(value: nil)
let previousCount = Atomic<Int32?>(value: nil)
let previousLoading = Atomic<Bool?>(value: nil)
let creatorPeer = context.account.postbox.loadedPeerWithId(invite.adminId) let creatorPeer = context.account.postbox.loadedPeerWithId(invite.adminId)
self.disposable = (combineLatest(self.presentationDataPromise.get(), self.importersContext.state, creatorPeer) self.disposable = (combineLatest(self.presentationDataPromise.get(), self.importersContext.state, creatorPeer)
@ -561,13 +565,20 @@ public final class InviteLinkViewController: ViewController {
entries.append(.importerHeader(presentationData.theme, presentationData.strings.InviteLink_PeopleJoined(Int32(state.count)).uppercased(), subtitle, subtitleExpired)) entries.append(.importerHeader(presentationData.theme, presentationData.strings.InviteLink_PeopleJoined(Int32(state.count)).uppercased(), subtitle, subtitleExpired))
} }
let count: Int32
let loading: Bool
var index: Int32 = 0 var index: Int32 = 0
if state.importers.isEmpty && state.isLoadingMore { if state.importers.isEmpty && state.isLoadingMore {
count = min(4, state.count)
loading = true
let fakeUser = TelegramUser(id: PeerId(namespace: -1, id: 0), accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) let fakeUser = TelegramUser(id: PeerId(namespace: -1, id: 0), accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
for i in 0 ..< min(4, state.count) { for i in 0 ..< count {
entries.append(.importer(Int32(i), presentationData.theme, presentationData.dateTimeFormat, fakeUser, 0, true)) entries.append(.importer(Int32(i), presentationData.theme, presentationData.dateTimeFormat, fakeUser, 0, true))
} }
} else { } else {
count = min(4, Int32(state.importers.count))
loading = false
for importer in state.importers { for importer in state.importers {
if let peer = importer.peer.peer { if let peer = importer.peer.peer {
entries.append(.importer(index, presentationData.theme, presentationData.dateTimeFormat, peer, importer.date, false)) entries.append(.importer(index, presentationData.theme, presentationData.dateTimeFormat, peer, importer.date, false))
@ -576,9 +587,21 @@ public final class InviteLinkViewController: ViewController {
} }
} }
let previousCount = previousCount.swap(count)
let previousLoading = previousLoading.swap(loading)
var animated = false
var crossfade = false
if let previousCount = previousCount, let previousLoading = previousLoading {
if (previousCount == count || previousCount >= 4) && previousLoading && !loading {
crossfade = true
} else if previousCount < 4 && previousCount != count && !loading {
animated = true
}
}
let previousEntries = previousEntries.swap(entries) let previousEntries = previousEntries.swap(entries)
let transition = preparedTransition(from: previousEntries ?? [], to: entries, isLoading: false, account: context.account, presentationData: presentationData, interaction: strongSelf.interaction!) let transition = preparedTransition(from: previousEntries ?? [], to: entries, isLoading: false, animated: animated, crossfade: crossfade, account: context.account, presentationData: presentationData, interaction: strongSelf.interaction!)
strongSelf.enqueueTransition(transition) strongSelf.enqueueTransition(transition)
} }
}) })
@ -700,7 +723,11 @@ public final class InviteLinkViewController: ViewController {
} }
self.enqueuedTransitions.remove(at: 0) self.enqueuedTransitions.remove(at: 0)
self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: ListViewDeleteAndInsertOptions(), updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { _ in var options = ListViewDeleteAndInsertOptions()
if transition.animated {
options.insert(.AnimateInsertion)
}
self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { _ in
}) })
} }

View File

@ -195,7 +195,7 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
self.offsetContainerNode = ASDisplayNode() self.offsetContainerNode = ASDisplayNode()
self.iconBackgroundNode = ASImageNode() self.iconBackgroundNode = ASDisplayNode()
self.iconBackgroundNode.setLayerBlock { () -> CALayer in self.iconBackgroundNode.setLayerBlock { () -> CALayer in
return CAShapeLayer() return CAShapeLayer()
} }

View File

@ -163,19 +163,13 @@ private final class OpenInActionSheetItemNode: ActionSheetItemNode {
} }
} }
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 148.0) let size = CGSize(width: constrainedSize.width, height: 148.0)
}
let titleSize = self.titleNode.measure(size)
override func layout() { self.titleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 16.0), size: CGSize(width: size.width, height: titleSize.height))
super.layout()
let bounds = self.bounds self.scrollNode.frame = CGRect(origin: CGPoint(x: 0, y: 36.0), size: CGSize(width: size.width, height: size.height - 36.0))
let titleSize = self.titleNode.measure(bounds.size)
self.titleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 16.0), size: CGSize(width: bounds.size.width, height: titleSize.height))
self.scrollNode.frame = CGRect(origin: CGPoint(x: 0, y: 36.0), size: CGSize(width: bounds.size.width, height: bounds.height - 36.0))
let nodeInset: CGFloat = 2.0 let nodeInset: CGFloat = 2.0
let nodeSize = CGSize(width: 80.0, height: 112.0) let nodeSize = CGSize(width: 80.0, height: 112.0)
@ -192,6 +186,9 @@ private final class OpenInActionSheetItemNode: ActionSheetItemNode {
self.scrollNode.view.contentSize = contentSize self.scrollNode.view.contentSize = contentSize
} }
} }
self.updateInternalLayout(size)
return size
} }
} }

View File

@ -87,7 +87,7 @@ private final class ChannelDiscussionGroupActionSheetItemNode: ActionSheetItemNo
self.textNode.attributedText = attributedText self.textNode.attributedText = attributedText
} }
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let textSize = self.textNode.updateLayout(CGSize(width: constrainedSize.width - 20.0, height: .greatestFiniteMagnitude)) let textSize = self.textNode.updateLayout(CGSize(width: constrainedSize.width - 20.0, height: .greatestFiniteMagnitude))
let topInset: CGFloat = 16.0 let topInset: CGFloat = 16.0
@ -105,10 +105,9 @@ private final class ChannelDiscussionGroupActionSheetItemNode: ActionSheetItemNo
self.textNode.frame = CGRect(origin: CGPoint(x: floor((constrainedSize.width - textSize.width) / 2.0), y: topInset + avatarSize + textSpacing), size: textSize) self.textNode.frame = CGRect(origin: CGPoint(x: floor((constrainedSize.width - textSize.width) / 2.0), y: topInset + avatarSize + textSpacing), size: textSize)
return CGSize(width: constrainedSize.width, height: topInset + avatarSize + textSpacing + textSize.height + bottomInset) let size = CGSize(width: constrainedSize.width, height: topInset + avatarSize + textSpacing + textSize.height + bottomInset)
}
self.updateInternalLayout(size)
override func layout() { return size
super.layout()
} }
} }

View File

@ -111,14 +111,13 @@ private final class PeerBanTimeoutActionSheetItemNode: ActionSheetItemNode {
self.pickerView.addTarget(self, action: #selector(self.datePickerUpdated), for: .valueChanged) self.pickerView.addTarget(self, action: #selector(self.datePickerUpdated), for: .valueChanged)
} }
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 216.0) let size = CGSize(width: constrainedSize.width, height: 216.0)
}
override func layout() {
super.layout()
self.pickerView.frame = CGRect(origin: CGPoint(), size: CGSize(width: self.bounds.size.width, height: 216.0)) self.pickerView.frame = CGRect(origin: CGPoint(), size: size)
self.updateInternalLayout(size)
return size
} }
@objc private func datePickerUpdated() { @objc private func datePickerUpdated() {

View File

@ -152,11 +152,11 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
case .copyright: case .copyright:
reportReason = .copyright reportReason = .copyright
case .other: case .other:
break reportReason = .custom
} }
if let reportReason = reportReason { if let reportReason = reportReason {
var passthrough = passthrough var passthrough = passthrough
if case .fake = reportReason { if [.fake, .custom].contains(reportReason) {
passthrough = false passthrough = false
} }
switch subject { switch subject {
@ -169,7 +169,7 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
if let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") { if let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") {
present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), nil) present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), nil)
} }
completion(reportReason, true) completion(nil, false)
}) })
} }
case let .messages(messageIds): case let .messages(messageIds):
@ -181,7 +181,7 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
if let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") { if let path = getAppBundle().path(forResource: "PoliceCar", ofType: "tgs") {
present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), nil) present(UndoOverlayController(presentationData: presentationData, content: .emoji(path: path, text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return false }), nil)
} }
completion(reportReason, true) completion(nil, false)
}) })
} }
} }

View File

@ -242,14 +242,8 @@ private final class ProxyServerInfoItemNode: ActionSheetItemNode {
self.setNeedsLayout() self.setNeedsLayout()
} }
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 36.0 * CGFloat(self.fieldNodes.count) + 12.0) let size = CGSize(width: constrainedSize.width, height: 36.0 * CGFloat(self.fieldNodes.count) + 12.0)
}
override func layout() {
super.layout()
let size = self.bounds.size
var offset: CGFloat = 15.0 var offset: CGFloat = 15.0
for (lhs, rhs) in self.fieldNodes { for (lhs, rhs) in self.fieldNodes {
@ -261,6 +255,9 @@ private final class ProxyServerInfoItemNode: ActionSheetItemNode {
offset += 36.0 offset += 36.0
} }
self.updateInternalLayout(size)
return size
} }
} }
@ -360,14 +357,8 @@ private final class ProxyServerActionItemNode: ActionSheetItemNode {
} }
} }
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0) let size = CGSize(width: constrainedSize.width, height: 57.0)
}
override func layout() {
super.layout()
let size = self.bounds.size
self.buttonNode.frame = CGRect(origin: CGPoint(), size: size) self.buttonNode.frame = CGRect(origin: CGPoint(), size: size)
@ -376,8 +367,11 @@ private final class ProxyServerActionItemNode: ActionSheetItemNode {
let activitySize = self.activityIndicator.measure(CGSize(width: 100.0, height: 100.0)) let activitySize = self.activityIndicator.measure(CGSize(width: 100.0, height: 100.0))
self.titleNode.frame = titleFrame self.titleNode.frame = titleFrame
self.activityIndicator.frame = CGRect(origin: CGPoint(x: 14.0, y: titleFrame.minY - 0.0), size: activitySize) self.activityIndicator.frame = CGRect(origin: CGPoint(x: 14.0, y: titleFrame.minY - 0.0), size: activitySize)
self.updateInternalLayout(size)
return size
} }
@objc private func buttonPressed() { @objc private func buttonPressed() {
let proxyServerSettings = self.server let proxyServerSettings = self.server
let _ = (self.accountManager.transaction { transaction -> ProxySettings in let _ = (self.accountManager.transaction { transaction -> ProxySettings in

View File

@ -115,14 +115,13 @@ private final class ThemeAutoNightTimeSelectionActionSheetItemNode: ActionSheetI
self.pickerView.addTarget(self, action: #selector(self.datePickerUpdated), for: .valueChanged) self.pickerView.addTarget(self, action: #selector(self.datePickerUpdated), for: .valueChanged)
} }
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 216.0) let size = CGSize(width: constrainedSize.width, height: 216.0)
}
override func layout() {
super.layout()
self.pickerView.frame = CGRect(origin: CGPoint(), size: CGSize(width: self.bounds.size.width, height: 216.0)) self.pickerView.frame = CGRect(origin: CGPoint(), size: size)
self.updateInternalLayout(size)
return size
} }
@objc private func datePickerUpdated() { @objc private func datePickerUpdated() {

View File

@ -112,14 +112,8 @@ public class LocationBroadcastActionSheetItemNode: ActionSheetItemNode {
self.setNeedsLayout() self.setNeedsLayout()
} }
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0) let size = CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
self.button.frame = CGRect(origin: CGPoint(), size: size) self.button.frame = CGRect(origin: CGPoint(), size: size)
@ -133,6 +127,9 @@ public class LocationBroadcastActionSheetItemNode: ActionSheetItemNode {
let timerSize = CGSize(width: 28.0, height: 28.0) let timerSize = CGSize(width: 28.0, height: 28.0)
self.timerNode.frame = CGRect(origin: CGPoint(x: size.width - 16.0 - timerSize.width, y: floorToScreenPixels((size.height - timerSize.height) / 2.0)), size: timerSize) self.timerNode.frame = CGRect(origin: CGPoint(x: size.width - 16.0 - timerSize.width, y: floorToScreenPixels((size.height - timerSize.height) / 2.0)), size: timerSize)
self.updateInternalLayout(size)
return size
} }
@objc func buttonPressed() { @objc func buttonPressed() {

View File

@ -136,14 +136,8 @@ public class CallRouteActionSheetItemNode: ActionSheetItemNode {
self.setNeedsLayout() self.setNeedsLayout()
} }
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0) let size = CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
self.button.frame = CGRect(origin: CGPoint(), size: size) self.button.frame = CGRect(origin: CGPoint(), size: size)
@ -157,6 +151,9 @@ public class CallRouteActionSheetItemNode: ActionSheetItemNode {
if let image = self.checkNode.image { if let image = self.checkNode.image {
self.checkNode.frame = CGRect(origin: CGPoint(x: size.width - image.size.width - 13.0, y: floor((size.height - image.size.height) / 2.0)), size: image.size) self.checkNode.frame = CGRect(origin: CGPoint(x: size.width - image.size.width - 13.0, y: floor((size.height - image.size.height) / 2.0)), size: image.size)
} }
self.updateInternalLayout(size)
return size
} }
@objc func buttonPressed() { @objc func buttonPressed() {

View File

@ -39,7 +39,7 @@ public func dismissServerProvidedSuggestion(account: Account, suggestion: Server
public enum PeerSpecificServerProvidedSuggestion: String { public enum PeerSpecificServerProvidedSuggestion: String {
case convertToGigagroup = "CONVERT_TO_GIGAGROUP" case convertToGigagroup = "CONVERT_GIGAGROUP"
} }
public func getPeerSpecificServerProvidedSuggestions(postbox: Postbox, peerId: PeerId) -> Signal<[PeerSpecificServerProvidedSuggestion], NoError> { public func getPeerSpecificServerProvidedSuggestions(postbox: Postbox, peerId: PeerId) -> Signal<[PeerSpecificServerProvidedSuggestion], NoError> {

View File

@ -37,7 +37,7 @@ public func presentationStringsFormattedNumber(_ count: Int32, _ groupingSeparat
} }
} }
public func timeIntervalString(strings: PresentationStrings, value: Int32) -> String { public func timeIntervalString(strings: PresentationStrings, value: Int32, roundToNearest: Bool = false) -> String {
if value < 60 { if value < 60 {
return strings.MessageTimer_Seconds(max(1, value)) return strings.MessageTimer_Seconds(max(1, value))
} else if value < 60 * 60 { } else if value < 60 * 60 {

View File

@ -1515,7 +1515,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
} }
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root)) strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
} }
}) })
} }
@ -7080,9 +7080,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: presentationData.theme.actionSheet.primaryTextColor) let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: presentationData.theme.actionSheet.primaryTextColor)
let attributedText = parseMarkdownIntoAttributedString(presentationData.strings.BroadcastGroups_ConfirmationAlert_Text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center) let attributedText = parseMarkdownIntoAttributedString(presentationData.strings.BroadcastGroups_ConfirmationAlert_Text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center)
let alertController = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.BroadcastGroups_ConfirmationAlert_Convert, action: { [weak controller] in let alertController = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
let _ = dismissPeerSpecificServerProvidedSuggestion(account: context.account, peerId: peerId, suggestion: .convertToGigagroup).start()
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.BroadcastGroups_ConfirmationAlert_Convert, action: { [weak controller] in
controller?.dismiss() controller?.dismiss()
let _ = dismissPeerSpecificServerProvidedSuggestion(account: context.account, peerId: peerId, suggestion: .convertToGigagroup).start()
let _ = (convertGroupToGigagroup(account: context.account, peerId: peerId) let _ = (convertGroupToGigagroup(account: context.account, peerId: peerId)
|> deliverOnMainQueue).start(completed: { |> deliverOnMainQueue).start(completed: {
@ -10395,7 +10399,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongController.dismiss() strongController.dismiss()
} else if peerId == strongSelf.context.account.peerId { } else if peerId == strongSelf.context.account.peerId {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: true, text: messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root)) strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: true, text: messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: messages.map { message -> EnqueueMessage in let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: messages.map { message -> EnqueueMessage in
return .forward(source: message.id, grouping: .auto, attributes: []) return .forward(source: message.id, grouping: .auto, attributes: [])

View File

@ -103,14 +103,13 @@ private final class ChatDateSelectorItemNode: ActionSheetItemNode {
self.pickerView.addTarget(self, action: #selector(self.pickerChanged), for: .valueChanged) self.pickerView.addTarget(self, action: #selector(self.pickerChanged), for: .valueChanged)
} }
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
return CGSize(width: constrainedSize.width, height: 157.0) let size = CGSize(width: constrainedSize.width, height: 157.0)
}
override func layout() {
super.layout()
self.pickerView.frame = CGRect(origin: CGPoint(), size: CGSize(width: self.bounds.size.width, height: 180.0)) self.pickerView.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: 180.0))
self.updateInternalLayout(size)
return size
} }
@objc func pickerChanged() { @objc func pickerChanged() {

View File

@ -150,10 +150,6 @@ private final class AutoremoveTimeoutSelectorItemNode: ActionSheetItemNode, UIPi
self.pickerView.selectRow(index, inComponent: 0, animated: false) self.pickerView.selectRow(index, inComponent: 0, animated: false)
} }
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 180.0)
}
func numberOfComponents(in pickerView: UIPickerView) -> Int { func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1 return 1
} }
@ -178,9 +174,12 @@ private final class AutoremoveTimeoutSelectorItemNode: ActionSheetItemNode, UIPi
self.valueChanged(self.timeoutValues[row]) self.valueChanged(self.timeoutValues[row])
} }
override func layout() { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
super.layout() let size = CGSize(width: constrainedSize.width, height: 180.0)
self.pickerView.frame = CGRect(origin: CGPoint(), size: CGSize(width: self.bounds.size.width, height: 180.0)) self.pickerView.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: 180.0))
self.updateInternalLayout(size)
return size
} }
} }

View File

@ -1201,7 +1201,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
})) }))
} }
if channel.flags.contains(.isCreator) || (channel.adminRights?.flags.contains(.canInviteUsers) == true) { if (channel.flags.contains(.isCreator) && (channel.username?.isEmpty ?? true)) || (channel.adminRights?.flags.contains(.canInviteUsers) == true) {
let invitesText: String let invitesText: String
if let count = data.invitations?.count, count > 0 { if let count = data.invitations?.count, count > 0 {
invitesText = "\(count)" invitesText = "\(count)"
@ -1340,7 +1340,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
} }
} }
if isCreator || (channel.adminRights?.flags.contains(.canInviteUsers) == true) { if (isCreator && (channel.username?.isEmpty ?? true)) || (channel.adminRights?.flags.contains(.canInviteUsers) == true) {
let invitesText: String let invitesText: String
if let count = data.invitations?.count, count > 0 { if let count = data.invitations?.count, count > 0 {
invitesText = "\(count)" invitesText = "\(count)"
@ -1438,17 +1438,19 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
activePermissionCount = count activePermissionCount = count
} }
let invitesText: String if (group.addressName?.isEmpty ?? true) {
if let count = data.invitations?.count, count > 0 { let invitesText: String
invitesText = "\(count)" if let count = data.invitations?.count, count > 0 {
} else { invitesText = "\(count)"
invitesText = "" } else {
invitesText = ""
}
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, icon: UIImage(bundleImageName: "Chat/Info/GroupLinksIcon"), action: {
interaction.editingOpenInviteLinksSetup()
}))
} }
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, icon: UIImage(bundleImageName: "Chat/Info/GroupLinksIcon"), action: {
interaction.editingOpenInviteLinksSetup()
}))
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPermissions, label: .text(activePermissionCount.flatMap({ "\($0)/\(allGroupPermissionList.count)" }) ?? ""), text: presentationData.strings.GroupInfo_Permissions, icon: UIImage(bundleImageName: "Settings/MenuIcons/SetPasscode"), action: { items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPermissions, label: .text(activePermissionCount.flatMap({ "\($0)/\(allGroupPermissionList.count)" }) ?? ""), text: presentationData.strings.GroupInfo_Permissions, icon: UIImage(bundleImageName: "Settings/MenuIcons/SetPasscode"), action: {
interaction.openPermissions() interaction.openPermissions()
})) }))

View File

@ -53,19 +53,18 @@ private final class ReportPeerDetailsActionSheetItemNode: ActionSheetItemNode {
self.inputFieldNode.updateText = { text in self.inputFieldNode.updateText = { text in
textUpdated(text) textUpdated(text)
} }
self.inputFieldNode.updateHeight = { self.inputFieldNode.updateHeight = { [weak self] in
self?.requestLayout?()
} }
} }
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let inputHeight = self.inputFieldNode.updateLayout(width: constrainedSize.width, transition: .immediate) let inputHeight = self.inputFieldNode.updateLayout(width: constrainedSize.width, transition: .immediate)
self.inputFieldNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: constrainedSize.width, height: inputHeight)) self.inputFieldNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: constrainedSize.width, height: inputHeight))
let size = CGSize(width: constrainedSize.width, height: inputHeight)
return CGSize(width: constrainedSize.width, height: inputHeight) self.updateInternalLayout(size)
} return size
override func layout() {
super.layout()
} }
} }

View File

@ -69,7 +69,7 @@ private final class ReportPeerHeaderActionSheetItemNode: ActionSheetItemNode {
self.accessibilityArea.accessibilityTraits = .staticText self.accessibilityArea.accessibilityTraits = .staticText
} }
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let textSize = self.textNode.updateLayout(CGSize(width: constrainedSize.width - 120.0, height: .greatestFiniteMagnitude)) let textSize = self.textNode.updateLayout(CGSize(width: constrainedSize.width - 120.0, height: .greatestFiniteMagnitude))
let topInset: CGFloat = 26.0 let topInset: CGFloat = 26.0
@ -84,11 +84,8 @@ private final class ReportPeerHeaderActionSheetItemNode: ActionSheetItemNode {
let size = CGSize(width: constrainedSize.width, height: topInset + iconSize.height + textSpacing + textSize.height + bottomInset) let size = CGSize(width: constrainedSize.width, height: topInset + iconSize.height + textSpacing + textSize.height + bottomInset)
self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size) self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size)
self.updateInternalLayout(size)
return size return size
} }
override func layout() {
super.layout()
}
} }