diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 47c351d864..da886e862e 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -485,7 +485,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController strongSelf.tabContainerNode.cancelAnimations() strongSelf.chatListDisplayNode.inlineTabContainerNode.cancelAnimations() } - strongSelf.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: tabContainerData.0, selectedFilter: filter, isReordering: strongSelf.chatListDisplayNode.isReorderingFilters || (strongSelf.chatListDisplayNode.containerNode.currentItemNode.currentState.editing && !strongSelf.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: false, transitionFraction: fraction, presentationData: strongSelf.presentationData, transition: transition) + strongSelf.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: tabContainerData.0, selectedFilter: filter, isReordering: strongSelf.chatListDisplayNode.isReorderingFilters || (strongSelf.chatListDisplayNode.containerNode.currentItemNode.currentState.editing && !strongSelf.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: strongSelf.chatListDisplayNode.containerNode.currentItemNode.currentState.editing, transitionFraction: fraction, presentationData: strongSelf.presentationData, transition: transition) strongSelf.chatListDisplayNode.inlineTabContainerNode.update(size: CGSize(width: layout.size.width, height: 40.0), sideInset: layout.safeInsets.left, filters: tabContainerData.0, selectedFilter: filter, isReordering: strongSelf.chatListDisplayNode.isReorderingFilters || (strongSelf.chatListDisplayNode.containerNode.currentItemNode.currentState.editing && !strongSelf.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: false, transitionFraction: fraction, presentationData: strongSelf.presentationData, transition: transition) } self.reloadFilters() @@ -549,7 +549,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData)) if let layout = self.validLayout { - self.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: self.tabContainerData?.0 ?? [], selectedFilter: self.chatListDisplayNode.containerNode.currentItemFilter, isReordering: self.chatListDisplayNode.isReorderingFilters || (self.chatListDisplayNode.containerNode.currentItemNode.currentState.editing && !self.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: false, transitionFraction: self.chatListDisplayNode.containerNode.transitionFraction, presentationData: self.presentationData, transition: .immediate) + self.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: self.tabContainerData?.0 ?? [], selectedFilter: self.chatListDisplayNode.containerNode.currentItemFilter, isReordering: self.chatListDisplayNode.isReorderingFilters || (self.chatListDisplayNode.containerNode.currentItemNode.currentState.editing && !self.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: self.chatListDisplayNode.containerNode.currentItemNode.currentState.editing, transitionFraction: self.chatListDisplayNode.containerNode.transitionFraction, presentationData: self.presentationData, transition: .immediate) self.chatListDisplayNode.inlineTabContainerNode.update(size: CGSize(width: layout.size.width, height: 40.0), sideInset: layout.safeInsets.left, filters: self.tabContainerData?.0 ?? [], selectedFilter: self.chatListDisplayNode.containerNode.currentItemFilter, isReordering: self.chatListDisplayNode.isReorderingFilters || (self.chatListDisplayNode.containerNode.currentItemNode.currentState.editing && !self.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: false, transitionFraction: self.chatListDisplayNode.containerNode.transitionFraction, presentationData: self.presentationData, transition: .immediate) } @@ -1414,7 +1414,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController let navigationBarHeight = self.navigationBar?.frame.maxY ?? 0.0 transition.updateFrame(node: self.tabContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationBarHeight - self.additionalNavigationBarHeight - 46.0 + tabContainerOffset), size: CGSize(width: layout.size.width, height: 46.0))) - self.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: self.tabContainerData?.0 ?? [], selectedFilter: self.chatListDisplayNode.containerNode.currentItemFilter, isReordering: self.chatListDisplayNode.isReorderingFilters || (self.chatListDisplayNode.containerNode.currentItemNode.currentState.editing && !self.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: false, transitionFraction: self.chatListDisplayNode.containerNode.transitionFraction, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring)) + self.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: self.tabContainerData?.0 ?? [], selectedFilter: self.chatListDisplayNode.containerNode.currentItemFilter, isReordering: self.chatListDisplayNode.isReorderingFilters || (self.chatListDisplayNode.containerNode.currentItemNode.currentState.editing && !self.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: self.chatListDisplayNode.containerNode.currentItemNode.currentState.editing, transitionFraction: self.chatListDisplayNode.containerNode.transitionFraction, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring)) if let tabContainerData = self.tabContainerData { self.chatListDisplayNode.inlineTabContainerNode.isHidden = !tabContainerData.1 || tabContainerData.0.count <= 1 } else { @@ -1621,7 +1621,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController strongSelf.containerLayoutUpdated(layout, transition: transition) (strongSelf.parent as? TabBarController)?.updateLayout(transition: transition) } else { - strongSelf.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: resolvedItems, selectedFilter: selectedEntryId, isReordering: strongSelf.chatListDisplayNode.isReorderingFilters || (strongSelf.chatListDisplayNode.containerNode.currentItemNode.currentState.editing && !strongSelf.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: false, transitionFraction: strongSelf.chatListDisplayNode.containerNode.transitionFraction, presentationData: strongSelf.presentationData, transition: .animated(duration: 0.4, curve: .spring)) + strongSelf.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: resolvedItems, selectedFilter: selectedEntryId, isReordering: strongSelf.chatListDisplayNode.isReorderingFilters || (strongSelf.chatListDisplayNode.containerNode.currentItemNode.currentState.editing && !strongSelf.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: strongSelf.chatListDisplayNode.containerNode.currentItemNode.currentState.editing, transitionFraction: strongSelf.chatListDisplayNode.containerNode.transitionFraction, presentationData: strongSelf.presentationData, transition: .animated(duration: 0.4, curve: .spring)) strongSelf.chatListDisplayNode.inlineTabContainerNode.update(size: CGSize(width: layout.size.width, height: 40.0), sideInset: layout.safeInsets.left, filters: resolvedItems, selectedFilter: selectedEntryId, isReordering: strongSelf.chatListDisplayNode.isReorderingFilters || (strongSelf.chatListDisplayNode.containerNode.currentItemNode.currentState.editing && !strongSelf.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: false, transitionFraction: strongSelf.chatListDisplayNode.containerNode.transitionFraction, presentationData: strongSelf.presentationData, transition: .animated(duration: 0.4, curve: .spring)) } } diff --git a/submodules/ChatListUI/Sources/ChatListFilterTabContainerNode.swift b/submodules/ChatListUI/Sources/ChatListFilterTabContainerNode.swift index 29a657aedf..f742a7985e 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterTabContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterTabContainerNode.swift @@ -83,6 +83,7 @@ private final class ItemNode: ASDisplayNode { private(set) var unreadCount: Int = 0 private var isReordering: Bool = false + private var isEditing: Bool = false private var theme: PresentationTheme? @@ -192,6 +193,8 @@ private final class ItemNode: ASDisplayNode { } func updateText(strings: PresentationStrings, title: String, shortTitle: String, unreadCount: Int, unreadHasUnmuted: Bool, isNoFilter: Bool, selectionFraction: CGFloat, isEditing: Bool, isAllChats: Bool, isReordering: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) { + self.isEditing = isEditing + if self.theme !== presentationData.theme { self.theme = presentationData.theme @@ -212,7 +215,7 @@ private final class ItemNode: ASDisplayNode { self.selectionFraction = selectionFraction self.unreadCount = unreadCount - transition.updateAlpha(node: self.containerNode, alpha: isReordering && isAllChats ? 0.5 : 1.0) + transition.updateAlpha(node: self.containerNode, alpha: isEditing || (isReordering && isAllChats) ? 0.5 : 1.0) if isReordering && !isAllChats { if self.deleteButtonNode == nil { @@ -234,7 +237,7 @@ private final class ItemNode: ASDisplayNode { }) } - transition.updateAlpha(node: self.badgeContainerNode, alpha: (isReordering || unreadCount == 0) ? 0.0 : 1.0) + transition.updateAlpha(node: self.badgeContainerNode, alpha: (isEditing || isReordering || unreadCount == 0) ? 0.0 : 1.0) let selectionAlpha: CGFloat = selectionFraction * selectionFraction let deselectionAlpha: CGFloat = 1.0// - selectionFraction @@ -302,7 +305,7 @@ private final class ItemNode: ASDisplayNode { self.badgeTextNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((badgeBackgroundFrame.width - badgeSize.width) / 2.0), y: floor((badgeBackgroundFrame.height - badgeSize.height) / 2.0)), size: badgeSize) let width: CGFloat - if self.unreadCount == 0 || self.isReordering { + if self.unreadCount == 0 || self.isReordering || self.isEditing { if !self.isReordering { self.badgeContainerNode.alpha = 0.0 } @@ -636,6 +639,11 @@ final class ChatListFilterTabContainerNode: ASDisplayNode { let isFirstTime = self.currentParams == nil let transition: ContainedViewLayoutTransition = isFirstTime ? .immediate : proposedTransition + var isEditing = isEditing + if isReordering { + isEditing = false + } + var focusOnSelectedFilter = self.currentParams?.selectedFilter != selectedFilter let previousScrollBounds = self.scrollNode.bounds let previousContentWidth = self.scrollNode.view.contentSize.width @@ -674,7 +682,7 @@ final class ChatListFilterTabContainerNode: ASDisplayNode { self.currentParams = (size: size, sideInset: sideInset, filters: filters, selectedFilter: selectedFilter, isReordering, isEditing, transitionFraction, presentationData: presentationData) - self.reorderingGesture?.isEnabled = isEditing || isReordering + self.reorderingGesture?.isEnabled = isReordering transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: size)) @@ -754,7 +762,7 @@ final class ChatListFilterTabContainerNode: ASDisplayNode { selectionFraction = 0.0 } - itemNode.updateText(strings: presentationData.strings, title: filter.title(strings: presentationData.strings), shortTitle: filter.shortTitle(strings: presentationData.strings), unreadCount: unreadCount, unreadHasUnmuted: unreadHasUnmuted, isNoFilter: isNoFilter, selectionFraction: selectionFraction, isEditing: false, isAllChats: isNoFilter, isReordering: isEditing || isReordering, presentationData: presentationData, transition: itemNodeTransition) + itemNode.updateText(strings: presentationData.strings, title: filter.title(strings: presentationData.strings), shortTitle: filter.shortTitle(strings: presentationData.strings), unreadCount: unreadCount, unreadHasUnmuted: unreadHasUnmuted, isNoFilter: isNoFilter, selectionFraction: selectionFraction, isEditing: isEditing, isAllChats: isNoFilter, isReordering: isReordering, presentationData: presentationData, transition: itemNodeTransition) } var removeKeys: [ChatListFilterTabEntryId] = [] for (id, _) in self.itemNodes { diff --git a/submodules/InviteLinksUI/Sources/InviteLinkQRCodeController.swift b/submodules/InviteLinksUI/Sources/InviteLinkQRCodeController.swift index b9efba0844..056c07231a 100644 --- a/submodules/InviteLinksUI/Sources/InviteLinkQRCodeController.swift +++ b/submodules/InviteLinksUI/Sources/InviteLinkQRCodeController.swift @@ -162,7 +162,6 @@ public final class InviteLinkQRCodeController: ViewController { private let backgroundNode: ASDisplayNode private let contentBackgroundNode: ASDisplayNode private let titleNode: ASTextNode - private let subtitleNode: ASTextNode private let cancelButton: HighlightableButtonNode private let textNode: ImmediateTextNode @@ -209,9 +208,6 @@ public final class InviteLinkQRCodeController: ViewController { self.titleNode = ASTextNode() self.titleNode.attributedText = NSAttributedString(string: self.presentationData.strings.InviteLink_QRCode_Title, font: Font.bold(17.0), textColor: textColor) - self.subtitleNode = ASTextNode() - self.subtitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.InviteLink_QRCode_Title, font: Font.regular(13.0), textColor: secondaryTextColor) - self.cancelButton = HighlightableButtonNode() self.cancelButton.setTitle(self.presentationData.strings.Common_Done, with: Font.bold(17.0), with: accentColor, for: .normal) @@ -254,10 +250,8 @@ public final class InviteLinkQRCodeController: ViewController { self.contentContainerNode.addSubnode(self.qrImageNode) self.contentContainerNode.addSubnode(self.qrIconNode) self.contentContainerNode.addSubnode(self.qrButtonNode) - - let textFont = Font.regular(13.0) - - self.textNode.attributedText = NSAttributedString(string: isGroup ? self.presentationData.strings.InviteLink_QRCode_Info : self.presentationData.strings.InviteLink_QRCode_InfoChannel, font: textFont, textColor: secondaryTextColor) + + self.textNode.attributedText = NSAttributedString(string: isGroup ? self.presentationData.strings.InviteLink_QRCode_Info : self.presentationData.strings.InviteLink_QRCode_InfoChannel, font: Font.regular(13.0), textColor: secondaryTextColor) self.buttonNode.title = self.presentationData.strings.InviteLink_QRCode_Share self.cancelButton.addTarget(self, action: #selector(self.cancelButtonPressed), forControlEvents: .touchUpInside) @@ -304,6 +298,7 @@ public final class InviteLinkQRCodeController: ViewController { self.contentBackgroundNode.backgroundColor = self.presentationData.theme.actionSheet.opaqueItemBackgroundColor self.titleNode.attributedText = NSAttributedString(string: self.titleNode.attributedText?.string ?? "", font: Font.bold(17.0), textColor: self.presentationData.theme.actionSheet.primaryTextColor) + self.textNode.attributedText = NSAttributedString(string: self.textNode.attributedText?.string ?? "", font: Font.regular(13.0), textColor: self.presentationData.theme.actionSheet.secondaryTextColor) if previousTheme !== presentationData.theme, let (layout, navigationBarHeight) = self.containerLayout { self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate) diff --git a/submodules/ItemListPeerActionItem/Sources/ItemListPeerActionItem.swift b/submodules/ItemListPeerActionItem/Sources/ItemListPeerActionItem.swift index c3856edc08..9548dde3c9 100644 --- a/submodules/ItemListPeerActionItem/Sources/ItemListPeerActionItem.swift +++ b/submodules/ItemListPeerActionItem/Sources/ItemListPeerActionItem.swift @@ -9,6 +9,7 @@ import PresentationDataUtils public enum ItemListPeerActionItemHeight { case generic + case compactPeerList case peerList } @@ -173,6 +174,10 @@ class ItemListPeerActionItemNode: ListViewItemNode { verticalInset = 14.0 verticalOffset = 0.0 leftInset = 65.0 + params.leftInset + case .compactPeerList: + verticalInset = 14.0 + verticalOffset = 0.0 + leftInset = 59.0 + params.leftInset } let editingOffset: CGFloat = (item.editing ? 38.0 : 0.0) diff --git a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenActionItem.swift b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenActionItem.swift index cf026d2cb8..442d8bfc65 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenActionItem.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenActionItem.swift @@ -10,6 +10,7 @@ enum PeerInfoScreenActionColor { enum PeerInfoScreenActionAligmnent { case natural case center + case peerList } final class PeerInfoScreenActionItem: PeerInfoScreenItem { @@ -78,7 +79,7 @@ private final class PeerInfoScreenActionItemNode: PeerInfoScreenItemNode { self.addSubnode(self.activateArea) } - override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat { guard let item = item as? PeerInfoScreenActionItem else { return 10.0 } @@ -88,7 +89,10 @@ private final class PeerInfoScreenActionItemNode: PeerInfoScreenItemNode { self.selectionNode.pressed = item.action let sideInset: CGFloat = 16.0 + safeInsets.left - let leftInset = (item.icon == nil ? sideInset : sideInset + 29.0 + 16.0) + var leftInset = (item.icon == nil ? sideInset : sideInset + 29.0 + 16.0) + if case .peerList = item.alignment { + leftInset += 5.0 + } let rightInset = sideInset let separatorInset = item.icon == nil ? sideInset : leftInset - 1.0 let titleFont = Font.regular(presentationData.listsFontSize.itemListBaseFontSize) @@ -131,7 +135,7 @@ private final class PeerInfoScreenActionItemNode: PeerInfoScreenItemNode { transition.updateFrame(node: self.textNode, frame: textFrame) } - let hasCorners = safeInsets.left > 0.0 && (topItem == nil || bottomItem == nil) + let hasCorners = hasCorners && (topItem == nil || bottomItem == nil) let hasTopCorners = hasCorners && topItem == nil let hasBottomCorners = hasCorners && bottomItem == nil diff --git a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenAddressItem.swift b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenAddressItem.swift index 28ef869a9f..0b1f06d683 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenAddressItem.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenAddressItem.swift @@ -42,6 +42,7 @@ final class PeerInfoScreenAddressItem: PeerInfoScreenItem { private final class PeerInfoScreenAddressItemNode: PeerInfoScreenItemNode { private let selectionNode: PeerInfoScreenSelectableBackgroundNode private let bottomSeparatorNode: ASDisplayNode + private let maskNode: ASImageNode private var item: PeerInfoScreenAddressItem? private var itemNode: ItemListAddressItemNode? @@ -53,6 +54,9 @@ private final class PeerInfoScreenAddressItemNode: PeerInfoScreenItemNode { self.bottomSeparatorNode = ASDisplayNode() self.bottomSeparatorNode.isLayerBacked = true + self.maskNode = ASImageNode() + self.maskNode.isUserInteractionEnabled = false + super.init() bringToFrontForHighlightImpl = { [weak self] in @@ -61,9 +65,10 @@ private final class PeerInfoScreenAddressItemNode: PeerInfoScreenItemNode { self.addSubnode(self.bottomSeparatorNode) self.addSubnode(self.selectionNode) + self.addSubnode(self.maskNode) } - override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat { guard let item = item as? PeerInfoScreenAddressItem else { return 10.0 } @@ -108,6 +113,14 @@ private final class PeerInfoScreenAddressItemNode: PeerInfoScreenItemNode { let height = itemNode.contentSize.height + let hasCorners = hasCorners && (topItem == nil || bottomItem == nil) + let hasTopCorners = hasCorners && topItem == nil + let hasBottomCorners = hasCorners && bottomItem == nil + + self.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil + self.maskNode.frame = CGRect(origin: CGPoint(x: safeInsets.left, y: 0.0), size: CGSize(width: width - safeInsets.left - safeInsets.right, height: height)) + self.bottomSeparatorNode.isHidden = hasBottomCorners + transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(), size: itemNode.bounds.size)) let highlightNodeOffset: CGFloat = topItem == nil ? 0.0 : UIScreenPixel diff --git a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenCallListItem.swift b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenCallListItem.swift index 982f15e4b3..5b2aa97897 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenCallListItem.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenCallListItem.swift @@ -52,7 +52,7 @@ private final class PeerInfoScreenCallListItemNode: PeerInfoScreenItemNode { self.addSubnode(self.selectionNode) } - override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat { guard let item = item as? PeerInfoScreenCallListItem else { return 10.0 } diff --git a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenCommentItem.swift b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenCommentItem.swift index 2c76b2558d..d797ac4362 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenCommentItem.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenCommentItem.swift @@ -36,7 +36,7 @@ private final class PeerInfoScreenCommentItemNode: PeerInfoScreenItemNode { self.addSubnode(self.activateArea) } - override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat { guard let item = item as? PeerInfoScreenCommentItem else { return 10.0 } diff --git a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenDisclosureEncryptionKeyItem.swift b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenDisclosureEncryptionKeyItem.swift index f532c81631..d05a1a25fc 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenDisclosureEncryptionKeyItem.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenDisclosureEncryptionKeyItem.swift @@ -28,6 +28,7 @@ private final class PeerInfoScreenDisclosureEncryptionKeyItemNode: PeerInfoScree private let keyNode: ASImageNode private let arrowNode: ASImageNode private let bottomSeparatorNode: ASDisplayNode + private let maskNode: ASImageNode private var item: PeerInfoScreenDisclosureEncryptionKeyItem? @@ -53,6 +54,9 @@ private final class PeerInfoScreenDisclosureEncryptionKeyItemNode: PeerInfoScree self.bottomSeparatorNode = ASDisplayNode() self.bottomSeparatorNode.isLayerBacked = true + self.maskNode = ASImageNode() + self.maskNode.isUserInteractionEnabled = false + super.init() bringToFrontForHighlightImpl = { [weak self] in @@ -64,9 +68,10 @@ private final class PeerInfoScreenDisclosureEncryptionKeyItemNode: PeerInfoScree self.addSubnode(self.textNode) self.addSubnode(self.keyNode) self.addSubnode(self.arrowNode) + self.addSubnode(self.maskNode) } - override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat { guard let item = item as? PeerInfoScreenDisclosureEncryptionKeyItem else { return 10.0 } @@ -106,6 +111,14 @@ private final class PeerInfoScreenDisclosureEncryptionKeyItemNode: PeerInfoScree transition.updateFrame(node: self.textNode, frame: textFrame) + let hasCorners = hasCorners && (topItem == nil || bottomItem == nil) + let hasTopCorners = hasCorners && topItem == nil + let hasBottomCorners = hasCorners && bottomItem == nil + + self.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil + self.maskNode.frame = CGRect(origin: CGPoint(x: safeInsets.left, y: 0.0), size: CGSize(width: width - safeInsets.left - safeInsets.right, height: height)) + self.bottomSeparatorNode.isHidden = hasBottomCorners + let highlightNodeOffset: CGFloat = topItem == nil ? 0.0 : UIScreenPixel self.selectionNode.update(size: CGSize(width: width, height: height + highlightNodeOffset), theme: presentationData.theme, transition: transition) transition.updateFrame(node: self.selectionNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -highlightNodeOffset), size: CGSize(width: width, height: height + highlightNodeOffset))) diff --git a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenDisclosureItem.swift b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenDisclosureItem.swift index a7e103e247..58cf4520ef 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenDisclosureItem.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenDisclosureItem.swift @@ -109,7 +109,7 @@ private final class PeerInfoScreenDisclosureItemNode: PeerInfoScreenItemNode { self.addSubnode(self.activateArea) } - override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat { guard let item = item as? PeerInfoScreenDisclosureItem else { return 10.0 } @@ -196,7 +196,7 @@ private final class PeerInfoScreenDisclosureItemNode: PeerInfoScreenItemNode { transition.updateFrame(node: self.labelNode, frame: labelFrame) transition.updateFrame(node: self.textNode, frame: textFrame) - let hasCorners = safeInsets.left > 0.0 && (topItem == nil || bottomItem == nil) + let hasCorners = hasCorners && (topItem == nil || bottomItem == nil) let hasTopCorners = hasCorners && topItem == nil let hasBottomCorners = hasCorners && bottomItem == nil diff --git a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenHeaderItem.swift b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenHeaderItem.swift index c67b135ea8..2e34525e62 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenHeaderItem.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenHeaderItem.swift @@ -36,7 +36,7 @@ private final class PeerInfoScreenHeaderItemNode: PeerInfoScreenItemNode { self.addSubnode(self.activateArea) } - override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat { guard let item = item as? PeerInfoScreenHeaderItem else { return 10.0 } diff --git a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenInfoItem.swift b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenInfoItem.swift index d97fd8fb65..ad6ad98d73 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenInfoItem.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenInfoItem.swift @@ -52,7 +52,7 @@ private final class PeerInfoScreenInfoItemNode: PeerInfoScreenItemNode { self.addSubnode(self.bottomSeparatorNode) } - override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat { guard let item = item as? PeerInfoScreenInfoItem else { return 10.0 } @@ -103,7 +103,7 @@ private final class PeerInfoScreenInfoItemNode: PeerInfoScreenItemNode { separatorInset += 49.0 } - let hasCorners = safeInsets.left > 0.0 && (topItem == nil || bottomItem == nil) + let hasCorners = hasCorners && (topItem == nil || bottomItem == nil) let hasTopCorners = hasCorners && topItem == nil let hasBottomCorners = hasCorners && bottomItem == nil diff --git a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenLabeledValueItem.swift b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenLabeledValueItem.swift index f3f7d8bcc2..190cb52ea3 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenLabeledValueItem.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenLabeledValueItem.swift @@ -54,6 +54,7 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem { private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode { private let selectionNode: PeerInfoScreenSelectableBackgroundNode + private let maskNode: ASImageNode private let labelNode: ImmediateTextNode private let textNode: ImmediateTextNode private let bottomSeparatorNode: ASDisplayNode @@ -75,6 +76,9 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode { self.selectionNode = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() }) self.selectionNode.isUserInteractionEnabled = false + self.maskNode = ASImageNode() + self.maskNode.isUserInteractionEnabled = false + self.labelNode = ImmediateTextNode() self.labelNode.displaysAsynchronously = false self.labelNode.isUserInteractionEnabled = false @@ -102,6 +106,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode { self.addSubnode(self.bottomSeparatorNode) self.addSubnode(self.selectionNode) + self.addSubnode(self.maskNode) self.addSubnode(self.labelNode) self.addSubnode(self.textNode) @@ -184,7 +189,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode { } } - override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat { guard let item = item as? PeerInfoScreenLabeledValueItem else { return 10.0 } @@ -267,6 +272,13 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode { transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: sideInset, y: height - UIScreenPixel), size: CGSize(width: width - sideInset, height: UIScreenPixel))) transition.updateAlpha(node: self.bottomSeparatorNode, alpha: bottomItem == nil ? 0.0 : 1.0) + let hasCorners = hasCorners && (topItem == nil || bottomItem == nil) + let hasTopCorners = hasCorners && topItem == nil + let hasBottomCorners = hasCorners && bottomItem == nil + + self.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil + self.maskNode.frame = CGRect(origin: CGPoint(x: safeInsets.left, y: 0.0), size: CGSize(width: width - safeInsets.left - safeInsets.right, height: height)) + self.bottomSeparatorNode.isHidden = hasBottomCorners self.activateArea.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: height)) self.activateArea.accessibilityLabel = item.label diff --git a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift index 2af5ba8af4..b1e3bc666b 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift @@ -112,7 +112,7 @@ private final class PeerInfoScreenMemberItemNode: PeerInfoScreenItemNode { } } - override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat { guard let item = item as? PeerInfoScreenMemberItem else { return 10.0 } @@ -226,7 +226,7 @@ private final class PeerInfoScreenMemberItemNode: PeerInfoScreenItemNode { transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(), size: itemNode.bounds.size)) - let hasCorners = safeInsets.left > 0.0 && (topItem == nil || bottomItem == nil) + let hasCorners = hasCorners && (topItem == nil || bottomItem == nil) let hasTopCorners = hasCorners && topItem == nil let hasBottomCorners = hasCorners && bottomItem == nil diff --git a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenSwitchItem.swift b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenSwitchItem.swift index 6320bdbcc6..0f0d6dfe61 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenSwitchItem.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenSwitchItem.swift @@ -84,7 +84,7 @@ private final class PeerInfoScreenSwitchItemNode: PeerInfoScreenItemNode { } } - override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat { guard let item = item as? PeerInfoScreenSwitchItem else { return 10.0 } @@ -149,7 +149,7 @@ private final class PeerInfoScreenSwitchItemNode: PeerInfoScreenItemNode { } } - let hasCorners = safeInsets.left > 0.0 && (topItem == nil || bottomItem == nil) + let hasCorners = hasCorners && (topItem == nil || bottomItem == nil) let hasTopCorners = hasCorners && topItem == nil let hasBottomCorners = hasCorners && bottomItem == nil diff --git a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoMembersPane.swift b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoMembersPane.swift index e5edf5d591..603fde8cf4 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoMembersPane.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoMembersPane.swift @@ -9,6 +9,7 @@ import ContextUI import PhotoResources import TelegramUIPreferences import ItemListPeerItem +import ItemListPeerActionItem import MergeLists import ItemListUI @@ -26,74 +27,117 @@ enum PeerMembersListAction { case remove } -private struct PeerMembersListEntry: Comparable, Identifiable { - let theme: PresentationTheme - let index: Int - let member: PeerInfoMember - - var stableId: PeerId { - return self.member.id +private enum PeerMembersListEntryStableId: Hashable { + case addMember + case peer(PeerId) +} + +private enum PeerMembersListEntry: Comparable, Identifiable { + case addMember(PresentationTheme, String) + case member(PresentationTheme, Int, PeerInfoMember) + + var stableId: PeerMembersListEntryStableId { + switch self { + case .addMember: + return .addMember + case let .member(_, _, member): + return .peer(member.id) + } } static func ==(lhs: PeerMembersListEntry, rhs: PeerMembersListEntry) -> Bool { - return lhs.theme === rhs.theme && lhs.member == rhs.member + switch lhs { + case let .addMember(lhsTheme, lhsText): + if case let .addMember(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .member(lhsTheme, lhsIndex, lhsMember): + if case let .member(rhsTheme, rhsIndex, rhsMember) = rhs, lhsTheme === rhsTheme, lhsIndex == rhsIndex, lhsMember == rhsMember { + return true + } else { + return false + } + } } static func <(lhs: PeerMembersListEntry, rhs: PeerMembersListEntry) -> Bool { - return lhs.index < rhs.index + switch lhs { + case .addMember: + switch rhs { + case .addMember: + return false + case .member: + return true + } + case let .member(_, lhsIndex, _): + switch rhs { + case .addMember: + return false + case let .member(_, rhsIndex, _): + return lhsIndex < rhsIndex + } + } } - func item(context: AccountContext, presentationData: PresentationData, enclosingPeer: Peer, action: @escaping (PeerInfoMember, PeerMembersListAction) -> Void) -> ListViewItem { - let member = self.member - let label: String? - if let rank = member.rank { - label = rank - } else { - switch member.role { - case .creator: - label = presentationData.strings.GroupInfo_LabelOwner - case .admin: - label = presentationData.strings.GroupInfo_LabelAdmin - case .member: - label = nil - } + func item(context: AccountContext, presentationData: PresentationData, enclosingPeer: Peer, addMemberAction: @escaping () -> Void, action: @escaping (PeerInfoMember, PeerMembersListAction) -> Void) -> ListViewItem { + switch self { + case let .addMember(_, text): + return ItemListPeerActionItem(presentationData: ItemListPresentationData(presentationData), icon: PresentationResourcesItemList.addPersonIcon(presentationData.theme), title: text, alwaysPlain: true, sectionId: 0, height: .compactPeerList, color: .accent, editing: false, action: { + addMemberAction() + }) + case let .member(_, _, member): + let label: String? + if let rank = member.rank { + label = rank + } else { + switch member.role { + case .creator: + label = presentationData.strings.GroupInfo_LabelOwner + case .admin: + label = presentationData.strings.GroupInfo_LabelAdmin + case .member: + label = nil + } + } + + let actions = availableActionsForMemberOfPeer(accountPeerId: context.account.peerId, peer: enclosingPeer, member: member) + + var options: [ItemListPeerItemRevealOption] = [] + if actions.contains(.promote) && enclosingPeer is TelegramChannel{ + options.append(ItemListPeerItemRevealOption(type: .neutral, title: presentationData.strings.GroupInfo_ActionPromote, action: { + action(member, .promote) + })) + } + if actions.contains(.restrict) { + if enclosingPeer is TelegramChannel { + options.append(ItemListPeerItemRevealOption(type: .warning, title: presentationData.strings.GroupInfo_ActionRestrict, action: { + action(member, .restrict) + })) + } + options.append(ItemListPeerItemRevealOption(type: .destructive, title: presentationData.strings.Common_Delete, action: { + action(member, .remove) + })) + } + + return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: EnginePeer(member.peer), presence: member.presence.flatMap(EnginePeer.Presence.init), text: .presence, label: label == nil ? .none : .text(label!, .standard), editing: ItemListPeerItemEditing(editable: !options.isEmpty, editing: false, revealed: false), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, selectable: member.id != context.account.peerId, sectionId: 0, action: { + action(member, .open) + }, setPeerIdWithRevealedOptions: { _, _ in + }, removePeer: { _ in + }, contextAction: nil/*{ node, gesture in + openPeerContextAction(peer, node, gesture) + }*/, hasTopStripe: false, noInsets: true, disableInteractiveTransitionIfNecessary: true) } - - let actions = availableActionsForMemberOfPeer(accountPeerId: context.account.peerId, peer: enclosingPeer, member: member) - - var options: [ItemListPeerItemRevealOption] = [] - if actions.contains(.promote) && enclosingPeer is TelegramChannel{ - options.append(ItemListPeerItemRevealOption(type: .neutral, title: presentationData.strings.GroupInfo_ActionPromote, action: { - action(member, .promote) - })) - } - if actions.contains(.restrict) { - if enclosingPeer is TelegramChannel { - options.append(ItemListPeerItemRevealOption(type: .warning, title: presentationData.strings.GroupInfo_ActionRestrict, action: { - action(member, .restrict) - })) - } - options.append(ItemListPeerItemRevealOption(type: .destructive, title: presentationData.strings.Common_Delete, action: { - action(member, .remove) - })) - } - - return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: EnginePeer(member.peer), presence: member.presence.flatMap(EnginePeer.Presence.init), text: .presence, label: label == nil ? .none : .text(label!, .standard), editing: ItemListPeerItemEditing(editable: !options.isEmpty, editing: false, revealed: false), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, selectable: member.id != context.account.peerId, sectionId: 0, action: { - action(member, .open) - }, setPeerIdWithRevealedOptions: { _, _ in - }, removePeer: { _ in - }, contextAction: nil/*{ node, gesture in - openPeerContextAction(peer, node, gesture) - }*/, hasTopStripe: false, noInsets: true, disableInteractiveTransitionIfNecessary: true) } } -private func preparedTransition(from fromEntries: [PeerMembersListEntry], to toEntries: [PeerMembersListEntry], context: AccountContext, presentationData: PresentationData, enclosingPeer: Peer, action: @escaping (PeerInfoMember, PeerMembersListAction) -> Void) -> PeerMembersListTransaction { +private func preparedTransition(from fromEntries: [PeerMembersListEntry], to toEntries: [PeerMembersListEntry], context: AccountContext, presentationData: PresentationData, enclosingPeer: Peer, addMemberAction: @escaping () -> Void, action: @escaping (PeerInfoMember, PeerMembersListAction) -> Void) -> PeerMembersListTransaction { 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(context: context, presentationData: presentationData, enclosingPeer: enclosingPeer, action: action), directionHint: nil) } - let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enclosingPeer: enclosingPeer, action: action), directionHint: nil) } + let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enclosingPeer: enclosingPeer, addMemberAction: addMemberAction, action: action), directionHint: nil) } + let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enclosingPeer: enclosingPeer, addMemberAction: addMemberAction, action: action), directionHint: nil) } return PeerMembersListTransaction(deletions: deletions, insertions: insertions, updates: updates, animated: toEntries.count < fromEntries.count) } @@ -101,6 +145,7 @@ private func preparedTransition(from fromEntries: [PeerMembersListEntry], to toE final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode { private let context: AccountContext private let membersContext: PeerInfoMembersContext + private let addMemberAction: () -> Void private let action: (PeerInfoMember, PeerMembersListAction) -> Void weak var parentController: ViewController? @@ -132,9 +177,10 @@ final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode { private var disposable: Disposable? - init(context: AccountContext, peerId: PeerId, membersContext: PeerInfoMembersContext, action: @escaping (PeerInfoMember, PeerMembersListAction) -> Void) { + init(context: AccountContext, peerId: PeerId, membersContext: PeerInfoMembersContext, addMemberAction: @escaping () -> Void, action: @escaping (PeerInfoMember, PeerMembersListAction) -> Void) { self.context = context self.membersContext = membersContext + self.addMemberAction = addMemberAction self.action = action let presentationData = context.sharedContext.currentPresentationData.with { $0 } @@ -216,10 +262,16 @@ final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode { private func updateState(enclosingPeer: Peer, state: PeerInfoMembersState, presentationData: PresentationData) { var entries: [PeerMembersListEntry] = [] - for member in state.members { - entries.append(PeerMembersListEntry(theme: presentationData.theme, index: entries.count, member: member)) + if state.canAddMembers { + entries.append(.addMember(presentationData.theme, presentationData.strings.PeerInfo_ButtonAddMember)) } - let transaction = preparedTransition(from: self.currentEntries, to: entries, context: self.context, presentationData: presentationData, enclosingPeer: enclosingPeer, action: { [weak self] member, action in + for member in state.members { + entries.append(.member(presentationData.theme, entries.count, member)) + } + + let transaction = preparedTransition(from: self.currentEntries, to: entries, context: self.context, presentationData: presentationData, enclosingPeer: enclosingPeer, addMemberAction: { [weak self] in + self?.addMemberAction() + }, action: { [weak self] member, action in self?.action(member, action) }) self.enclosingPeer = enclosingPeer diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift index accf0f0a89..f12904a654 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift @@ -1066,9 +1066,6 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro hasDiscussion = true } case .group: - if channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers) { - result.append(.addMember) - } if channel.flags.contains(.hasVoiceChat) { hasVoiceChat = true } @@ -1082,10 +1079,10 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro default: displayLeave = false } - result.append(.mute) if hasVoiceChat || canStartVoiceChat { result.append(.voiceChat) } + result.append(.mute) if hasDiscussion { result.append(.discussion) } @@ -1104,7 +1101,6 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro result.append(.more) } } else if let group = peer as? TelegramGroup { - var canAddMembers = false var hasVoiceChat = false var canStartVoiceChat = false @@ -1119,18 +1115,6 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro } } - switch group.role { - case .admin, .creator: - canAddMembers = true - case .member: - break - } - if !group.hasBannedPermission(.banAddMembers) { - canAddMembers = true - } - if canAddMembers { - result.append(.addMember) - } result.append(.mute) if hasVoiceChat || canStartVoiceChat { result.append(.voiceChat) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift index 05b55fd2d5..6ceea907db 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift @@ -53,7 +53,7 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode { private let action: (PeerInfoHeaderButtonNode, ContextGesture?) -> Void let referenceNode: ContextReferenceContentNode let containerNode: ContextControllerSourceNode - private let backgroundNode: ASImageNode + private let backgroundNode: ASDisplayNode private let iconNode: ASImageNode private let textNode: ImmediateTextNode private var animationNode: AnimationNode? @@ -70,9 +70,8 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode { self.containerNode = ContextControllerSourceNode() self.containerNode.animateScale = false - self.backgroundNode = ASImageNode() - self.backgroundNode.displaysAsynchronously = false - self.backgroundNode.displayWithoutProcessing = true + self.backgroundNode = ASDisplayNode() + self.backgroundNode.cornerRadius = 11.0 self.iconNode = ASImageNode() self.iconNode.displaysAsynchronously = false @@ -127,6 +126,9 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode { let iconUpdated = self.icon != icon let isActiveUpdated = self.isActive != isActive self.isActive = isActive + + let iconSize = CGSize(width: 40.0, height: 40.0) + if self.theme != presentationData.theme || self.icon != icon { self.theme = presentationData.theme self.icon = icon @@ -141,7 +143,7 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode { var colors: [String: UIColor] = [:] var playOnce = false var seekToEnd = false - let iconColor = presentationData.theme.list.itemCheckColors.foregroundColor + let iconColor = presentationData.theme.list.itemAccentColor switch icon { case .voiceChat: animationName = "anim_profilevc" @@ -198,7 +200,6 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode { self.referenceNode.addSubnode(animationNode) self.animationNode = animationNode } - animationNode.frame = CGRect(origin: CGPoint(), size: size) } else if let animationNode = self.animationNode { self.animationNode = nil animationNode.removeFromSupernode() @@ -210,11 +211,12 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode { self.animationNode?.seekToEnd() } - self.backgroundNode.image = generateFilledCircleImage(diameter: 40.0, color: presentationData.theme.list.itemAccentColor) - self.iconNode.image = generateImage(CGSize(width: 40.0, height: 40.0), contextGenerator: { size, context in + self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor + transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size)) + self.iconNode.image = generateImage(iconSize, contextGenerator: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) context.setBlendMode(.normal) - context.setFillColor(presentationData.theme.list.itemCheckColors.foregroundColor.cgColor) + context.setFillColor(iconColor.cgColor) let imageName: String? switch icon { case .message: @@ -246,24 +248,26 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode { }) } - let alpha: CGFloat = isActive ? 1.0 : 0.3 - if isActiveUpdated, !self.containerNode.alpha.isZero { + if isActiveUpdated { let alphaTransition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut) - alphaTransition.updateAlpha(node: self.backgroundNode, alpha: isActive ? 1.0 : 0.3) - if !isExpanded { - alphaTransition.updateAlpha(node: self.textNode, alpha: isActive ? 1.0 : 0.3) + alphaTransition.updateAlpha(node: self.iconNode, alpha: isActive ? 1.0 : 0.3) + if let animationNode = self.animationNode { + alphaTransition.updateAlpha(node: animationNode, alpha: isActive ? 1.0 : 0.3) } + alphaTransition.updateAlpha(node: self.textNode, alpha: isActive ? 1.0 : 0.3) } - self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(12.0), textColor: presentationData.theme.list.itemAccentColor) + self.textNode.attributedText = NSAttributedString(string: text.lowercased(), font: Font.regular(11.0), textColor: presentationData.theme.list.itemAccentColor) self.accessibilityLabel = text let titleSize = self.textNode.updateLayout(CGSize(width: 120.0, height: .greatestFiniteMagnitude)) transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(), size: size)) transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size)) - transition.updateFrame(node: self.iconNode, frame: CGRect(origin: CGPoint(), size: size)) - transition.updateFrameAdditiveToCenter(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: size.height + 6.0), size: titleSize)) - transition.updateAlpha(node: self.textNode, alpha: isExpanded ? 0.0 : alpha) + transition.updateFrame(node: self.iconNode, frame: CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: 1.0), size: iconSize)) + if let animationNode = self.animationNode { + transition.updateFrame(node: animationNode, frame: CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: 1.0), size: iconSize)) + } + transition.updateFrameAdditiveToCenter(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: size.height - titleSize.height - 9.0), size: titleSize)) self.referenceNode.frame = self.containerNode.bounds } @@ -1267,9 +1271,9 @@ final class PeerInfoHeaderSingleLineTextFieldNode: ASDisplayNode, PeerInfoHeader if self.theme !== presentationData.theme { self.theme = presentationData.theme - if isSettings { - self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor - } + + self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor + self.textNode.textField.textColor = presentationData.theme.list.itemPrimaryTextColor self.textNode.textField.keyboardAppearance = presentationData.theme.rootController.keyboardColor.keyboardAppearance self.textNode.textField.tintColor = presentationData.theme.list.itemAccentColor @@ -1287,7 +1291,7 @@ final class PeerInfoHeaderSingleLineTextFieldNode: ASDisplayNode, PeerInfoHeader self.textNode.textField.text = updateText } - if !hasPrevious && isSettings { + if !hasPrevious { self.topSeparator.isHidden = true } self.topSeparator.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor @@ -1325,12 +1329,14 @@ final class PeerInfoHeaderSingleLineTextFieldNode: ASDisplayNode, PeerInfoHeader } final class PeerInfoHeaderMultiLineTextFieldNode: ASDisplayNode, PeerInfoHeaderTextFieldNode, ASEditableTextNodeDelegate { + private let backgroundNode: ASDisplayNode private let textNode: EditableTextNode private let textNodeContainer: ASDisplayNode private let measureTextNode: ImmediateTextNode private let clearIconNode: ASImageNode private let clearButtonNode: HighlightableButtonNode private let topSeparator: ASDisplayNode + private let maskNode: ASImageNode private let requestUpdateHeight: () -> Void @@ -1346,6 +1352,8 @@ final class PeerInfoHeaderMultiLineTextFieldNode: ASDisplayNode, PeerInfoHeaderT init(requestUpdateHeight: @escaping () -> Void) { self.requestUpdateHeight = requestUpdateHeight + self.backgroundNode = ASDisplayNode() + self.textNode = EditableTextNode() self.textNode.clipsToBounds = false self.textNode.textView.clipsToBounds = false @@ -1365,13 +1373,18 @@ final class PeerInfoHeaderMultiLineTextFieldNode: ASDisplayNode, PeerInfoHeaderT self.clearButtonNode = HighlightableButtonNode() self.clearButtonNode.isHidden = true + self.maskNode = ASImageNode() + self.maskNode.isUserInteractionEnabled = false + super.init() + self.addSubnode(self.backgroundNode) self.textNodeContainer.addSubnode(self.textNode) self.addSubnode(self.textNodeContainer) self.addSubnode(self.clearIconNode) self.addSubnode(self.clearButtonNode) self.addSubnode(self.topSeparator) + self.addSubnode(self.maskNode) self.clearButtonNode.addTarget(self, action: #selector(self.clearButtonPressed), forControlEvents: .touchUpInside) self.clearButtonNode.highligthedChanged = { [weak self] highlighted in @@ -1411,8 +1424,10 @@ final class PeerInfoHeaderMultiLineTextFieldNode: ASDisplayNode, PeerInfoHeaderT if self.theme !== presentationData.theme { self.theme = presentationData.theme - let textColor = presentationData.theme.list.itemPrimaryTextColor + self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor + + let textColor = presentationData.theme.list.itemPrimaryTextColor self.textNode.typingAttributes = [NSAttributedString.Key.font.rawValue: titleFont, NSAttributedString.Key.foregroundColor.rawValue: textColor] self.textNode.keyboardAppearance = presentationData.theme.rootController.keyboardColor.keyboardAppearance self.textNode.tintColor = presentationData.theme.list.itemAccentColor @@ -1425,7 +1440,9 @@ final class PeerInfoHeaderMultiLineTextFieldNode: ASDisplayNode, PeerInfoHeaderT } self.topSeparator.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor - self.topSeparator.frame = CGRect(origin: CGPoint(x: safeInset + (hasPrevious ? 16.0 : 0.0), y: 0.0), size: CGSize(width: width, height: UIScreenPixel)) + + let separatorX = safeInset + (hasPrevious ? 16.0 : 0.0) + self.topSeparator.frame = CGRect(origin: CGPoint(x: separatorX, y: 0.0), size: CGSize(width: width - separatorX - safeInset, height: UIScreenPixel)) let attributedPlaceholderText = NSAttributedString(string: placeholder, font: titleFont, textColor: presentationData.theme.list.itemPlaceholderTextColor) if self.textNode.attributedPlaceholderText == nil || !self.textNode.attributedPlaceholderText!.isEqual(to: attributedPlaceholderText) { @@ -1458,6 +1475,15 @@ final class PeerInfoHeaderMultiLineTextFieldNode: ASDisplayNode, PeerInfoHeaderT self.textNodeContainer.frame = textNodeFrame self.textNode.frame = CGRect(origin: CGPoint(), size: textNodeFrame.size) + self.backgroundNode.frame = CGRect(origin: CGPoint(x: safeInset, y: 0.0), size: CGSize(width: max(1.0, width - safeInset * 2.0), height: height)) + + let hasCorners = safeInset > 0.0 && (!hasPrevious || !hasNext) + let hasTopCorners = hasCorners && !hasPrevious + let hasBottomCorners = hasCorners && !hasNext + + self.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil + self.maskNode.frame = CGRect(origin: CGPoint(x: safeInset, y: 0.0), size: CGSize(width: width - safeInset - safeInset, height: height)) + return height } @@ -1560,10 +1586,7 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode { func update(width: CGFloat, safeInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, peer: Peer?, cachedData: CachedPeerData?, isContact: Bool, isSettings: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat { let avatarSize: CGFloat = isModalOverlay ? 200.0 : 100.0 - var avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize)) - if isSettings { - avatarFrame = avatarFrame.offsetBy(dx: 0.0, dy: 3.0) - } + let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 13.0), size: CGSize(width: avatarSize, height: avatarSize)) transition.updateFrameAdditiveToCenter(node: self.avatarNode, frame: CGRect(origin: avatarFrame.center, size: CGSize())) var contentHeight: CGFloat = statusBarHeight + 10.0 + avatarSize + 20.0 @@ -1691,12 +1714,12 @@ final class PeerInfoHeaderNode: ASDisplayNode { private let videoCallsEnabled: Bool private(set) var isAvatarExpanded: Bool - private(set) var twoLineInfo = false var skipCollapseCompletion = false var ignoreCollapse = false let avatarListNode: PeerInfoAvatarListNode + let buttonsContainerNode: SparseNode let regularContentNode: PeerInfoHeaderRegularContentNode let editingContentNode: PeerInfoHeaderEditingContentNode let avatarOverlayNode: PeerInfoEditingAvatarOverlayNode @@ -1735,6 +1758,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { var navigationTransition: PeerInfoHeaderNavigationTransition? + var backgroundAlpha: CGFloat = 1.0 var updateHeaderAlpha: ((CGFloat, ContainedViewLayoutTransition) -> Void)? init(context: AccountContext, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, isSettings: Bool) { @@ -1774,6 +1798,9 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.usernameNode = MultiScaleTextNode(stateKeys: [TitleNodeStateRegular, TitleNodeStateExpanded]) self.usernameNode.displaysAsynchronously = false + self.buttonsContainerNode = SparseNode() + self.buttonsContainerNode.clipsToBounds = true + self.regularContentNode = PeerInfoHeaderRegularContentNode() var requestUpdateLayoutImpl: (() -> Void)? self.editingContentNode = PeerInfoHeaderEditingContentNode(context: context, requestUpdateLayout: { @@ -1813,28 +1840,22 @@ final class PeerInfoHeaderNode: ASDisplayNode { self?.requestUpdateLayout?() } + self.addSubnode(self.buttonsContainerNode) self.addSubnode(self.backgroundNode) self.addSubnode(self.expandedBackgroundNode) self.titleNodeContainer.addSubnode(self.titleNode) self.subtitleNodeContainer.addSubnode(self.subtitleNode) self.subtitleNodeContainer.addSubnode(self.panelSubtitleNode) self.usernameNodeContainer.addSubnode(self.usernameNode) - if !self.isSettings { - self.regularContentNode.addSubnode(self.titleNodeContainer) - self.regularContentNode.addSubnode(self.subtitleNodeContainer) - self.regularContentNode.addSubnode(self.subtitleNodeRawContainer) - self.regularContentNode.addSubnode(self.usernameNodeContainer) - self.regularContentNode.addSubnode(self.usernameNodeRawContainer) - } + self.regularContentNode.addSubnode(self.avatarListNode) self.regularContentNode.addSubnode(self.avatarListNode.listContainerNode.controlsClippingOffsetNode) - if self.isSettings { - self.regularContentNode.addSubnode(self.titleNodeContainer) - self.regularContentNode.addSubnode(self.subtitleNodeContainer) - self.regularContentNode.addSubnode(self.subtitleNodeRawContainer) - self.regularContentNode.addSubnode(self.usernameNodeContainer) - self.regularContentNode.addSubnode(self.usernameNodeRawContainer) - } + self.regularContentNode.addSubnode(self.titleNodeContainer) + self.regularContentNode.addSubnode(self.subtitleNodeContainer) + self.regularContentNode.addSubnode(self.subtitleNodeRawContainer) + self.regularContentNode.addSubnode(self.usernameNodeContainer) + self.regularContentNode.addSubnode(self.usernameNodeRawContainer) + self.addSubnode(self.regularContentNode) self.addSubnode(self.editingContentNode) self.addSubnode(self.avatarOverlayNode) @@ -1956,7 +1977,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { } self.avatarListNode.listContainerNode.updateEntryIsHidden(entry: entry) } - + var initializedCredibilityIcon = false func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, notificationSettings: TelegramPeerNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: PeerInfoStatusData?, isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat { self.state = state @@ -2011,6 +2032,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { } self.regularContentNode.alpha = state.isEditing ? 0.0 : 1.0 + self.buttonsContainerNode.alpha = self.regularContentNode.alpha self.editingContentNode.alpha = state.isEditing ? 1.0 : 0.0 let editingContentHeight = self.editingContentNode.update(width: width, safeInset: containerInset, statusBarHeight: statusBarHeight, navigationHeight: navigationHeight, isModalOverlay: isModalOverlay, peer: state.isEditing ? peer : nil, cachedData: cachedData, isContact: isContact, isSettings: isSettings, presentationData: presentationData, transition: transition) @@ -2027,6 +2049,8 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.backgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate) + let headerBackgroundColor: UIColor = presentationData.theme.list.blocksBackgroundColor + var effectiveSeparatorAlpha: CGFloat if let navigationTransition = self.navigationTransition, let sourceAvatarNode = (navigationTransition.sourceNavigationBar.rightButtonNode.singleCustomNode as? ChatAvatarNavigationNode)?.avatarNode { transitionSourceHeight = navigationTransition.sourceNavigationBar.backgroundNode.bounds.height transitionFraction = navigationTransition.fraction @@ -2034,15 +2058,18 @@ final class PeerInfoHeaderNode: ASDisplayNode { transitionSourceTitleFrame = navigationTransition.sourceTitleFrame transitionSourceSubtitleFrame = navigationTransition.sourceSubtitleFrame - self.expandedBackgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.blurredBackgroundColor.mixedWith(presentationData.theme.list.itemBlocksBackgroundColor, alpha: 1.0 - transitionFraction), forceKeepBlur: true, transition: transition) + self.expandedBackgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.blurredBackgroundColor.mixedWith(headerBackgroundColor, alpha: 1.0 - transitionFraction), forceKeepBlur: true, transition: transition) + effectiveSeparatorAlpha = transitionFraction if self.isAvatarExpanded, case .animated = transition, transitionFraction == 1.0 { self.avatarListNode.animateAvatarCollapse(transition: transition) } } else { - let backgroundTransitionFraction: CGFloat = max(0.0, min(1.0, contentOffset / (112.0 + avatarSize))) + let contentOffset = max(0.0, contentOffset - 140.0) + let backgroundTransitionFraction: CGFloat = max(0.0, min(1.0, contentOffset / 30.0)) - self.expandedBackgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.opaqueBackgroundColor.mixedWith(presentationData.theme.list.itemBlocksBackgroundColor, alpha: 1.0 - backgroundTransitionFraction), forceKeepBlur: true, transition: transition) + self.expandedBackgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.opaqueBackgroundColor.mixedWith(headerBackgroundColor, alpha: 1.0 - backgroundTransitionFraction), forceKeepBlur: true, transition: transition) + effectiveSeparatorAlpha = backgroundTransitionFraction } self.avatarListNode.avatarContainerNode.updateTransitionFraction(transitionFraction, transition: transition) @@ -2062,13 +2089,12 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.navigationBackgroundBackgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.opaqueBackgroundColor self.navigationSeparatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor - let separatorAlpha: CGFloat = state.isEditing && self.isSettings ? min(1.0, contentOffset / (navigationHeight * 0.5)) : 0.0 - transition.updateAlpha(node: self.navigationBackgroundBackgroundNode, alpha: 1.0 - separatorAlpha) - transition.updateAlpha(node: self.navigationSeparatorNode, alpha: separatorAlpha) + let navigationSeparatorAlpha: CGFloat = state.isEditing && self.isSettings ? min(1.0, contentOffset / (navigationHeight * 0.5)) : 0.0 + transition.updateAlpha(node: self.navigationBackgroundBackgroundNode, alpha: 1.0 - navigationSeparatorAlpha) + transition.updateAlpha(node: self.navigationSeparatorNode, alpha: navigationSeparatorAlpha) self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor - let defaultButtonSize: CGFloat = 40.0 let expandedAvatarControlsHeight: CGFloat = 61.0 let expandedAvatarListHeight = min(width, containerHeight - expandedAvatarControlsHeight) let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight) @@ -2105,13 +2131,13 @@ final class PeerInfoHeaderNode: ASDisplayNode { title = " " } } - if self.isSettings { +// if self.isSettings { titleString = NSAttributedString(string: title, font: Font.medium(29.0), textColor: presentationData.theme.list.itemPrimaryTextColor) smallTitleString = NSAttributedString(string: title, font: Font.semibold(28.0), textColor: .white) - } else { - titleString = NSAttributedString(string: title, font: Font.semibold(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) - smallTitleString = titleString - } +// } else { +// titleString = NSAttributedString(string: title, font: Font.semibold(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) +// smallTitleString = titleString +// } if self.isSettings, let user = peer as? TelegramUser { var subtitle = formatPhoneNumber(user.phone ?? "") @@ -2128,8 +2154,8 @@ final class PeerInfoHeaderNode: ASDisplayNode { } else { subtitleColor = presentationData.theme.list.itemSecondaryTextColor } - subtitleString = NSAttributedString(string: statusData.text, font: Font.regular(15.0), textColor: subtitleColor) - smallSubtitleString = subtitleString + smallSubtitleString = NSAttributedString(string: statusData.text, font: Font.regular(15.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.7)) + subtitleString = NSAttributedString(string: statusData.text, font: Font.regular(17.0), textColor: subtitleColor) usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor) if let panelStatusData = panelStatusData { @@ -2139,7 +2165,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { } else { subtitleColor = presentationData.theme.list.itemSecondaryTextColor } - panelSubtitleString = NSAttributedString(string: panelStatusData.text, font: Font.regular(15.0), textColor: subtitleColor) + panelSubtitleString = NSAttributedString(string: panelStatusData.text, font: Font.regular(17.0), textColor: subtitleColor) } } else { subtitleString = NSAttributedString(string: " ", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor) @@ -2154,11 +2180,8 @@ final class PeerInfoHeaderNode: ASDisplayNode { usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor) } - let textSideInset: CGFloat = 44.0 - var expandedAvatarHeight: CGFloat = expandedAvatarListSize.height - if !self.isSettings { - expandedAvatarHeight += expandedAvatarControlsHeight - } + let textSideInset: CGFloat = 36.0 + let expandedAvatarHeight: CGFloat = expandedAvatarListSize.height let titleConstrainedSize = CGSize(width: width - textSideInset * 2.0 - (isVerified ? 16.0 : 0.0), height: .greatestFiniteMagnitude) @@ -2170,13 +2193,13 @@ final class PeerInfoHeaderNode: ASDisplayNode { let subtitleNodeLayout = self.subtitleNode.updateLayout(states: [ TitleNodeStateRegular: MultiScaleTextState(attributedText: subtitleString, constrainedSize: titleConstrainedSize), - TitleNodeStateExpanded: MultiScaleTextState(attributedText: smallSubtitleString, constrainedSize: self.isSettings ? titleConstrainedSize : CGSize(width: titleConstrainedSize.width - 82.0, height: titleConstrainedSize.height)) + TitleNodeStateExpanded: MultiScaleTextState(attributedText: smallSubtitleString, constrainedSize: titleConstrainedSize) ], mainState: TitleNodeStateRegular) self.subtitleNode.accessibilityLabel = subtitleString.string let panelSubtitleNodeLayout = self.panelSubtitleNode.updateLayout(states: [ TitleNodeStateRegular: MultiScaleTextState(attributedText: panelSubtitleString ?? subtitleString, constrainedSize: titleConstrainedSize), - TitleNodeStateExpanded: MultiScaleTextState(attributedText: panelSubtitleString ?? subtitleString, constrainedSize: CGSize(width: titleConstrainedSize.width - 82.0, height: titleConstrainedSize.height)) + TitleNodeStateExpanded: MultiScaleTextState(attributedText: panelSubtitleString ?? subtitleString, constrainedSize: titleConstrainedSize) ], mainState: TitleNodeStateRegular) self.panelSubtitleNode.accessibilityLabel = (panelSubtitleString ?? subtitleString).string @@ -2186,10 +2209,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { ], mainState: TitleNodeStateRegular) self.usernameNode.accessibilityLabel = usernameString.string - var avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize)) - if isSettings { - avatarFrame = avatarFrame.offsetBy(dx: 0.0, dy: 3.0) - } + let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 13.0), size: CGSize(width: avatarSize, height: avatarSize)) let avatarCenter = CGPoint(x: (1.0 - transitionFraction) * avatarFrame.midX + transitionFraction * transitionSourceAvatarFrame.midX, y: (1.0 - transitionFraction) * avatarFrame.midY + transitionFraction * transitionSourceAvatarFrame.midY) let titleSize = titleNodeLayout[TitleNodeStateRegular]!.size @@ -2208,34 +2228,25 @@ final class PeerInfoHeaderNode: ASDisplayNode { let subtitleFrame: CGRect let usernameFrame: CGRect let usernameSpacing: CGFloat = 4.0 - var twoLineInfo = false - if self.isSettings { - transition.updateFrame(node: self.avatarListNode.listContainerNode.bottomShadowNode, frame: CGRect(origin: CGPoint(x: 0.0, y: expandedAvatarHeight - 70.0), size: CGSize(width: width, height: 70.0))) - } + + transition.updateFrame(node: self.avatarListNode.listContainerNode.bottomShadowNode, frame: CGRect(origin: CGPoint(x: 0.0, y: expandedAvatarHeight - 70.0), size: CGSize(width: width, height: 70.0))) if self.isAvatarExpanded { let minTitleSize = CGSize(width: titleSize.width * 0.7, height: titleSize.height * 0.7) let minTitleFrame: CGRect - if self.isSettings { - minTitleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - 58.0 - UIScreenPixel + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: minTitleSize) - } else { - minTitleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - expandedAvatarControlsHeight + 9.0 + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: minTitleSize) - } + + minTitleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - 58.0 - UIScreenPixel + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: minTitleSize) + titleFrame = CGRect(origin: CGPoint(x: minTitleFrame.midX - titleSize.width / 2.0, y: minTitleFrame.midY - titleSize.height / 2.0), size: titleSize) - if self.isSettings { - subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: minTitleFrame.maxY + 2.0), size: subtitleSize) - } else { - subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: minTitleFrame.maxY + 4.0), size: subtitleSize) - } + subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: minTitleFrame.maxY + 2.0), size: subtitleSize) usernameFrame = CGRect(origin: CGPoint(x: width - usernameSize.width - 16.0, y: minTitleFrame.midY - usernameSize.height / 2.0), size: usernameSize) } else { titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 7.0 + (subtitleSize.height.isZero ? 11.0 : 0.0)), size: titleSize) - if self.isSettings { - titleFrame = titleFrame.offsetBy(dx: 0.0, dy: 11.0) - } + + titleFrame = titleFrame.offsetBy(dx: 0.0, dy: 11.0) + let totalSubtitleWidth = subtitleSize.width + usernameSpacing + usernameSize.width - twoLineInfo = false - if usernameSize.width == 0.0 || twoLineInfo { + if usernameSize.width == 0.0 { subtitleFrame = CGRect(origin: CGPoint(x: floor((width - subtitleSize.width) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize) usernameFrame = CGRect(origin: CGPoint(x: floor((width - usernameSize.width) / 2.0), y: subtitleFrame.maxY + 1.0), size: usernameSize) } else { @@ -2243,7 +2254,6 @@ final class PeerInfoHeaderNode: ASDisplayNode { usernameFrame = CGRect(origin: CGPoint(x: subtitleFrame.maxX + usernameSpacing, y: titleFrame.maxY + 1.0), size: usernameSize) } } - self.twoLineInfo = twoLineInfo let singleTitleLockOffset: CGFloat = (peer?.id == self.context.account.peerId || subtitleSize.height.isZero) ? 8.0 : 0.0 @@ -2253,7 +2263,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { let titleOffset = -min(titleCollapseOffset, contentOffset) let titleCollapseFraction = max(0.0, min(1.0, contentOffset / titleCollapseOffset)) - let titleMinScale: CGFloat = self.isSettings ? 0.6 : 0.7 + let titleMinScale: CGFloat = 0.6 let subtitleMinScale: CGFloat = 0.8 let avatarMinScale: CGFloat = 0.7 @@ -2273,6 +2283,12 @@ final class PeerInfoHeaderNode: ASDisplayNode { effectiveAreaExpansionFraction = 1.0 - paneAreaExpansionDelta / paneAreaExpansionDistance } + let secondarySeparatorAlpha = 1.0 - effectiveAreaExpansionFraction + if self.navigationTransition == nil && !self.isSettings && effectiveSeparatorAlpha == 1.0 && secondarySeparatorAlpha < 1.0 { + effectiveSeparatorAlpha = secondarySeparatorAlpha + } + transition.updateAlpha(node: self.separatorNode, alpha: effectiveSeparatorAlpha) + self.titleNode.update(stateFractions: [ TitleNodeStateRegular: self.isAvatarExpanded ? 0.0 : 1.0, TitleNodeStateExpanded: self.isAvatarExpanded ? 1.0 : 0.0 @@ -2285,12 +2301,6 @@ final class PeerInfoHeaderNode: ASDisplayNode { if self.isSettings { subtitleAlpha = 1.0 - titleCollapseFraction panelSubtitleAlpha = 0.0 - - var headerBackgroundAlpha: CGFloat = 0.0 - if !state.isEditing && titleCollapseFraction >= 0.8 { - headerBackgroundAlpha = (titleCollapseFraction - 0.8) / 0.2 - } - self.updateHeaderAlpha?(headerBackgroundAlpha, transition) } else { if (panelSubtitleString ?? subtitleString).string != subtitleString.string { subtitleAlpha = 1.0 - effectiveAreaExpansionFraction @@ -2422,23 +2432,19 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.avatarListNode.avatarContainerNode.canAttachVideo = false } - var panelWithAvatarHeight: CGFloat = (self.isSettings ? 40.0 : 112.0) + avatarSize - if twoLineInfo { - panelWithAvatarHeight += 17.0 - } - let buttonsCollapseStart = titleCollapseOffset - let buttonsCollapseEnd = panelWithAvatarHeight - (navigationHeight - statusBarHeight) + 10.0 - - let buttonsCollapseFraction = max(0.0, contentOffset - buttonsCollapseStart) / (buttonsCollapseEnd - buttonsCollapseStart) + let panelWithAvatarHeight: CGFloat = 40.0 + avatarSize let rawHeight: CGFloat let height: CGFloat + let maxY: CGFloat if self.isAvatarExpanded { rawHeight = expandedAvatarHeight height = max(navigationHeight, rawHeight - contentOffset) + maxY = height } else { rawHeight = navigationHeight + panelWithAvatarHeight height = navigationHeight + max(0.0, panelWithAvatarHeight - contentOffset) + maxY = navigationHeight + panelWithAvatarHeight - contentOffset } let apparentHeight = (1.0 - transitionFraction) * height + transitionFraction * transitionSourceHeight @@ -2474,12 +2480,14 @@ final class PeerInfoHeaderNode: ASDisplayNode { } else { let titleScale: CGFloat let subtitleScale: CGFloat + var subtitleOffset: CGFloat = 0.0 if self.isAvatarExpanded { titleScale = 0.7 subtitleScale = 1.0 } else { titleScale = (1.0 - titleCollapseFraction) * 1.0 + titleCollapseFraction * titleMinScale subtitleScale = (1.0 - titleCollapseFraction) * 1.0 + titleCollapseFraction * subtitleMinScale + subtitleOffset = titleCollapseFraction * -2.0 } let rawTitleFrame = titleFrame @@ -2498,6 +2506,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { var subtitleCenter = rawSubtitleFrame.center subtitleCenter.x = rawTitleFrame.center.x + (subtitleCenter.x - rawTitleFrame.center.x) * subtitleScale + subtitleCenter.y += subtitleOffset transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: CGRect(origin: subtitleCenter, size: CGSize()).offsetBy(dx: 0.0, dy: titleOffset)) var usernameCenter = rawUsernameFrame.center @@ -2513,63 +2522,16 @@ final class PeerInfoHeaderNode: ASDisplayNode { } } - let buttonSpacing: CGFloat - if self.isAvatarExpanded { - buttonSpacing = 16.0 - } else { - let normWidth = min(width, containerHeight) - let buttonSpacingValue = floor((normWidth - floor(CGFloat(buttonKeys.count) * defaultButtonSize)) / CGFloat(buttonKeys.count + 1)) - buttonSpacing = min(buttonSpacingValue, 160.0) - } + let buttonSpacing: CGFloat = 12.0 + var buttonRightOrigin = CGPoint(x: width - containerInset, y: maxY + 25.0 - navigationHeight - UIScreenPixel) + let buttonWidth = (width - containerInset * 2.0 + buttonSpacing) / CGFloat(buttonKeys.count) - buttonSpacing - let expandedButtonSize: CGFloat = 32.0 - let buttonsWidth = buttonSpacing * CGFloat(buttonKeys.count - 1) + CGFloat(buttonKeys.count) * defaultButtonSize - var buttonRightOrigin: CGPoint - if self.isAvatarExpanded { - buttonRightOrigin = CGPoint(x: width - 16.0, y: apparentHeight - 74.0) - } else { - buttonRightOrigin = CGPoint(x: floor((width - buttonsWidth) / 2.0) + buttonsWidth, y: apparentHeight - 74.0) - } - let buttonsScale: CGFloat - let buttonsAlpha: CGFloat - let apparentButtonSize: CGFloat - let buttonsVerticalOffset: CGFloat + let apparentButtonSize = CGSize(width: buttonWidth, height: 58.0) + let buttonsAlpha: CGFloat = 1.0 + let buttonsVerticalOffset: CGFloat = 0.0 - var buttonsAlphaTransition = transition + let buttonsAlphaTransition = transition - if self.navigationTransition != nil { - if case let .animated(duration, curve) = transition, transitionFraction >= 1.0 - CGFloat.ulpOfOne { - buttonsAlphaTransition = .animated(duration: duration * 0.6, curve: curve) - } - if self.isAvatarExpanded { - apparentButtonSize = expandedButtonSize - } else { - apparentButtonSize = defaultButtonSize - } - let neutralButtonsScale = apparentButtonSize / defaultButtonSize - buttonsScale = (1.0 - transitionFraction) * neutralButtonsScale + 0.2 * transitionFraction - buttonsAlpha = 1.0 - transitionFraction - - let neutralButtonsOffset: CGFloat - if self.isAvatarExpanded { - neutralButtonsOffset = 74.0 - 15.0 - defaultButtonSize + (defaultButtonSize - apparentButtonSize) / 2.0 - } else { - neutralButtonsOffset = (1.0 - buttonsScale) * apparentButtonSize - } - - buttonsVerticalOffset = (1.0 - transitionFraction) * neutralButtonsOffset + ((1.0 - buttonsScale) * apparentButtonSize) * transitionFraction - } else { - apparentButtonSize = self.isAvatarExpanded ? expandedButtonSize : defaultButtonSize - if self.isAvatarExpanded { - buttonsScale = apparentButtonSize / defaultButtonSize - buttonsVerticalOffset = 74.0 - 15.0 - defaultButtonSize + (defaultButtonSize - apparentButtonSize) / 2.0 - } else { - buttonsScale = (1.0 - buttonsCollapseFraction) * 1.0 + 0.2 * buttonsCollapseFraction - buttonsVerticalOffset = (1.0 - buttonsScale) * apparentButtonSize - } - buttonsAlpha = 1.0 - buttonsCollapseFraction - } - let buttonsScaledOffset = (defaultButtonSize - apparentButtonSize) / 2.0 for buttonKey in buttonKeys.reversed() { let buttonNode: PeerInfoHeaderButtonNode var wasAdded = false @@ -2581,10 +2543,10 @@ final class PeerInfoHeaderNode: ASDisplayNode { self?.buttonPressed(buttonNode, gesture: gesture) }) self.buttonNodes[buttonKey] = buttonNode - self.regularContentNode.addSubnode(buttonNode) + self.buttonsContainerNode.addSubnode(buttonNode) } - let buttonFrame = CGRect(origin: CGPoint(x: buttonRightOrigin.x - defaultButtonSize + buttonsScaledOffset, y: buttonRightOrigin.y), size: CGSize(width: defaultButtonSize, height: defaultButtonSize)) + let buttonFrame = CGRect(origin: CGPoint(x: buttonRightOrigin.x - apparentButtonSize.width, y: buttonRightOrigin.y), size: apparentButtonSize) let buttonTransition: ContainedViewLayoutTransition = wasAdded ? .immediate : transition let apparentButtonFrame = buttonFrame.offsetBy(dx: 0.0, dy: buttonsVerticalOffset) @@ -2642,39 +2604,23 @@ final class PeerInfoHeaderNode: ASDisplayNode { isActive = buttonKey == highlightedButton } - buttonNode.update(size: buttonFrame.size, text: buttonText, icon: buttonIcon, isActive: isActive, isExpanded: self.isAvatarExpanded, presentationData: presentationData, transition: buttonTransition) - transition.updateSublayerTransformScaleAdditive(node: buttonNode, scale: buttonsScale) + buttonNode.update(size: buttonFrame.size, text: buttonText, icon: buttonIcon, isActive: isActive, isExpanded: false, presentationData: presentationData, transition: buttonTransition) if wasAdded { buttonNode.alpha = 0.0 } buttonsAlphaTransition.updateAlpha(node: buttonNode, alpha: buttonsAlpha) - let hiddenWhileExpanded: Bool - if buttonKeys.count > 3 { - hiddenWhileExpanded = peerInfoHeaderButtonIsHiddenWhileExpanded(buttonKey: buttonKey, isOpenedFromChat: self.isOpenedFromChat) - } else { - hiddenWhileExpanded = false - } - - if self.isAvatarExpanded, hiddenWhileExpanded { + if case .mute = buttonKey, buttonNode.containerNode.alpha.isZero, additive { if case let .animated(duration, curve) = transition { - ContainedViewLayoutTransition.animated(duration: duration * 0.3, curve: curve).updateAlpha(node: buttonNode.containerNode, alpha: 0.0) - } else { - transition.updateAlpha(node: buttonNode.containerNode, alpha: 0.0) - } - } else { - if case .mute = buttonKey, buttonNode.containerNode.alpha.isZero, additive { - if case let .animated(duration, curve) = transition { - ContainedViewLayoutTransition.animated(duration: duration * 0.3, curve: curve).updateAlpha(node: buttonNode.containerNode, alpha: 1.0) - } else { - transition.updateAlpha(node: buttonNode.containerNode, alpha: 1.0) - } + ContainedViewLayoutTransition.animated(duration: duration * 0.3, curve: curve).updateAlpha(node: buttonNode.containerNode, alpha: 1.0) } else { transition.updateAlpha(node: buttonNode.containerNode, alpha: 1.0) } - buttonRightOrigin.x -= apparentButtonSize + buttonSpacing + } else { + transition.updateAlpha(node: buttonNode.containerNode, alpha: 1.0) } + buttonRightOrigin.x -= apparentButtonSize.width + buttonSpacing } for key in self.buttonNodes.keys { @@ -2690,11 +2636,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { let resolvedRegularHeight: CGFloat if self.isAvatarExpanded { - if self.isSettings { - resolvedRegularHeight = expandedAvatarListSize.height - } else { - resolvedRegularHeight = expandedAvatarListSize.height + expandedAvatarControlsHeight - } + resolvedRegularHeight = expandedAvatarListSize.height } else { resolvedRegularHeight = panelWithAvatarHeight + navigationHeight } @@ -2703,6 +2645,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { let separatorFrame: CGRect let resolvedHeight: CGFloat + if state.isEditing { resolvedHeight = editingContentHeight backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -2000.0 + max(navigationHeight, resolvedHeight - contentOffset)), size: CGSize(width: width, height: 2000.0)) @@ -2714,6 +2657,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { } transition.updateFrame(node: self.regularContentNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: resolvedHeight))) + transition.updateFrame(node: self.buttonsContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationHeight + UIScreenPixel), size: CGSize(width: width, height: resolvedHeight - navigationHeight + 180.0))) if additive { transition.updateFrameAdditive(node: self.backgroundNode, frame: backgroundFrame) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoMembers.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoMembers.swift index 5a870b205c..831fb5442c 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoMembers.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoMembers.swift @@ -92,6 +92,7 @@ enum PeerInfoMembersDataState: Equatable { } struct PeerInfoMembersState: Equatable { + var canAddMembers: Bool var members: [PeerInfoMember] var dataState: PeerInfoMembersDataState } @@ -126,6 +127,7 @@ private final class PeerInfoMembersContextImpl { private let context: AccountContext private let peerId: PeerId + private var canAddMembers = false private var members: [PeerInfoMember] = [] private var dataState: PeerInfoMembersDataState = .loading(isInitial: true) private var removingMemberIds: [PeerId: Disposable] = [:] @@ -135,7 +137,7 @@ private final class PeerInfoMembersContextImpl { return self.stateValue.get() } private let disposable = MetaDisposable() - + private let peerDisposable = MetaDisposable() private var channelMembersControl: PeerChannelMemberCategoryControl? init(queue: Queue, context: AccountContext, peerId: PeerId) { @@ -170,8 +172,28 @@ private final class PeerInfoMembersContextImpl { }) self.disposable.set(disposable) self.channelMembersControl = control + + self.peerDisposable.set((context.account.postbox.peerView(id: peerId) + |> deliverOn(self.queue)).start(next: { [weak self] view in + guard let strongSelf = self else { + return + } + if let channel = peerViewMainPeer(view) as? TelegramChannel { + var canAddMembers = false + switch channel.info { + case .broadcast: + break + case .group: + if channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers) { + canAddMembers = true + } + } + strongSelf.canAddMembers = canAddMembers + strongSelf.pushState() + } + })) } else if peerId.namespace == Namespaces.Peer.CloudGroup { - disposable.set((context.account.postbox.peerView(id: peerId) + self.disposable.set((context.account.postbox.peerView(id: peerId) |> deliverOn(self.queue)).start(next: { [weak self] view in guard let strongSelf = self, let cachedData = view.cachedData as? CachedGroupData, let participantsData = cachedData.participants else { return @@ -195,6 +217,21 @@ private final class PeerInfoMembersContextImpl { unsortedMembers.append(.legacyGroupMember(peer: RenderedPeer(peer: peer), role: role, invitedBy: invitedBy, presence: view.peerPresences[participant.peerId] as? TelegramUserPresence)) } } + + if let group = peerViewMainPeer(view) as? TelegramGroup { + var canAddMembers = false + switch group.role { + case .admin, .creator: + canAddMembers = true + case .member: + break + } + if !group.hasBannedPermission(.banAddMembers) { + canAddMembers = true + } + strongSelf.canAddMembers = canAddMembers + } + strongSelf.members = membersSortedByPresence(unsortedMembers, accountPeerId: strongSelf.context.account.peerId) strongSelf.dataState = .ready(canLoadMore: false) strongSelf.pushState() @@ -207,13 +244,14 @@ private final class PeerInfoMembersContextImpl { deinit { self.disposable.dispose() + self.peerDisposable.dispose() } private func pushState() { if self.removingMemberIds.isEmpty { - self.stateValue.set(.single(PeerInfoMembersState(members: self.members, dataState: self.dataState))) + self.stateValue.set(.single(PeerInfoMembersState(canAddMembers: self.canAddMembers, members: self.members, dataState: self.dataState))) } else { - self.stateValue.set(.single(PeerInfoMembersState(members: self.members.filter { member in + self.stateValue.set(.single(PeerInfoMembersState(canAddMembers: self.canAddMembers, members: self.members.filter { member in return self.removingMemberIds[member.id] == nil }, dataState: self.dataState))) } diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoPaneContainerNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoPaneContainerNode.swift index 29740fba5d..f3b66bd805 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoPaneContainerNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoPaneContainerNode.swift @@ -383,6 +383,7 @@ private final class PeerInfoPendingPane { chatControllerInteraction: ChatControllerInteraction, data: PeerInfoScreenData, openPeerContextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void, + openAddMemberAction: @escaping () -> Void, requestPerformPeerMemberAction: @escaping (PeerInfoMember, PeerMembersListAction) -> Void, peerId: PeerId, key: PeerInfoPaneKey, @@ -423,7 +424,9 @@ private final class PeerInfoPendingPane { paneNode = PeerInfoGroupsInCommonPaneNode(context: context, peerId: peerId, chatControllerInteraction: chatControllerInteraction, openPeerContextAction: openPeerContextAction, groupsInCommonContext: data.groupsInCommon!) case .members: if case let .longList(membersContext) = data.members { - paneNode = PeerInfoMembersPaneNode(context: context, peerId: peerId, membersContext: membersContext, action: { member, action in + paneNode = PeerInfoMembersPaneNode(context: context, peerId: peerId, membersContext: membersContext, addMemberAction: { + openAddMemberAction() + }, action: { member, action in requestPerformPeerMemberAction(member, action) }) } else { @@ -487,6 +490,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat var chatControllerInteraction: ChatControllerInteraction? var openPeerContextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)? + var openAddMemberAction: (() -> Void)? var requestPerformPeerMemberAction: ((PeerInfoMember, PeerMembersListAction) -> Void)? var currentPaneUpdated: ((Bool) -> Void)? @@ -517,7 +521,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat super.init() - self.addSubnode(self.separatorNode) +// self.addSubnode(self.separatorNode) self.addSubnode(self.coveringBackgroundNode) self.addSubnode(self.tabsContainerNode) self.addSubnode(self.tabsSeparatorNode) @@ -772,6 +776,9 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat openPeerContextAction: { [weak self] peer, node, gesture in self?.openPeerContextAction?(peer, node, gesture) }, + openAddMemberAction: { [weak self] in + self?.openAddMemberAction?() + }, requestPerformPeerMemberAction: { [weak self] member, action in self?.requestPerformPeerMemberAction?(member, action) }, diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index fdeb13b557..9316405bc5 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -71,7 +71,7 @@ protocol PeerInfoScreenItem: AnyObject { class PeerInfoScreenItemNode: ASDisplayNode, AccessibilityFocusableNode { var bringToFrontForHighlight: (() -> Void)? - func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat { preconditionFailure() } @@ -110,18 +110,13 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { self.addSubnode(self.bottomSeparatorNode) } - func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, items: [PeerInfoScreenItem], transition: ContainedViewLayoutTransition) -> CGFloat { + func update(width: CGFloat, safeInsets: UIEdgeInsets, hasCorners: Bool, presentationData: PresentationData, items: [PeerInfoScreenItem], transition: ContainedViewLayoutTransition) -> CGFloat { self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor self.topSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor - if safeInsets.left > 0.0 { - self.topSeparatorNode.isHidden = true - self.bottomSeparatorNode.isHidden = true - } else { - self.topSeparatorNode.isHidden = false - self.bottomSeparatorNode.isHidden = false - } + self.topSeparatorNode.isHidden = hasCorners + self.bottomSeparatorNode.isHidden = hasCorners var contentHeight: CGFloat = 0.0 var contentWithBackgroundHeight: CGFloat = 0.0 @@ -167,7 +162,7 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { bottomItem = items[i + 1] } - let itemHeight = itemNode.update(width: width, safeInsets: safeInsets, presentationData: presentationData, item: item, topItem: topItem, bottomItem: bottomItem, transition: itemTransition) + let itemHeight = itemNode.update(width: width, safeInsets: safeInsets, presentationData: presentationData, item: item, topItem: topItem, bottomItem: bottomItem, hasCorners: hasCorners, transition: itemTransition) let itemFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight)) itemTransition.updateFrame(node: itemNode, frame: itemFrame) if wasAdded { @@ -219,133 +214,6 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { } } -private final class PeerInfoScreenDynamicItemSectionContainerNode: ASDisplayNode { - private let backgroundNode: ASDisplayNode - private let topSeparatorNode: ASDisplayNode - private let bottomSeparatorNode: ASDisplayNode - - private var currentItems: [PeerInfoScreenItem] = [] - private var itemNodes: [AnyHashable: PeerInfoScreenItemNode] = [:] - - override init() { - self.backgroundNode = ASDisplayNode() - self.backgroundNode.isLayerBacked = true - - self.topSeparatorNode = ASDisplayNode() - self.topSeparatorNode.isLayerBacked = true - - self.bottomSeparatorNode = ASDisplayNode() - self.bottomSeparatorNode.isLayerBacked = true - - super.init() - - self.addSubnode(self.backgroundNode) - self.addSubnode(self.topSeparatorNode) - self.addSubnode(self.bottomSeparatorNode) - } - - func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, items: [PeerInfoScreenItem], transition: ContainedViewLayoutTransition) -> CGFloat { - self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor - self.topSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor - self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor - - var contentHeight: CGFloat = 0.0 - var contentWithBackgroundHeight: CGFloat = 0.0 - var contentWithBackgroundOffset: CGFloat = 0.0 - - for i in 0 ..< items.count { - let item = items[i] - - let itemNode: PeerInfoScreenItemNode - var wasAdded = false - if let current = self.itemNodes[item.id] { - itemNode = current - } else { - wasAdded = true - itemNode = item.node() - self.itemNodes[item.id] = itemNode - self.addSubnode(itemNode) - itemNode.bringToFrontForHighlight = { [weak self, weak itemNode] in - guard let strongSelf = self, let itemNode = itemNode else { - return - } - strongSelf.view.bringSubviewToFront(itemNode.view) - } - } - - let itemTransition: ContainedViewLayoutTransition = wasAdded ? .immediate : transition - - let topItem: PeerInfoScreenItem? - if i == 0 { - topItem = nil - } else if items[i - 1] is PeerInfoScreenHeaderItem { - topItem = nil - } else { - topItem = items[i - 1] - } - - let bottomItem: PeerInfoScreenItem? - if i == items.count - 1 { - bottomItem = nil - } else if items[i + 1] is PeerInfoScreenCommentItem { - bottomItem = nil - } else { - bottomItem = items[i + 1] - } - - let itemHeight = itemNode.update(width: width, safeInsets: safeInsets, presentationData: presentationData, item: item, topItem: topItem, bottomItem: bottomItem, transition: itemTransition) - let itemFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight)) - itemTransition.updateFrame(node: itemNode, frame: itemFrame) - if wasAdded { - itemNode.alpha = 0.0 - transition.updateAlpha(node: itemNode, alpha: 1.0) - } - - if item is PeerInfoScreenCommentItem { - } else { - contentWithBackgroundHeight += itemHeight - } - contentHeight += itemHeight - - if item is PeerInfoScreenHeaderItem { - contentWithBackgroundOffset = contentHeight - } - } - - var removeIds: [AnyHashable] = [] - for (id, _) in self.itemNodes { - if !items.contains(where: { $0.id == id }) { - removeIds.append(id) - } - } - for id in removeIds { - if let itemNode = self.itemNodes.removeValue(forKey: id) { - transition.updateAlpha(node: itemNode, alpha: 0.0, completion: { [weak itemNode] _ in - itemNode?.removeFromSupernode() - }) - } - } - - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentWithBackgroundOffset), size: CGSize(width: width, height: max(0.0, contentWithBackgroundHeight - contentWithBackgroundOffset)))) - transition.updateFrame(node: self.topSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentWithBackgroundOffset - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) - transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentWithBackgroundHeight), size: CGSize(width: width, height: UIScreenPixel))) - - if contentHeight.isZero { - transition.updateAlpha(node: self.topSeparatorNode, alpha: 0.0) - transition.updateAlpha(node: self.bottomSeparatorNode, alpha: 0.0) - } else { - transition.updateAlpha(node: self.topSeparatorNode, alpha: 1.0) - transition.updateAlpha(node: self.bottomSeparatorNode, alpha: 1.0) - } - - return contentHeight - } - - func updateVisibleItems(in rect: CGRect) { - - } -} - final class PeerInfoSelectionPanelNode: ASDisplayNode { private let context: AccountContext private let peerId: PeerId @@ -589,6 +457,7 @@ private final class PeerInfoInteraction { let updateBio: (String) -> Void let openDeletePeer: () -> Void let openFaq: (String?) -> Void + let openAddMember: () -> Void init( openUsername: @escaping (String) -> Void, @@ -628,7 +497,8 @@ private final class PeerInfoInteraction { accountContextMenu: @escaping (AccountRecordId, ASDisplayNode, ContextGesture?) -> Void, updateBio: @escaping (String) -> Void, openDeletePeer: @escaping () -> Void, - openFaq: @escaping (String?) -> Void + openFaq: @escaping (String?) -> Void, + openAddMember: @escaping () -> Void ) { self.openUsername = openUsername self.openPhone = openPhone @@ -668,6 +538,7 @@ private final class PeerInfoInteraction { self.updateBio = updateBio self.openDeletePeer = openDeletePeer self.openFaq = openFaq + self.openAddMember = openAddMember } } @@ -1161,6 +1032,34 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese } if let peer = data.peer, let members = data.members, case let .shortList(_, memberList) = members { + var canAddMembers = false + if let group = data.peer as? TelegramGroup { + switch group.role { + case .admin, .creator: + canAddMembers = true + case .member: + break + } + if !group.hasBannedPermission(.banAddMembers) { + canAddMembers = true + } + } else if let channel = data.peer as? TelegramChannel { + switch channel.info { + case .broadcast: + break + case .group: + if channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers) { + canAddMembers = true + } + } + } + + if canAddMembers { + items[.peerMembers]!.append(PeerInfoScreenActionItem(id: 0, text: presentationData.strings.PeerInfo_ButtonAddMember, color: .accent, icon: UIImage(bundleImageName: "Contact List/AddMemberIcon"), alignment: .peerList, action: { + interaction.openAddMember() + })) + } + for member in memberList { let isAccountPeer = member.id == context.account.peerId items[.peerMembers]!.append(PeerInfoScreenMemberItem(id: member.id, context: context, enclosingPeer: peer, member: member, action: isAccountPeer ? nil : { action in @@ -1543,8 +1442,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate fileprivate let cachedDataPromise = Promise() let scrollNode: ASScrollNode - private let leftOverlayNode: ASDisplayNode - private let rightOverlayNode: ASDisplayNode let headerNode: PeerInfoHeaderNode private var regularSections: [AnyHashable: PeerInfoScreenItemSectionContainerNode] = [:] @@ -1641,11 +1538,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate self.scrollNode.view.delaysContentTouches = false self.scrollNode.canCancelAllTouchesInViews = true - self.leftOverlayNode = ASDisplayNode() - self.leftOverlayNode.isUserInteractionEnabled = false - self.rightOverlayNode = ASDisplayNode() - self.rightOverlayNode.isUserInteractionEnabled = false - self.headerNode = PeerInfoHeaderNode(context: context, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, isSettings: isSettings) self.paneContainerNode = PeerInfoPaneContainerNode(context: context, updatedPresentationData: controller.updatedPresentationData, peerId: peerId, isMediaOnly: self.isMediaOnly) @@ -1653,10 +1545,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate self.paneContainerNode.parentController = controller - self.headerNode.updateHeaderAlpha = { [weak self] alpha, transition in - self?.updateHeaderBackgroundAlpha(alpha, transition: transition) - } - self._interaction = PeerInfoInteraction( openUsername: { [weak self] value in self?.openUsername(value: value) @@ -1771,6 +1659,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate }, openFaq: { [weak self] anchor in self?.openFaq(anchor: anchor) + }, + openAddMember: { [weak self] in + self?.openAddMember() } ) @@ -2283,13 +2174,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate self.addSubnode(self.scrollNode) self.scrollNode.addSubnode(self.paneContainerNode) - - self.leftOverlayNode.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor - self.rightOverlayNode.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor - - self.addSubnode(self.leftOverlayNode) - self.addSubnode(self.rightOverlayNode) - + self.addSubnode(self.headerNode.buttonsContainerNode) self.addSubnode(self.headerNode) self.scrollNode.view.isScrollEnabled = !self.isMediaOnly @@ -2380,6 +2265,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } } + self.paneContainerNode.openAddMemberAction = { [weak self] in + guard let strongSelf = self else { + return + } + strongSelf.openAddMember() + } + self.paneContainerNode.requestPerformPeerMemberAction = { [weak self] member, action in guard let strongSelf = self else { return @@ -2996,11 +2888,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate override func didLoad() { super.didLoad() - - if self.isSettings { - self.updateHeaderBackgroundAlpha(0.0, transition: .immediate) - } - + self.view.disablesInteractiveTransitionGestureRecognizerNow = { [weak self] in if let strongSelf = self { return strongSelf.state.isEditing @@ -3009,15 +2897,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } } } - - public func updateHeaderBackgroundAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) { - self.controller?.navigationBar?.updateBackgroundAlpha(alpha, transition: transition) - transition.updateAlpha(node: self.headerNode.backgroundNode, alpha: alpha, delay: 0.15) - transition.updateAlpha(node: self.headerNode.expandedBackgroundNode, alpha: alpha, delay: 0.15) - transition.updateAlpha(node: self.headerNode.separatorNode, alpha: alpha, delay: 0.15) - } - var canAttachVideo: Bool? private func updateData(_ data: PeerInfoScreenData) { @@ -3613,7 +3493,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate return .single(items) } - let allHeaderButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: false, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false)) + let allHeaderButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: true, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false)) let headerButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: strongSelf.headerNode.isAvatarExpanded, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false)) let filteredButtons = allHeaderButtons.subtracting(headerButtons) @@ -6356,9 +6236,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate self.presentationData = presentationData self.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor - self.leftOverlayNode.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor - self.rightOverlayNode.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor - + self.updateNavigationExpansionPresentation(isExpanded: self.headerNode.isAvatarExpanded, animated: false) if let (layout, navigationHeight) = self.validLayout { @@ -6395,14 +6273,12 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } else { sectionInset = 0.0 } - let headerInset: CGFloat - if self.isSettings { - headerInset = sectionInset - } else { - headerInset = layout.safeInsets.left - } + let headerInset = sectionInset - let headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, transition: transition, additive: additive) + var headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, transition: transition, additive: additive) + if !self.isSettings && !self.state.isEditing { + headerHeight += 71.0 + } let headerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: headerHeight)) if additive { transition.updateFrameAdditive(node: self.headerNode, frame: headerFrame) @@ -6413,20 +6289,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate contentHeight += navigationHeight } - var currentInsets = UIEdgeInsets() var validRegularSections: [AnyHashable] = [] if !self.isMediaOnly { var insets = UIEdgeInsets() - if self.isSettings { - insets.left += sectionInset - insets.right += sectionInset - } else { - insets = layout.safeInsets - } - - if !self.state.isEditing { - currentInsets = insets - } + insets.left += sectionInset + insets.right += sectionInset let items = self.isSettings ? settingsItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction, isExpanded: self.headerNode.isAvatarExpanded) : infoItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction, nearbyPeerDistance: self.nearbyPeerDistance, callMessages: self.callMessages) @@ -6453,9 +6320,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate sectionNode.alpha = 0.0 transition.updateAlpha(node: sectionNode, alpha: 1.0, delay: 0.1) } - - let sectionHeight = sectionNode.update(width: layout.size.width, safeInsets: insets, presentationData: self.presentationData, items: sectionItems, transition: transition) - let sectionFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: sectionHeight)) + + let sectionWidth = layout.size.width - insets.left - insets.right + let sectionHeight = sectionNode.update(width: sectionWidth, safeInsets: UIEdgeInsets(), hasCorners: !insets.left.isZero, presentationData: self.presentationData, items: sectionItems, transition: transition) + let sectionFrame = CGRect(origin: CGPoint(x: insets.left, y: contentHeight), size: CGSize(width: sectionWidth, height: sectionHeight)) if additive { transition.updateFrameAdditive(node: sectionNode, frame: sectionFrame) } else { @@ -6500,10 +6368,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate var insets = UIEdgeInsets() insets.left += sectionInset insets.right += sectionInset - - if self.state.isEditing { - currentInsets = insets - } validEditingSections.append(sectionId) @@ -6517,9 +6381,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate self.editingSections[sectionId] = sectionNode self.scrollNode.addSubnode(sectionNode) } - - let sectionHeight = sectionNode.update(width: layout.size.width, safeInsets: insets, presentationData: self.presentationData, items: sectionItems, transition: transition) - let sectionFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: sectionHeight)) + + let sectionWidth = layout.size.width - insets.left - insets.right + let sectionHeight = sectionNode.update(width: sectionWidth, safeInsets: UIEdgeInsets(), hasCorners: !insets.left.isZero, presentationData: self.presentationData, items: sectionItems, transition: transition) + let sectionFrame = CGRect(origin: CGPoint(x: insets.left, y: contentHeight), size: CGSize(width: sectionWidth, height: sectionHeight)) if wasAdded { sectionNode.frame = sectionFrame @@ -6636,7 +6501,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } if self.isSettings { - contentHeight = max(contentHeight, layout.size.height + 140.0 + (self.headerNode.twoLineInfo ? 17.0 : 0.0) - layout.intrinsicInsets.bottom) + contentHeight = max(contentHeight, layout.size.height + 140.0 - layout.intrinsicInsets.bottom) } self.scrollNode.view.contentSize = CGSize(width: layout.size.width, height: contentHeight) if self.isSettings { @@ -6645,17 +6510,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate if let restoreContentOffset = restoreContentOffset { self.scrollNode.view.contentOffset = restoreContentOffset } - - let relativeHeaderFrame = self.headerNode.view.convert(self.headerNode.bounds, to: self.view) - transition.updateFrame(node: self.leftOverlayNode, frame: CGRect(x: 0.0, y: relativeHeaderFrame.maxY + UIScreenPixel - self.scrollNode.view.contentOffset.y, width: currentInsets.left, height: layout.size.height * 10.0)) - transition.updateFrame(node: self.rightOverlayNode, frame: CGRect(x: layout.size.width - currentInsets.right, y: relativeHeaderFrame.maxY + UIScreenPixel - self.scrollNode.view.contentOffset.y, width: currentInsets.right, height: layout.size.height * 10.0)) - + if additive { transition.updateFrameAdditive(node: self.paneContainerNode, frame: paneContainerFrame) } else { transition.updateFrame(node: self.paneContainerNode, frame: paneContainerFrame) } - + self.ignoreScrolling = false self.updateNavigation(transition: transition, additive: additive) @@ -6707,13 +6568,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } else { sectionInset = 0.0 } - let headerInset: CGFloat - if self.isSettings { - headerInset = sectionInset - } else { - headerInset = layout.safeInsets.left - } - + let headerInset = sectionInset + let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, transition: transition, additive: additive) } @@ -6731,10 +6587,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate effectiveAreaExpansionFraction = 1.0 - paneAreaExpansionDelta / paneAreaExpansionDistance } - if !self.isSettings { - transition.updateAlpha(node: self.headerNode.separatorNode, alpha: 1.0 - effectiveAreaExpansionFraction) - } - let visibleHeight = self.scrollNode.view.contentOffset.y + self.scrollNode.view.bounds.height - self.paneContainerNode.frame.minY var bottomInset = layout.intrinsicInsets.bottom @@ -6797,18 +6649,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate private var canOpenAvatarByDragging = false func scrollViewDidScroll(_ scrollView: UIScrollView) { - if self.ignoreScrolling { + guard !self.ignoreScrolling else { return } - - let headerFrame = self.headerNode.view.convert(self.headerNode.bounds, to: self.view) - if !self.headerNode.isAvatarExpanded { - self.leftOverlayNode.layer.removeAllAnimations() - self.rightOverlayNode.layer.removeAllAnimations() - } - self.leftOverlayNode.frame = CGRect(x: 0.0, y: headerFrame.maxY + UIScreenPixel - scrollView.contentOffset.y, width: self.leftOverlayNode.frame.width, height: self.leftOverlayNode.frame.height) - self.rightOverlayNode.frame = CGRect(x: self.rightOverlayNode.frame.minX, y: headerFrame.maxY + UIScreenPixel - scrollView.contentOffset.y, width: self.rightOverlayNode.frame.width, height: self.rightOverlayNode.frame.height) - + if !self.state.isEditing { if self.canAddVelocity { self.previousVelocityM1 = self.previousVelocity @@ -6938,10 +6782,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } } } else { - var height: CGFloat = self.isSettings ? 140.0 : 212.0 - if self.headerNode.twoLineInfo { - height += 17.0 - } + let height: CGFloat = self.isSettings ? 140.0 : 140.0 if targetContentOffset.pointee.y < height { if targetContentOffset.pointee.y < height / 2.0 { targetContentOffset.pointee.y = 0.0 @@ -7618,12 +7459,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig } else { sectionInset = 0.0 } - let headerInset: CGFloat - if screenNode.isSettings { - headerInset = sectionInset - } else { - headerInset = layout.safeInsets.left - } + let headerInset = sectionInset topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, notificationSettings: self.screenNode.data?.notificationSettings, statusData: self.screenNode.data?.status, panelStatusData: nil, isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, transition: transition, additive: false) } diff --git a/submodules/TelegramUI/Sources/PeerInfoScreenMultilineInputtem.swift b/submodules/TelegramUI/Sources/PeerInfoScreenMultilineInputtem.swift index ba36b2b1e8..41c7c682c4 100644 --- a/submodules/TelegramUI/Sources/PeerInfoScreenMultilineInputtem.swift +++ b/submodules/TelegramUI/Sources/PeerInfoScreenMultilineInputtem.swift @@ -50,7 +50,7 @@ private final class PeerInfoScreenMultilineInputItemNode: PeerInfoScreenItemNode self.addSubnode(self.bottomSeparatorNode) } - override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat { guard let item = item as? PeerInfoScreenMultilineInputItem else { return 10.0 } @@ -101,7 +101,7 @@ private final class PeerInfoScreenMultilineInputItemNode: PeerInfoScreenItemNode separatorInset += 49.0 } - let hasCorners = safeInsets.left > 0.0 && (topItem == nil || bottomItem == nil) + let hasCorners = hasCorners && (topItem == nil || bottomItem == nil) let hasTopCorners = hasCorners && topItem == nil let hasBottomCorners = hasCorners && bottomItem == nil