Merge commit '9dd0e3f69e5af701c617e63febbb33f4d75a83bf'

This commit is contained in:
Ali 2021-02-14 18:22:33 +04:00
commit 335d2107f6
33 changed files with 361 additions and 333 deletions

View File

@ -136,14 +136,8 @@ public class ActionSheetPeerItemNode: ActionSheetItemNode {
self.setNeedsLayout()
}
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let size = CGSize(width: constrainedSize.width, height: 57.0)
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.updateInternalLayout(size)
return size
}
@objc private func buttonPressed() {
if let item = self.item {
item.action()

View File

@ -213,14 +213,8 @@ public class BotCheckoutPaymentMethodItemNode: ActionSheetItemNode {
self.setNeedsLayout()
}
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let size = CGSize(width: constrainedSize.width, height: 57.0)
self.button.frame = CGRect(origin: CGPoint(), size: size)
@ -242,6 +236,9 @@ public class BotCheckoutPaymentMethodItemNode: ActionSheetItemNode {
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.updateInternalLayout(size)
return size
}
@objc func buttonPressed() {

View File

@ -190,15 +190,9 @@ public class BotCheckoutPaymentShippingOptionItemNode: ActionSheetItemNode {
self.setNeedsLayout()
}
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let size = CGSize(width: constrainedSize.width, height: 57.0)
self.button.frame = CGRect(origin: CGPoint(), size: size)
var checkInset: CGFloat = 15.0
@ -214,6 +208,9 @@ public class BotCheckoutPaymentShippingOptionItemNode: ActionSheetItemNode {
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.updateInternalLayout(size)
return size
}
@objc func buttonPressed() {

View File

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

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 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)
self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size)
self.updateInternalLayout(size)
return size
}
override func layout() {
super.layout()
}
}

View File

@ -152,20 +152,17 @@ public class ActionSheetButtonNode: ActionSheetItemNode {
self.setNeedsLayout()
}
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let size = CGSize(width: constrainedSize.width, height: 57.0)
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))
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.updateInternalLayout(size)
return size
}
@objc func buttonPressed() {

View File

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

View File

@ -61,7 +61,7 @@ final class ActionSheetControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.itemGroupsContainerNode = ActionSheetItemGroupsContainerNode(theme: self.theme)
super.init()
self.scrollView.delegate = self
self.addSubnode(self.scrollNode)
@ -78,6 +78,12 @@ final class ActionSheetControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.scrollNode.addSubnode(self.itemGroupsContainerNode)
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() {
@ -107,9 +113,9 @@ final class ActionSheetControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.scrollView.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
}
@ -117,8 +123,7 @@ final class ActionSheetControllerNode: ASDisplayNode, UIScrollViewDelegate {
if !self.allowInputInset {
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))
self.itemGroupsContainerNode.updateLayout(transition: transition)
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.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 leadingVisibleNodeCount: CGFloat = 100.0
private var validLayout: CGSize?
init(theme: ActionSheetControllerTheme) {
self.theme = theme
@ -81,45 +83,8 @@ final class ActionSheetItemGroupNode: ASDisplayNode, UIScrollViewDelegate {
self.leadingVisibleNodeCount = leadingVisibleNodeCount
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 leadingVisibleNodeSize: CGFloat = 0.0
@ -130,24 +95,42 @@ final class ActionSheetItemGroupNode: ASDisplayNode, UIScrollViewDelegate {
itemNodesHeight += UIScreenPixel
}
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(0.0).isLess(than: leadingVisibleNodeSize), node.hasSeparator {
leadingVisibleNodeSize += UIScreenPixel
}
let factor: CGFloat = min(1.0, leadingVisibleNodeCount - CGFloat(i))
leadingVisibleNodeSize += node.calculatedSize.height * factor
leadingVisibleNodeSize += nodeSize.height * factor
}
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) {
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 {
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.updateOverscroll(transition: transition)
self.updateOverscroll(size: size, transition: transition)
return size
}
private func currentVerticalOverscroll() -> CGFloat {
@ -180,11 +165,11 @@ final class ActionSheetItemGroupNode: ASDisplayNode, UIScrollViewDelegate {
return verticalOverscroll
}
private func updateOverscroll(transition: ContainedViewLayoutTransition) {
private func updateOverscroll(size: CGSize, transition: ContainedViewLayoutTransition) {
let verticalOverscroll = self.currentVerticalOverscroll()
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) {
transition.updateFrame(node: self.clippingNode, frame: clippingNodeFrame)
@ -195,7 +180,9 @@ final class ActionSheetItemGroupNode: ASDisplayNode, UIScrollViewDelegate {
}
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? {

View File

@ -14,6 +14,8 @@ final class ActionSheetItemGroupsContainerNode: ASDisplayNode {
private var groups: [ActionSheetItemGroup] = []
var groupNodes: [ActionSheetItemGroupNode] = []
var requestLayout: (() -> Void)?
init(theme: ActionSheetControllerTheme) {
self.theme = theme
@ -30,46 +32,49 @@ final class ActionSheetItemGroupsContainerNode: ASDisplayNode {
for group in groups {
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.addSubnode(groupNode)
}
}
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
var groupsHeight: CGFloat = 0.0
var calculatedSizes: [CGSize] = []
for groupNode in self.groupNodes.reversed() {
if CGFloat(0.0).isLess(than: groupsHeight) {
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
}
return CGSize(width: constrainedSize.width, height: min(groupsHeight, constrainedSize.height))
}
func updateLayout(transition: ContainedViewLayoutTransition) {
var groupsHeight: CGFloat = 0.0
var itemGroupsHeight: CGFloat = 0.0
for i in 0 ..< self.groupNodes.count {
let groupNode = self.groupNodes[i]
let size = groupNode.calculatedSize
let size = calculatedSizes[i]
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))
}
groupNode.updateLayout(transition: transition)
transition.updateFrame(node: groupNode, frame: CGRect(origin: CGPoint(x: 0.0, y: groupsHeight), size: size))
transition.updateFrame(node: groupNode, frame: CGRect(origin: CGPoint(x: 0.0, y: itemGroupsHeight), size: size))
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? {

View File

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

View File

@ -103,15 +103,9 @@ public class ActionSheetSwitchNode: ActionSheetItemNode {
self.setNeedsLayout()
}
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let size = CGSize(width: constrainedSize.width, height: 57.0)
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))
@ -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.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size)
self.updateInternalLayout(size)
return size
}
@objc func buttonPressed() {

View File

@ -69,19 +69,15 @@ public class ActionSheetTextNode: ActionSheetItemNode {
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))
return 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))
let size = CGSize(width: constrainedSize.width, height: max(57.0, labelSize.height + 32.0))
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.updateInternalLayout(size)
return size
}
}

View File

@ -563,33 +563,37 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId, ad
})))
if !invite.isRevoked {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextShare, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
f(.default)
let shareController = ShareController(context: context, subject: .url(invite.link))
presentControllerImpl?(shareController, nil)
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
f(.default)
if !invitationAvailability(invite).isZero {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextShare, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
f(.default)
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|> deliverOnMainQueue).start(next: { peer in
let isGroup: Bool
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
isGroup = false
} else {
isGroup = true
}
let controller = InviteLinkQRCodeController(context: context, invite: invite, isGroup: isGroup)
presentControllerImpl?(controller, nil)
})
})))
let shareController = ShareController(context: context, subject: .url(invite.link))
presentControllerImpl?(shareController, nil)
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
f(.default)
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|> deliverOnMainQueue).start(next: { peer in
let isGroup: Bool
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
isGroup = false
} else {
isGroup = true
}
Queue.mainQueue().after(0.2) {
let controller = InviteLinkQRCodeController(context: context, invite: invite, isGroup: isGroup)
presentControllerImpl?(controller, nil)
}
})
})))
}
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextEdit, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
@ -727,15 +731,21 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId, ad
timer.start()
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())
|> deliverOnMainQueue
|> map { presentationData, view, importersContext, importers, invites, revokedInvites, creators, tick -> (ItemListControllerState, (ItemListNodeState, Any)) in
let previousRevokedInvites = previousRevokedInvites.swap(invites)
let previousCreators = previousCreators.swap(creators)
var crossfade = false
if (previousRevokedInvites?.hasLoadedOnce ?? false) != (revokedInvites.hasLoadedOnce) {
crossfade = true
}
if (previousCreators?.count ?? 0) != creators.count {
crossfade = true
}
let title: ItemListControllerTitle
if let admin = admin, let peer = admin.peer.peer {

View File

@ -45,6 +45,8 @@ private struct InviteLinkViewTransaction {
let insertions: [ListViewInsertItem]
let updates: [ListViewUpdateItem]
let isLoading: Bool
let animated: Bool
let crossfade: Bool
}
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 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 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)
@ -485,23 +487,25 @@ public final class InviteLinkViewController: ViewController {
self?.controller?.present(controller, in: .window(.root))
})))
} else {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in
f(.dismissWithoutContent)
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|> deliverOnMainQueue).start(next: { [weak self] peer in
let isGroup: Bool
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
isGroup = false
} else {
isGroup = true
}
let controller = InviteLinkQRCodeController(context: context, invite: invite, isGroup: isGroup)
self?.controller?.present(controller, in: .window(.root))
})
})))
if !invitationAvailability(invite).isZero {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in
f(.dismissWithoutContent)
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|> deliverOnMainQueue).start(next: { [weak self] peer in
let isGroup: Bool
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
isGroup = false
} else {
isGroup = true
}
let controller = InviteLinkQRCodeController(context: context, invite: invite, isGroup: isGroup)
self?.controller?.present(controller, in: .window(.root))
})
})))
}
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextRevoke, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor)
}, action: { [weak self] _, f in
@ -535,6 +539,8 @@ public final class InviteLinkViewController: ViewController {
})
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)
self.disposable = (combineLatest(self.presentationDataPromise.get(), self.importersContext.state, creatorPeer)
@ -561,13 +567,20 @@ public final class InviteLinkViewController: ViewController {
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
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: [])
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))
}
} else {
count = min(4, Int32(state.importers.count))
loading = false
for importer in state.importers {
if let peer = importer.peer.peer {
entries.append(.importer(index, presentationData.theme, presentationData.dateTimeFormat, peer, importer.date, false))
@ -576,9 +589,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 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)
}
})
@ -700,7 +725,11 @@ public final class InviteLinkViewController: ViewController {
}
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.iconBackgroundNode = ASImageNode()
self.iconBackgroundNode = ASDisplayNode()
self.iconBackgroundNode.setLayerBlock { () -> CALayer in
return CAShapeLayer()
}

View File

@ -163,19 +163,13 @@ private final class OpenInActionSheetItemNode: ActionSheetItemNode {
}
}
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 148.0)
}
override func layout() {
super.layout()
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let size = CGSize(width: constrainedSize.width, height: 148.0)
let titleSize = self.titleNode.measure(size)
self.titleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 16.0), size: CGSize(width: size.width, height: titleSize.height))
let bounds = self.bounds
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))
self.scrollNode.frame = CGRect(origin: CGPoint(x: 0, y: 36.0), size: CGSize(width: size.width, height: size.height - 36.0))
let nodeInset: CGFloat = 2.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.updateInternalLayout(size)
return size
}
}

View File

@ -87,7 +87,7 @@ private final class ChannelDiscussionGroupActionSheetItemNode: ActionSheetItemNo
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 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)
return CGSize(width: constrainedSize.width, height: topInset + avatarSize + textSpacing + textSize.height + bottomInset)
}
override func layout() {
super.layout()
let size = CGSize(width: constrainedSize.width, height: topInset + avatarSize + textSpacing + textSize.height + bottomInset)
self.updateInternalLayout(size)
return size
}
}

View File

@ -111,14 +111,13 @@ private final class PeerBanTimeoutActionSheetItemNode: ActionSheetItemNode {
self.pickerView.addTarget(self, action: #selector(self.datePickerUpdated), for: .valueChanged)
}
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 216.0)
}
override func layout() {
super.layout()
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let size = CGSize(width: constrainedSize.width, height: 216.0)
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() {

View File

@ -14,6 +14,8 @@ import AlertUI
import PresentationDataUtils
import UndoUI
import AppBundle
import TelegramPermissionsUI
import Markdown
public enum PeerReportSubject {
case peer(PeerId)
@ -152,38 +154,67 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe
case .copyright:
reportReason = .copyright
case .other:
break
reportReason = .custom
}
if let reportReason = reportReason {
var passthrough = passthrough
if case .fake = reportReason {
if [.fake, .custom].contains(reportReason) {
passthrough = false
}
switch subject {
case let .peer(peerId):
if passthrough {
completion(reportReason, true)
} else {
let _ = (reportPeer(account: context.account, peerId: peerId, reason: reportReason, message: "")
|> deliverOnMainQueue).start(completed: {
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)
}
let action = {
switch subject {
case let .peer(peerId):
if passthrough {
completion(reportReason, true)
})
}
case let .messages(messageIds):
if passthrough {
completion(reportReason, true)
} else {
let _ = (reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason, message: "")
|> deliverOnMainQueue).start(completed: {
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)
}
} else {
let _ = (reportPeer(account: context.account, peerId: peerId, reason: reportReason, message: "")
|> deliverOnMainQueue).start(completed: {
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)
}
completion(nil, false)
})
}
case let .messages(messageIds):
if passthrough {
completion(reportReason, true)
})
}
} else {
let _ = (reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason, message: "")
|> deliverOnMainQueue).start(completed: {
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)
}
completion(nil, false)
})
}
}
}
if [.fake, .custom].contains(reportReason) {
let controller = ActionSheetController(presentationData: presentationData, allowInputInset: true)
let dismissAction: () -> Void = { [weak controller] in
controller?.dismissAnimated()
}
var message = ""
var items: [ActionSheetItem] = []
items.append(ReportPeerHeaderActionSheetItem(context: context, text: presentationData.strings.Report_AdditionalDetailsText))
items.append(ReportPeerDetailsActionSheetItem(context: context, placeholderText: presentationData.strings.Report_AdditionalDetailsPlaceholder, textUpdated: { text in
message = text
}))
items.append(ActionSheetButtonItem(title: presentationData.strings.Report_Report, color: .accent, font: .bold, enabled: true, action: {
dismissAction()
action()
}))
controller.setItemGroups([
ActionSheetItemGroup(items: items),
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
])
present(controller, nil)
} else {
action()
}
} else {
push(peerReportController(context: context, subject: subject, completion: completion))

View File

@ -53,19 +53,18 @@ private final class ReportPeerDetailsActionSheetItemNode: ActionSheetItemNode {
self.inputFieldNode.updateText = { text in
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)
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)
}
override func layout() {
super.layout()
self.updateInternalLayout(size)
return size
}
}

View File

@ -69,7 +69,7 @@ private final class ReportPeerHeaderActionSheetItemNode: ActionSheetItemNode {
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 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)
self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size)
self.updateInternalLayout(size)
return size
}
override func layout() {
super.layout()
}
}

View File

@ -242,14 +242,8 @@ private final class ProxyServerInfoItemNode: ActionSheetItemNode {
self.setNeedsLayout()
}
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 36.0 * CGFloat(self.fieldNodes.count) + 12.0)
}
override func layout() {
super.layout()
let size = self.bounds.size
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let size = CGSize(width: constrainedSize.width, height: 36.0 * CGFloat(self.fieldNodes.count) + 12.0)
var offset: CGFloat = 15.0
for (lhs, rhs) in self.fieldNodes {
@ -261,6 +255,9 @@ private final class ProxyServerInfoItemNode: ActionSheetItemNode {
offset += 36.0
}
self.updateInternalLayout(size)
return size
}
}
@ -360,14 +357,8 @@ private final class ProxyServerActionItemNode: ActionSheetItemNode {
}
}
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0)
}
override func layout() {
super.layout()
let size = self.bounds.size
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let size = CGSize(width: constrainedSize.width, height: 57.0)
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))
self.titleNode.frame = titleFrame
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() {
let proxyServerSettings = self.server
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)
}
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 216.0)
}
override func layout() {
super.layout()
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let size = CGSize(width: constrainedSize.width, height: 216.0)
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() {

View File

@ -112,14 +112,8 @@ public class LocationBroadcastActionSheetItemNode: ActionSheetItemNode {
self.setNeedsLayout()
}
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let size = CGSize(width: constrainedSize.width, height: 57.0)
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)
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() {

View File

@ -136,14 +136,8 @@ public class CallRouteActionSheetItemNode: ActionSheetItemNode {
self.setNeedsLayout()
}
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let size = CGSize(width: constrainedSize.width, height: 57.0)
self.button.frame = CGRect(origin: CGPoint(), size: size)
@ -157,6 +151,9 @@ public class CallRouteActionSheetItemNode: ActionSheetItemNode {
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.updateInternalLayout(size)
return size
}
@objc func buttonPressed() {

View File

@ -39,7 +39,7 @@ public func dismissServerProvidedSuggestion(account: Account, suggestion: Server
public enum PeerSpecificServerProvidedSuggestion: String {
case convertToGigagroup = "CONVERT_TO_GIGAGROUP"
case convertToGigagroup = "CONVERT_GIGAGROUP"
}
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 {
return strings.MessageTimer_Seconds(max(1, value))
} 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 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()
let _ = dismissPeerSpecificServerProvidedSuggestion(account: context.account, peerId: peerId, suggestion: .convertToGigagroup).start()
let _ = (convertGroupToGigagroup(account: context.account, peerId: peerId)
|> deliverOnMainQueue).start(completed: {
@ -10395,7 +10399,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongController.dismiss()
} else if peerId == strongSelf.context.account.peerId {
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
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)
}
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 157.0)
}
override func layout() {
super.layout()
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
let size = CGSize(width: constrainedSize.width, height: 157.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
}
@objc func pickerChanged() {

View File

@ -150,10 +150,6 @@ private final class AutoremoveTimeoutSelectorItemNode: ActionSheetItemNode, UIPi
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 {
return 1
}
@ -178,9 +174,12 @@ private final class AutoremoveTimeoutSelectorItemNode: ActionSheetItemNode, UIPi
self.valueChanged(self.timeoutValues[row])
}
override func layout() {
super.layout()
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
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

@ -1097,6 +1097,8 @@ func peerInfoCanEdit(peer: Peer?, cachedData: CachedPeerData?, isContact: Bool?)
} else if let peer = peer as? TelegramChannel {
if peer.flags.contains(.isCreator) {
return true
} else if peer.hasPermission(.changeInfo) {
return true
} else if let adminRights = peer.adminRights, adminRights.flags.contains(.canAddAdmins) || adminRights.flags.contains(.canBanUsers) || adminRights.flags.contains(.canChangeInfo) || adminRights.flags.contains(.canInviteUsers) {
return true
}
@ -1109,8 +1111,8 @@ func peerInfoCanEdit(peer: Peer?, cachedData: CachedPeerData?, isContact: Bool?)
return true
}
return false
} else {
return false
} else if !peer.hasBannedPermission(.banChangeInfo) {
return true
}
}
return false

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
if let count = data.invitations?.count, count > 0 {
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
if let count = data.invitations?.count, count > 0 {
invitesText = "\(count)"
@ -1438,17 +1438,19 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
activePermissionCount = count
}
let invitesText: String
if let count = data.invitations?.count, count > 0 {
invitesText = "\(count)"
} else {
invitesText = ""
if (group.addressName?.isEmpty ?? true) {
let invitesText: String
if let count = data.invitations?.count, count > 0 {
invitesText = "\(count)"
} 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: {
interaction.openPermissions()
}))