Merge commit '78db6173fb9fb575f8f1a09c73109c4936e5491c' into beta

This commit is contained in:
Ali 2021-10-27 16:35:21 +04:00
commit 5a811112b3
55 changed files with 1583 additions and 363 deletions

View File

@ -6978,3 +6978,9 @@ Sorry for the inconvenience.";
"Notifications.On" = "On"; "Notifications.On" = "On";
"Notifications.Off" = "Off"; "Notifications.Off" = "Off";
"AuthSessions.View.Device" = "Device";
"AuthSessions.View.Location" = "Location";
"AuthSessions.View.IP" = "IP";
"AuthSessions.View.TerminateSession" = "Terminate Session";
"AuthSessions.View.Logout" = "Log Out";

View File

@ -208,6 +208,7 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode {
self.backgroundNode.isLayerBacked = true self.backgroundNode.isLayerBacked = true
self.maskNode = ASImageNode() self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
self.topStripeNode = ASDisplayNode() self.topStripeNode = ASDisplayNode()
self.topStripeNode.isLayerBacked = true self.topStripeNode.isLayerBacked = true
@ -513,6 +514,35 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode {
strongSelf.highlightedBackgroundNode.backgroundColor = item.presentationData.theme.list.itemHighlightedBackgroundColor strongSelf.highlightedBackgroundNode.backgroundColor = item.presentationData.theme.list.itemHighlightedBackgroundColor
} }
if let editableControlSizeAndApply = editableControlSizeAndApply {
let editableControlFrame = CGRect(origin: CGPoint(x: params.leftInset + revealOffset, y: 0.0), size: CGSize(width: editableControlSizeAndApply.0, height: nodeLayout.contentSize.height))
if strongSelf.editableControlNode == nil {
let editableControlNode = editableControlSizeAndApply.1(nodeLayout.contentSize.height)
editableControlNode.tapped = {
if let strongSelf = self {
strongSelf.setRevealOptionsOpened(true, animated: true)
strongSelf.revealOptionsInteractivelyOpened()
}
}
strongSelf.editableControlNode = editableControlNode
strongSelf.addSubnode(editableControlNode)
editableControlNode.frame = editableControlFrame
transition.animatePosition(node: editableControlNode, from: CGPoint(x: -editableControlFrame.size.width / 2.0, y: editableControlFrame.midY))
editableControlNode.alpha = 0.0
transition.updateAlpha(node: editableControlNode, alpha: 1.0)
} else {
strongSelf.editableControlNode?.frame = editableControlFrame
}
} else if let editableControlNode = strongSelf.editableControlNode {
var editableControlFrame = editableControlNode.frame
editableControlFrame.origin.x = -editableControlFrame.size.width
strongSelf.editableControlNode = nil
transition.updateAlpha(node: editableControlNode, alpha: 0.0)
transition.updateFrame(node: editableControlNode, frame: editableControlFrame, completion: { [weak editableControlNode] _ in
editableControlNode?.removeFromSupernode()
})
}
switch item.style { switch item.style {
case .plain: case .plain:
if strongSelf.backgroundNode.supernode == nil { if strongSelf.backgroundNode.supernode == nil {
@ -541,7 +571,7 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode {
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
} }
if strongSelf.maskNode.supernode == nil { if strongSelf.maskNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.maskNode, at: 3) strongSelf.addSubnode(strongSelf.maskNode)
} }
let hasCorners = itemListHasRoundedBlockLayout(params) let hasCorners = itemListHasRoundedBlockLayout(params)
var hasTopCorners = false var hasTopCorners = false
@ -571,34 +601,6 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode {
transition.updateFrameAdditive(node: strongSelf.bottomStripeNode, frame: CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: nodeLayout.size.width - bottomStripeInset, height: separatorHeight))) transition.updateFrameAdditive(node: strongSelf.bottomStripeNode, frame: CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: nodeLayout.size.width - bottomStripeInset, height: separatorHeight)))
} }
if let editableControlSizeAndApply = editableControlSizeAndApply {
let editableControlFrame = CGRect(origin: CGPoint(x: params.leftInset + revealOffset, y: 0.0), size: CGSize(width: editableControlSizeAndApply.0, height: nodeLayout.contentSize.height))
if strongSelf.editableControlNode == nil {
let editableControlNode = editableControlSizeAndApply.1(nodeLayout.contentSize.height)
editableControlNode.tapped = {
if let strongSelf = self {
strongSelf.setRevealOptionsOpened(true, animated: true)
strongSelf.revealOptionsInteractivelyOpened()
}
}
strongSelf.editableControlNode = editableControlNode
strongSelf.addSubnode(editableControlNode)
editableControlNode.frame = editableControlFrame
transition.animatePosition(node: editableControlNode, from: CGPoint(x: -editableControlFrame.size.width / 2.0, y: editableControlFrame.midY))
editableControlNode.alpha = 0.0
transition.updateAlpha(node: editableControlNode, alpha: 1.0)
} else {
strongSelf.editableControlNode?.frame = editableControlFrame
}
} else if let editableControlNode = strongSelf.editableControlNode {
var editableControlFrame = editableControlNode.frame
editableControlFrame.origin.x = -editableControlFrame.size.width
strongSelf.editableControlNode = nil
transition.updateAlpha(node: editableControlNode, alpha: 0.0)
transition.updateFrame(node: editableControlNode, frame: editableControlFrame, completion: { [weak editableControlNode] _ in
editableControlNode?.removeFromSupernode()
})
}
transition.updateFrameAdditive(node: strongSelf.avatarNode, frame: CGRect(origin: CGPoint(x: revealOffset + leftInset - 52.0, y: floor((contentSize.height - avatarDiameter) / 2.0)), size: CGSize(width: avatarDiameter, height: avatarDiameter))) transition.updateFrameAdditive(node: strongSelf.avatarNode, frame: CGRect(origin: CGPoint(x: revealOffset + leftInset - 52.0, y: floor((contentSize.height - avatarDiameter) / 2.0)), size: CGSize(width: avatarDiameter, height: avatarDiameter)))

View File

@ -130,7 +130,9 @@ class ChatListFilterPresetCategoryItemNode: ItemListRevealOptionsItemNode, ItemL
self.bottomStripeNode = ASDisplayNode() self.bottomStripeNode = ASDisplayNode()
self.bottomStripeNode.isLayerBacked = true self.bottomStripeNode.isLayerBacked = true
self.maskNode = ASImageNode() self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
self.avatarNode = ASImageNode() self.avatarNode = ASImageNode()
self.avatarNode.isUserInteractionEnabled = false self.avatarNode.isUserInteractionEnabled = false
@ -311,7 +313,7 @@ class ChatListFilterPresetCategoryItemNode: ItemListRevealOptionsItemNode, ItemL
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
} }
if strongSelf.maskNode.supernode == nil { if strongSelf.maskNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.maskNode, at: 3) strongSelf.addSubnode(strongSelf.maskNode)
} }
let hasCorners = itemListHasRoundedBlockLayout(params) let hasCorners = itemListHasRoundedBlockLayout(params)

View File

@ -139,6 +139,7 @@ private final class ChatListFilterPresetListItemNode: ItemListRevealOptionsItemN
self.bottomStripeNode.isLayerBacked = true self.bottomStripeNode.isLayerBacked = true
self.maskNode = ASImageNode() self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
self.titleNode = TextNode() self.titleNode = TextNode()
self.titleNode.isUserInteractionEnabled = false self.titleNode.isUserInteractionEnabled = false
@ -315,7 +316,7 @@ private final class ChatListFilterPresetListItemNode: ItemListRevealOptionsItemN
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
} }
if strongSelf.maskNode.supernode == nil { if strongSelf.maskNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.maskNode, at: 3) strongSelf.addSubnode(strongSelf.maskNode)
} }
let hasCorners = itemListHasRoundedBlockLayout(params) let hasCorners = itemListHasRoundedBlockLayout(params)

View File

@ -921,7 +921,12 @@ open class NavigationBar: ASDisplayNode {
} }
} }
public var isBackgroundVisible: Bool {
return self.backgroundNode.alpha == 1.0
}
public func updateBackgroundAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) { public func updateBackgroundAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) {
let alpha = max(0.0, min(1.0, alpha))
transition.updateAlpha(node: self.backgroundNode, alpha: alpha, delay: 0.15) transition.updateAlpha(node: self.backgroundNode, alpha: alpha, delay: 0.15)
transition.updateAlpha(node: self.stripeNode, alpha: alpha, delay: 0.15) transition.updateAlpha(node: self.stripeNode, alpha: alpha, delay: 0.15)
} }

View File

@ -125,7 +125,11 @@ final class NavigationTransitionCoordinator {
var dimInset: CGFloat = 0.0 var dimInset: CGFloat = 0.0
if let bottomNavigationBar = self.bottomNavigationBar , self.inlineNavigationBarTransition { if let bottomNavigationBar = self.bottomNavigationBar , self.inlineNavigationBarTransition {
dimInset = bottomNavigationBar.frame.maxY if self.bottomNavigationBar?.isBackgroundVisible == false || self.topNavigationBar?.isBackgroundVisible == false {
} else {
dimInset = bottomNavigationBar.frame.maxY
}
} }
let containerSize = self.container.bounds.size let containerSize = self.container.bounds.size

View File

@ -273,6 +273,12 @@ open class TabBarController: ViewController {
self.displayNodeDidLoad() self.displayNodeDidLoad()
} }
public func updateBackgroundAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) {
let alpha = max(0.0, min(1.0, alpha))
transition.updateAlpha(node: self.tabBarControllerNode.tabBarNode.backgroundNode, alpha: alpha, delay: 0.15)
transition.updateAlpha(node: self.tabBarControllerNode.tabBarNode.separatorNode, alpha: alpha, delay: 0.15)
}
private func updateSelectedIndex() { private func updateSelectedIndex() {
if !self.isNodeLoaded { if !self.isNodeLoaded {
return return

View File

@ -220,7 +220,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
let arguments = arguments as! InviteLinkEditControllerArguments let arguments = arguments as! InviteLinkEditControllerArguments
switch self { switch self {
case let .title(_, placeholder, value): case let .title(_, placeholder, value):
return ItemListSingleLineInputItem(presentationData: presentationData, title: NSAttributedString(), text: value, placeholder: placeholder, sectionId: self.section, textUpdated: { value in return ItemListSingleLineInputItem(presentationData: presentationData, title: NSAttributedString(), text: value, placeholder: placeholder, maxLength: 32, sectionId: self.section, textUpdated: { value in
arguments.updateState { state in arguments.updateState { state in
var updatedState = state var updatedState = state
updatedState.title = value updatedState.title = value
@ -421,7 +421,7 @@ public func inviteLinkEditController(context: AccountContext, updatedPresentatio
timeLimit = .unlimited timeLimit = .unlimited
} }
initialState = InviteLinkEditControllerState(title: "", usage: InviteLinkUsageLimit(value: usageLimit), time: timeLimit, requestApproval: invite.requestApproval, pickingTimeLimit: false, pickingUsageLimit: false) initialState = InviteLinkEditControllerState(title: invite.title ?? "", usage: InviteLinkUsageLimit(value: usageLimit), time: timeLimit, requestApproval: invite.requestApproval, pickingTimeLimit: false, pickingUsageLimit: false)
} else { } else {
initialState = InviteLinkEditControllerState(title: "", usage: .unlimited, time: .unlimited, requestApproval: false, pickingTimeLimit: false, pickingUsageLimit: false) initialState = InviteLinkEditControllerState(title: "", usage: .unlimited, time: .unlimited, requestApproval: false, pickingTimeLimit: false, pickingUsageLimit: false)
} }
@ -525,11 +525,13 @@ public func inviteLinkEditController(context: AccountContext, updatedPresentatio
expireDate = 0 expireDate = 0
} }
let titleString = state.title.trimmingCharacters(in: .whitespacesAndNewlines)
let title = titleString.isEmpty ? nil : titleString
let usageLimit = state.usage.value let usageLimit = state.usage.value
let requestNeeded = state.requestApproval let requestNeeded = state.requestApproval
if invite == nil { if invite == nil {
let _ = (context.engine.peers.createPeerExportedInvitation(peerId: peerId, expireDate: expireDate, usageLimit: requestNeeded ? 0 : usageLimit, requestNeeded: requestNeeded) let _ = (context.engine.peers.createPeerExportedInvitation(peerId: peerId, title: title, expireDate: expireDate, usageLimit: requestNeeded ? 0 : usageLimit, requestNeeded: requestNeeded)
|> timeout(10, queue: Queue.mainQueue(), alternate: .fail(.generic)) |> timeout(10, queue: Queue.mainQueue(), alternate: .fail(.generic))
|> deliverOnMainQueue).start(next: { invite in |> deliverOnMainQueue).start(next: { invite in
completion?(invite) completion?(invite)
@ -548,7 +550,7 @@ public func inviteLinkEditController(context: AccountContext, updatedPresentatio
dismissImpl?() dismissImpl?()
return return
} }
let _ = (context.engine.peers.editPeerExportedInvitation(peerId: peerId, link: initialInvite.link, expireDate: expireDate, usageLimit: requestNeeded ? 0 : usageLimit, requestNeeded: requestNeeded) let _ = (context.engine.peers.editPeerExportedInvitation(peerId: peerId, link: initialInvite.link, title: title, expireDate: expireDate, usageLimit: requestNeeded ? 0 : usageLimit, requestNeeded: requestNeeded)
|> timeout(10, queue: Queue.mainQueue(), alternate: .fail(.generic)) |> timeout(10, queue: Queue.mainQueue(), alternate: .fail(.generic))
|> deliverOnMainQueue).start(next: { invite in |> deliverOnMainQueue).start(next: { invite in
completion?(invite) completion?(invite)

View File

@ -284,7 +284,7 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData,
let mainInvite: ExportedInvitation? let mainInvite: ExportedInvitation?
var isPublic = false var isPublic = false
if let peer = peer, let address = peer.addressName, !address.isEmpty && admin == nil { if let peer = peer, let address = peer.addressName, !address.isEmpty && admin == nil {
mainInvite = ExportedInvitation(link: "t.me/\(address)", isPermanent: true, requestApproval: false, isRevoked: false, adminId: EnginePeer.Id(0), date: 0, startDate: nil, expireDate: nil, usageLimit: nil, count: nil, requestedCount: nil) mainInvite = ExportedInvitation(link: "t.me/\(address)", title: nil, isPermanent: true, requestApproval: false, isRevoked: false, adminId: EnginePeer.Id(0), date: 0, startDate: nil, expireDate: nil, usageLimit: nil, count: nil, requestedCount: nil)
isPublic = true isPublic = true
} else if let invites = invites, let invite = invites.first(where: { $0.isPermanent && !$0.isRevoked }) { } else if let invites = invites, let invite = invites.first(where: { $0.isPermanent && !$0.isRevoked }) {
mainInvite = invite mainInvite = invite

View File

@ -841,7 +841,7 @@ public final class InviteLinkViewController: ViewController {
self.historyBackgroundContentNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor self.historyBackgroundContentNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
self.headerBackgroundNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor self.headerBackgroundNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
self.titleNode.attributedText = NSAttributedString(string: self.presentationData.strings.InviteLink_InviteLink, font: titleFont, textColor: self.presentationData.theme.actionSheet.primaryTextColor) self.titleNode.attributedText = NSAttributedString(string: self.titleNode.attributedText?.string ?? "", font: titleFont, textColor: self.presentationData.theme.actionSheet.primaryTextColor)
self.subtitleNode.attributedText = NSAttributedString(string: self.subtitleNode.attributedText?.string ?? "", font: subtitleFont, textColor: self.presentationData.theme.list.itemSecondaryTextColor) self.subtitleNode.attributedText = NSAttributedString(string: self.subtitleNode.attributedText?.string ?? "", font: subtitleFont, textColor: self.presentationData.theme.list.itemSecondaryTextColor)
let accentColor = self.presentationData.theme.actionSheet.controlAccentColor let accentColor = self.presentationData.theme.actionSheet.controlAccentColor
@ -936,6 +936,7 @@ public final class InviteLinkViewController: ViewController {
var titleText = self.presentationData.strings.InviteLink_InviteLink var titleText = self.presentationData.strings.InviteLink_InviteLink
var subtitleText = "" var subtitleText = ""
var subtitleColor = self.presentationData.theme.list.itemSecondaryTextColor var subtitleColor = self.presentationData.theme.list.itemSecondaryTextColor
if self.invite.isRevoked { if self.invite.isRevoked {
@ -970,6 +971,10 @@ public final class InviteLinkViewController: ViewController {
} }
} }
if let title = self.invite.title, !title.isEmpty {
titleText = title
}
self.titleNode.attributedText = NSAttributedString(string: titleText, font: Font.bold(17.0), textColor: self.presentationData.theme.actionSheet.primaryTextColor) self.titleNode.attributedText = NSAttributedString(string: titleText, font: Font.bold(17.0), textColor: self.presentationData.theme.actionSheet.primaryTextColor)
self.subtitleNode.attributedText = NSAttributedString(string: subtitleText, font: subtitleFont, textColor: subtitleColor) self.subtitleNode.attributedText = NSAttributedString(string: subtitleText, font: subtitleFont, textColor: subtitleColor)

View File

@ -338,6 +338,9 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
let inviteLink = item.invite?.link.replacingOccurrences(of: "https://", with: "") ?? "" let inviteLink = item.invite?.link.replacingOccurrences(of: "https://", with: "") ?? ""
var titleText = inviteLink var titleText = inviteLink
if let title = item.invite?.title, !title.isEmpty {
titleText = title
}
var subtitleText: String = "" var subtitleText: String = ""
var timerValue: TimerNode.Value? var timerValue: TimerNode.Value?

View File

@ -385,7 +385,7 @@ public class ItemListInviteRequestItemNode: ListViewItemNode, ItemListItemNode {
avatarListNode.controlsClippingNode.frame = CGRect(x: -targetRect.width / 2.0, y: -targetRect.height / 2.0, width: targetRect.width, height: targetRect.height) avatarListNode.controlsClippingNode.frame = CGRect(x: -targetRect.width / 2.0, y: -targetRect.height / 2.0, width: targetRect.width, height: targetRect.height)
avatarListNode.controlsClippingOffsetNode.frame = CGRect(origin: CGPoint(x: targetRect.width / 2.0, y: targetRect.height / 2.0), size: CGSize()) avatarListNode.controlsClippingOffsetNode.frame = CGRect(origin: CGPoint(x: targetRect.width / 2.0, y: targetRect.height / 2.0), size: CGSize())
avatarListNode.stripContainerNode.frame = CGRect(x: 0.0, y: 13.0, width: targetRect.width, height: 2.0) avatarListNode.stripContainerNode.frame = CGRect(x: 0.0, y: 13.0, width: targetRect.width, height: 2.0)
avatarListNode.shadowNode.frame = CGRect(x: 0.0, y: 0.0, width: targetRect.width, height: 44.0) avatarListNode.topShadowNode.frame = CGRect(x: 0.0, y: 0.0, width: targetRect.width, height: 44.0)
avatarListContainerNode.addSubnode(avatarListNode) avatarListContainerNode.addSubnode(avatarListNode)
avatarListContainerNode.addSubnode(avatarListNode.controlsClippingOffsetNode) avatarListContainerNode.addSubnode(avatarListNode.controlsClippingOffsetNode)
@ -675,7 +675,7 @@ public class ItemListInviteRequestItemNode: ListViewItemNode, ItemListItemNode {
strongSelf.avatarNode.frame = avatarFrame strongSelf.avatarNode.frame = avatarFrame
if let importer = item.importer, let peer = importer.peer.peer.flatMap({ EnginePeer($0) }) { if let importer = item.importer, let peer = importer.peer.peer.flatMap({ EnginePeer($0) }) {
strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: nil, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: false) strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: nil, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: false, storeUnrounded: true)
} }
transition.updateFrame(node: strongSelf.titleNode, frame: CGRect(origin: CGPoint(x: leftInset, y: verticalInset), size: titleLayout.size)) transition.updateFrame(node: strongSelf.titleNode, frame: CGRect(origin: CGPoint(x: leftInset, y: verticalInset), size: titleLayout.size))

View File

@ -98,6 +98,7 @@ public class ItemListAddressItemNode: ListViewItemNode {
private let topStripeNode: ASDisplayNode private let topStripeNode: ASDisplayNode
private let bottomStripeNode: ASDisplayNode private let bottomStripeNode: ASDisplayNode
private let highlightedBackgroundNode: ASDisplayNode private let highlightedBackgroundNode: ASDisplayNode
private let maskNode: ASImageNode
private let imageNode: TransformImageNode private let imageNode: TransformImageNode
private let iconNode: ASImageNode private let iconNode: ASImageNode
private var selectionNode: ItemListSelectableControlNode? private var selectionNode: ItemListSelectableControlNode?
@ -118,6 +119,9 @@ public class ItemListAddressItemNode: ListViewItemNode {
self.bottomStripeNode = ASDisplayNode() self.bottomStripeNode = ASDisplayNode()
self.bottomStripeNode.isLayerBacked = true self.bottomStripeNode.isLayerBacked = true
self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
self.highlightedBackgroundNode = ASDisplayNode() self.highlightedBackgroundNode = ASDisplayNode()
self.highlightedBackgroundNode.isLayerBacked = true self.highlightedBackgroundNode.isLayerBacked = true
@ -286,6 +290,9 @@ public class ItemListAddressItemNode: ListViewItemNode {
if strongSelf.bottomStripeNode.supernode == nil { if strongSelf.bottomStripeNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0) strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
} }
if strongSelf.maskNode.supernode != nil {
strongSelf.maskNode.removeFromSupernode()
}
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight)) strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
case .blocks: case .blocks:
@ -300,11 +307,19 @@ public class ItemListAddressItemNode: ListViewItemNode {
if strongSelf.bottomStripeNode.supernode == nil { if strongSelf.bottomStripeNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
} }
if strongSelf.maskNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
}
let hasCorners = itemListHasRoundedBlockLayout(params)
var hasTopCorners = false
var hasBottomCorners = false
switch neighbors.top { switch neighbors.top {
case .sameSection(false): case .sameSection(false):
strongSelf.topStripeNode.isHidden = true strongSelf.topStripeNode.isHidden = true
default: default:
strongSelf.topStripeNode.isHidden = !item.displayDecorations hasTopCorners = true
strongSelf.topStripeNode.isHidden = hasCorners || !item.displayDecorations
} }
let bottomStripeInset: CGFloat let bottomStripeInset: CGFloat
let bottomStripeOffset: CGFloat let bottomStripeOffset: CGFloat
@ -315,8 +330,14 @@ public class ItemListAddressItemNode: ListViewItemNode {
default: default:
bottomStripeInset = 0.0 bottomStripeInset = 0.0
bottomStripeOffset = 0.0 bottomStripeOffset = 0.0
hasBottomCorners = true
strongSelf.bottomStripeNode.isHidden = hasCorners
} }
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight)) strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight))
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight)) strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight))
} }

View File

@ -15,6 +15,7 @@ public enum ItemListPeerActionItemHeight {
public enum ItemListPeerActionItemColor { public enum ItemListPeerActionItemColor {
case accent case accent
case destructive case destructive
case disabled
} }
public class ItemListPeerActionItem: ListViewItem, ItemListItem { public class ItemListPeerActionItem: ListViewItem, ItemListItem {
@ -29,7 +30,7 @@ public class ItemListPeerActionItem: ListViewItem, ItemListItem {
public let sectionId: ItemListSectionId public let sectionId: ItemListSectionId
let action: (() -> Void)? let action: (() -> Void)?
public init(presentationData: ItemListPresentationData, icon: UIImage?, title: String, alwaysPlain: Bool = false, hasSeparator: Bool = true, sectionId: ItemListSectionId, height: ItemListPeerActionItemHeight = .peerList, color: ItemListPeerActionItemColor = .accent, editing: Bool, action: (() -> Void)?) { public init(presentationData: ItemListPresentationData, icon: UIImage?, title: String, alwaysPlain: Bool = false, hasSeparator: Bool = true, sectionId: ItemListSectionId, height: ItemListPeerActionItemHeight = .peerList, color: ItemListPeerActionItemColor = .accent, editing: Bool = false, action: (() -> Void)?) {
self.presentationData = presentationData self.presentationData = presentationData
self.icon = icon self.icon = icon
self.title = title self.title = title
@ -182,6 +183,8 @@ class ItemListPeerActionItemNode: ListViewItemNode {
textColor = item.presentationData.theme.list.itemAccentColor textColor = item.presentationData.theme.list.itemAccentColor
case .destructive: case .destructive:
textColor = item.presentationData.theme.list.itemDestructiveColor textColor = item.presentationData.theme.list.itemDestructiveColor
case .disabled:
textColor = item.presentationData.theme.list.itemDisabledTextColor
} }
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: textColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - editingOffset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: textColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - editingOffset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))

View File

@ -492,7 +492,9 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
self.bottomStripeNode = ASDisplayNode() self.bottomStripeNode = ASDisplayNode()
self.bottomStripeNode.isLayerBacked = true self.bottomStripeNode.isLayerBacked = true
self.maskNode = ASImageNode() self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
self.containerNode = ContextControllerSourceNode() self.containerNode = ContextControllerSourceNode()
@ -991,7 +993,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
} }
if strongSelf.maskNode.supernode == nil { if strongSelf.maskNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.maskNode, at: 3) strongSelf.addSubnode(strongSelf.maskNode)
} }
let hasCorners = itemListHasRoundedBlockLayout(params) && !item.noInsets let hasCorners = itemListHasRoundedBlockLayout(params) && !item.noInsets

View File

@ -204,6 +204,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
self.bottomStripeNode.isLayerBacked = true self.bottomStripeNode.isLayerBacked = true
self.maskNode = ASImageNode() self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
self.imageNode = TransformImageNode() self.imageNode = TransformImageNode()
self.imageNode.isLayerBacked = !smartInvertColorsEnabled() self.imageNode.isLayerBacked = !smartInvertColorsEnabled()
@ -659,7 +660,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
} }
if strongSelf.maskNode.supernode == nil { if strongSelf.maskNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.maskNode, at: 3) strongSelf.addSubnode(strongSelf.maskNode)
} }
let hasCorners = itemListHasRoundedBlockLayout(params) let hasCorners = itemListHasRoundedBlockLayout(params)

View File

@ -350,13 +350,17 @@ open class ItemListControllerNode: ASDisplayNode {
if let strongSelf = self { if let strongSelf = self {
var previousContentOffsetValue: CGFloat? var previousContentOffsetValue: CGFloat?
if let previousContentOffset = strongSelf.previousContentOffset, case let .known(value) = previousContentOffset { if let previousContentOffset = strongSelf.previousContentOffset {
previousContentOffsetValue = value if case let .known(value) = previousContentOffset {
previousContentOffsetValue = value
} else {
previousContentOffsetValue = 30.0
}
} }
switch offset { switch offset {
case let .known(value): case let .known(value):
let transition: ContainedViewLayoutTransition let transition: ContainedViewLayoutTransition
if let previousContentOffsetValue = previousContentOffsetValue, value <= 0.0, previousContentOffsetValue > 30.0 { if let previousContentOffsetValue = previousContentOffsetValue, value <= 0.0, previousContentOffsetValue >= 30.0 {
transition = .animated(duration: 0.2, curve: .easeInOut) transition = .animated(duration: 0.2, curve: .easeInOut)
} else { } else {
transition = .immediate transition = .immediate
@ -699,7 +703,11 @@ open class ItemListControllerNode: ASDisplayNode {
if let validLayout = self.validLayout { if let validLayout = self.validLayout {
updatedNode.updateLayout(layout: validLayout.0, navigationBarHeight: validLayout.1, transition: .immediate) updatedNode.updateLayout(layout: validLayout.0, navigationBarHeight: validLayout.1, transition: .immediate)
} }
self.insertSubnode(updatedNode, aboveSubnode: self.listNode) if self.rightOverlayNode.supernode != nil {
self.insertSubnode(updatedNode, aboveSubnode: self.rightOverlayNode)
} else {
self.insertSubnode(updatedNode, aboveSubnode: self.listNode)
}
updatedNode.activate() updatedNode.activate()
} }
} else { } else {

View File

@ -139,6 +139,7 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
self.backgroundNode.backgroundColor = .white self.backgroundNode.backgroundColor = .white
self.maskNode = ASImageNode() self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
self.topStripeNode = ASDisplayNode() self.topStripeNode = ASDisplayNode()
self.topStripeNode.isLayerBacked = true self.topStripeNode.isLayerBacked = true

View File

@ -141,7 +141,9 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode {
self.bottomStripeNode = ASDisplayNode() self.bottomStripeNode = ASDisplayNode()
self.bottomStripeNode.isLayerBacked = true self.bottomStripeNode.isLayerBacked = true
self.maskNode = ASImageNode() self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
self.iconNode = TransformImageNode() self.iconNode = TransformImageNode()

View File

@ -254,6 +254,7 @@ final class LocationLiveListItemNode: ListViewItemNode {
if strongSelf.drivingButtonNode == nil { if strongSelf.drivingButtonNode == nil {
strongSelf.drivingButtonNode = SolidRoundedButtonNode(icon: generateTintedImage(image: UIImage(bundleImageName: "Location/DirectionsDriving"), color: item.presentationData.theme.list.itemCheckColors.foregroundColor), theme: buttonTheme, fontSize: 15.0, height: 32.0, cornerRadius: 16.0) strongSelf.drivingButtonNode = SolidRoundedButtonNode(icon: generateTintedImage(image: UIImage(bundleImageName: "Location/DirectionsDriving"), color: item.presentationData.theme.list.itemCheckColors.foregroundColor), theme: buttonTheme, fontSize: 15.0, height: 32.0, cornerRadius: 16.0)
strongSelf.drivingButtonNode?.alpha = 0.0 strongSelf.drivingButtonNode?.alpha = 0.0
strongSelf.drivingButtonNode?.iconSpacing = 5.0
strongSelf.drivingButtonNode?.allowsGroupOpacity = true strongSelf.drivingButtonNode?.allowsGroupOpacity = true
strongSelf.drivingButtonNode?.pressed = { [weak self] in strongSelf.drivingButtonNode?.pressed = { [weak self] in
if let item = self?.item { if let item = self?.item {
@ -264,6 +265,7 @@ final class LocationLiveListItemNode: ListViewItemNode {
strongSelf.transitButtonNode = SolidRoundedButtonNode(icon: generateTintedImage(image: UIImage(bundleImageName: "Location/DirectionsTransit"), color: item.presentationData.theme.list.itemCheckColors.foregroundColor), theme: buttonTheme, fontSize: 15.0, height: 32.0, cornerRadius: 16.0) strongSelf.transitButtonNode = SolidRoundedButtonNode(icon: generateTintedImage(image: UIImage(bundleImageName: "Location/DirectionsTransit"), color: item.presentationData.theme.list.itemCheckColors.foregroundColor), theme: buttonTheme, fontSize: 15.0, height: 32.0, cornerRadius: 16.0)
strongSelf.transitButtonNode?.alpha = 0.0 strongSelf.transitButtonNode?.alpha = 0.0
strongSelf.transitButtonNode?.iconSpacing = 2.0
strongSelf.transitButtonNode?.allowsGroupOpacity = true strongSelf.transitButtonNode?.allowsGroupOpacity = true
strongSelf.transitButtonNode?.pressed = { [weak self] in strongSelf.transitButtonNode?.pressed = { [weak self] in
if let item = self?.item { if let item = self?.item {
@ -274,6 +276,7 @@ final class LocationLiveListItemNode: ListViewItemNode {
strongSelf.walkingButtonNode = SolidRoundedButtonNode(icon: generateTintedImage(image: UIImage(bundleImageName: "Location/DirectionsWalking"), color: item.presentationData.theme.list.itemCheckColors.foregroundColor), theme: buttonTheme, fontSize: 15.0, height: 32.0, cornerRadius: 16.0) strongSelf.walkingButtonNode = SolidRoundedButtonNode(icon: generateTintedImage(image: UIImage(bundleImageName: "Location/DirectionsWalking"), color: item.presentationData.theme.list.itemCheckColors.foregroundColor), theme: buttonTheme, fontSize: 15.0, height: 32.0, cornerRadius: 16.0)
strongSelf.walkingButtonNode?.alpha = 0.0 strongSelf.walkingButtonNode?.alpha = 0.0
strongSelf.walkingButtonNode?.iconSpacing = 2.0
strongSelf.walkingButtonNode?.allowsGroupOpacity = true strongSelf.walkingButtonNode?.allowsGroupOpacity = true
strongSelf.walkingButtonNode?.pressed = { [weak self] in strongSelf.walkingButtonNode?.pressed = { [weak self] in
if let item = self?.item { if let item = self?.item {

View File

@ -447,7 +447,8 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
public let controlsContainerNode: ASDisplayNode public let controlsContainerNode: ASDisplayNode
public let controlsClippingNode: ASDisplayNode public let controlsClippingNode: ASDisplayNode
public let controlsClippingOffsetNode: ASDisplayNode public let controlsClippingOffsetNode: ASDisplayNode
public let shadowNode: ASImageNode public let topShadowNode: ASImageNode
public let bottomShadowNode: ASImageNode
public let contentNode: ASDisplayNode public let contentNode: ASDisplayNode
let leftHighlightNode: ASDisplayNode let leftHighlightNode: ASDisplayNode
@ -631,10 +632,15 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
self.controlsClippingNode.isUserInteractionEnabled = false self.controlsClippingNode.isUserInteractionEnabled = false
self.controlsClippingNode.clipsToBounds = true self.controlsClippingNode.clipsToBounds = true
self.shadowNode = ASImageNode() self.topShadowNode = ASImageNode()
self.shadowNode.displaysAsynchronously = false self.topShadowNode.displaysAsynchronously = false
self.shadowNode.displayWithoutProcessing = true self.topShadowNode.displayWithoutProcessing = true
self.shadowNode.contentMode = .scaleToFill self.topShadowNode.contentMode = .scaleToFill
self.bottomShadowNode = ASImageNode()
self.bottomShadowNode.displaysAsynchronously = false
self.bottomShadowNode.displayWithoutProcessing = true
self.bottomShadowNode.contentMode = .scaleToFill
do { do {
let size = CGSize(width: 88.0, height: 88.0) let size = CGSize(width: 88.0, height: 88.0)
@ -656,13 +662,20 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
let image = UIGraphicsGetImageFromCurrentImageContext() let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext() UIGraphicsEndImageContext()
if let image = image { if let image = image {
self.shadowNode.image = generateImage(image.size, contextGenerator: { size, context in self.topShadowNode.image = generateImage(image.size, contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size)) context.clear(CGRect(origin: CGPoint(), size: size))
context.translateBy(x: size.width / 2.0, y: size.height / 2.0) context.translateBy(x: size.width / 2.0, y: size.height / 2.0)
context.rotate(by: -CGFloat.pi / 2.0) context.rotate(by: -CGFloat.pi / 2.0)
context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0) context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0)
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size)) context.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size))
}) })
self.bottomShadowNode.image = generateImage(image.size, contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.translateBy(x: size.width / 2.0, y: size.height / 2.0)
context.rotate(by: CGFloat.pi / 2.0)
context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0)
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size))
})
} }
} }
} }
@ -674,7 +687,8 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
self.addSubnode(self.contentNode) self.addSubnode(self.contentNode)
self.controlsContainerNode.addSubnode(self.highlightContainerNode) self.controlsContainerNode.addSubnode(self.highlightContainerNode)
self.controlsContainerNode.addSubnode(self.shadowNode) self.controlsContainerNode.addSubnode(self.topShadowNode)
self.addSubnode(self.bottomShadowNode)
self.controlsContainerNode.addSubnode(self.stripContainerNode) self.controlsContainerNode.addSubnode(self.stripContainerNode)
self.controlsClippingNode.addSubnode(self.controlsContainerNode) self.controlsClippingNode.addSubnode(self.controlsContainerNode)
self.controlsClippingOffsetNode.addSubnode(self.controlsClippingNode) self.controlsClippingOffsetNode.addSubnode(self.controlsClippingNode)

View File

@ -32,7 +32,7 @@ final class ChannelMembersSearchItem: ItemListControllerSearch {
self.pushController = pushController self.pushController = pushController
self.dismissInput = dismissInput self.dismissInput = dismissInput
self.searchMode = searchMode self.searchMode = searchMode
activityDisposable.set((activity.get() |> mapToSignal { value -> Signal<Bool, NoError> in self.activityDisposable.set((activity.get() |> mapToSignal { value -> Signal<Bool, NoError> in
if value { if value {
return .single(value) |> delay(0.2, queue: Queue.mainQueue()) return .single(value) |> delay(0.2, queue: Queue.mainQueue())
} else { } else {

View File

@ -50,8 +50,8 @@ extension _AdaptedPostboxEncoder.KeyedContainer: KeyedEncodingContainerProtocol
let innerEncoder = _AdaptedPostboxEncoder(typeHash: typeHash) let innerEncoder = _AdaptedPostboxEncoder(typeHash: typeHash)
try! value.encode(to: innerEncoder) try! value.encode(to: innerEncoder)
let type = type(of: value) let typeOfValue = type(of: value)
let typeString = "\(type)" let typeString = "\(typeOfValue)"
var isDictionary = false var isDictionary = false
if typeString.hasPrefix("Dictionary<") { if typeString.hasPrefix("Dictionary<") {
isDictionary = true isDictionary = true

View File

@ -94,6 +94,8 @@ final class ChangePhoneNumberController: ViewController, MFMailComposeViewContro
strongSelf.controllerNode.updateCountryCode() strongSelf.controllerNode.updateCountryCode()
} }
}) })
self.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
} }
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {

View File

@ -120,6 +120,8 @@ public final class ChangePhoneNumberIntroController: ViewController {
self?.proceed() self?.proceed()
} }
self.displayNodeDidLoad() self.displayNodeDidLoad()
self.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
} }
public override func viewDidAppear(_ animated: Bool) { public override func viewDidAppear(_ animated: Bool) {

View File

@ -11,6 +11,7 @@ import ItemListUI
import PresentationDataUtils import PresentationDataUtils
import AccountContext import AccountContext
import OpenInExternalAppUI import OpenInExternalAppUI
import ItemListPeerActionItem
private final class DataAndStorageControllerArguments { private final class DataAndStorageControllerArguments {
let openStorageUsage: () -> Void let openStorageUsage: () -> Void
@ -322,12 +323,16 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Settings/Menu/WiFi")?.precomposed(), title: text, label: value, labelStyle: .detailText, sectionId: self.section, style: .blocks, action: { return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Settings/Menu/WiFi")?.precomposed(), title: text, label: value, labelStyle: .detailText, sectionId: self.section, style: .blocks, action: {
arguments.openAutomaticDownloadConnectionType(.wifi) arguments.openAutomaticDownloadConnectionType(.wifi)
}) })
case let .automaticDownloadReset(_, text, enabled): case let .automaticDownloadReset(theme, text, enabled):
return ItemListActionItem(presentationData: presentationData, title: text, kind: enabled ? .generic : .disabled, alignment: .natural, sectionId: self.section, style: .blocks, action: { var icon = PresentationResourcesItemList.resetIcon(theme)
if !enabled {
icon = generateTintedImage(image: icon, color: theme.list.itemDisabledTextColor)
}
return ItemListPeerActionItem(presentationData: presentationData, icon: icon, title: text, sectionId: self.section, height: .generic, color: enabled ? .accent : .disabled, editing: false, action: {
if enabled { if enabled {
arguments.resetAutomaticDownload() arguments.resetAutomaticDownload()
} }
}, tag: DataAndStorageEntryTag.automaticDownloadReset) })
case let .autoplayHeader(_, text): case let .autoplayHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .autoplayGifs(_, text, value): case let .autoplayGifs(_, text, value):

View File

@ -141,6 +141,7 @@ private final class ProxySettingsServerItemNode: ItemListRevealOptionsItemNode {
self.bottomStripeNode.isLayerBacked = true self.bottomStripeNode.isLayerBacked = true
self.maskNode = ASImageNode() self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
self.infoIconNode = ASImageNode() self.infoIconNode = ASImageNode()
self.infoIconNode.isLayerBacked = true self.infoIconNode.isLayerBacked = true
@ -369,7 +370,7 @@ private final class ProxySettingsServerItemNode: ItemListRevealOptionsItemNode {
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
} }
if strongSelf.maskNode.supernode == nil { if strongSelf.maskNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.maskNode, at: 3) strongSelf.addSubnode(strongSelf.maskNode)
} }
let hasCorners = itemListHasRoundedBlockLayout(params) let hasCorners = itemListHasRoundedBlockLayout(params)

View File

@ -1,6 +1,7 @@
import Foundation import Foundation
import UIKit import UIKit
import Display import Display
import AsyncDisplayKit
import SwiftSignalKit import SwiftSignalKit
import Postbox import Postbox
import TelegramCore import TelegramCore
@ -375,47 +376,41 @@ public enum NotificationsPeerCategory {
private final class NotificationExceptionState : Equatable { private final class NotificationExceptionState : Equatable {
let mode: NotificationExceptionMode let mode: NotificationExceptionMode
let isSearchMode: Bool
let revealedPeerId: PeerId? let revealedPeerId: PeerId?
let editing: Bool let editing: Bool
init(mode: NotificationExceptionMode, isSearchMode: Bool = false, revealedPeerId: PeerId? = nil, editing: Bool = false) { init(mode: NotificationExceptionMode, revealedPeerId: PeerId? = nil, editing: Bool = false) {
self.mode = mode self.mode = mode
self.isSearchMode = isSearchMode
self.revealedPeerId = revealedPeerId self.revealedPeerId = revealedPeerId
self.editing = editing self.editing = editing
} }
func withUpdatedMode(_ mode: NotificationExceptionMode) -> NotificationExceptionState { func withUpdatedMode(_ mode: NotificationExceptionMode) -> NotificationExceptionState {
return NotificationExceptionState(mode: mode, isSearchMode: self.isSearchMode, revealedPeerId: self.revealedPeerId, editing: self.editing) return NotificationExceptionState(mode: mode, revealedPeerId: self.revealedPeerId, editing: self.editing)
}
func withUpdatedSearchMode(_ isSearchMode: Bool) -> NotificationExceptionState {
return NotificationExceptionState(mode: self.mode, isSearchMode: isSearchMode, revealedPeerId: self.revealedPeerId, editing: self.editing)
} }
func withUpdatedEditing(_ editing: Bool) -> NotificationExceptionState { func withUpdatedEditing(_ editing: Bool) -> NotificationExceptionState {
return NotificationExceptionState(mode: self.mode, isSearchMode: self.isSearchMode, revealedPeerId: self.revealedPeerId, editing: editing) return NotificationExceptionState(mode: self.mode, revealedPeerId: self.revealedPeerId, editing: editing)
} }
func withUpdatedRevealedPeerId(_ revealedPeerId: PeerId?) -> NotificationExceptionState { func withUpdatedRevealedPeerId(_ revealedPeerId: PeerId?) -> NotificationExceptionState {
return NotificationExceptionState(mode: self.mode, isSearchMode: self.isSearchMode, revealedPeerId: revealedPeerId, editing: self.editing) return NotificationExceptionState(mode: self.mode, revealedPeerId: revealedPeerId, editing: self.editing)
} }
func withUpdatedPeerSound(_ peer: Peer, _ sound: PeerMessageSound) -> NotificationExceptionState { func withUpdatedPeerSound(_ peer: Peer, _ sound: PeerMessageSound) -> NotificationExceptionState {
return NotificationExceptionState(mode: mode.withUpdatedPeerSound(peer, sound), isSearchMode: isSearchMode, revealedPeerId: self.revealedPeerId, editing: self.editing) return NotificationExceptionState(mode: mode.withUpdatedPeerSound(peer, sound), revealedPeerId: self.revealedPeerId, editing: self.editing)
} }
func withUpdatedPeerMuteInterval(_ peer: Peer, _ muteInterval: Int32?) -> NotificationExceptionState { func withUpdatedPeerMuteInterval(_ peer: Peer, _ muteInterval: Int32?) -> NotificationExceptionState {
return NotificationExceptionState(mode: mode.withUpdatedPeerMuteInterval(peer, muteInterval), isSearchMode: isSearchMode, revealedPeerId: self.revealedPeerId, editing: self.editing) return NotificationExceptionState(mode: mode.withUpdatedPeerMuteInterval(peer, muteInterval), revealedPeerId: self.revealedPeerId, editing: self.editing)
} }
func withUpdatedPeerDisplayPreviews(_ peer: Peer, _ displayPreviews: PeerNotificationDisplayPreviews) -> NotificationExceptionState { func withUpdatedPeerDisplayPreviews(_ peer: Peer, _ displayPreviews: PeerNotificationDisplayPreviews) -> NotificationExceptionState {
return NotificationExceptionState(mode: mode.withUpdatedPeerDisplayPreviews(peer, displayPreviews), isSearchMode: isSearchMode, revealedPeerId: self.revealedPeerId, editing: self.editing) return NotificationExceptionState(mode: mode.withUpdatedPeerDisplayPreviews(peer, displayPreviews), revealedPeerId: self.revealedPeerId, editing: self.editing)
} }
static func == (lhs: NotificationExceptionState, rhs: NotificationExceptionState) -> Bool { static func == (lhs: NotificationExceptionState, rhs: NotificationExceptionState) -> Bool {
return lhs.mode == rhs.mode && lhs.isSearchMode == rhs.isSearchMode && lhs.revealedPeerId == rhs.revealedPeerId && lhs.editing == rhs.editing return lhs.mode == rhs.mode && lhs.revealedPeerId == rhs.revealedPeerId && lhs.editing == rhs.editing
} }
} }
@ -714,7 +709,30 @@ public func notificationsPeerCategoryController(context: AccountContext, categor
} }
} }
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.Notifications_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) let leftNavigationButton: ItemListNavigationButton?
let rightNavigationButton: ItemListNavigationButton?
if !state.mode.peerIds.isEmpty {
if state.editing {
leftNavigationButton = ItemListNavigationButton(content: .none, style: .regular, enabled: false, action: {})
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: {
updateState { value in
return value.withUpdatedEditing(false)
}
})
} else {
leftNavigationButton = nil
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Edit), style: .regular, enabled: true, action: {
updateState { value in
return value.withUpdatedEditing(true)
}
})
}
} else {
leftNavigationButton = nil
rightNavigationButton = nil
}
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.Notifications_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: entries, style: .blocks, ensureVisibleItemTag: focusOnItemTag, initialScrollToItem: scrollToItem) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: entries, style: .blocks, ensureVisibleItemTag: focusOnItemTag, initialScrollToItem: scrollToItem)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))

View File

@ -46,8 +46,9 @@ final class ItemListRecentSessionItem: ListViewItem, ItemListItem {
let sectionId: ItemListSectionId let sectionId: ItemListSectionId
let setSessionIdWithRevealedOptions: (Int64?, Int64?) -> Void let setSessionIdWithRevealedOptions: (Int64?, Int64?) -> Void
let removeSession: (Int64) -> Void let removeSession: (Int64) -> Void
let action: (() -> Void)?
init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, session: RecentAccountSession, enabled: Bool, editable: Bool, editing: Bool, revealed: Bool, sectionId: ItemListSectionId, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void) { init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, session: RecentAccountSession, enabled: Bool, editable: Bool, editing: Bool, revealed: Bool, sectionId: ItemListSectionId, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void, action: (() -> Void)?) {
self.presentationData = presentationData self.presentationData = presentationData
self.dateTimeFormat = dateTimeFormat self.dateTimeFormat = dateTimeFormat
self.session = session self.session = session
@ -58,6 +59,7 @@ final class ItemListRecentSessionItem: ListViewItem, ItemListItem {
self.sectionId = sectionId self.sectionId = sectionId
self.setSessionIdWithRevealedOptions = setSessionIdWithRevealedOptions self.setSessionIdWithRevealedOptions = setSessionIdWithRevealedOptions
self.removeSession = removeSession self.removeSession = removeSession
self.action = action
} }
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) { func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
@ -97,11 +99,29 @@ final class ItemListRecentSessionItem: ListViewItem, ItemListItem {
} }
} }
} }
public var selectable: Bool = true
public func selected(listView: ListView){
listView.clearHighlightAnimated(true)
if self.enabled {
self.action?()
}
}
} }
private func iconForSession(_ session: RecentAccountSession) -> UIImage? { private func iconForSession(_ session: RecentAccountSession) -> UIImage? {
let platform = session.platform.lowercased() let platform = session.platform.lowercased()
let device = session.deviceModel.lowercased() let device = session.deviceModel.lowercased()
if device.contains("chrome") && !device.contains("chromebook") {
return UIImage(bundleImageName: "Settings/Devices/Chrome")
}
if device.contains("brave") {
return UIImage(bundleImageName: "Settings/Devices/Brave")
}
if device.contains("vivaldi") {
return UIImage(bundleImageName: "Settings/Devices/Vivaldi")
}
if device.contains("safari") { if device.contains("safari") {
return UIImage(bundleImageName: "Settings/Devices/Safari") return UIImage(bundleImageName: "Settings/Devices/Safari")
} }
@ -111,12 +131,27 @@ private func iconForSession(_ session: RecentAccountSession) -> UIImage? {
if device.contains("opera") { if device.contains("opera") {
return UIImage(bundleImageName: "Settings/Devices/Opera") return UIImage(bundleImageName: "Settings/Devices/Opera")
} }
if platform.contains("android") {
return UIImage(bundleImageName: "Settings/Devices/Android")
}
if platform.contains("ios") || platform.contains("macos") { if platform.contains("ios") || platform.contains("macos") {
return UIImage(bundleImageName: "Settings/Devices/iOS") return UIImage(bundleImageName: "Settings/Devices/iOS")
} }
if platform.contains("linux") {
return UIImage(bundleImageName: "Settings/Devices/Linux")
}
if platform.contains("windows") {
return UIImage(bundleImageName: "Settings/Devices/Windows")
}
return nil return nil
} }
private func trimmedLocationName(_ session: RecentAccountSession) -> String {
var country = session.country
country = country.replacingOccurrences(of: "United Arab Emirates", with: "UAE")
return country
}
class ItemListRecentSessionItemNode: ItemListRevealOptionsItemNode { class ItemListRecentSessionItemNode: ItemListRevealOptionsItemNode {
private let backgroundNode: ASDisplayNode private let backgroundNode: ASDisplayNode
private let topStripeNode: ASDisplayNode private let topStripeNode: ASDisplayNode
@ -130,12 +165,25 @@ class ItemListRecentSessionItemNode: ItemListRevealOptionsItemNode {
private let appNode: TextNode private let appNode: TextNode
private let locationNode: TextNode private let locationNode: TextNode
private let containerNode: ASDisplayNode
override var controlsContainer: ASDisplayNode {
return self.containerNode
}
private let activateArea: AccessibilityAreaNode private let activateArea: AccessibilityAreaNode
private var layoutParams: (ItemListRecentSessionItem, ListViewItemLayoutParams, ItemListNeighbors)? private var layoutParams: (ItemListRecentSessionItem, ListViewItemLayoutParams, ItemListNeighbors)?
private var editableControlNode: ItemListEditableControlNode? private var editableControlNode: ItemListEditableControlNode?
override public var canBeSelected: Bool {
if let item = self.layoutParams?.0, let _ = item.action {
return true
} else {
return false
}
}
init() { init() {
self.backgroundNode = ASDisplayNode() self.backgroundNode = ASDisplayNode()
self.backgroundNode.isLayerBacked = true self.backgroundNode.isLayerBacked = true
@ -147,6 +195,9 @@ class ItemListRecentSessionItemNode: ItemListRevealOptionsItemNode {
self.bottomStripeNode.isLayerBacked = true self.bottomStripeNode.isLayerBacked = true
self.maskNode = ASImageNode() self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
self.containerNode = ASDisplayNode()
self.iconNode = ASImageNode() self.iconNode = ASImageNode()
self.iconNode.cornerRadius = 7.0 self.iconNode.cornerRadius = 7.0
@ -174,10 +225,11 @@ class ItemListRecentSessionItemNode: ItemListRevealOptionsItemNode {
super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false) super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
self.addSubnode(self.iconNode) self.addSubnode(self.containerNode)
self.addSubnode(self.titleNode) self.containerNode.addSubnode(self.iconNode)
self.addSubnode(self.appNode) self.containerNode.addSubnode(self.titleNode)
self.addSubnode(self.locationNode) self.containerNode.addSubnode(self.appNode)
self.containerNode.addSubnode(self.locationNode)
self.addSubnode(self.activateArea) self.addSubnode(self.activateArea)
} }
@ -221,23 +273,23 @@ class ItemListRecentSessionItemNode: ItemListRevealOptionsItemNode {
titleAttributedString = NSAttributedString(string: "\(item.session.appName) \(item.session.appVersion)", font: titleFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor) titleAttributedString = NSAttributedString(string: "\(item.session.appName) \(item.session.appVersion)", font: titleFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor)
var appString = "" var deviceString = ""
if !item.session.deviceModel.isEmpty { if !item.session.deviceModel.isEmpty {
appString = item.session.deviceModel deviceString = item.session.deviceModel
} }
if !item.session.platform.isEmpty { if !item.session.platform.isEmpty {
if !appString.isEmpty { if !deviceString.isEmpty {
appString += ", " deviceString += ", "
} }
appString += item.session.platform deviceString += item.session.platform
} }
if !item.session.systemVersion.isEmpty { if !item.session.systemVersion.isEmpty {
if !appString.isEmpty { if !deviceString.isEmpty {
appString += ", " deviceString += ", "
} }
appString += item.session.systemVersion deviceString += item.session.systemVersion
} }
var updatedIcon: UIImage? var updatedIcon: UIImage?
@ -245,7 +297,7 @@ class ItemListRecentSessionItemNode: ItemListRevealOptionsItemNode {
updatedIcon = iconForSession(item.session) updatedIcon = iconForSession(item.session)
} }
appAttributedString = NSAttributedString(string: appString, font: textFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor) appAttributedString = NSAttributedString(string: deviceString, font: textFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor)
let label: String let label: String
if item.session.isCurrent { if item.session.isCurrent {
@ -255,7 +307,7 @@ class ItemListRecentSessionItemNode: ItemListRevealOptionsItemNode {
label = stringForRelativeActivityTimestamp(strings: item.presentationData.strings, dateTimeFormat: item.dateTimeFormat, relativeTimestamp: item.session.activityDate, relativeTo: timestamp) label = stringForRelativeActivityTimestamp(strings: item.presentationData.strings, dateTimeFormat: item.dateTimeFormat, relativeTimestamp: item.session.activityDate, relativeTo: timestamp)
} }
locationAttributedString = NSAttributedString(string: "\(item.session.country)\(label)", font: textFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor) locationAttributedString = NSAttributedString(string: "\(trimmedLocationName(item.session))\(label)", font: textFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor)
let leftInset: CGFloat = 59.0 + params.leftInset let leftInset: CGFloat = 59.0 + params.leftInset
@ -403,7 +455,7 @@ class ItemListRecentSessionItemNode: ItemListRevealOptionsItemNode {
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
} }
if strongSelf.maskNode.supernode == nil { if strongSelf.maskNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.maskNode, at: 3) strongSelf.addSubnode(strongSelf.maskNode)
} }
let hasCorners = itemListHasRoundedBlockLayout(params) let hasCorners = itemListHasRoundedBlockLayout(params)
@ -432,6 +484,7 @@ class ItemListRecentSessionItemNode: ItemListRevealOptionsItemNode {
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: strongSelf.backgroundNode.frame.size)
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0) strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
transition.updateFrame(node: strongSelf.topStripeNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))) transition.updateFrame(node: strongSelf.topStripeNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight)))
transition.updateFrame(node: strongSelf.bottomStripeNode, frame: CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))) transition.updateFrame(node: strongSelf.bottomStripeNode, frame: CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight)))
@ -441,7 +494,7 @@ class ItemListRecentSessionItemNode: ItemListRevealOptionsItemNode {
transition.updateFrame(node: strongSelf.appNode, frame: CGRect(origin: CGPoint(x: leftInset + revealOffset + editingOffset, y: strongSelf.titleNode.frame.maxY + titleSpacing), size: appLayout.size)) transition.updateFrame(node: strongSelf.appNode, frame: CGRect(origin: CGPoint(x: leftInset + revealOffset + editingOffset, y: strongSelf.titleNode.frame.maxY + titleSpacing), size: appLayout.size))
transition.updateFrame(node: strongSelf.locationNode, frame: CGRect(origin: CGPoint(x: leftInset + revealOffset + editingOffset, y: strongSelf.appNode.frame.maxY + textSpacing), size: locationLayout.size)) transition.updateFrame(node: strongSelf.locationNode, frame: CGRect(origin: CGPoint(x: leftInset + revealOffset + editingOffset, y: strongSelf.appNode.frame.maxY + textSpacing), size: locationLayout.size))
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: 75.0 + UIScreenPixel + UIScreenPixel)) strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
strongSelf.updateLayout(size: layout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset) strongSelf.updateLayout(size: layout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset)
@ -452,6 +505,44 @@ class ItemListRecentSessionItemNode: ItemListRevealOptionsItemNode {
} }
} }
override public func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
super.setHighlighted(highlighted, at: point, animated: animated)
if highlighted && (self.layoutParams?.0.enabled ?? false) {
self.highlightedBackgroundNode.alpha = 1.0
if self.highlightedBackgroundNode.supernode == nil {
var anchorNode: ASDisplayNode?
if self.bottomStripeNode.supernode != nil {
anchorNode = self.bottomStripeNode
} else if self.topStripeNode.supernode != nil {
anchorNode = self.topStripeNode
} else if self.backgroundNode.supernode != nil {
anchorNode = self.backgroundNode
}
if let anchorNode = anchorNode {
self.insertSubnode(self.highlightedBackgroundNode, aboveSubnode: anchorNode)
} else {
self.addSubnode(self.highlightedBackgroundNode)
}
}
} else {
if self.highlightedBackgroundNode.supernode != nil {
if animated {
self.highlightedBackgroundNode.layer.animateAlpha(from: self.highlightedBackgroundNode.alpha, to: 0.0, duration: 0.4, completion: { [weak self] completed in
if let strongSelf = self {
if completed {
strongSelf.highlightedBackgroundNode.removeFromSupernode()
}
}
})
self.highlightedBackgroundNode.alpha = 0.0
} else {
self.highlightedBackgroundNode.removeFromSupernode()
}
}
}
}
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) { override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4) self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
} }

View File

@ -42,8 +42,9 @@ final class ItemListWebsiteItem: ListViewItem, ItemListItem {
let sectionId: ItemListSectionId let sectionId: ItemListSectionId
let setSessionIdWithRevealedOptions: (Int64?, Int64?) -> Void let setSessionIdWithRevealedOptions: (Int64?, Int64?) -> Void
let removeSession: (Int64) -> Void let removeSession: (Int64) -> Void
let action: (() -> Void)?
init(context: AccountContext, presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, website: WebAuthorization, peer: Peer?, enabled: Bool, editing: Bool, revealed: Bool, sectionId: ItemListSectionId, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void) { init(context: AccountContext, presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, website: WebAuthorization, peer: Peer?, enabled: Bool, editing: Bool, revealed: Bool, sectionId: ItemListSectionId, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void, action: (() -> Void)?) {
self.context = context self.context = context
self.presentationData = presentationData self.presentationData = presentationData
self.dateTimeFormat = dateTimeFormat self.dateTimeFormat = dateTimeFormat
@ -56,6 +57,7 @@ final class ItemListWebsiteItem: ListViewItem, ItemListItem {
self.sectionId = sectionId self.sectionId = sectionId
self.setSessionIdWithRevealedOptions = setSessionIdWithRevealedOptions self.setSessionIdWithRevealedOptions = setSessionIdWithRevealedOptions
self.removeSession = removeSession self.removeSession = removeSession
self.action = action
} }
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) { func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
@ -95,10 +97,26 @@ final class ItemListWebsiteItem: ListViewItem, ItemListItem {
} }
} }
} }
public var selectable: Bool = true
public func selected(listView: ListView){
listView.clearHighlightAnimated(true)
if self.enabled {
self.action?()
}
}
} }
private let avatarFont = avatarPlaceholderFont(size: 11.0) private let avatarFont = avatarPlaceholderFont(size: 11.0)
private func trimmedLocationName(_ session: WebAuthorization) -> String {
var country = session.region
country = country.replacingOccurrences(of: "United Arab Emirates", with: "UAE")
return country
}
class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode { class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode {
private let backgroundNode: ASDisplayNode private let backgroundNode: ASDisplayNode
private let topStripeNode: ASDisplayNode private let topStripeNode: ASDisplayNode
@ -111,12 +129,19 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode {
private let titleNode: TextNode private let titleNode: TextNode
private let appNode: TextNode private let appNode: TextNode
private let locationNode: TextNode private let locationNode: TextNode
private let labelNode: TextNode
private var layoutParams: (ItemListWebsiteItem, ListViewItemLayoutParams, ItemListNeighbors)? private var layoutParams: (ItemListWebsiteItem, ListViewItemLayoutParams, ItemListNeighbors)?
private var editableControlNode: ItemListEditableControlNode? private var editableControlNode: ItemListEditableControlNode?
override public var canBeSelected: Bool {
if let item = self.layoutParams?.0, let _ = item.action {
return true
} else {
return false
}
}
init() { init() {
self.backgroundNode = ASDisplayNode() self.backgroundNode = ASDisplayNode()
self.backgroundNode.isLayerBacked = true self.backgroundNode.isLayerBacked = true
@ -128,6 +153,7 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode {
self.bottomStripeNode.isLayerBacked = true self.bottomStripeNode.isLayerBacked = true
self.maskNode = ASImageNode() self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
self.avatarNode = AvatarNode(font: avatarFont) self.avatarNode = AvatarNode(font: avatarFont)
self.avatarNode.cornerRadius = 7.0 self.avatarNode.cornerRadius = 7.0
@ -148,11 +174,6 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode {
self.locationNode.contentMode = .left self.locationNode.contentMode = .left
self.locationNode.contentsScale = UIScreen.main.scale self.locationNode.contentsScale = UIScreen.main.scale
self.labelNode = TextNode()
self.labelNode.isUserInteractionEnabled = false
self.labelNode.contentMode = .left
self.labelNode.contentsScale = UIScreen.main.scale
self.highlightedBackgroundNode = ASDisplayNode() self.highlightedBackgroundNode = ASDisplayNode()
self.highlightedBackgroundNode.isLayerBacked = true self.highlightedBackgroundNode.isLayerBacked = true
@ -162,7 +183,6 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode {
self.addSubnode(self.titleNode) self.addSubnode(self.titleNode)
self.addSubnode(self.appNode) self.addSubnode(self.appNode)
self.addSubnode(self.locationNode) self.addSubnode(self.locationNode)
self.addSubnode(self.labelNode)
} }
func asyncLayout() -> (_ item: ItemListWebsiteItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, (Bool) -> Void) { func asyncLayout() -> (_ item: ItemListWebsiteItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, (Bool) -> Void) {
@ -221,7 +241,7 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode {
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
let label = stringForRelativeActivityTimestamp(strings: item.presentationData.strings, dateTimeFormat: item.dateTimeFormat, relativeTimestamp: item.website.dateActive, relativeTo: timestamp) let label = stringForRelativeActivityTimestamp(strings: item.presentationData.strings, dateTimeFormat: item.dateTimeFormat, relativeTimestamp: item.website.dateActive, relativeTo: timestamp)
locationAttributedString = NSAttributedString(string: "\(item.website.region)\(label)", font: textFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor) locationAttributedString = NSAttributedString(string: "\(trimmedLocationName(item.website))\(label)", font: textFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor)
let leftInset: CGFloat = 59.0 + params.leftInset let leftInset: CGFloat = 59.0 + params.leftInset
@ -341,7 +361,7 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode {
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
} }
if strongSelf.maskNode.supernode == nil { if strongSelf.maskNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.maskNode, at: 3) strongSelf.addSubnode(strongSelf.maskNode)
} }
let hasCorners = itemListHasRoundedBlockLayout(params) let hasCorners = itemListHasRoundedBlockLayout(params)
@ -381,7 +401,7 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode {
transition.updateFrame(node: strongSelf.appNode, frame: CGRect(origin: CGPoint(x: leftInset + revealOffset + editingOffset, y: 30.0), size: appLayout.size)) transition.updateFrame(node: strongSelf.appNode, frame: CGRect(origin: CGPoint(x: leftInset + revealOffset + editingOffset, y: 30.0), size: appLayout.size))
transition.updateFrame(node: strongSelf.locationNode, frame: CGRect(origin: CGPoint(x: leftInset + revealOffset + editingOffset, y: 50.0), size: locationLayout.size)) transition.updateFrame(node: strongSelf.locationNode, frame: CGRect(origin: CGPoint(x: leftInset + revealOffset + editingOffset, y: 50.0), size: locationLayout.size))
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: 75.0 + UIScreenPixel + UIScreenPixel)) strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
strongSelf.updateLayout(size: layout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset) strongSelf.updateLayout(size: layout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset)
@ -392,6 +412,44 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode {
} }
} }
override public func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
super.setHighlighted(highlighted, at: point, animated: animated)
if highlighted && (self.layoutParams?.0.enabled ?? false) {
self.highlightedBackgroundNode.alpha = 1.0
if self.highlightedBackgroundNode.supernode == nil {
var anchorNode: ASDisplayNode?
if self.bottomStripeNode.supernode != nil {
anchorNode = self.bottomStripeNode
} else if self.topStripeNode.supernode != nil {
anchorNode = self.topStripeNode
} else if self.backgroundNode.supernode != nil {
anchorNode = self.backgroundNode
}
if let anchorNode = anchorNode {
self.insertSubnode(self.highlightedBackgroundNode, aboveSubnode: anchorNode)
} else {
self.addSubnode(self.highlightedBackgroundNode)
}
}
} else {
if self.highlightedBackgroundNode.supernode != nil {
if animated {
self.highlightedBackgroundNode.layer.animateAlpha(from: self.highlightedBackgroundNode.alpha, to: 0.0, duration: 0.4, completion: { [weak self] completed in
if let strongSelf = self {
if completed {
strongSelf.highlightedBackgroundNode.removeFromSupernode()
}
}
})
self.highlightedBackgroundNode.alpha = 0.0
} else {
self.highlightedBackgroundNode.removeFromSupernode()
}
}
}
}
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) { override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4) self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
} }
@ -420,8 +478,7 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode {
} }
transition.updateFrame(node: self.avatarNode, frame: CGRect(origin: CGPoint(x: params.leftInset + self.revealOffset + editingOffset + 16.0, y: self.avatarNode.frame.minY), size: self.avatarNode.bounds.size)) transition.updateFrame(node: self.avatarNode, frame: CGRect(origin: CGPoint(x: params.leftInset + self.revealOffset + editingOffset + 16.0, y: self.avatarNode.frame.minY), size: self.avatarNode.bounds.size))
transition.updateFrame(node: self.labelNode, frame: CGRect(origin: CGPoint(x: self.revealOffset + params.width - params.rightInset - self.labelNode.bounds.size.width - 15.0, y: self.labelNode.frame.minY), size: self.labelNode.bounds.size)) transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: leftInset + self.revealOffset + editingOffset, y: self.titleNode.frame.minY), size: self.titleNode.bounds.size))
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: leftInset + self.revealOffset + editingOffset + 20.0, y: self.titleNode.frame.minY), size: self.titleNode.bounds.size))
transition.updateFrame(node: self.appNode, frame: CGRect(origin: CGPoint(x: leftInset + self.revealOffset + editingOffset, y: self.appNode.frame.minY), size: self.appNode.bounds.size)) transition.updateFrame(node: self.appNode, frame: CGRect(origin: CGPoint(x: leftInset + self.revealOffset + editingOffset, y: self.appNode.frame.minY), size: self.appNode.bounds.size))
transition.updateFrame(node: self.locationNode, frame: CGRect(origin: CGPoint(x: leftInset + self.revealOffset + editingOffset, y: self.locationNode.frame.minY), size: self.locationNode.bounds.size)) transition.updateFrame(node: self.locationNode, frame: CGRect(origin: CGPoint(x: leftInset + self.revealOffset + editingOffset, y: self.locationNode.frame.minY), size: self.locationNode.bounds.size))
} }

View File

@ -19,6 +19,9 @@ private final class RecentSessionsControllerArguments {
let removeSession: (Int64) -> Void let removeSession: (Int64) -> Void
let terminateOtherSessions: () -> Void let terminateOtherSessions: () -> Void
let openSession: (RecentAccountSession) -> Void
let openWebSession: (WebAuthorization) -> Void
let removeWebSession: (Int64) -> Void let removeWebSession: (Int64) -> Void
let terminateAllWebSessions: () -> Void let terminateAllWebSessions: () -> Void
@ -26,12 +29,15 @@ private final class RecentSessionsControllerArguments {
let openOtherAppsUrl: () -> Void let openOtherAppsUrl: () -> Void
init(context: AccountContext, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void, terminateOtherSessions: @escaping () -> Void, removeWebSession: @escaping (Int64) -> Void, terminateAllWebSessions: @escaping () -> Void, addDevice: @escaping () -> Void, openOtherAppsUrl: @escaping () -> Void) { init(context: AccountContext, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void, terminateOtherSessions: @escaping () -> Void, openSession: @escaping (RecentAccountSession) -> Void, openWebSession: @escaping (WebAuthorization) -> Void, removeWebSession: @escaping (Int64) -> Void, terminateAllWebSessions: @escaping () -> Void, addDevice: @escaping () -> Void, openOtherAppsUrl: @escaping () -> Void) {
self.context = context self.context = context
self.setSessionIdWithRevealedOptions = setSessionIdWithRevealedOptions self.setSessionIdWithRevealedOptions = setSessionIdWithRevealedOptions
self.removeSession = removeSession self.removeSession = removeSession
self.terminateOtherSessions = terminateOtherSessions self.terminateOtherSessions = terminateOtherSessions
self.openSession = openSession
self.openWebSession = openWebSession
self.removeWebSession = removeWebSession self.removeWebSession = removeWebSession
self.terminateAllWebSessions = terminateAllWebSessions self.terminateAllWebSessions = terminateAllWebSessions
@ -271,6 +277,8 @@ private enum RecentSessionsEntry: ItemListNodeEntry {
case let .currentSession(_, _, dateTimeFormat, session): case let .currentSession(_, _, dateTimeFormat, session):
return ItemListRecentSessionItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, session: session, enabled: true, editable: false, editing: false, revealed: false, sectionId: self.section, setSessionIdWithRevealedOptions: { _, _ in return ItemListRecentSessionItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, session: session, enabled: true, editable: false, editing: false, revealed: false, sectionId: self.section, setSessionIdWithRevealedOptions: { _, _ in
}, removeSession: { _ in }, removeSession: { _ in
}, action: {
}) })
case let .terminateOtherSessions(theme, text): case let .terminateOtherSessions(theme, text):
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.blockDestructiveIcon(theme), title: text, sectionId: self.section, height: .generic, color: .destructive, editing: false, action: { return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.blockDestructiveIcon(theme), title: text, sectionId: self.section, height: .generic, color: .destructive, editing: false, action: {
@ -298,6 +306,8 @@ private enum RecentSessionsEntry: ItemListNodeEntry {
arguments.setSessionIdWithRevealedOptions(previousId, id) arguments.setSessionIdWithRevealedOptions(previousId, id)
}, removeSession: { id in }, removeSession: { id in
arguments.removeSession(id) arguments.removeSession(id)
}, action: {
}) })
case let .pendingSessionsInfo(_, text): case let .pendingSessionsInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
@ -312,12 +322,16 @@ private enum RecentSessionsEntry: ItemListNodeEntry {
arguments.setSessionIdWithRevealedOptions(previousId, id) arguments.setSessionIdWithRevealedOptions(previousId, id)
}, removeSession: { id in }, removeSession: { id in
arguments.removeSession(id) arguments.removeSession(id)
}, action: {
arguments.openSession(session)
}) })
case let .website(_, _, _, dateTimeFormat, nameDisplayOrder, website, peer, enabled, editing, revealed): case let .website(_, _, _, dateTimeFormat, nameDisplayOrder, website, peer, enabled, editing, revealed):
return ItemListWebsiteItem(context: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, website: website, peer: peer, enabled: enabled, editing: editing, revealed: revealed, sectionId: self.section, setSessionIdWithRevealedOptions: { previousId, id in return ItemListWebsiteItem(context: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, website: website, peer: peer, enabled: enabled, editing: editing, revealed: revealed, sectionId: self.section, setSessionIdWithRevealedOptions: { previousId, id in
arguments.setSessionIdWithRevealedOptions(previousId, id) arguments.setSessionIdWithRevealedOptions(previousId, id)
}, removeSession: { id in }, removeSession: { id in
arguments.removeWebSession(id) arguments.removeWebSession(id)
}, action: {
arguments.openWebSession(website)
}) })
case let .devicesInfo(_, text): case let .devicesInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section, linkAction: { action in return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section, linkAction: { action in
@ -588,6 +602,16 @@ public func recentSessionsController(context: AccountContext, activeSessionsCont
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
]) ])
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}, openSession: { session in
let controller = RecentSessionScreen(context: context, subject: .session(session), remove: {
})
presentControllerImpl?(controller, nil)
}, openWebSession: { session in
let controller = RecentSessionScreen(context: context, subject: .website(session), remove: {
})
presentControllerImpl?(controller, nil)
}, removeWebSession: { sessionId in }, removeWebSession: { sessionId in
updateState { updateState {
return $0.withUpdatedRemovingSessionId(sessionId) return $0.withUpdatedRemovingSessionId(sessionId)

View File

@ -0,0 +1,506 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
import Postbox
import TelegramCore
import SwiftSignalKit
import AccountContext
import SolidRoundedButtonNode
import TelegramPresentationData
import TelegramUIPreferences
import TelegramStringFormatting
import PresentationDataUtils
import AnimationUI
import MergeLists
import MediaResources
import StickerResources
import AnimatedStickerNode
import TelegramAnimatedStickerNode
private func closeButtonImage(theme: PresentationTheme) -> UIImage? {
return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor(rgb: 0x808084, alpha: 0.1).cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
context.setLineWidth(2.0)
context.setLineCap(.round)
context.setStrokeColor(theme.actionSheet.inputClearButtonColor.cgColor)
context.move(to: CGPoint(x: 10.0, y: 10.0))
context.addLine(to: CGPoint(x: 20.0, y: 20.0))
context.strokePath()
context.move(to: CGPoint(x: 20.0, y: 10.0))
context.addLine(to: CGPoint(x: 10.0, y: 20.0))
context.strokePath()
})
}
final class RecentSessionScreen: ViewController {
enum Subject {
case session(RecentAccountSession)
case website(WebAuthorization)
}
private var controllerNode: RecentSessionScreenNode {
return self.displayNode as! RecentSessionScreenNode
}
private var animatedIn = false
private let context: AccountContext
private let subject: RecentSessionScreen.Subject
private let remove: () -> Void
private var presentationData: PresentationData
private var presentationDataDisposable: Disposable?
var dismissed: (() -> Void)?
var passthroughHitTestImpl: ((CGPoint) -> UIView?)? {
didSet {
if self.isNodeLoaded {
self.controllerNode.passthroughHitTestImpl = self.passthroughHitTestImpl
}
}
}
init(context: AccountContext, subject: RecentSessionScreen.Subject, remove: @escaping () -> Void) {
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.subject = subject
self.remove = remove
super.init(navigationBarPresentationData: nil)
self.statusBar.statusBarStyle = .Ignore
self.blocksBackgroundWhenInOverlay = true
self.presentationDataDisposable = (context.sharedContext.presentationData
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
if let strongSelf = self {
strongSelf.presentationData = presentationData
strongSelf.controllerNode.updatePresentationData(presentationData)
}
})
self.statusBar.statusBarStyle = .Ignore
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.presentationDataDisposable?.dispose()
}
override public func loadDisplayNode() {
self.displayNode = RecentSessionScreenNode(context: self.context, presentationData: self.presentationData, controller: self, subject: self.subject)
self.controllerNode.passthroughHitTestImpl = self.passthroughHitTestImpl
self.controllerNode.present = { [weak self] c in
self?.present(c, in: .current)
}
self.controllerNode.dismiss = { [weak self] in
self?.presentingViewController?.dismiss(animated: false, completion: nil)
}
}
override public func loadView() {
super.loadView()
self.view.disablesInteractiveTransitionGestureRecognizer = true
}
override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if !self.animatedIn {
self.animatedIn = true
self.controllerNode.animateIn()
}
}
override public func dismiss(completion: (() -> Void)? = nil) {
self.controllerNode.animateOut(completion: completion)
self.dismissed?()
}
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
}
}
private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDelegate {
private let context: AccountContext
private var presentationData: PresentationData
private weak var controller: RecentSessionScreen?
private let subject: RecentSessionScreen.Subject
private let dimNode: ASDisplayNode
private let wrappingScrollNode: ASScrollNode
private let contentContainerNode: ASDisplayNode
private let topContentContainerNode: SparseNode
private let backgroundNode: ASDisplayNode
private let contentBackgroundNode: ASDisplayNode
private let titleNode: ImmediateTextNode
private let textNode: ImmediateTextNode
private let fieldBackgroundNode: ASDisplayNode
private let deviceTitleNode: ImmediateTextNode
private let deviceValueNode: ImmediateTextNode
private let firstSeparatorNode: ASDisplayNode
private let locationTitleNode: ImmediateTextNode
private let locationValueNode: ImmediateTextNode
private let secondSeparatorNode: ASDisplayNode
private let ipTitleNode: ImmediateTextNode
private let ipValueNode: ImmediateTextNode
private let cancelButton: HighlightableButtonNode
private let terminateButton: SolidRoundedButtonNode
private var containerLayout: (ContainerViewLayout, CGFloat)?
var present: ((ViewController) -> Void)?
var remove: (() -> Void)?
var dismiss: (() -> Void)?
init(context: AccountContext, presentationData: PresentationData, controller: RecentSessionScreen, subject: RecentSessionScreen.Subject) {
self.context = context
self.controller = controller
self.presentationData = presentationData
self.subject = subject
self.wrappingScrollNode = ASScrollNode()
self.wrappingScrollNode.view.alwaysBounceVertical = true
self.wrappingScrollNode.view.delaysContentTouches = false
self.wrappingScrollNode.view.canCancelContentTouches = true
self.dimNode = ASDisplayNode()
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
self.contentContainerNode = ASDisplayNode()
self.contentContainerNode.isOpaque = false
self.topContentContainerNode = SparseNode()
self.topContentContainerNode.isOpaque = false
self.backgroundNode = ASDisplayNode()
self.backgroundNode.clipsToBounds = true
self.backgroundNode.cornerRadius = 16.0
let backgroundColor = self.presentationData.theme.list.blocksBackgroundColor
let textColor = self.presentationData.theme.list.itemPrimaryTextColor
let accentColor = self.presentationData.theme.list.itemAccentColor
let secondaryTextColor = self.presentationData.theme.list.itemSecondaryTextColor
self.contentBackgroundNode = ASDisplayNode()
self.contentBackgroundNode.backgroundColor = backgroundColor
self.titleNode = ImmediateTextNode()
self.textNode = ImmediateTextNode()
self.fieldBackgroundNode = ASDisplayNode()
self.fieldBackgroundNode.clipsToBounds = true
self.fieldBackgroundNode.cornerRadius = 11
self.fieldBackgroundNode.backgroundColor = self.presentationData.theme.list.itemBlocksBackgroundColor
self.deviceTitleNode = ImmediateTextNode()
self.deviceValueNode = ImmediateTextNode()
self.locationTitleNode = ImmediateTextNode()
self.locationValueNode = ImmediateTextNode()
self.ipTitleNode = ImmediateTextNode()
self.ipValueNode = ImmediateTextNode()
self.cancelButton = HighlightableButtonNode()
self.cancelButton.setImage(closeButtonImage(theme: self.presentationData.theme), for: .normal)
self.terminateButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(backgroundColor: self.presentationData.theme.list.itemBlocksBackgroundColor, foregroundColor: self.presentationData.theme.list.itemDestructiveColor), font: .regular, height: 44.0, cornerRadius: 11.0, gloss: false)
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
let title: String
let subtitle: String
let subtitleActive: Bool
let device: String
let location: String
let ip: String
switch subject {
case let .session(session):
self.terminateButton.title = self.presentationData.strings.AuthSessions_View_TerminateSession
title = "\(session.appName) \(session.appVersion)"
if session.isCurrent {
subtitle = presentationData.strings.Presence_online
subtitleActive = true
} else {
subtitle = stringForRelativeActivityTimestamp(strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, relativeTimestamp: session.activityDate, relativeTo: timestamp)
subtitleActive = false
}
var deviceString = ""
if !session.deviceModel.isEmpty {
deviceString = session.deviceModel
}
if !session.platform.isEmpty {
if !deviceString.isEmpty {
deviceString += ", "
}
deviceString += session.platform
}
if !session.systemVersion.isEmpty {
if !deviceString.isEmpty {
deviceString += ", "
}
deviceString += session.systemVersion
}
device = deviceString
location = session.country
ip = session.ip
case let .website(website):
self.terminateButton.title = self.presentationData.strings.AuthSessions_View_Logout
title = website.domain
subtitle = stringForRelativeActivityTimestamp(strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, relativeTimestamp: website.dateActive, relativeTo: timestamp)
subtitleActive = false
var deviceString = ""
if !website.domain.isEmpty {
deviceString = website.domain
}
if !website.browser.isEmpty {
if !deviceString.isEmpty {
deviceString += ", "
}
deviceString += website.browser
}
if !website.platform.isEmpty {
if !deviceString.isEmpty {
deviceString += ", "
}
deviceString += website.platform
}
device = deviceString
location = website.region
ip = website.ip
}
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.regular(30.0), textColor: textColor)
self.textNode.attributedText = NSAttributedString(string: subtitle, font: Font.regular(17.0), textColor: subtitleActive ? accentColor : secondaryTextColor)
self.deviceTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_Device, font: Font.regular(17.0), textColor: textColor)
self.deviceValueNode.attributedText = NSAttributedString(string: device, font: Font.regular(17.0), textColor: secondaryTextColor)
self.firstSeparatorNode = ASDisplayNode()
self.locationTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_Location, font: Font.regular(17.0), textColor: textColor)
self.locationValueNode.attributedText = NSAttributedString(string: location, font: Font.regular(17.0), textColor: secondaryTextColor)
self.secondSeparatorNode = ASDisplayNode()
self.ipTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_IP, font: Font.regular(17.0), textColor: textColor)
self.ipValueNode.attributedText = NSAttributedString(string: ip, font: Font.regular(17.0), textColor: secondaryTextColor)
super.init()
self.backgroundColor = nil
self.isOpaque = false
self.addSubnode(self.dimNode)
self.wrappingScrollNode.view.delegate = self
self.addSubnode(self.wrappingScrollNode)
self.wrappingScrollNode.addSubnode(self.backgroundNode)
self.wrappingScrollNode.addSubnode(self.contentContainerNode)
self.wrappingScrollNode.addSubnode(self.topContentContainerNode)
self.backgroundNode.addSubnode(self.contentBackgroundNode)
self.contentContainerNode.addSubnode(self.titleNode)
self.contentContainerNode.addSubnode(self.textNode)
self.contentContainerNode.addSubnode(self.fieldBackgroundNode)
self.contentContainerNode.addSubnode(self.deviceTitleNode)
self.contentContainerNode.addSubnode(self.deviceValueNode)
self.contentContainerNode.addSubnode(self.locationTitleNode)
self.contentContainerNode.addSubnode(self.locationValueNode)
self.contentContainerNode.addSubnode(self.ipTitleNode)
self.contentContainerNode.addSubnode(self.ipValueNode)
self.contentContainerNode.addSubnode(self.terminateButton)
self.topContentContainerNode.addSubnode(self.cancelButton)
self.cancelButton.addTarget(self, action: #selector(self.cancelButtonPressed), forControlEvents: .touchUpInside)
self.terminateButton.pressed = { [weak self] in
if let strongSelf = self {
strongSelf.terminateButton.isUserInteractionEnabled = false
strongSelf.remove?()
}
}
}
func updatePresentationData(_ presentationData: PresentationData) {
guard !self.animatedOut else {
return
}
let previousTheme = self.presentationData.theme
self.presentationData = presentationData
self.titleNode.attributedText = NSAttributedString(string: self.titleNode.attributedText?.string ?? "", font: Font.regular(30.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
self.textNode.attributedText = NSAttributedString(string: self.textNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemSecondaryTextColor)
self.fieldBackgroundNode.backgroundColor = self.presentationData.theme.list.itemBlocksBackgroundColor
self.deviceTitleNode.attributedText = NSAttributedString(string: self.deviceTitleNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
self.locationTitleNode.attributedText = NSAttributedString(string: self.locationTitleNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
self.ipTitleNode.attributedText = NSAttributedString(string: self.ipTitleNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
self.deviceValueNode.attributedText = NSAttributedString(string: self.deviceValueNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemSecondaryTextColor)
self.locationValueNode.attributedText = NSAttributedString(string: self.locationValueNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemSecondaryTextColor)
self.ipValueNode.attributedText = NSAttributedString(string: self.ipValueNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemSecondaryTextColor)
if previousTheme !== presentationData.theme, let (layout, navigationBarHeight) = self.containerLayout {
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
}
self.cancelButton.setImage(closeButtonImage(theme: self.presentationData.theme), for: .normal)
self.terminateButton.updateTheme(SolidRoundedButtonTheme(backgroundColor: self.presentationData.theme.list.itemBlocksBackgroundColor, foregroundColor: self.presentationData.theme.list.itemDestructiveColor))
}
override func didLoad() {
super.didLoad()
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
self.wrappingScrollNode.view.contentInsetAdjustmentBehavior = .never
}
self.dimNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimTapGesture)))
}
@objc func cancelButtonPressed() {
self.animateOut()
}
@objc func dimTapGesture() {
self.cancelButtonPressed()
}
private var animatedOut = false
func animateIn() {
self.dimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
let offset = self.bounds.size.height - self.contentBackgroundNode.frame.minY
let dimPosition = self.dimNode.layer.position
let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring)
let targetBounds = self.bounds
self.bounds = self.bounds.offsetBy(dx: 0.0, dy: -offset)
self.dimNode.position = CGPoint(x: dimPosition.x, y: dimPosition.y - offset)
transition.animateView({
self.bounds = targetBounds
self.dimNode.position = dimPosition
})
}
func animateOut(completion: (() -> Void)? = nil) {
self.animatedOut = true
var dimCompleted = false
var offsetCompleted = false
let internalCompletion: () -> Void = { [weak self] in
if let strongSelf = self, dimCompleted && offsetCompleted {
strongSelf.dismiss?()
}
completion?()
}
self.dimNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
dimCompleted = true
internalCompletion()
})
let offset = self.bounds.size.height - self.contentBackgroundNode.frame.minY
self.wrappingScrollNode.layer.animateBoundsOriginYAdditive(from: 0.0, to: -offset, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, completion: { _ in
offsetCompleted = true
internalCompletion()
})
}
var passthroughHitTestImpl: ((CGPoint) -> UIView?)?
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if self.bounds.contains(point) {
if !self.contentBackgroundNode.bounds.contains(self.convert(point, to: self.contentBackgroundNode)) {
return self.dimNode.view
}
}
return super.hitTest(point, with: event)
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
let contentOffset = scrollView.contentOffset
let additionalTopHeight = max(0.0, -contentOffset.y)
if additionalTopHeight >= 30.0 {
self.cancelButtonPressed()
}
}
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
self.containerLayout = (layout, navigationBarHeight)
var insets = layout.insets(options: [.statusBar, .input])
let cleanInsets = layout.insets(options: [.statusBar])
insets.top = max(10.0, insets.top)
let bottomInset: CGFloat = 10.0 + cleanInsets.bottom
let titleHeight: CGFloat = 54.0
let contentHeight = titleHeight + bottomInset + 188.0
let width = horizontalContainerFillingSizeForLayout(layout: layout, sideInset: layout.safeInsets.left)
let sideInset = floor((layout.size.width - width) / 2.0)
let contentContainerFrame = CGRect(origin: CGPoint(x: sideInset, y: layout.size.height - contentHeight), size: CGSize(width: width, height: contentHeight))
let contentFrame = contentContainerFrame
var backgroundFrame = CGRect(origin: CGPoint(x: contentFrame.minX, y: contentFrame.minY), size: CGSize(width: contentFrame.width, height: contentFrame.height + 2000.0))
if backgroundFrame.minY < contentFrame.minY {
backgroundFrame.origin.y = contentFrame.minY
}
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
transition.updateFrame(node: self.contentBackgroundNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
transition.updateFrame(node: self.wrappingScrollNode, frame: CGRect(origin: CGPoint(), size: layout.size))
transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(), size: layout.size))
let titleSize = self.titleNode.updateLayout(CGSize(width: width - 90.0, height: titleHeight))
let titleFrame = CGRect(origin: CGPoint(x: floor((contentFrame.width - titleSize.width) / 2.0), y: 120.0), size: titleSize)
transition.updateFrame(node: self.titleNode, frame: titleFrame)
let textSize = self.textNode.updateLayout(CGSize(width: width - 90.0, height: titleHeight))
let textFrame = CGRect(origin: CGPoint(x: floor((contentFrame.width - textSize.width) / 2.0), y: titleFrame.maxY), size: textSize)
transition.updateFrame(node: self.textNode, frame: textFrame)
let cancelSize = CGSize(width: 44.0, height: 44.0)
let cancelFrame = CGRect(origin: CGPoint(x: contentFrame.width - cancelSize.width - 3.0, y: 6.0), size: cancelSize)
transition.updateFrame(node: self.cancelButton, frame: cancelFrame)
let buttonInset: CGFloat = 16.0
let doneButtonHeight = self.terminateButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition)
transition.updateFrame(node: self.terminateButton, frame: CGRect(x: buttonInset, y: contentHeight - doneButtonHeight - insets.bottom - 6.0, width: contentFrame.width, height: doneButtonHeight))
transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame)
transition.updateFrame(node: self.topContentContainerNode, frame: contentContainerFrame)
var listInsets = UIEdgeInsets()
listInsets.top += layout.safeInsets.left + 12.0
listInsets.bottom += layout.safeInsets.right + 12.0
}
}

View File

@ -1012,7 +1012,9 @@ public func themePickerController(context: AccountContext, focusOnItemTag: Theme
colorItemNode?.prepareCrossfadeTransition() colorItemNode?.prepareCrossfadeTransition()
} }
let crossfadeController = ThemeSettingsCrossfadeController(view: view, topOffset: topOffset, bottomOffset: bottomOffset, leftOffset: leftOffset) let sectionInset = max(16.0, floor((controller.displayNode.frame.width - 674.0) / 2.0))
let crossfadeController = ThemeSettingsCrossfadeController(view: view, topOffset: topOffset, bottomOffset: bottomOffset, leftOffset: leftOffset, sideInset: sectionInset)
crossfadeController.didAppear = { [weak themeItemNode, weak colorItemNode] in crossfadeController.didAppear = { [weak themeItemNode, weak colorItemNode] in
if view != nil { if view != nil {
themeItemNode?.animateCrossfadeTransition() themeItemNode?.animateCrossfadeTransition()

View File

@ -446,7 +446,6 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
var selectThemeImpl: ((PresentationThemeReference) -> Void)? var selectThemeImpl: ((PresentationThemeReference) -> Void)?
var selectAccentColorImpl: ((PresentationThemeAccentColor?) -> Void)? var selectAccentColorImpl: ((PresentationThemeAccentColor?) -> Void)?
var openAccentColorPickerImpl: ((PresentationThemeReference, Bool) -> Void)? var openAccentColorPickerImpl: ((PresentationThemeReference, Bool) -> Void)?
var moreImpl: (() -> Void)?
let _ = telegramWallpapers(postbox: context.account.postbox, network: context.account.network).start() let _ = telegramWallpapers(postbox: context.account.postbox, network: context.account.network).start()
@ -973,10 +972,6 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
themeReference = settings.theme themeReference = settings.theme
} }
let rightNavigationButton = ItemListNavigationButton(content: .icon(.add), style: .regular, enabled: true, action: {
moreImpl?()
})
var defaultThemes: [PresentationThemeReference] = [] var defaultThemes: [PresentationThemeReference] = []
if presentationData.autoNightModeTriggered { if presentationData.autoNightModeTriggered {
defaultThemes.append(contentsOf: [.builtin(.nightAccent), .builtin(.night)]) defaultThemes.append(contentsOf: [.builtin(.nightAccent), .builtin(.night)])
@ -1000,7 +995,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
var chatThemes = cloudThemes.filter { $0.emoticon != nil } var chatThemes = cloudThemes.filter { $0.emoticon != nil }
chatThemes.insert(.builtin(.dayClassic), at: 0) chatThemes.insert(.builtin(.dayClassic), at: 0)
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.Appearance_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.Appearance_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: themeSettingsControllerEntries(presentationData: presentationData, presentationThemeSettings: settings, themeReference: themeReference, availableThemes: availableThemes, availableAppIcons: availableAppIcons, currentAppIconName: currentAppIconName, chatThemes: chatThemes, animatedEmojiStickers: animatedEmojiStickers), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: themeSettingsControllerEntries(presentationData: presentationData, presentationThemeSettings: settings, themeReference: themeReference, availableThemes: availableThemes, availableAppIcons: availableAppIcons, currentAppIconName: currentAppIconName, chatThemes: chatThemes, animatedEmojiStickers: animatedEmojiStickers), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
@ -1072,7 +1067,9 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
themeItemNode?.prepareCrossfadeTransition() themeItemNode?.prepareCrossfadeTransition()
} }
let crossfadeController = ThemeSettingsCrossfadeController(view: view, topOffset: topOffset, bottomOffset: bottomOffset, leftOffset: leftOffset) let sectionInset = max(16.0, floor((controller.displayNode.frame.width - 674.0) / 2.0))
let crossfadeController = ThemeSettingsCrossfadeController(view: view, topOffset: topOffset, bottomOffset: bottomOffset, leftOffset: leftOffset, sideInset: sectionInset)
crossfadeController.didAppear = { [weak themeItemNode] in crossfadeController.didAppear = { [weak themeItemNode] in
if view != nil { if view != nil {
themeItemNode?.animateCrossfadeTransition() themeItemNode?.animateCrossfadeTransition()
@ -1243,42 +1240,6 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
presentCrossfadeControllerImpl?(true) presentCrossfadeControllerImpl?(true)
}) })
} }
moreImpl = {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let actionSheet = ActionSheetController(presentationData: presentationData)
var items: [ActionSheetItem] = []
items.append(ActionSheetButtonItem(title: presentationData.strings.Appearance_CreateTheme, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
let _ = (context.sharedContext.accountManager.transaction { transaction -> PresentationThemeReference in
let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings)?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings
let themeReference: PresentationThemeReference
let autoNightModeTriggered = context.sharedContext.currentPresentationData.with { $0 }.autoNightModeTriggered
if autoNightModeTriggered {
themeReference = settings.automaticThemeSwitchSetting.theme
} else {
themeReference = settings.theme
}
return themeReference
}
|> deliverOnMainQueue).start(next: { themeReference in
let controller = editThemeController(context: context, mode: .create(nil, nil), navigateToChat: { peerId in
if let navigationController = getNavigationControllerImpl?() {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
}
})
pushControllerImpl?(controller)
})
}))
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
})
])])
presentControllerImpl?(actionSheet, nil)
}
return controller return controller
} }
@ -1289,9 +1250,12 @@ public final class ThemeSettingsCrossfadeController: ViewController {
private var bottomSnapshotView: UIView? private var bottomSnapshotView: UIView?
private var sideSnapshotView: UIView? private var sideSnapshotView: UIView?
private var leftSnapshotView: UIView?
private var rightSnapshotView: UIView?
var didAppear: (() -> Void)? var didAppear: (() -> Void)?
public init(view: UIView? = nil, topOffset: CGFloat? = nil, bottomOffset: CGFloat? = nil, leftOffset: CGFloat? = nil) { public init(view: UIView? = nil, topOffset: CGFloat? = nil, bottomOffset: CGFloat? = nil, leftOffset: CGFloat? = nil, sideInset: CGFloat = 0.0) {
if let view = view { if let view = view {
if var leftOffset = leftOffset { if var leftOffset = leftOffset {
leftOffset += UIScreenPixel leftOffset += UIScreenPixel
@ -1322,6 +1286,58 @@ public final class ThemeSettingsCrossfadeController: ViewController {
} }
} }
if sideInset > 0.0 {
if let view = view.snapshotView(afterScreenUpdates: false) {
let clipView = UIView()
clipView.clipsToBounds = true
clipView.addSubview(view)
view.clipsToBounds = true
view.contentMode = .topLeft
if let topOffset = topOffset, let bottomOffset = bottomOffset {
var frame = view.frame
frame.origin.y = topOffset
frame.size.width = sideInset
frame.size.height = bottomOffset - topOffset
clipView.frame = frame
frame = view.frame
frame.origin.y = -topOffset
frame.size.width = sideInset
frame.size.height = bottomOffset
view.frame = frame
}
self.leftSnapshotView = clipView
}
if let view = view.snapshotView(afterScreenUpdates: false) {
let clipView = UIView()
clipView.clipsToBounds = true
clipView.addSubview(view)
view.clipsToBounds = true
view.contentMode = .topRight
if let topOffset = topOffset, let bottomOffset = bottomOffset {
var frame = view.frame
frame.origin.x = frame.width - sideInset
frame.origin.y = topOffset
frame.size.width = sideInset
frame.size.height = bottomOffset - topOffset
clipView.frame = frame
frame = view.frame
frame.origin.y = -topOffset
frame.size.width = sideInset
frame.size.height = bottomOffset
view.frame = frame
}
self.rightSnapshotView = clipView
}
}
if let view = view.snapshotView(afterScreenUpdates: false) { if let view = view.snapshotView(afterScreenUpdates: false) {
view.clipsToBounds = true view.clipsToBounds = true
view.contentMode = .top view.contentMode = .top
@ -1373,7 +1389,13 @@ public final class ThemeSettingsCrossfadeController: ViewController {
} }
if let sideSnapshotView = self.sideSnapshotView { if let sideSnapshotView = self.sideSnapshotView {
self.displayNode.view.addSubview(sideSnapshotView) self.displayNode.view.addSubview(sideSnapshotView)
} }
if let leftSnapshotView = self.leftSnapshotView {
self.displayNode.view.addSubview(leftSnapshotView)
}
if let rightSnapshotView = self.rightSnapshotView {
self.displayNode.view.addSubview(rightSnapshotView)
}
} }
override public func viewDidAppear(_ animated: Bool) { override public func viewDidAppear(_ animated: Bool) {

View File

@ -11,8 +11,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) } dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) } dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) } dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) }
dict[-2097579871] = { return Api.ChatFull.parse_chatFull($0) } dict[1185349556] = { return Api.ChatFull.parse_chatFull($0) }
dict[1084166537] = { return Api.ChatFull.parse_channelFull($0) } dict[1506802019] = { return Api.ChatFull.parse_channelFull($0) }
dict[-591909213] = { return Api.PollResults.parse_pollResults($0) } dict[-591909213] = { return Api.PollResults.parse_pollResults($0) }
dict[-1070776313] = { return Api.ChatParticipant.parse_chatParticipant($0) } dict[-1070776313] = { return Api.ChatParticipant.parse_chatParticipant($0) }
dict[-462696732] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) } dict[-462696732] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) }
@ -286,7 +286,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-997782967] = { return Api.Update.parse_updateBotStopped($0) } dict[-997782967] = { return Api.Update.parse_updateBotStopped($0) }
dict[192428418] = { return Api.Update.parse_updateGroupCallConnection($0) } dict[192428418] = { return Api.Update.parse_updateGroupCallConnection($0) }
dict[1299263278] = { return Api.Update.parse_updateBotCommands($0) } dict[1299263278] = { return Api.Update.parse_updateBotCommands($0) }
dict[-82532135] = { return Api.Update.parse_updatePendingJoinRequests($0) } dict[1885586395] = { return Api.Update.parse_updatePendingJoinRequests($0) }
dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) } dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) }
dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) } dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) }
dict[-592373577] = { return Api.GroupCallParticipantVideoSourceGroup.parse_groupCallParticipantVideoSourceGroup($0) } dict[-592373577] = { return Api.GroupCallParticipantVideoSourceGroup.parse_groupCallParticipantVideoSourceGroup($0) }
@ -336,6 +336,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-842824308] = { return Api.account.WallPapers.parse_wallPapers($0) } dict[-842824308] = { return Api.account.WallPapers.parse_wallPapers($0) }
dict[1012306921] = { return Api.InputTheme.parse_inputTheme($0) } dict[1012306921] = { return Api.InputTheme.parse_inputTheme($0) }
dict[-175567375] = { return Api.InputTheme.parse_inputThemeSlug($0) } dict[-175567375] = { return Api.InputTheme.parse_inputThemeSlug($0) }
dict[2014782332] = { return Api.messages.SearchResultsRawMessages.parse_searchResultsRawMessages($0) }
dict[-2032041631] = { return Api.Poll.parse_poll($0) } dict[-2032041631] = { return Api.Poll.parse_poll($0) }
dict[-1195615476] = { return Api.InputNotifyPeer.parse_inputNotifyPeer($0) } dict[-1195615476] = { return Api.InputNotifyPeer.parse_inputNotifyPeer($0) }
dict[423314455] = { return Api.InputNotifyPeer.parse_inputNotifyUsers($0) } dict[423314455] = { return Api.InputNotifyPeer.parse_inputNotifyUsers($0) }
@ -785,7 +786,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1673717362] = { return Api.InputPeerNotifySettings.parse_inputPeerNotifySettings($0) } dict[-1673717362] = { return Api.InputPeerNotifySettings.parse_inputPeerNotifySettings($0) }
dict[-1634752813] = { return Api.messages.FavedStickers.parse_favedStickersNotModified($0) } dict[-1634752813] = { return Api.messages.FavedStickers.parse_favedStickersNotModified($0) }
dict[750063767] = { return Api.messages.FavedStickers.parse_favedStickers($0) } dict[750063767] = { return Api.messages.FavedStickers.parse_favedStickers($0) }
dict[-1283792928] = { return Api.ExportedChatInvite.parse_chatInviteExported($0) } dict[179611673] = { return Api.ExportedChatInvite.parse_chatInviteExported($0) }
dict[-1389486888] = { return Api.account.AuthorizationForm.parse_authorizationForm($0) } dict[-1389486888] = { return Api.account.AuthorizationForm.parse_authorizationForm($0) }
dict[-1392388579] = { return Api.Authorization.parse_authorization($0) } dict[-1392388579] = { return Api.Authorization.parse_authorization($0) }
dict[-1361650766] = { return Api.MaskCoords.parse_maskCoords($0) } dict[-1361650766] = { return Api.MaskCoords.parse_maskCoords($0) }
@ -836,6 +837,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1781355374] = { return Api.MessageAction.parse_messageActionChannelCreate($0) } dict[-1781355374] = { return Api.MessageAction.parse_messageActionChannelCreate($0) }
dict[-519864430] = { return Api.MessageAction.parse_messageActionChatMigrateTo($0) } dict[-519864430] = { return Api.MessageAction.parse_messageActionChatMigrateTo($0) }
dict[-365344535] = { return Api.MessageAction.parse_messageActionChannelMigrateFrom($0) } dict[-365344535] = { return Api.MessageAction.parse_messageActionChannelMigrateFrom($0) }
dict[-339958837] = { return Api.MessageAction.parse_messageActionChatJoinedByRequest($0) }
dict[-1799538451] = { return Api.MessageAction.parse_messageActionPinMessage($0) } dict[-1799538451] = { return Api.MessageAction.parse_messageActionPinMessage($0) }
dict[-1615153660] = { return Api.MessageAction.parse_messageActionHistoryClear($0) } dict[-1615153660] = { return Api.MessageAction.parse_messageActionHistoryClear($0) }
dict[-1834538890] = { return Api.MessageAction.parse_messageActionGameScore($0) } dict[-1834538890] = { return Api.MessageAction.parse_messageActionGameScore($0) }
@ -854,7 +856,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1441072131] = { return Api.MessageAction.parse_messageActionSetMessagesTTL($0) } dict[-1441072131] = { return Api.MessageAction.parse_messageActionSetMessagesTTL($0) }
dict[-1281329567] = { return Api.MessageAction.parse_messageActionGroupCallScheduled($0) } dict[-1281329567] = { return Api.MessageAction.parse_messageActionGroupCallScheduled($0) }
dict[-1434950843] = { return Api.MessageAction.parse_messageActionSetChatTheme($0) } dict[-1434950843] = { return Api.MessageAction.parse_messageActionSetChatTheme($0) }
dict[-339958837] = { return Api.MessageAction.parse_messageActionChatJoinedByRequest($0) }
dict[1399245077] = { return Api.PhoneCall.parse_phoneCallEmpty($0) } dict[1399245077] = { return Api.PhoneCall.parse_phoneCallEmpty($0) }
dict[-987599081] = { return Api.PhoneCall.parse_phoneCallWaiting($0) } dict[-987599081] = { return Api.PhoneCall.parse_phoneCallWaiting($0) }
dict[347139340] = { return Api.PhoneCall.parse_phoneCallRequested($0) } dict[347139340] = { return Api.PhoneCall.parse_phoneCallRequested($0) }
@ -1150,6 +1151,8 @@ public struct Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.InputTheme: case let _1 as Api.InputTheme:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.messages.SearchResultsRawMessages:
_1.serialize(buffer, boxed)
case let _1 as Api.Poll: case let _1 as Api.Poll:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.InputNotifyPeer: case let _1 as Api.InputNotifyPeer:

View File

@ -477,6 +477,56 @@ public struct messages {
} }
} }
}
public enum SearchResultsRawMessages: TypeConstructorDescription {
case searchResultsRawMessages(msgIds: [Int32], msgDates: [Int32])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .searchResultsRawMessages(let msgIds, let msgDates):
if boxed {
buffer.appendInt32(2014782332)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(msgIds.count))
for item in msgIds {
serializeInt32(item, buffer: buffer, boxed: false)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(msgDates.count))
for item in msgDates {
serializeInt32(item, buffer: buffer, boxed: false)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .searchResultsRawMessages(let msgIds, let msgDates):
return ("searchResultsRawMessages", [("msgIds", msgIds), ("msgDates", msgDates)])
}
}
public static func parse_searchResultsRawMessages(_ reader: BufferReader) -> SearchResultsRawMessages? {
var _1: [Int32]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self)
}
var _2: [Int32]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.messages.SearchResultsRawMessages.searchResultsRawMessages(msgIds: _1!, msgDates: _2!)
}
else {
return nil
}
}
} }
public enum ExportedChatInvites: TypeConstructorDescription { public enum ExportedChatInvites: TypeConstructorDescription {
case exportedChatInvites(count: Int32, invites: [Api.ExportedChatInvite], users: [Api.User]) case exportedChatInvites(count: Int32, invites: [Api.ExportedChatInvite], users: [Api.User])

View File

@ -160,14 +160,14 @@ public extension Api {
} }
public enum ChatFull: TypeConstructorDescription { public enum ChatFull: TypeConstructorDescription {
case chatFull(flags: Int32, id: Int64, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?, call: Api.InputGroupCall?, ttlPeriod: Int32?, groupcallDefaultJoinAs: Api.Peer?, themeEmoticon: String?, requestsPending: Int32?) case chatFull(flags: Int32, id: Int64, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?, call: Api.InputGroupCall?, ttlPeriod: Int32?, groupcallDefaultJoinAs: Api.Peer?, themeEmoticon: String?, requestsPending: Int32?, recentRequesters: [Int64]?)
case channelFull(flags: Int32, id: Int64, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo], migratedFromChatId: Int64?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int64?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32, call: Api.InputGroupCall?, ttlPeriod: Int32?, pendingSuggestions: [String]?, groupcallDefaultJoinAs: Api.Peer?, themeEmoticon: String?, requestsPending: Int32?) case channelFull(flags: Int32, id: Int64, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo], migratedFromChatId: Int64?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int64?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32, call: Api.InputGroupCall?, ttlPeriod: Int32?, pendingSuggestions: [String]?, groupcallDefaultJoinAs: Api.Peer?, themeEmoticon: String?, requestsPending: Int32?, recentRequesters: [Int64]?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call, let ttlPeriod, let groupcallDefaultJoinAs, let themeEmoticon, let requestsPending): case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call, let ttlPeriod, let groupcallDefaultJoinAs, let themeEmoticon, let requestsPending, let recentRequesters):
if boxed { if boxed {
buffer.appendInt32(-2097579871) buffer.appendInt32(1185349556)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(id, buffer: buffer, boxed: false) serializeInt64(id, buffer: buffer, boxed: false)
@ -188,10 +188,15 @@ public extension Api {
if Int(flags) & Int(1 << 15) != 0 {groupcallDefaultJoinAs!.serialize(buffer, true)} if Int(flags) & Int(1 << 15) != 0 {groupcallDefaultJoinAs!.serialize(buffer, true)}
if Int(flags) & Int(1 << 16) != 0 {serializeString(themeEmoticon!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 16) != 0 {serializeString(themeEmoticon!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 17) != 0 {serializeInt32(requestsPending!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 17) != 0 {serializeInt32(requestsPending!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 17) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(recentRequesters!.count))
for item in recentRequesters! {
serializeInt64(item, buffer: buffer, boxed: false)
}}
break break
case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts, let call, let ttlPeriod, let pendingSuggestions, let groupcallDefaultJoinAs, let themeEmoticon, let requestsPending): case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts, let call, let ttlPeriod, let pendingSuggestions, let groupcallDefaultJoinAs, let themeEmoticon, let requestsPending, let recentRequesters):
if boxed { if boxed {
buffer.appendInt32(1084166537) buffer.appendInt32(1506802019)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(id, buffer: buffer, boxed: false) serializeInt64(id, buffer: buffer, boxed: false)
@ -234,16 +239,21 @@ public extension Api {
if Int(flags) & Int(1 << 26) != 0 {groupcallDefaultJoinAs!.serialize(buffer, true)} if Int(flags) & Int(1 << 26) != 0 {groupcallDefaultJoinAs!.serialize(buffer, true)}
if Int(flags) & Int(1 << 27) != 0 {serializeString(themeEmoticon!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 27) != 0 {serializeString(themeEmoticon!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 28) != 0 {serializeInt32(requestsPending!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 28) != 0 {serializeInt32(requestsPending!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 28) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(recentRequesters!.count))
for item in recentRequesters! {
serializeInt64(item, buffer: buffer, boxed: false)
}}
break break
} }
} }
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call, let ttlPeriod, let groupcallDefaultJoinAs, let themeEmoticon, let requestsPending): case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call, let ttlPeriod, let groupcallDefaultJoinAs, let themeEmoticon, let requestsPending, let recentRequesters):
return ("chatFull", [("flags", flags), ("id", id), ("about", about), ("participants", participants), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("folderId", folderId), ("call", call), ("ttlPeriod", ttlPeriod), ("groupcallDefaultJoinAs", groupcallDefaultJoinAs), ("themeEmoticon", themeEmoticon), ("requestsPending", requestsPending)]) return ("chatFull", [("flags", flags), ("id", id), ("about", about), ("participants", participants), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("folderId", folderId), ("call", call), ("ttlPeriod", ttlPeriod), ("groupcallDefaultJoinAs", groupcallDefaultJoinAs), ("themeEmoticon", themeEmoticon), ("requestsPending", requestsPending), ("recentRequesters", recentRequesters)])
case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts, let call, let ttlPeriod, let pendingSuggestions, let groupcallDefaultJoinAs, let themeEmoticon, let requestsPending): case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts, let call, let ttlPeriod, let pendingSuggestions, let groupcallDefaultJoinAs, let themeEmoticon, let requestsPending, let recentRequesters):
return ("channelFull", [("flags", flags), ("id", id), ("about", about), ("participantsCount", participantsCount), ("adminsCount", adminsCount), ("kickedCount", kickedCount), ("bannedCount", bannedCount), ("onlineCount", onlineCount), ("readInboxMaxId", readInboxMaxId), ("readOutboxMaxId", readOutboxMaxId), ("unreadCount", unreadCount), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("migratedFromChatId", migratedFromChatId), ("migratedFromMaxId", migratedFromMaxId), ("pinnedMsgId", pinnedMsgId), ("stickerset", stickerset), ("availableMinId", availableMinId), ("folderId", folderId), ("linkedChatId", linkedChatId), ("location", location), ("slowmodeSeconds", slowmodeSeconds), ("slowmodeNextSendDate", slowmodeNextSendDate), ("statsDc", statsDc), ("pts", pts), ("call", call), ("ttlPeriod", ttlPeriod), ("pendingSuggestions", pendingSuggestions), ("groupcallDefaultJoinAs", groupcallDefaultJoinAs), ("themeEmoticon", themeEmoticon), ("requestsPending", requestsPending)]) return ("channelFull", [("flags", flags), ("id", id), ("about", about), ("participantsCount", participantsCount), ("adminsCount", adminsCount), ("kickedCount", kickedCount), ("bannedCount", bannedCount), ("onlineCount", onlineCount), ("readInboxMaxId", readInboxMaxId), ("readOutboxMaxId", readOutboxMaxId), ("unreadCount", unreadCount), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("migratedFromChatId", migratedFromChatId), ("migratedFromMaxId", migratedFromMaxId), ("pinnedMsgId", pinnedMsgId), ("stickerset", stickerset), ("availableMinId", availableMinId), ("folderId", folderId), ("linkedChatId", linkedChatId), ("location", location), ("slowmodeSeconds", slowmodeSeconds), ("slowmodeNextSendDate", slowmodeNextSendDate), ("statsDc", statsDc), ("pts", pts), ("call", call), ("ttlPeriod", ttlPeriod), ("pendingSuggestions", pendingSuggestions), ("groupcallDefaultJoinAs", groupcallDefaultJoinAs), ("themeEmoticon", themeEmoticon), ("requestsPending", requestsPending), ("recentRequesters", recentRequesters)])
} }
} }
@ -292,6 +302,10 @@ public extension Api {
if Int(_1!) & Int(1 << 16) != 0 {_14 = parseString(reader) } if Int(_1!) & Int(1 << 16) != 0 {_14 = parseString(reader) }
var _15: Int32? var _15: Int32?
if Int(_1!) & Int(1 << 17) != 0 {_15 = reader.readInt32() } if Int(_1!) & Int(1 << 17) != 0 {_15 = reader.readInt32() }
var _16: [Int64]?
if Int(_1!) & Int(1 << 17) != 0 {if let _ = reader.readInt32() {
_16 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
} }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
@ -307,8 +321,9 @@ public extension Api {
let _c13 = (Int(_1!) & Int(1 << 15) == 0) || _13 != nil let _c13 = (Int(_1!) & Int(1 << 15) == 0) || _13 != nil
let _c14 = (Int(_1!) & Int(1 << 16) == 0) || _14 != nil let _c14 = (Int(_1!) & Int(1 << 16) == 0) || _14 != nil
let _c15 = (Int(_1!) & Int(1 << 17) == 0) || _15 != nil let _c15 = (Int(_1!) & Int(1 << 17) == 0) || _15 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 { let _c16 = (Int(_1!) & Int(1 << 17) == 0) || _16 != nil
return Api.ChatFull.chatFull(flags: _1!, id: _2!, about: _3!, participants: _4!, chatPhoto: _5, notifySettings: _6!, exportedInvite: _7, botInfo: _8, pinnedMsgId: _9, folderId: _10, call: _11, ttlPeriod: _12, groupcallDefaultJoinAs: _13, themeEmoticon: _14, requestsPending: _15) if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 {
return Api.ChatFull.chatFull(flags: _1!, id: _2!, about: _3!, participants: _4!, chatPhoto: _5, notifySettings: _6!, exportedInvite: _7, botInfo: _8, pinnedMsgId: _9, folderId: _10, call: _11, ttlPeriod: _12, groupcallDefaultJoinAs: _13, themeEmoticon: _14, requestsPending: _15, recentRequesters: _16)
} }
else { else {
return nil return nil
@ -399,6 +414,10 @@ public extension Api {
if Int(_1!) & Int(1 << 27) != 0 {_32 = parseString(reader) } if Int(_1!) & Int(1 << 27) != 0 {_32 = parseString(reader) }
var _33: Int32? var _33: Int32?
if Int(_1!) & Int(1 << 28) != 0 {_33 = reader.readInt32() } if Int(_1!) & Int(1 << 28) != 0 {_33 = reader.readInt32() }
var _34: [Int64]?
if Int(_1!) & Int(1 << 28) != 0 {if let _ = reader.readInt32() {
_34 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
} }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
@ -432,8 +451,9 @@ public extension Api {
let _c31 = (Int(_1!) & Int(1 << 26) == 0) || _31 != nil let _c31 = (Int(_1!) & Int(1 << 26) == 0) || _31 != nil
let _c32 = (Int(_1!) & Int(1 << 27) == 0) || _32 != nil let _c32 = (Int(_1!) & Int(1 << 27) == 0) || _32 != nil
let _c33 = (Int(_1!) & Int(1 << 28) == 0) || _33 != nil let _c33 = (Int(_1!) & Int(1 << 28) == 0) || _33 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 && _c28 && _c29 && _c30 && _c31 && _c32 && _c33 { let _c34 = (Int(_1!) & Int(1 << 28) == 0) || _34 != nil
return Api.ChatFull.channelFull(flags: _1!, id: _2!, about: _3!, participantsCount: _4, adminsCount: _5, kickedCount: _6, bannedCount: _7, onlineCount: _8, readInboxMaxId: _9!, readOutboxMaxId: _10!, unreadCount: _11!, chatPhoto: _12!, notifySettings: _13!, exportedInvite: _14, botInfo: _15!, migratedFromChatId: _16, migratedFromMaxId: _17, pinnedMsgId: _18, stickerset: _19, availableMinId: _20, folderId: _21, linkedChatId: _22, location: _23, slowmodeSeconds: _24, slowmodeNextSendDate: _25, statsDc: _26, pts: _27!, call: _28, ttlPeriod: _29, pendingSuggestions: _30, groupcallDefaultJoinAs: _31, themeEmoticon: _32, requestsPending: _33) if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 && _c28 && _c29 && _c30 && _c31 && _c32 && _c33 && _c34 {
return Api.ChatFull.channelFull(flags: _1!, id: _2!, about: _3!, participantsCount: _4, adminsCount: _5, kickedCount: _6, bannedCount: _7, onlineCount: _8, readInboxMaxId: _9!, readOutboxMaxId: _10!, unreadCount: _11!, chatPhoto: _12!, notifySettings: _13!, exportedInvite: _14, botInfo: _15!, migratedFromChatId: _16, migratedFromMaxId: _17, pinnedMsgId: _18, stickerset: _19, availableMinId: _20, folderId: _21, linkedChatId: _22, location: _23, slowmodeSeconds: _24, slowmodeNextSendDate: _25, statsDc: _26, pts: _27!, call: _28, ttlPeriod: _29, pendingSuggestions: _30, groupcallDefaultJoinAs: _31, themeEmoticon: _32, requestsPending: _33, recentRequesters: _34)
} }
else { else {
return nil return nil
@ -4827,7 +4847,7 @@ public extension Api {
case updateBotStopped(userId: Int64, date: Int32, stopped: Api.Bool, qts: Int32) case updateBotStopped(userId: Int64, date: Int32, stopped: Api.Bool, qts: Int32)
case updateGroupCallConnection(flags: Int32, params: Api.DataJSON) case updateGroupCallConnection(flags: Int32, params: Api.DataJSON)
case updateBotCommands(peer: Api.Peer, botId: Int64, commands: [Api.BotCommand]) case updateBotCommands(peer: Api.Peer, botId: Int64, commands: [Api.BotCommand])
case updatePendingJoinRequests(peer: Api.Peer, requestsPending: Int32) case updatePendingJoinRequests(peer: Api.Peer, requestsPending: Int32, recentRequesters: [Int64])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -5642,12 +5662,17 @@ public extension Api {
item.serialize(buffer, true) item.serialize(buffer, true)
} }
break break
case .updatePendingJoinRequests(let peer, let requestsPending): case .updatePendingJoinRequests(let peer, let requestsPending, let recentRequesters):
if boxed { if boxed {
buffer.appendInt32(-82532135) buffer.appendInt32(1885586395)
} }
peer.serialize(buffer, true) peer.serialize(buffer, true)
serializeInt32(requestsPending, buffer: buffer, boxed: false) serializeInt32(requestsPending, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(recentRequesters.count))
for item in recentRequesters {
serializeInt64(item, buffer: buffer, boxed: false)
}
break break
} }
} }
@ -5840,8 +5865,8 @@ public extension Api {
return ("updateGroupCallConnection", [("flags", flags), ("params", params)]) return ("updateGroupCallConnection", [("flags", flags), ("params", params)])
case .updateBotCommands(let peer, let botId, let commands): case .updateBotCommands(let peer, let botId, let commands):
return ("updateBotCommands", [("peer", peer), ("botId", botId), ("commands", commands)]) return ("updateBotCommands", [("peer", peer), ("botId", botId), ("commands", commands)])
case .updatePendingJoinRequests(let peer, let requestsPending): case .updatePendingJoinRequests(let peer, let requestsPending, let recentRequesters):
return ("updatePendingJoinRequests", [("peer", peer), ("requestsPending", requestsPending)]) return ("updatePendingJoinRequests", [("peer", peer), ("requestsPending", requestsPending), ("recentRequesters", recentRequesters)])
} }
} }
@ -7508,10 +7533,15 @@ public extension Api {
} }
var _2: Int32? var _2: Int32?
_2 = reader.readInt32() _2 = reader.readInt32()
var _3: [Int64]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
}
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
if _c1 && _c2 { let _c3 = _3 != nil
return Api.Update.updatePendingJoinRequests(peer: _1!, requestsPending: _2!) if _c1 && _c2 && _c3 {
return Api.Update.updatePendingJoinRequests(peer: _1!, requestsPending: _2!, recentRequesters: _3!)
} }
else { else {
return nil return nil
@ -20176,13 +20206,13 @@ public extension Api {
} }
public enum ExportedChatInvite: TypeConstructorDescription { public enum ExportedChatInvite: TypeConstructorDescription {
case chatInviteExported(flags: Int32, link: String, adminId: Int64, date: Int32, startDate: Int32?, expireDate: Int32?, usageLimit: Int32?, usage: Int32?, requested: Int32?) case chatInviteExported(flags: Int32, link: String, adminId: Int64, date: Int32, startDate: Int32?, expireDate: Int32?, usageLimit: Int32?, usage: Int32?, requested: Int32?, title: String?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .chatInviteExported(let flags, let link, let adminId, let date, let startDate, let expireDate, let usageLimit, let usage, let requested): case .chatInviteExported(let flags, let link, let adminId, let date, let startDate, let expireDate, let usageLimit, let usage, let requested, let title):
if boxed { if boxed {
buffer.appendInt32(-1283792928) buffer.appendInt32(179611673)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(link, buffer: buffer, boxed: false) serializeString(link, buffer: buffer, boxed: false)
@ -20193,14 +20223,15 @@ public extension Api {
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(usageLimit!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 2) != 0 {serializeInt32(usageLimit!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 3) != 0 {serializeInt32(usage!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 3) != 0 {serializeInt32(usage!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 7) != 0 {serializeInt32(requested!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 7) != 0 {serializeInt32(requested!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 8) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
break break
} }
} }
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .chatInviteExported(let flags, let link, let adminId, let date, let startDate, let expireDate, let usageLimit, let usage, let requested): case .chatInviteExported(let flags, let link, let adminId, let date, let startDate, let expireDate, let usageLimit, let usage, let requested, let title):
return ("chatInviteExported", [("flags", flags), ("link", link), ("adminId", adminId), ("date", date), ("startDate", startDate), ("expireDate", expireDate), ("usageLimit", usageLimit), ("usage", usage), ("requested", requested)]) return ("chatInviteExported", [("flags", flags), ("link", link), ("adminId", adminId), ("date", date), ("startDate", startDate), ("expireDate", expireDate), ("usageLimit", usageLimit), ("usage", usage), ("requested", requested), ("title", title)])
} }
} }
@ -20223,6 +20254,8 @@ public extension Api {
if Int(_1!) & Int(1 << 3) != 0 {_8 = reader.readInt32() } if Int(_1!) & Int(1 << 3) != 0 {_8 = reader.readInt32() }
var _9: Int32? var _9: Int32?
if Int(_1!) & Int(1 << 7) != 0 {_9 = reader.readInt32() } if Int(_1!) & Int(1 << 7) != 0 {_9 = reader.readInt32() }
var _10: String?
if Int(_1!) & Int(1 << 8) != 0 {_10 = parseString(reader) }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
@ -20232,8 +20265,9 @@ public extension Api {
let _c7 = (Int(_1!) & Int(1 << 2) == 0) || _7 != nil let _c7 = (Int(_1!) & Int(1 << 2) == 0) || _7 != nil
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil
let _c9 = (Int(_1!) & Int(1 << 7) == 0) || _9 != nil let _c9 = (Int(_1!) & Int(1 << 7) == 0) || _9 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { let _c10 = (Int(_1!) & Int(1 << 8) == 0) || _10 != nil
return Api.ExportedChatInvite.chatInviteExported(flags: _1!, link: _2!, adminId: _3!, date: _4!, startDate: _5, expireDate: _6, usageLimit: _7, usage: _8, requested: _9) if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 {
return Api.ExportedChatInvite.chatInviteExported(flags: _1!, link: _2!, adminId: _3!, date: _4!, startDate: _5, expireDate: _6, usageLimit: _7, usage: _8, requested: _9, title: _10)
} }
else { else {
return nil return nil
@ -21089,6 +21123,7 @@ public extension Api {
case messageActionChannelCreate(title: String) case messageActionChannelCreate(title: String)
case messageActionChatMigrateTo(channelId: Int64) case messageActionChatMigrateTo(channelId: Int64)
case messageActionChannelMigrateFrom(title: String, chatId: Int64) case messageActionChannelMigrateFrom(title: String, chatId: Int64)
case messageActionChatJoinedByRequest
case messageActionPinMessage case messageActionPinMessage
case messageActionHistoryClear case messageActionHistoryClear
case messageActionGameScore(gameId: Int64, score: Int32) case messageActionGameScore(gameId: Int64, score: Int32)
@ -21107,7 +21142,6 @@ public extension Api {
case messageActionSetMessagesTTL(period: Int32) case messageActionSetMessagesTTL(period: Int32)
case messageActionGroupCallScheduled(call: Api.InputGroupCall, scheduleDate: Int32) case messageActionGroupCallScheduled(call: Api.InputGroupCall, scheduleDate: Int32)
case messageActionSetChatTheme(emoticon: String) case messageActionSetChatTheme(emoticon: String)
case messageActionChatJoinedByRequest
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -21186,6 +21220,12 @@ public extension Api {
} }
serializeString(title, buffer: buffer, boxed: false) serializeString(title, buffer: buffer, boxed: false)
serializeInt64(chatId, buffer: buffer, boxed: false) serializeInt64(chatId, buffer: buffer, boxed: false)
break
case .messageActionChatJoinedByRequest:
if boxed {
buffer.appendInt32(-339958837)
}
break break
case .messageActionPinMessage: case .messageActionPinMessage:
if boxed { if boxed {
@ -21324,12 +21364,6 @@ public extension Api {
buffer.appendInt32(-1434950843) buffer.appendInt32(-1434950843)
} }
serializeString(emoticon, buffer: buffer, boxed: false) serializeString(emoticon, buffer: buffer, boxed: false)
break
case .messageActionChatJoinedByRequest:
if boxed {
buffer.appendInt32(-339958837)
}
break break
} }
} }
@ -21358,6 +21392,8 @@ public extension Api {
return ("messageActionChatMigrateTo", [("channelId", channelId)]) return ("messageActionChatMigrateTo", [("channelId", channelId)])
case .messageActionChannelMigrateFrom(let title, let chatId): case .messageActionChannelMigrateFrom(let title, let chatId):
return ("messageActionChannelMigrateFrom", [("title", title), ("chatId", chatId)]) return ("messageActionChannelMigrateFrom", [("title", title), ("chatId", chatId)])
case .messageActionChatJoinedByRequest:
return ("messageActionChatJoinedByRequest", [])
case .messageActionPinMessage: case .messageActionPinMessage:
return ("messageActionPinMessage", []) return ("messageActionPinMessage", [])
case .messageActionHistoryClear: case .messageActionHistoryClear:
@ -21394,8 +21430,6 @@ public extension Api {
return ("messageActionGroupCallScheduled", [("call", call), ("scheduleDate", scheduleDate)]) return ("messageActionGroupCallScheduled", [("call", call), ("scheduleDate", scheduleDate)])
case .messageActionSetChatTheme(let emoticon): case .messageActionSetChatTheme(let emoticon):
return ("messageActionSetChatTheme", [("emoticon", emoticon)]) return ("messageActionSetChatTheme", [("emoticon", emoticon)])
case .messageActionChatJoinedByRequest:
return ("messageActionChatJoinedByRequest", [])
} }
} }
@ -21516,6 +21550,9 @@ public extension Api {
return nil return nil
} }
} }
public static func parse_messageActionChatJoinedByRequest(_ reader: BufferReader) -> MessageAction? {
return Api.MessageAction.messageActionChatJoinedByRequest
}
public static func parse_messageActionPinMessage(_ reader: BufferReader) -> MessageAction? { public static func parse_messageActionPinMessage(_ reader: BufferReader) -> MessageAction? {
return Api.MessageAction.messageActionPinMessage return Api.MessageAction.messageActionPinMessage
} }
@ -21760,9 +21797,6 @@ public extension Api {
return nil return nil
} }
} }
public static func parse_messageActionChatJoinedByRequest(_ reader: BufferReader) -> MessageAction? {
return Api.MessageAction.messageActionChatJoinedByRequest
}
} }
public enum PhoneCall: TypeConstructorDescription { public enum PhoneCall: TypeConstructorDescription {

View File

@ -2652,23 +2652,6 @@ public extension Api {
}) })
} }
public static func exportChatInvite(flags: Int32, peer: Api.InputPeer, expireDate: Int32?, usageLimit: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ExportedChatInvite>) {
let buffer = Buffer()
buffer.appendInt32(347716823)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(expireDate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(usageLimit!, buffer: buffer, boxed: false)}
return (FunctionDescription(name: "messages.exportChatInvite", parameters: [("flags", flags), ("peer", peer), ("expireDate", expireDate), ("usageLimit", usageLimit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.ExportedChatInvite? in
let reader = BufferReader(buffer)
var result: Api.ExportedChatInvite?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite
}
return result
})
}
public static func checkChatInvite(hash: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ChatInvite>) { public static func checkChatInvite(hash: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ChatInvite>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(1051570619) buffer.appendInt32(1051570619)
@ -4254,16 +4237,17 @@ public extension Api {
}) })
} }
public static func editExportedChatInvite(flags: Int32, peer: Api.InputPeer, link: String, expireDate: Int32?, usageLimit: Int32?, requestNeeded: Api.Bool?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ExportedChatInvite>) { public static func editExportedChatInvite(flags: Int32, peer: Api.InputPeer, link: String, expireDate: Int32?, usageLimit: Int32?, requestNeeded: Api.Bool?, title: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ExportedChatInvite>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(1557932235) buffer.appendInt32(-1110823051)
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true) peer.serialize(buffer, true)
serializeString(link, buffer: buffer, boxed: false) serializeString(link, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(expireDate!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 0) != 0 {serializeInt32(expireDate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(usageLimit!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 1) != 0 {serializeInt32(usageLimit!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 3) != 0 {requestNeeded!.serialize(buffer, true)} if Int(flags) & Int(1 << 3) != 0 {requestNeeded!.serialize(buffer, true)}
return (FunctionDescription(name: "messages.editExportedChatInvite", parameters: [("flags", flags), ("peer", peer), ("link", link), ("expireDate", expireDate), ("usageLimit", usageLimit), ("requestNeeded", requestNeeded)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ExportedChatInvite? in if Int(flags) & Int(1 << 4) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
return (FunctionDescription(name: "messages.editExportedChatInvite", parameters: [("flags", flags), ("peer", peer), ("link", link), ("expireDate", expireDate), ("usageLimit", usageLimit), ("requestNeeded", requestNeeded), ("title", title)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ExportedChatInvite? in
let reader = BufferReader(buffer) let reader = BufferReader(buffer)
var result: Api.messages.ExportedChatInvite? var result: Api.messages.ExportedChatInvite?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
@ -4273,6 +4257,24 @@ public extension Api {
}) })
} }
public static func exportChatInvite(flags: Int32, peer: Api.InputPeer, expireDate: Int32?, usageLimit: Int32?, title: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ExportedChatInvite>) {
let buffer = Buffer()
buffer.appendInt32(-1607670315)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(expireDate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(usageLimit!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 4) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
return (FunctionDescription(name: "messages.exportChatInvite", parameters: [("flags", flags), ("peer", peer), ("expireDate", expireDate), ("usageLimit", usageLimit), ("title", title)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.ExportedChatInvite? in
let reader = BufferReader(buffer)
var result: Api.ExportedChatInvite?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite
}
return result
})
}
public static func deleteRevokedExportedChatInvites(peer: Api.InputPeer, adminId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) { public static func deleteRevokedExportedChatInvites(peer: Api.InputPeer, adminId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(1452833749) buffer.appendInt32(1452833749)
@ -4413,18 +4415,18 @@ public extension Api {
}) })
} }
public static func getSearchResultsPositions(peer: Api.InputPeer, filter: Api.MessagesFilter, offsetId: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SearchResultsPositions>) { public static func getSearchResultsRawMessages(peer: Api.InputPeer, filter: Api.MessagesFilter, offsetId: Int32, offsetDate: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SearchResultsRawMessages>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(1855292323) buffer.appendInt32(1258852762)
peer.serialize(buffer, true) peer.serialize(buffer, true)
filter.serialize(buffer, true) filter.serialize(buffer, true)
serializeInt32(offsetId, buffer: buffer, boxed: false) serializeInt32(offsetId, buffer: buffer, boxed: false)
serializeInt32(limit, buffer: buffer, boxed: false) serializeInt32(offsetDate, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.getSearchResultsPositions", parameters: [("peer", peer), ("filter", filter), ("offsetId", offsetId), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SearchResultsPositions? in return (FunctionDescription(name: "messages.getSearchResultsRawMessages", parameters: [("peer", peer), ("filter", filter), ("offsetId", offsetId), ("offsetDate", offsetDate)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SearchResultsRawMessages? in
let reader = BufferReader(buffer) let reader = BufferReader(buffer)
var result: Api.messages.SearchResultsPositions? var result: Api.messages.SearchResultsRawMessages?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.SearchResultsPositions result = Api.parse(reader, signature: signature) as? Api.messages.SearchResultsRawMessages
} }
return result return result
}) })
@ -4445,6 +4447,23 @@ public extension Api {
return result return result
}) })
} }
public static func getSearchResultsPositions(peer: Api.InputPeer, filter: Api.MessagesFilter, offsetId: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SearchResultsPositions>) {
let buffer = Buffer()
buffer.appendInt32(1855292323)
peer.serialize(buffer, true)
filter.serialize(buffer, true)
serializeInt32(offsetId, buffer: buffer, boxed: false)
serializeInt32(limit, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.getSearchResultsPositions", parameters: [("peer", peer), ("filter", filter), ("offsetId", offsetId), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SearchResultsPositions? in
let reader = BufferReader(buffer)
var result: Api.messages.SearchResultsPositions?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.SearchResultsPositions
}
return result
})
}
} }
public struct channels { public struct channels {
public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) { public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
@ -7542,12 +7561,14 @@ public extension Api {
}) })
} }
public static func saveTheme(theme: Api.InputTheme, unsave: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) { public static func installTheme(flags: Int32, theme: Api.InputTheme?, format: String?, baseTheme: Api.BaseTheme?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(-229175188) buffer.appendInt32(-953697477)
theme.serialize(buffer, true) serializeInt32(flags, buffer: buffer, boxed: false)
unsave.serialize(buffer, true) if Int(flags) & Int(1 << 1) != 0 {theme!.serialize(buffer, true)}
return (FunctionDescription(name: "account.saveTheme", parameters: [("theme", theme), ("unsave", unsave)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in if Int(flags) & Int(1 << 2) != 0 {serializeString(format!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 3) != 0 {baseTheme!.serialize(buffer, true)}
return (FunctionDescription(name: "account.installTheme", parameters: [("flags", flags), ("theme", theme), ("format", format), ("baseTheme", baseTheme)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer) let reader = BufferReader(buffer)
var result: Api.Bool? var result: Api.Bool?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
@ -7557,14 +7578,26 @@ public extension Api {
}) })
} }
public static func installTheme(flags: Int32, theme: Api.InputTheme?, format: String?, baseTheme: Api.BaseTheme?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) { public static func getChatThemes(hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.account.Themes>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(-953697477) buffer.appendInt32(-700916087)
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt64(hash, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {theme!.serialize(buffer, true)} return (FunctionDescription(name: "account.getChatThemes", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.Themes? in
if Int(flags) & Int(1 << 2) != 0 {serializeString(format!, buffer: buffer, boxed: false)} let reader = BufferReader(buffer)
if Int(flags) & Int(1 << 3) != 0 {baseTheme!.serialize(buffer, true)} var result: Api.account.Themes?
return (FunctionDescription(name: "account.installTheme", parameters: [("flags", flags), ("theme", theme), ("format", format), ("baseTheme", baseTheme)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.account.Themes
}
return result
})
}
public static func saveTheme(theme: Api.InputTheme, unsave: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-229175188)
theme.serialize(buffer, true)
unsave.serialize(buffer, true)
return (FunctionDescription(name: "account.saveTheme", parameters: [("theme", theme), ("unsave", unsave)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer) let reader = BufferReader(buffer)
var result: Api.Bool? var result: Api.Bool?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
@ -7723,20 +7756,6 @@ public extension Api {
return result return result
}) })
} }
public static func getChatThemes(hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.account.Themes>) {
let buffer = Buffer()
buffer.appendInt32(-700916087)
serializeInt64(hash, buffer: buffer, boxed: false)
return (FunctionDescription(name: "account.getChatThemes", parameters: [("hash", hash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.Themes? in
let reader = BufferReader(buffer)
var result: Api.account.Themes?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.account.Themes
}
return result
})
}
} }
public struct langpack { public struct langpack {
public static func getLangPack(langPack: String, langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.LangPackDifference>) { public static func getLangPack(langPack: String, langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.LangPackDifference>) {

View File

@ -520,7 +520,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
avatarListNode.controlsClippingNode.frame = CGRect(x: -targetRect.width / 2.0, y: -targetRect.height / 2.0, width: targetRect.width, height: targetRect.height) avatarListNode.controlsClippingNode.frame = CGRect(x: -targetRect.width / 2.0, y: -targetRect.height / 2.0, width: targetRect.width, height: targetRect.height)
avatarListNode.controlsClippingOffsetNode.frame = CGRect(origin: CGPoint(x: targetRect.width / 2.0, y: targetRect.height / 2.0), size: CGSize()) avatarListNode.controlsClippingOffsetNode.frame = CGRect(origin: CGPoint(x: targetRect.width / 2.0, y: targetRect.height / 2.0), size: CGSize())
avatarListNode.stripContainerNode.frame = CGRect(x: 0.0, y: 13.0, width: targetRect.width, height: 2.0) avatarListNode.stripContainerNode.frame = CGRect(x: 0.0, y: 13.0, width: targetRect.width, height: 2.0)
avatarListNode.shadowNode.frame = CGRect(x: 0.0, y: 0.0, width: targetRect.width, height: 44.0) avatarListNode.topShadowNode.frame = CGRect(x: 0.0, y: 0.0, width: targetRect.width, height: 44.0)
avatarListContainerNode.addSubnode(avatarListNode) avatarListContainerNode.addSubnode(avatarListNode)
avatarListContainerNode.addSubnode(avatarListNode.controlsClippingOffsetNode) avatarListContainerNode.addSubnode(avatarListNode.controlsClippingOffsetNode)

View File

@ -265,7 +265,7 @@ final class VoiceChatPeerProfileNode: ASDisplayNode {
self.avatarListNode.controlsClippingNode.frame = CGRect(x: -targetRect.width / 2.0, y: -targetRect.width / 2.0, width: targetRect.width, height: targetRect.width) self.avatarListNode.controlsClippingNode.frame = CGRect(x: -targetRect.width / 2.0, y: -targetRect.width / 2.0, width: targetRect.width, height: targetRect.width)
self.avatarListNode.controlsClippingOffsetNode.frame = CGRect(origin: CGPoint(x: targetRect.width / 2.0, y: targetRect.width / 2.0), size: CGSize()) self.avatarListNode.controlsClippingOffsetNode.frame = CGRect(origin: CGPoint(x: targetRect.width / 2.0, y: targetRect.width / 2.0), size: CGSize())
self.avatarListNode.stripContainerNode.frame = CGRect(x: 0.0, y: 13.0, width: targetRect.width, height: 2.0) self.avatarListNode.stripContainerNode.frame = CGRect(x: 0.0, y: 13.0, width: targetRect.width, height: 2.0)
self.avatarListNode.shadowNode.frame = CGRect(x: 0.0, y: 0.0, width: targetRect.width, height: 44.0) self.avatarListNode.topShadowNode.frame = CGRect(x: 0.0, y: 0.0, width: targetRect.width, height: 44.0)
self.avatarListNode.updateCustomItemsOnlySynchronously = true self.avatarListNode.updateCustomItemsOnlySynchronously = true
self.avatarListNode.update(size: targetSize, peer: self.peer, customNode: self.customNode, additionalEntry: self.additionalEntry, isExpanded: true, transition: .immediate) self.avatarListNode.update(size: targetSize, peer: self.peer, customNode: self.customNode, additionalEntry: self.additionalEntry, isExpanded: true, transition: .immediate)
@ -359,7 +359,7 @@ final class VoiceChatPeerProfileNode: ASDisplayNode {
self.avatarListNode.controlsClippingNode.frame = CGRect(x: -targetRect.width / 2.0, y: -targetRect.width / 2.0, width: targetRect.width, height: targetRect.width) self.avatarListNode.controlsClippingNode.frame = CGRect(x: -targetRect.width / 2.0, y: -targetRect.width / 2.0, width: targetRect.width, height: targetRect.width)
self.avatarListNode.controlsClippingOffsetNode.frame = CGRect(origin: CGPoint(x: targetRect.width / 2.0, y: targetRect.width / 2.0), size: CGSize()) self.avatarListNode.controlsClippingOffsetNode.frame = CGRect(origin: CGPoint(x: targetRect.width / 2.0, y: targetRect.width / 2.0), size: CGSize())
self.avatarListNode.stripContainerNode.frame = CGRect(x: 0.0, y: 13.0, width: targetRect.width, height: 2.0) self.avatarListNode.stripContainerNode.frame = CGRect(x: 0.0, y: 13.0, width: targetRect.width, height: 2.0)
self.avatarListNode.shadowNode.frame = CGRect(x: 0.0, y: 0.0, width: targetRect.width, height: 44.0) self.avatarListNode.topShadowNode.frame = CGRect(x: 0.0, y: 0.0, width: targetRect.width, height: 44.0)
self.avatarListNode.updateCustomItemsOnlySynchronously = true self.avatarListNode.updateCustomItemsOnlySynchronously = true
self.avatarListNode.update(size: targetSize, peer: self.peer, customNode: self.customNode, additionalEntry: self.additionalEntry, isExpanded: true, transition: .immediate) self.avatarListNode.update(size: targetSize, peer: self.peer, customNode: self.customNode, additionalEntry: self.additionalEntry, isExpanded: true, transition: .immediate)
@ -432,8 +432,8 @@ final class VoiceChatPeerProfileNode: ASDisplayNode {
self.avatarListNode.stripContainerNode.alpha = 0.0 self.avatarListNode.stripContainerNode.alpha = 0.0
self.avatarListNode.stripContainerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2) self.avatarListNode.stripContainerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
self.avatarListNode.shadowNode.alpha = 0.0 self.avatarListNode.topShadowNode.alpha = 0.0
self.avatarListNode.shadowNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2) self.avatarListNode.topShadowNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
self.infoNode.alpha = 0.0 self.infoNode.alpha = 0.0
self.infoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2) self.infoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
@ -492,8 +492,8 @@ final class VoiceChatPeerProfileNode: ASDisplayNode {
self.avatarListNode.stripContainerNode.alpha = 0.0 self.avatarListNode.stripContainerNode.alpha = 0.0
self.avatarListNode.stripContainerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2) self.avatarListNode.stripContainerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
self.avatarListNode.shadowNode.alpha = 0.0 self.avatarListNode.topShadowNode.alpha = 0.0
self.avatarListNode.shadowNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2) self.avatarListNode.topShadowNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
self.infoNode.alpha = 0.0 self.infoNode.alpha = 0.0
self.infoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2) self.infoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)

View File

@ -6,8 +6,8 @@ import TelegramApi
extension ExportedInvitation { extension ExportedInvitation {
init(apiExportedInvite: Api.ExportedChatInvite) { init(apiExportedInvite: Api.ExportedChatInvite) {
switch apiExportedInvite { switch apiExportedInvite {
case let .chatInviteExported(flags, link, adminId, date, startDate, expireDate, usageLimit, usage, requested): case let .chatInviteExported(flags, link, adminId, date, startDate, expireDate, usageLimit, usage, requested, title):
self = ExportedInvitation(link: link, isPermanent: (flags & (1 << 5)) != 0, requestApproval: (flags & (1 << 6)) != 0, isRevoked: (flags & (1 << 0)) != 0, adminId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(adminId)), date: date, startDate: startDate, expireDate: expireDate, usageLimit: usageLimit, count: usage, requestedCount: requested) self = ExportedInvitation(link: link, title: title, isPermanent: (flags & (1 << 5)) != 0, requestApproval: (flags & (1 << 6)) != 0, isRevoked: (flags & (1 << 0)) != 0, adminId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(adminId)), date: date, startDate: startDate, expireDate: expireDate, usageLimit: usageLimit, count: usage, requestedCount: requested)
} }
} }
} }

View File

@ -1451,7 +1451,7 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
} }
return current return current
}) })
case let .updatePendingJoinRequests(peer, requestsPending): case let .updatePendingJoinRequests(peer, requestsPending, _):
updatedState.updateCachedPeerData(peer.peerId, { current in updatedState.updateCachedPeerData(peer.peerId, { current in
if peer.peerId.namespace == Namespaces.Peer.CloudGroup { if peer.peerId.namespace == Namespaces.Peer.CloudGroup {
let previous: CachedGroupData let previous: CachedGroupData

View File

@ -2,6 +2,7 @@ import Postbox
public struct ExportedInvitation: Codable, Equatable { public struct ExportedInvitation: Codable, Equatable {
public let link: String public let link: String
public let title: String?
public let isPermanent: Bool public let isPermanent: Bool
public let requestApproval: Bool public let requestApproval: Bool
public let isRevoked: Bool public let isRevoked: Bool
@ -13,8 +14,9 @@ public struct ExportedInvitation: Codable, Equatable {
public let count: Int32? public let count: Int32?
public let requestedCount: Int32? public let requestedCount: Int32?
public init(link: String, isPermanent: Bool, requestApproval: Bool, isRevoked: Bool, adminId: PeerId, date: Int32, startDate: Int32?, expireDate: Int32?, usageLimit: Int32?, count: Int32?, requestedCount: Int32?) { public init(link: String, title: String?, isPermanent: Bool, requestApproval: Bool, isRevoked: Bool, adminId: PeerId, date: Int32, startDate: Int32?, expireDate: Int32?, usageLimit: Int32?, count: Int32?, requestedCount: Int32?) {
self.link = link self.link = link
self.title = title
self.isPermanent = isPermanent self.isPermanent = isPermanent
self.requestApproval = requestApproval self.requestApproval = requestApproval
self.isRevoked = isRevoked self.isRevoked = isRevoked
@ -31,6 +33,7 @@ public struct ExportedInvitation: Codable, Equatable {
let container = try decoder.container(keyedBy: StringCodingKey.self) let container = try decoder.container(keyedBy: StringCodingKey.self)
self.link = try container.decode(String.self, forKey: "l") self.link = try container.decode(String.self, forKey: "l")
self.title = try container.decodeIfPresent(String.self, forKey: "title")
self.isPermanent = try container.decode(Bool.self, forKey: "permanent") self.isPermanent = try container.decode(Bool.self, forKey: "permanent")
self.requestApproval = try container.decodeIfPresent(Bool.self, forKey: "requestApproval") ?? false self.requestApproval = try container.decodeIfPresent(Bool.self, forKey: "requestApproval") ?? false
self.isRevoked = try container.decode(Bool.self, forKey: "revoked") self.isRevoked = try container.decode(Bool.self, forKey: "revoked")
@ -47,6 +50,7 @@ public struct ExportedInvitation: Codable, Equatable {
var container = encoder.container(keyedBy: StringCodingKey.self) var container = encoder.container(keyedBy: StringCodingKey.self)
try container.encode(self.link, forKey: "l") try container.encode(self.link, forKey: "l")
try container.encodeIfPresent(self.title, forKey: "title")
try container.encode(self.isPermanent, forKey: "permanent") try container.encode(self.isPermanent, forKey: "permanent")
try container.encode(self.requestApproval, forKey: "requestApproval") try container.encode(self.requestApproval, forKey: "requestApproval")
try container.encode(self.isRevoked, forKey: "revoked") try container.encode(self.isRevoked, forKey: "revoked")
@ -60,10 +64,10 @@ public struct ExportedInvitation: Codable, Equatable {
} }
public static func ==(lhs: ExportedInvitation, rhs: ExportedInvitation) -> Bool { public static func ==(lhs: ExportedInvitation, rhs: ExportedInvitation) -> Bool {
return lhs.link == rhs.link && lhs.isPermanent == rhs.isPermanent && lhs.requestApproval == rhs.requestApproval && lhs.isRevoked == rhs.isRevoked && lhs.adminId == rhs.adminId && lhs.date == rhs.date && lhs.startDate == rhs.startDate && lhs.expireDate == rhs.expireDate && lhs.usageLimit == rhs.usageLimit && lhs.count == rhs.count && lhs.requestedCount == rhs.requestedCount return lhs.link == rhs.link && lhs.title == rhs.title && lhs.isPermanent == rhs.isPermanent && lhs.requestApproval == rhs.requestApproval && lhs.isRevoked == rhs.isRevoked && lhs.adminId == rhs.adminId && lhs.date == rhs.date && lhs.startDate == rhs.startDate && lhs.expireDate == rhs.expireDate && lhs.usageLimit == rhs.usageLimit && lhs.count == rhs.count && lhs.requestedCount == rhs.requestedCount
} }
public func withUpdated(isRevoked: Bool) -> ExportedInvitation { public func withUpdated(isRevoked: Bool) -> ExportedInvitation {
return ExportedInvitation(link: self.link, isPermanent: self.isPermanent, requestApproval: self.requestApproval, isRevoked: isRevoked, adminId: self.adminId, date: self.date, startDate: self.startDate, expireDate: self.expireDate, usageLimit: self.usageLimit, count: self.count, requestedCount: self.requestedCount) return ExportedInvitation(link: self.link, title: self.title, isPermanent: self.isPermanent, requestApproval: self.requestApproval, isRevoked: isRevoked, adminId: self.adminId, date: self.date, startDate: self.startDate, expireDate: self.expireDate, usageLimit: self.usageLimit, count: self.count, requestedCount: self.requestedCount)
} }
} }

View File

@ -25,7 +25,7 @@ func _internal_revokePersistentPeerExportedInvitation(account: Account, peerId:
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
let flags: Int32 = (1 << 2) let flags: Int32 = (1 << 2)
if let _ = peer as? TelegramChannel { if let _ = peer as? TelegramChannel {
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil)) return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil, title: nil))
|> retryRequest |> retryRequest
|> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in |> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in
return account.postbox.transaction { transaction -> ExportedInvitation? in return account.postbox.transaction { transaction -> ExportedInvitation? in
@ -42,7 +42,7 @@ func _internal_revokePersistentPeerExportedInvitation(account: Account, peerId:
} }
} }
} else if let _ = peer as? TelegramGroup { } else if let _ = peer as? TelegramGroup {
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil)) return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil, title: nil))
|> retryRequest |> retryRequest
|> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in |> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in
return account.postbox.transaction { transaction -> ExportedInvitation? in return account.postbox.transaction { transaction -> ExportedInvitation? in
@ -71,7 +71,7 @@ public enum CreatePeerExportedInvitationError {
case generic case generic
} }
func _internal_createPeerExportedInvitation(account: Account, peerId: PeerId, expireDate: Int32?, usageLimit: Int32?, requestNeeded: Bool?) -> Signal<ExportedInvitation?, CreatePeerExportedInvitationError> { func _internal_createPeerExportedInvitation(account: Account, peerId: PeerId, title: String?, expireDate: Int32?, usageLimit: Int32?, requestNeeded: Bool?) -> Signal<ExportedInvitation?, CreatePeerExportedInvitationError> {
return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, CreatePeerExportedInvitationError> in return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, CreatePeerExportedInvitationError> in
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
var flags: Int32 = 0 var flags: Int32 = 0
@ -84,7 +84,10 @@ func _internal_createPeerExportedInvitation(account: Account, peerId: PeerId, ex
if let requestNeeded = requestNeeded, requestNeeded { if let requestNeeded = requestNeeded, requestNeeded {
flags |= (1 << 3) flags |= (1 << 3)
} }
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: expireDate, usageLimit: usageLimit)) if let _ = title {
flags |= (1 << 4)
}
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: expireDate, usageLimit: usageLimit, title: title))
|> mapError { _ in return CreatePeerExportedInvitationError.generic } |> mapError { _ in return CreatePeerExportedInvitationError.generic }
|> map { result -> ExportedInvitation? in |> map { result -> ExportedInvitation? in
return ExportedInvitation(apiExportedInvite: result) return ExportedInvitation(apiExportedInvite: result)
@ -101,7 +104,7 @@ public enum EditPeerExportedInvitationError {
case generic case generic
} }
func _internal_editPeerExportedInvitation(account: Account, peerId: PeerId, link: String, expireDate: Int32?, usageLimit: Int32?, requestNeeded: Bool?) -> Signal<ExportedInvitation?, EditPeerExportedInvitationError> { func _internal_editPeerExportedInvitation(account: Account, peerId: PeerId, link: String, title: String?, expireDate: Int32?, usageLimit: Int32?, requestNeeded: Bool?) -> Signal<ExportedInvitation?, EditPeerExportedInvitationError> {
return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, EditPeerExportedInvitationError> in return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, EditPeerExportedInvitationError> in
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
var flags: Int32 = 0 var flags: Int32 = 0
@ -114,7 +117,10 @@ func _internal_editPeerExportedInvitation(account: Account, peerId: PeerId, link
if let _ = requestNeeded { if let _ = requestNeeded {
flags |= (1 << 3) flags |= (1 << 3)
} }
return account.network.request(Api.functions.messages.editExportedChatInvite(flags: flags, peer: inputPeer, link: link, expireDate: expireDate, usageLimit: usageLimit, requestNeeded: requestNeeded.flatMap { $0 ? .boolTrue : .boolFalse })) if let _ = title {
flags |= (1 << 4)
}
return account.network.request(Api.functions.messages.editExportedChatInvite(flags: flags, peer: inputPeer, link: link, expireDate: expireDate, usageLimit: usageLimit, requestNeeded: requestNeeded.flatMap { $0 ? .boolTrue : .boolFalse }, title: title))
|> mapError { _ in return EditPeerExportedInvitationError.generic } |> mapError { _ in return EditPeerExportedInvitationError.generic }
|> mapToSignal { result -> Signal<ExportedInvitation?, EditPeerExportedInvitationError> in |> mapToSignal { result -> Signal<ExportedInvitation?, EditPeerExportedInvitationError> in
return account.postbox.transaction { transaction in return account.postbox.transaction { transaction in
@ -154,7 +160,7 @@ func _internal_revokePeerExportedInvitation(account: Account, peerId: PeerId, li
return account.postbox.transaction { transaction -> Signal<RevokeExportedInvitationResult?, RevokePeerExportedInvitationError> in return account.postbox.transaction { transaction -> Signal<RevokeExportedInvitationResult?, RevokePeerExportedInvitationError> in
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
let flags: Int32 = (1 << 2) let flags: Int32 = (1 << 2)
return account.network.request(Api.functions.messages.editExportedChatInvite(flags: flags, peer: inputPeer, link: link, expireDate: nil, usageLimit: nil, requestNeeded: nil)) return account.network.request(Api.functions.messages.editExportedChatInvite(flags: flags, peer: inputPeer, link: link, expireDate: nil, usageLimit: nil, requestNeeded: nil, title: nil))
|> mapError { _ in return RevokePeerExportedInvitationError.generic } |> mapError { _ in return RevokePeerExportedInvitationError.generic }
|> mapToSignal { result -> Signal<RevokeExportedInvitationResult?, RevokePeerExportedInvitationError> in |> mapToSignal { result -> Signal<RevokeExportedInvitationResult?, RevokePeerExportedInvitationError> in
return account.postbox.transaction { transaction in return account.postbox.transaction { transaction in

View File

@ -419,12 +419,12 @@ public extension TelegramEngine {
return _internal_checkPeerChatServiceActions(postbox: self.account.postbox, peerId: peerId) return _internal_checkPeerChatServiceActions(postbox: self.account.postbox, peerId: peerId)
} }
public func createPeerExportedInvitation(peerId: PeerId, expireDate: Int32?, usageLimit: Int32?, requestNeeded: Bool?) -> Signal<ExportedInvitation?, CreatePeerExportedInvitationError> { public func createPeerExportedInvitation(peerId: PeerId, title: String?, expireDate: Int32?, usageLimit: Int32?, requestNeeded: Bool?) -> Signal<ExportedInvitation?, CreatePeerExportedInvitationError> {
return _internal_createPeerExportedInvitation(account: self.account, peerId: peerId, expireDate: expireDate, usageLimit: usageLimit, requestNeeded: requestNeeded) return _internal_createPeerExportedInvitation(account: self.account, peerId: peerId, title: title, expireDate: expireDate, usageLimit: usageLimit, requestNeeded: requestNeeded)
} }
public func editPeerExportedInvitation(peerId: PeerId, link: String, expireDate: Int32?, usageLimit: Int32?, requestNeeded: Bool?) -> Signal<ExportedInvitation?, EditPeerExportedInvitationError> { public func editPeerExportedInvitation(peerId: PeerId, link: String, title: String?, expireDate: Int32?, usageLimit: Int32?, requestNeeded: Bool?) -> Signal<ExportedInvitation?, EditPeerExportedInvitationError> {
return _internal_editPeerExportedInvitation(account: self.account, peerId: peerId, link: link, expireDate: expireDate, usageLimit: usageLimit, requestNeeded: requestNeeded) return _internal_editPeerExportedInvitation(account: self.account, peerId: peerId, link: link, title: title, expireDate: expireDate, usageLimit: usageLimit, requestNeeded: requestNeeded)
} }
public func revokePeerExportedInvitation(peerId: PeerId, link: String) -> Signal<RevokeExportedInvitationResult?, RevokePeerExportedInvitationError> { public func revokePeerExportedInvitation(peerId: PeerId, link: String) -> Signal<RevokeExportedInvitationResult?, RevokePeerExportedInvitationError> {

View File

@ -222,14 +222,14 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
switch result { switch result {
case let .chatFull(fullChat, chats, users): case let .chatFull(fullChat, chats, users):
switch fullChat { switch fullChat {
case let .chatFull(_, _, _, _, _, notifySettings, _, _, _, _, _, _, _, _, _): case let .chatFull(_, _, _, _, _, notifySettings, _, _, _, _, _, _, _, _, _, _):
transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: notifySettings)]) transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: notifySettings)])
case .channelFull: case .channelFull:
break break
} }
switch fullChat { switch fullChat {
case let .chatFull(chatFullFlags, _, chatFullAbout, chatFullParticipants, chatFullChatPhoto, _, chatFullExportedInvite, chatFullBotInfo, chatFullPinnedMsgId, _, chatFullCall, _, chatFullGroupcallDefaultJoinAs, chatFullThemeEmoticon, chatFullRequestsPending): case let .chatFull(chatFullFlags, _, chatFullAbout, chatFullParticipants, chatFullChatPhoto, _, chatFullExportedInvite, chatFullBotInfo, chatFullPinnedMsgId, _, chatFullCall, _, chatFullGroupcallDefaultJoinAs, chatFullThemeEmoticon, chatFullRequestsPending, _):
var botInfos: [CachedPeerBotInfo] = [] var botInfos: [CachedPeerBotInfo] = []
for botInfo in chatFullBotInfo ?? [] { for botInfo in chatFullBotInfo ?? [] {
switch botInfo { switch botInfo {
@ -351,14 +351,14 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
switch result { switch result {
case let .chatFull(fullChat, chats, users): case let .chatFull(fullChat, chats, users):
switch fullChat { switch fullChat {
case let .channelFull(_, _, _, _, _, _, _, _, _, _, _, _, notifySettings, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): case let .channelFull(_, _, _, _, _, _, _, _, _, _, _, _, notifySettings, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: notifySettings)]) transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: notifySettings)])
case .chatFull: case .chatFull:
break break
} }
switch fullChat { switch fullChat {
case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, chatPhoto, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, _, linkedChatId, location, slowmodeSeconds, slowmodeNextSendDate, statsDc, _, inputCall, ttl, pendingSuggestions, groupcallDefaultJoinAs, themeEmoticon, requestsPending): case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, chatPhoto, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, _, linkedChatId, location, slowmodeSeconds, slowmodeNextSendDate, statsDc, _, inputCall, ttl, pendingSuggestions, groupcallDefaultJoinAs, themeEmoticon, requestsPending, _):
var channelFlags = CachedChannelFlags() var channelFlags = CachedChannelFlags()
if (flags & (1 << 3)) != 0 { if (flags & (1 << 3)) != 0 {
channelFlags.insert(.canDisplayParticipants) channelFlags.insert(.canDisplayParticipants)

View File

@ -63,6 +63,7 @@ public enum PresentationResourceKey: Int32 {
case itemListBlockAccentIcon case itemListBlockAccentIcon
case itemListBlockDestructiveIcon case itemListBlockDestructiveIcon
case itemListAddDeviceIcon case itemListAddDeviceIcon
case itemListResetIcon
case itemListVoiceCallIcon case itemListVoiceCallIcon
case itemListVideoCallIcon case itemListVideoCallIcon

View File

@ -216,6 +216,12 @@ public struct PresentationResourcesItemList {
}) })
} }
public static func resetIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListEditThemeIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Settings/Reset"), color: theme.list.itemAccentColor)
})
}
public static func cornersImage(_ theme: PresentationTheme, top: Bool, bottom: Bool) -> UIImage? { public static func cornersImage(_ theme: PresentationTheme, top: Bool, bottom: Bool) -> UIImage? {
if !top && !bottom { if !top && !bottom {
return nil return nil

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Icon-36.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,88 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 5.334961 5.270020 cm
0.000000 0.478431 1.000000 scn
6.194835 19.200245 m
5.935136 18.940548 5.935136 18.519493 6.194835 18.259792 c
9.694835 14.759793 l
9.954534 14.500095 10.375588 14.500095 10.635287 14.759793 c
10.894985 15.019492 10.894985 15.440547 10.635287 15.700245 c
8.370360 17.965172 l
8.791913 18.030869 9.224258 18.065020 9.665000 18.065020 c
14.268293 18.065020 18.000000 14.333313 18.000000 9.730020 c
18.000000 5.126726 14.268293 1.395020 9.665000 1.395020 c
5.061707 1.395020 1.330000 5.126726 1.330000 9.730020 c
1.330000 11.844328 2.116372 13.773348 3.413577 15.243072 c
3.656611 15.518428 3.630409 15.938666 3.355053 16.181702 c
3.079696 16.424736 2.659458 16.398533 2.416424 16.123177 c
0.912993 14.419802 0.000000 12.180721 0.000000 9.730020 c
0.000000 4.392187 4.327168 0.065018 9.665000 0.065018 c
15.002832 0.065018 19.330002 4.392187 19.330002 9.730020 c
19.330002 15.067852 15.002832 19.395020 9.665000 19.395020 c
9.150949 19.395020 8.645859 19.354828 8.152806 19.277313 c
10.635287 21.759794 l
10.894985 22.019493 10.894985 22.440548 10.635287 22.700245 c
10.375588 22.959944 9.954534 22.959944 9.694835 22.700245 c
6.194835 19.200245 l
h
f*
n
Q
endstream
endobj
3 0 obj
1242
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Type /Catalog
/Pages 5 0 R
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000001332 00000 n
0000001355 00000 n
0000001528 00000 n
0000001602 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
1661
%%EOF

View File

@ -35,6 +35,7 @@ final class PeerInfoScreenInfoItem: PeerInfoScreenItem {
private final class PeerInfoScreenInfoItemNode: PeerInfoScreenItemNode { private final class PeerInfoScreenInfoItemNode: PeerInfoScreenItemNode {
private let bottomSeparatorNode: ASDisplayNode private let bottomSeparatorNode: ASDisplayNode
private let maskNode: ASImageNode
private var item: PeerInfoScreenInfoItem? private var item: PeerInfoScreenInfoItem?
private var itemNode: InfoItemNode? private var itemNode: InfoItemNode?
@ -43,6 +44,9 @@ private final class PeerInfoScreenInfoItemNode: PeerInfoScreenItemNode {
self.bottomSeparatorNode = ASDisplayNode() self.bottomSeparatorNode = ASDisplayNode()
self.bottomSeparatorNode.isLayerBacked = true self.bottomSeparatorNode.isLayerBacked = true
self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
super.init() super.init()
self.addSubnode(self.bottomSeparatorNode) self.addSubnode(self.bottomSeparatorNode)
@ -99,6 +103,18 @@ private final class PeerInfoScreenInfoItemNode: PeerInfoScreenItemNode {
separatorInset += 49.0 separatorInset += 49.0
} }
let hasCorners = safeInsets.left > 0.0 && (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
if self.maskNode.supernode == nil {
self.addSubnode(self.maskNode)
}
transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: separatorInset, y: height - UIScreenPixel), size: CGSize(width: width - sideInset, height: UIScreenPixel))) transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: separatorInset, y: height - UIScreenPixel), size: CGSize(width: width - sideInset, height: UIScreenPixel)))
transition.updateAlpha(node: self.bottomSeparatorNode, alpha: bottomItem == nil ? 0.0 : 1.0) transition.updateAlpha(node: self.bottomSeparatorNode, alpha: bottomItem == nil ? 0.0 : 1.0)

View File

@ -51,6 +51,7 @@ final class PeerInfoScreenMemberItem: PeerInfoScreenItem {
private final class PeerInfoScreenMemberItemNode: PeerInfoScreenItemNode { private final class PeerInfoScreenMemberItemNode: PeerInfoScreenItemNode {
private let selectionNode: PeerInfoScreenSelectableBackgroundNode private let selectionNode: PeerInfoScreenSelectableBackgroundNode
private let maskNode: ASImageNode
private let bottomSeparatorNode: ASDisplayNode private let bottomSeparatorNode: ASDisplayNode
private var item: PeerInfoScreenMemberItem? private var item: PeerInfoScreenMemberItem?
@ -61,6 +62,9 @@ private final class PeerInfoScreenMemberItemNode: PeerInfoScreenItemNode {
self.selectionNode = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() }) self.selectionNode = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() })
self.selectionNode.isUserInteractionEnabled = false self.selectionNode.isUserInteractionEnabled = false
self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
self.bottomSeparatorNode = ASDisplayNode() self.bottomSeparatorNode = ASDisplayNode()
self.bottomSeparatorNode.isLayerBacked = true self.bottomSeparatorNode.isLayerBacked = true
@ -221,6 +225,19 @@ private final class PeerInfoScreenMemberItemNode: PeerInfoScreenItemNode {
transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(), size: itemNode.bounds.size)) transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(), size: itemNode.bounds.size))
let hasCorners = safeInsets.left > 0.0 && (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
if self.maskNode.supernode == nil {
self.addSubnode(self.maskNode)
}
let highlightNodeOffset: CGFloat = topItem == nil ? 0.0 : UIScreenPixel let highlightNodeOffset: CGFloat = topItem == nil ? 0.0 : UIScreenPixel
self.selectionNode.update(size: CGSize(width: width, height: height + highlightNodeOffset), theme: presentationData.theme, transition: transition) 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))) transition.updateFrame(node: self.selectionNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -highlightNodeOffset), size: CGSize(width: width, height: height + highlightNodeOffset)))

View File

@ -1044,6 +1044,7 @@ struct PeerInfoHeaderNavigationButtonSpec: Equatable {
} }
final class PeerInfoHeaderNavigationButtonContainerNode: ASDisplayNode { final class PeerInfoHeaderNavigationButtonContainerNode: ASDisplayNode {
private var presentationData: PresentationData?
private(set) var buttonNodes: [PeerInfoHeaderNavigationButtonKey: PeerInfoHeaderNavigationButton] = [:] private(set) var buttonNodes: [PeerInfoHeaderNavigationButtonKey: PeerInfoHeaderNavigationButton] = [:]
private var currentButtons: [PeerInfoHeaderNavigationButtonSpec] = [] private var currentButtons: [PeerInfoHeaderNavigationButtonSpec] = []
@ -1060,14 +1061,10 @@ final class PeerInfoHeaderNavigationButtonContainerNode: ASDisplayNode {
var performAction: ((PeerInfoHeaderNavigationButtonKey, ContextReferenceContentNode?) -> Void)? var performAction: ((PeerInfoHeaderNavigationButtonKey, ContextReferenceContentNode?) -> Void)?
override init() {
super.init()
}
func update(size: CGSize, presentationData: PresentationData, buttons: [PeerInfoHeaderNavigationButtonSpec], expandFraction: CGFloat, transition: ContainedViewLayoutTransition) { func update(size: CGSize, presentationData: PresentationData, buttons: [PeerInfoHeaderNavigationButtonSpec], expandFraction: CGFloat, transition: ContainedViewLayoutTransition) {
let maximumExpandOffset: CGFloat = 14.0 let maximumExpandOffset: CGFloat = 14.0
let expandOffset: CGFloat = -expandFraction * maximumExpandOffset let expandOffset: CGFloat = -expandFraction * maximumExpandOffset
if self.currentButtons != buttons { if self.currentButtons != buttons || presentationData.strings !== self.presentationData?.strings {
self.currentButtons = buttons self.currentButtons = buttons
var nextRegularButtonOrigin = size.width - 16.0 var nextRegularButtonOrigin = size.width - 16.0
@ -1145,6 +1142,7 @@ final class PeerInfoHeaderNavigationButtonContainerNode: ASDisplayNode {
} }
} }
} }
self.presentationData = presentationData
} }
} }
@ -1152,7 +1150,7 @@ final class PeerInfoHeaderRegularContentNode: ASDisplayNode {
} }
enum PeerInfoHeaderTextFieldNodeKey { enum PeerInfoHeaderTextFieldNodeKey: Equatable {
case firstName case firstName
case lastName case lastName
case title case title
@ -1162,15 +1160,17 @@ enum PeerInfoHeaderTextFieldNodeKey {
protocol PeerInfoHeaderTextFieldNode: ASDisplayNode { protocol PeerInfoHeaderTextFieldNode: ASDisplayNode {
var text: String { get } var text: String { get }
func update(width: CGFloat, safeInset: CGFloat, hasPrevious: Bool, placeholder: String, isEnabled: Bool, presentationData: PresentationData, updateText: String?) -> CGFloat func update(width: CGFloat, safeInset: CGFloat, isSettings: Bool, hasPrevious: Bool, hasNext: Bool, placeholder: String, isEnabled: Bool, presentationData: PresentationData, updateText: String?) -> CGFloat
} }
final class PeerInfoHeaderSingleLineTextFieldNode: ASDisplayNode, PeerInfoHeaderTextFieldNode, UITextFieldDelegate { final class PeerInfoHeaderSingleLineTextFieldNode: ASDisplayNode, PeerInfoHeaderTextFieldNode, UITextFieldDelegate {
private let backgroundNode: ASDisplayNode
private let textNode: TextFieldNode private let textNode: TextFieldNode
private let measureTextNode: ImmediateTextNode private let measureTextNode: ImmediateTextNode
private let clearIconNode: ASImageNode private let clearIconNode: ASImageNode
private let clearButtonNode: HighlightableButtonNode private let clearButtonNode: HighlightableButtonNode
private let topSeparator: ASDisplayNode private let topSeparator: ASDisplayNode
private let maskNode: ASImageNode
private var theme: PresentationTheme? private var theme: PresentationTheme?
@ -1179,6 +1179,8 @@ final class PeerInfoHeaderSingleLineTextFieldNode: ASDisplayNode, PeerInfoHeader
} }
override init() { override init() {
self.backgroundNode = ASDisplayNode()
self.textNode = TextFieldNode() self.textNode = TextFieldNode()
self.measureTextNode = ImmediateTextNode() self.measureTextNode = ImmediateTextNode()
self.measureTextNode.maximumNumberOfLines = 0 self.measureTextNode.maximumNumberOfLines = 0
@ -1194,12 +1196,17 @@ final class PeerInfoHeaderSingleLineTextFieldNode: ASDisplayNode, PeerInfoHeader
self.topSeparator = ASDisplayNode() self.topSeparator = ASDisplayNode()
self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
super.init() super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.textNode) self.addSubnode(self.textNode)
self.addSubnode(self.clearIconNode) self.addSubnode(self.clearIconNode)
self.addSubnode(self.clearButtonNode) self.addSubnode(self.clearButtonNode)
self.addSubnode(self.topSeparator) self.addSubnode(self.topSeparator)
self.addSubnode(self.maskNode)
self.textNode.textField.delegate = self self.textNode.textField.delegate = self
@ -1237,12 +1244,15 @@ final class PeerInfoHeaderSingleLineTextFieldNode: ASDisplayNode, PeerInfoHeader
self.clearButtonNode.isAccessibilityElement = isHidden self.clearButtonNode.isAccessibilityElement = isHidden
} }
func update(width: CGFloat, safeInset: CGFloat, hasPrevious: Bool, placeholder: String, isEnabled: Bool, presentationData: PresentationData, updateText: String?) -> CGFloat { func update(width: CGFloat, safeInset: CGFloat, isSettings: Bool, hasPrevious: Bool, hasNext: Bool, placeholder: String, isEnabled: Bool, presentationData: PresentationData, updateText: String?) -> CGFloat {
let titleFont = Font.regular(presentationData.listsFontSize.itemListBaseFontSize) let titleFont = Font.regular(presentationData.listsFontSize.itemListBaseFontSize)
self.textNode.textField.font = titleFont self.textNode.textField.font = titleFont
if self.theme !== presentationData.theme { if self.theme !== presentationData.theme {
self.theme = presentationData.theme self.theme = presentationData.theme
if isSettings {
self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor
}
self.textNode.textField.textColor = presentationData.theme.list.itemPrimaryTextColor self.textNode.textField.textColor = presentationData.theme.list.itemPrimaryTextColor
self.textNode.textField.keyboardAppearance = presentationData.theme.rootController.keyboardColor.keyboardAppearance self.textNode.textField.keyboardAppearance = presentationData.theme.rootController.keyboardColor.keyboardAppearance
self.textNode.textField.tintColor = presentationData.theme.list.itemAccentColor self.textNode.textField.tintColor = presentationData.theme.list.itemAccentColor
@ -1260,8 +1270,12 @@ final class PeerInfoHeaderSingleLineTextFieldNode: ASDisplayNode, PeerInfoHeader
self.textNode.textField.text = updateText self.textNode.textField.text = updateText
} }
if !hasPrevious && isSettings {
self.topSeparator.isHidden = true
}
self.topSeparator.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor 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 measureText = "|" let measureText = "|"
let attributedMeasureText = NSAttributedString(string: measureText, font: titleFont, textColor: .black) let attributedMeasureText = NSAttributedString(string: measureText, font: titleFont, textColor: .black)
@ -1276,8 +1290,16 @@ final class PeerInfoHeaderSingleLineTextFieldNode: ASDisplayNode, PeerInfoHeader
self.clearIconNode.frame = CGRect(origin: CGPoint(x: width - safeInset - buttonSize.width + floor((buttonSize.width - image.size.width) / 2.0), y: floor((height - image.size.height) / 2.0)), size: image.size) self.clearIconNode.frame = CGRect(origin: CGPoint(x: width - safeInset - buttonSize.width + floor((buttonSize.width - image.size.width) / 2.0), y: floor((height - image.size.height) / 2.0)), size: image.size)
} }
self.backgroundNode.frame = CGRect(origin: CGPoint(x: safeInset, y: 0.0), size: CGSize(width: max(1.0, width - safeInset * 2.0), height: height))
self.textNode.frame = CGRect(origin: CGPoint(x: safeInset + 16.0, y: floor((height - 40.0) / 2.0)), size: CGSize(width: max(1.0, width - 16.0 * 2.0 - 32.0), height: 40.0)) self.textNode.frame = CGRect(origin: CGPoint(x: safeInset + 16.0, y: floor((height - 40.0) / 2.0)), size: CGSize(width: max(1.0, width - 16.0 * 2.0 - 32.0), height: 40.0))
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))
self.textNode.isUserInteractionEnabled = isEnabled self.textNode.isUserInteractionEnabled = isEnabled
self.textNode.alpha = isEnabled ? 1.0 : 0.6 self.textNode.alpha = isEnabled ? 1.0 : 0.6
@ -1364,7 +1386,7 @@ final class PeerInfoHeaderMultiLineTextFieldNode: ASDisplayNode, PeerInfoHeaderT
self.updateClearButtonVisibility() self.updateClearButtonVisibility()
} }
func update(width: CGFloat, safeInset: CGFloat, hasPrevious: Bool, placeholder: String, isEnabled: Bool, presentationData: PresentationData, updateText: String?) -> CGFloat { func update(width: CGFloat, safeInset: CGFloat, isSettings: Bool, hasPrevious: Bool, hasNext: Bool, placeholder: String, isEnabled: Bool, presentationData: PresentationData, updateText: String?) -> CGFloat {
self.currentParams = (width, safeInset) self.currentParams = (width, safeInset)
self.fontSize = presentationData.listsFontSize self.fontSize = presentationData.listsFontSize
@ -1613,7 +1635,7 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
placeholder = presentationData.strings.Channel_Edit_AboutItem placeholder = presentationData.strings.Channel_Edit_AboutItem
isEnabled = canEditPeerInfo(context: self.context, peer: peer) isEnabled = canEditPeerInfo(context: self.context, peer: peer)
} }
let itemHeight = itemNode.update(width: width, safeInset: safeInset, hasPrevious: hasPrevious, placeholder: placeholder, isEnabled: isEnabled, presentationData: presentationData, updateText: updateText) let itemHeight = itemNode.update(width: width, safeInset: safeInset, isSettings: isSettings, hasPrevious: hasPrevious, hasNext: key != fieldKeys.last, placeholder: placeholder, isEnabled: isEnabled, presentationData: presentationData, updateText: updateText)
transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight))) transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight)))
contentHeight += itemHeight contentHeight += itemHeight
hasPrevious = true hasPrevious = true
@ -1671,8 +1693,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let usernameNodeRawContainer: ASDisplayNode let usernameNodeRawContainer: ASDisplayNode
let usernameNode: MultiScaleTextNode let usernameNode: MultiScaleTextNode
var buttonNodes: [PeerInfoHeaderButtonKey: PeerInfoHeaderButtonNode] = [:] var buttonNodes: [PeerInfoHeaderButtonKey: PeerInfoHeaderButtonNode] = [:]
private let backgroundNode: NavigationBackgroundNode let backgroundNode: NavigationBackgroundNode
private let expandedBackgroundNode: NavigationBackgroundNode let expandedBackgroundNode: NavigationBackgroundNode
let separatorNode: ASDisplayNode let separatorNode: ASDisplayNode
let navigationBackgroundNode: ASDisplayNode let navigationBackgroundNode: ASDisplayNode
let navigationBackgroundBackgroundNode: ASDisplayNode let navigationBackgroundBackgroundNode: ASDisplayNode
@ -1693,6 +1715,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
var navigationTransition: PeerInfoHeaderNavigationTransition? var navigationTransition: PeerInfoHeaderNavigationTransition?
var updateHeaderAlpha: ((CGFloat, ContainedViewLayoutTransition) -> Void)?
init(context: AccountContext, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, isSettings: Bool) { init(context: AccountContext, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, isSettings: Bool) {
self.context = context self.context = context
self.isAvatarExpanded = avatarInitiallyExpanded self.isAvatarExpanded = avatarInitiallyExpanded
@ -1772,16 +1796,25 @@ final class PeerInfoHeaderNode: ASDisplayNode {
self.addSubnode(self.backgroundNode) self.addSubnode(self.backgroundNode)
self.addSubnode(self.expandedBackgroundNode) self.addSubnode(self.expandedBackgroundNode)
self.titleNodeContainer.addSubnode(self.titleNode) self.titleNodeContainer.addSubnode(self.titleNode)
self.regularContentNode.addSubnode(self.titleNodeContainer)
self.subtitleNodeContainer.addSubnode(self.subtitleNode) self.subtitleNodeContainer.addSubnode(self.subtitleNode)
self.subtitleNodeContainer.addSubnode(self.panelSubtitleNode) self.subtitleNodeContainer.addSubnode(self.panelSubtitleNode)
self.regularContentNode.addSubnode(self.subtitleNodeContainer)
self.regularContentNode.addSubnode(self.subtitleNodeRawContainer)
self.usernameNodeContainer.addSubnode(self.usernameNode) self.usernameNodeContainer.addSubnode(self.usernameNode)
self.regularContentNode.addSubnode(self.usernameNodeContainer) if !self.isSettings {
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.regularContentNode.addSubnode(self.avatarListNode) self.regularContentNode.addSubnode(self.avatarListNode)
self.regularContentNode.addSubnode(self.avatarListNode.listContainerNode.controlsClippingOffsetNode) 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.addSubnode(self.regularContentNode) self.addSubnode(self.regularContentNode)
self.addSubnode(self.editingContentNode) self.addSubnode(self.editingContentNode)
self.addSubnode(self.avatarOverlayNode) self.addSubnode(self.avatarOverlayNode)
@ -1818,7 +1851,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
return return
} }
strongSelf.navigationButtonContainer.layer.animateAlpha(from: 0.0, to: strongSelf.navigationButtonContainer.alpha, duration: 0.25) strongSelf.navigationButtonContainer.layer.animateAlpha(from: 0.0, to: strongSelf.navigationButtonContainer.alpha, duration: 0.25)
strongSelf.avatarListNode.listContainerNode.shadowNode.layer.animateAlpha(from: 0.0, to: strongSelf.avatarListNode.listContainerNode.shadowNode.alpha, duration: 0.25) strongSelf.avatarListNode.listContainerNode.topShadowNode.layer.animateAlpha(from: 0.0, to: strongSelf.avatarListNode.listContainerNode.topShadowNode.alpha, duration: 0.25)
strongSelf.avatarListNode.listContainerNode.bottomShadowNode.layer.animateAlpha(from: 0.0, to: strongSelf.avatarListNode.listContainerNode.bottomShadowNode.alpha, duration: 0.25)
strongSelf.avatarListNode.listContainerNode.controlsContainerNode.layer.animateAlpha(from: 0.0, to: strongSelf.avatarListNode.listContainerNode.controlsContainerNode.alpha, duration: 0.25) strongSelf.avatarListNode.listContainerNode.controlsContainerNode.layer.animateAlpha(from: 0.0, to: strongSelf.avatarListNode.listContainerNode.controlsContainerNode.alpha, duration: 0.25)
strongSelf.animateOverlaysFadeIn?() strongSelf.animateOverlaysFadeIn?()
@ -2022,7 +2056,9 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let buttonKeys: [PeerInfoHeaderButtonKey] = self.isSettings ? [] : peerInfoHeaderButtons(peer: peer, cachedData: cachedData, isOpenedFromChat: self.isOpenedFromChat, isExpanded: false, videoCallsEnabled: self.videoCallsEnabled, isSecretChat: isSecretChat, isContact: isContact) let buttonKeys: [PeerInfoHeaderButtonKey] = self.isSettings ? [] : peerInfoHeaderButtons(peer: peer, cachedData: cachedData, isOpenedFromChat: self.isOpenedFromChat, isExpanded: false, videoCallsEnabled: self.videoCallsEnabled, isSecretChat: isSecretChat, isContact: isContact)
var isVerified = false var isVerified = false
let smallTitleString: NSAttributedString
let titleString: NSAttributedString let titleString: NSAttributedString
let smallSubtitleString: NSAttributedString
let subtitleString: NSAttributedString let subtitleString: NSAttributedString
var panelSubtitleString: NSAttributedString? var panelSubtitleString: NSAttributedString?
let usernameString: NSAttributedString let usernameString: NSAttributedString
@ -2049,17 +2085,22 @@ final class PeerInfoHeaderNode: ASDisplayNode {
title = " " title = " "
} }
} }
titleString = NSAttributedString(string: title, font: Font.semibold(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) if self.isSettings {
titleString = NSAttributedString(string: title, font: Font.semibold(26.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
}
if self.isSettings, let user = peer as? TelegramUser { if self.isSettings, let user = peer as? TelegramUser {
let formattedPhone = formatPhoneNumber(user.phone ?? "") var subtitle = formatPhoneNumber(user.phone ?? "")
subtitleString = NSAttributedString(string: formattedPhone, font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
var username = ""
if let addressName = user.addressName, !addressName.isEmpty { if let addressName = user.addressName, !addressName.isEmpty {
username = "@\(addressName)" subtitle = "\(subtitle)@\(addressName)"
} }
usernameString = NSAttributedString(string: username, font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor) smallSubtitleString = NSAttributedString(string: subtitle, font: Font.regular(15.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.7))
subtitleString = NSAttributedString(string: subtitle, font: Font.regular(17.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
} else if let statusData = statusData { } else if let statusData = statusData {
let subtitleColor: UIColor let subtitleColor: UIColor
if statusData.isActivity { if statusData.isActivity {
@ -2068,6 +2109,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
subtitleColor = presentationData.theme.list.itemSecondaryTextColor subtitleColor = presentationData.theme.list.itemSecondaryTextColor
} }
subtitleString = NSAttributedString(string: statusData.text, font: Font.regular(15.0), textColor: subtitleColor) subtitleString = NSAttributedString(string: statusData.text, font: Font.regular(15.0), textColor: subtitleColor)
smallSubtitleString = subtitleString
usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor) usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
if let panelStatusData = panelStatusData { if let panelStatusData = panelStatusData {
@ -2081,28 +2123,34 @@ final class PeerInfoHeaderNode: ASDisplayNode {
} }
} else { } else {
subtitleString = NSAttributedString(string: " ", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor) subtitleString = NSAttributedString(string: " ", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
smallSubtitleString = subtitleString
usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor) usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
} }
} else { } else {
titleString = NSAttributedString(string: " ", font: Font.semibold(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) titleString = NSAttributedString(string: " ", font: Font.semibold(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
smallTitleString = titleString
subtitleString = NSAttributedString(string: " ", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor) subtitleString = NSAttributedString(string: " ", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
smallSubtitleString = subtitleString
usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor) usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
} }
let textSideInset: CGFloat = 44.0 let textSideInset: CGFloat = 44.0
let expandedAvatarHeight: CGFloat = expandedAvatarListSize.height + expandedAvatarControlsHeight var expandedAvatarHeight: CGFloat = expandedAvatarListSize.height
if !self.isSettings {
expandedAvatarHeight += expandedAvatarControlsHeight
}
let titleConstrainedSize = CGSize(width: width - textSideInset * 2.0 - (isVerified ? 16.0 : 0.0), height: .greatestFiniteMagnitude) let titleConstrainedSize = CGSize(width: width - textSideInset * 2.0 - (isVerified ? 16.0 : 0.0), height: .greatestFiniteMagnitude)
let titleNodeLayout = self.titleNode.updateLayout(states: [ let titleNodeLayout = self.titleNode.updateLayout(states: [
TitleNodeStateRegular: MultiScaleTextState(attributedText: titleString, constrainedSize: titleConstrainedSize), TitleNodeStateRegular: MultiScaleTextState(attributedText: titleString, constrainedSize: titleConstrainedSize),
TitleNodeStateExpanded: MultiScaleTextState(attributedText: titleString, constrainedSize: CGSize(width: titleConstrainedSize.width, height: titleConstrainedSize.height)) TitleNodeStateExpanded: MultiScaleTextState(attributedText: smallTitleString, constrainedSize: CGSize(width: titleConstrainedSize.width, height: titleConstrainedSize.height))
], mainState: TitleNodeStateRegular) ], mainState: TitleNodeStateRegular)
self.titleNode.accessibilityLabel = titleString.string self.titleNode.accessibilityLabel = titleString.string
let subtitleNodeLayout = self.subtitleNode.updateLayout(states: [ let subtitleNodeLayout = self.subtitleNode.updateLayout(states: [
TitleNodeStateRegular: MultiScaleTextState(attributedText: subtitleString, constrainedSize: titleConstrainedSize), TitleNodeStateRegular: MultiScaleTextState(attributedText: subtitleString, constrainedSize: titleConstrainedSize),
TitleNodeStateExpanded: MultiScaleTextState(attributedText: subtitleString, constrainedSize: CGSize(width: titleConstrainedSize.width - 82.0, height: titleConstrainedSize.height)) TitleNodeStateExpanded: MultiScaleTextState(attributedText: smallSubtitleString, constrainedSize: self.isSettings ? titleConstrainedSize : CGSize(width: titleConstrainedSize.width - 82.0, height: titleConstrainedSize.height))
], mainState: TitleNodeStateRegular) ], mainState: TitleNodeStateRegular)
self.subtitleNode.accessibilityLabel = subtitleString.string self.subtitleNode.accessibilityLabel = subtitleString.string
@ -2133,26 +2181,40 @@ final class PeerInfoHeaderNode: ASDisplayNode {
transition.updateFrame(node: self.titleExpandedCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleExpandedSize.width + 4.0, y: floor((titleExpandedSize.height - image.size.height) / 2.0) + 1.0), size: image.size)) transition.updateFrame(node: self.titleExpandedCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleExpandedSize.width + 4.0, y: floor((titleExpandedSize.height - image.size.height) / 2.0) + 1.0), size: image.size))
} }
let titleFrame: CGRect var titleFrame: CGRect
let subtitleFrame: CGRect let subtitleFrame: CGRect
let usernameFrame: CGRect let usernameFrame: CGRect
let usernameSpacing: CGFloat = 4.0 let usernameSpacing: CGFloat = 4.0
var twoLineInfo = false 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)))
}
if self.isAvatarExpanded { if self.isAvatarExpanded {
let minTitleSize = CGSize(width: titleSize.width * 0.7, height: titleSize.height * 0.7) let minTitleSize = CGSize(width: titleSize.width * 0.7, height: titleSize.height * 0.7)
let minTitleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - expandedAvatarControlsHeight + 9.0 + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: minTitleSize) let minTitleFrame: CGRect
if self.isSettings {
minTitleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - 58.0 + (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)
}
titleFrame = CGRect(origin: CGPoint(x: minTitleFrame.midX - titleSize.width / 2.0, y: minTitleFrame.midY - titleSize.height / 2.0), size: titleSize) titleFrame = CGRect(origin: CGPoint(x: minTitleFrame.midX - titleSize.width / 2.0, y: minTitleFrame.midY - titleSize.height / 2.0), size: titleSize)
subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: minTitleFrame.maxY + 4.0), size: subtitleSize) 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)
}
usernameFrame = CGRect(origin: CGPoint(x: width - usernameSize.width - 16.0, y: minTitleFrame.midY - usernameSize.height / 2.0), size: usernameSize) usernameFrame = CGRect(origin: CGPoint(x: width - usernameSize.width - 16.0, y: minTitleFrame.midY - usernameSize.height / 2.0), size: usernameSize)
} else { } else {
titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 10.0 + (subtitleSize.height.isZero ? 11.0 : 0.0)), size: titleSize) titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 10.0 + (subtitleSize.height.isZero ? 11.0 : 0.0)), size: titleSize)
if self.isSettings {
titleFrame = titleFrame.offsetBy(dx: 0.0, dy: 13.0)
}
let totalSubtitleWidth = subtitleSize.width + usernameSpacing + usernameSize.width let totalSubtitleWidth = subtitleSize.width + usernameSpacing + usernameSize.width
twoLineInfo = true twoLineInfo = false
if usernameSize.width == 0.0 || twoLineInfo { if usernameSize.width == 0.0 || twoLineInfo {
subtitleFrame = CGRect(origin: CGPoint(x: floor((width - subtitleSize.width) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize) 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) usernameFrame = CGRect(origin: CGPoint(x: floor((width - usernameSize.width) / 2.0), y: subtitleFrame.maxY + 1.0), size: usernameSize)
} else { } else {
subtitleFrame = CGRect(origin: CGPoint(x: floor((width - totalSubtitleWidth) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize) subtitleFrame = CGRect(origin: CGPoint(x: floor((width - totalSubtitleWidth) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize)
usernameFrame = CGRect(origin: CGPoint(x: subtitleFrame.maxX + usernameSpacing, y: titleFrame.maxY + 1.0), size: usernameSize) usernameFrame = CGRect(origin: CGPoint(x: subtitleFrame.maxX + usernameSpacing, y: titleFrame.maxY + 1.0), size: usernameSize)
@ -2200,6 +2262,12 @@ final class PeerInfoHeaderNode: ASDisplayNode {
if self.isSettings { if self.isSettings {
subtitleAlpha = 1.0 - titleCollapseFraction subtitleAlpha = 1.0 - titleCollapseFraction
panelSubtitleAlpha = 0.0 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 { } else {
if (panelSubtitleString ?? subtitleString).string != subtitleString.string { if (panelSubtitleString ?? subtitleString).string != subtitleString.string {
subtitleAlpha = 1.0 - effectiveAreaExpansionFraction subtitleAlpha = 1.0 - effectiveAreaExpansionFraction
@ -2315,7 +2383,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
transition.updateFrame(node: self.avatarListNode.listContainerNode.controlsClippingNode, frame: CGRect(origin: CGPoint(x: -controlsClippingFrame.width / 2.0, y: -controlsClippingFrame.height / 2.0), size: controlsClippingFrame.size)) transition.updateFrame(node: self.avatarListNode.listContainerNode.controlsClippingNode, frame: CGRect(origin: CGPoint(x: -controlsClippingFrame.width / 2.0, y: -controlsClippingFrame.height / 2.0), size: controlsClippingFrame.size))
transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.controlsContainerNode, frame: CGRect(origin: CGPoint(x: -controlsClippingFrame.minX, y: -controlsClippingFrame.minY), size: CGSize(width: expandedAvatarListSize.width, height: expandedAvatarListSize.height))) transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.controlsContainerNode, frame: CGRect(origin: CGPoint(x: -controlsClippingFrame.minX, y: -controlsClippingFrame.minY), size: CGSize(width: expandedAvatarListSize.width, height: expandedAvatarListSize.height)))
transition.updateFrame(node: self.avatarListNode.listContainerNode.shadowNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: expandedAvatarListSize.width, height: navigationHeight + 20.0))) transition.updateFrame(node: self.avatarListNode.listContainerNode.topShadowNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: expandedAvatarListSize.width, height: navigationHeight + 20.0)))
transition.updateFrame(node: self.avatarListNode.listContainerNode.stripContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: statusBarHeight < 25.0 ? (statusBarHeight + 2.0) : (statusBarHeight - 3.0)), size: CGSize(width: expandedAvatarListSize.width, height: 2.0))) transition.updateFrame(node: self.avatarListNode.listContainerNode.stripContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: statusBarHeight < 25.0 ? (statusBarHeight + 2.0) : (statusBarHeight - 3.0)), size: CGSize(width: expandedAvatarListSize.width, height: 2.0)))
transition.updateFrame(node: self.avatarListNode.listContainerNode.highlightContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: expandedAvatarListSize.width, height: expandedAvatarListSize.height))) transition.updateFrame(node: self.avatarListNode.listContainerNode.highlightContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: expandedAvatarListSize.width, height: expandedAvatarListSize.height)))
transition.updateAlpha(node: self.avatarListNode.listContainerNode.controlsContainerNode, alpha: self.isAvatarExpanded ? (1.0 - transitionFraction) : 0.0) transition.updateAlpha(node: self.avatarListNode.listContainerNode.controlsContainerNode, alpha: self.isAvatarExpanded ? (1.0 - transitionFraction) : 0.0)
@ -2599,7 +2667,11 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let resolvedRegularHeight: CGFloat let resolvedRegularHeight: CGFloat
if self.isAvatarExpanded { if self.isAvatarExpanded {
resolvedRegularHeight = expandedAvatarListSize.height + expandedAvatarControlsHeight if self.isSettings {
resolvedRegularHeight = expandedAvatarListSize.height
} else {
resolvedRegularHeight = expandedAvatarListSize.height + expandedAvatarControlsHeight
}
} else { } else {
resolvedRegularHeight = panelWithAvatarHeight + navigationHeight resolvedRegularHeight = panelWithAvatarHeight + navigationHeight
} }

View File

@ -172,7 +172,8 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode {
itemTransition.updateFrame(node: itemNode, frame: itemFrame) itemTransition.updateFrame(node: itemNode, frame: itemFrame)
if wasAdded { if wasAdded {
itemNode.alpha = 0.0 itemNode.alpha = 0.0
transition.updateAlpha(node: itemNode, alpha: 1.0) let alphaTransition: ContainedViewLayoutTransition = transition.isAnimated ? .animated(duration: 0.35, curve: .linear) : .immediate
alphaTransition.updateAlpha(node: itemNode, alpha: 1.0)
} }
if item is PeerInfoScreenCommentItem { if item is PeerInfoScreenCommentItem {
@ -1639,6 +1640,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
self.paneContainerNode.parentController = controller self.paneContainerNode.parentController = controller
self.headerNode.updateHeaderAlpha = { [weak self] alpha, transition in
self?.updateHeaderBackgroundAlpha(alpha, transition: transition)
}
self._interaction = PeerInfoInteraction( self._interaction = PeerInfoInteraction(
openUsername: { [weak self] value in openUsername: { [weak self] value in
self?.openUsername(value: value) self?.openUsername(value: value)
@ -2971,6 +2976,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
override func didLoad() { override func didLoad() {
super.didLoad() super.didLoad()
if self.isSettings {
self.updateHeaderBackgroundAlpha(0.0, transition: .immediate)
}
self.view.disablesInteractiveTransitionGestureRecognizerNow = { [weak self] in self.view.disablesInteractiveTransitionGestureRecognizerNow = { [weak self] in
if let strongSelf = self { if let strongSelf = self {
return strongSelf.state.isEditing return strongSelf.state.isEditing
@ -2980,6 +2989,14 @@ 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? var canAttachVideo: Bool?
private func updateData(_ data: PeerInfoScreenData) { private func updateData(_ data: PeerInfoScreenData) {
@ -6326,7 +6343,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
var contentHeight: CGFloat = 0.0 var contentHeight: CGFloat = 0.0
let headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: layout.safeInsets.left, 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) let sectionInset = max(16.0, floor((layout.size.width - 674.0) / 2.0))
let headerInset: CGFloat
if self.isSettings {
headerInset = sectionInset
} else {
headerInset = layout.safeInsets.left
}
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)
let headerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: headerHeight)) let headerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: headerHeight))
if additive { if additive {
transition.updateFrameAdditive(node: self.headerNode, frame: headerFrame) transition.updateFrameAdditive(node: self.headerNode, frame: headerFrame)
@ -6341,10 +6366,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
var validRegularSections: [AnyHashable] = [] var validRegularSections: [AnyHashable] = []
if !self.isMediaOnly { if !self.isMediaOnly {
var insets = UIEdgeInsets() var insets = UIEdgeInsets()
let inset = max(16.0, floor((layout.size.width - 674.0) / 2.0))
if self.isSettings { if self.isSettings {
insets.left += inset insets.left += sectionInset
insets.right += inset insets.right += sectionInset
} else { } else {
insets = layout.safeInsets insets = layout.safeInsets
} }
@ -6363,6 +6387,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
for (sectionId, sectionItems) in items { for (sectionId, sectionItems) in items {
validRegularSections.append(sectionId) validRegularSections.append(sectionId)
var wasAdded = false
let sectionNode: PeerInfoScreenItemSectionContainerNode let sectionNode: PeerInfoScreenItemSectionContainerNode
if let current = self.regularSections[sectionId] { if let current = self.regularSections[sectionId] {
sectionNode = current sectionNode = current
@ -6370,6 +6395,12 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
sectionNode = PeerInfoScreenItemSectionContainerNode() sectionNode = PeerInfoScreenItemSectionContainerNode()
self.regularSections[sectionId] = sectionNode self.regularSections[sectionId] = sectionNode
self.scrollNode.addSubnode(sectionNode) self.scrollNode.addSubnode(sectionNode)
wasAdded = true
}
if wasAdded && transition.isAnimated && self.isSettings && !self.state.isEditing {
sectionNode.alpha = 0.0
transition.updateAlpha(node: sectionNode, alpha: 1.0)
} }
let sectionHeight = sectionNode.update(width: layout.size.width, safeInsets: insets, presentationData: self.presentationData, items: sectionItems, transition: transition) let sectionHeight = sectionNode.update(width: layout.size.width, safeInsets: insets, presentationData: self.presentationData, items: sectionItems, transition: transition)
@ -6405,9 +6436,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
for (sectionId, sectionItems) in editItems { for (sectionId, sectionItems) in editItems {
var insets = UIEdgeInsets() var insets = UIEdgeInsets()
let inset = max(16.0, floor((layout.size.width - 674.0) / 2.0)) insets.left += sectionInset
insets.left += inset insets.right += sectionInset
insets.right += inset
if self.state.isEditing { if self.state.isEditing {
currentInsets = insets currentInsets = insets
@ -6583,9 +6613,18 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
} }
} }
private func updateNavigation(transition: ContainedViewLayoutTransition, additive: Bool) { fileprivate func updateNavigation(transition: ContainedViewLayoutTransition, additive: Bool) {
let offsetY = self.scrollNode.view.contentOffset.y let offsetY = self.scrollNode.view.contentOffset.y
if self.isSettings, !(self.controller?.movingInHierarchy == true) {
let bottomOffsetY = self.scrollNode.view.contentSize.height + self.scrollNode.view.contentInset.bottom - offsetY - self.scrollNode.frame.height
let backgroundAlpha: CGFloat = min(30.0, bottomOffsetY) / 30.0
if let tabBarController = self.controller?.parent as? TabBarController {
tabBarController.updateBackgroundAlpha(backgroundAlpha, transition: transition)
}
}
if self.state.isEditing || offsetY <= 50.0 || self.paneContainerNode.alpha.isZero { if self.state.isEditing || offsetY <= 50.0 || self.paneContainerNode.alpha.isZero {
if !self.scrollNode.view.bounces { if !self.scrollNode.view.bounces {
self.scrollNode.view.bounces = true self.scrollNode.view.bounces = true
@ -6600,7 +6639,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
if let (layout, navigationHeight) = self.validLayout { if let (layout, navigationHeight) = self.validLayout {
if !additive { if !additive {
let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: layout.safeInsets.left, 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) let sectionInset = max(16.0, floor((layout.size.width - 674.0) / 2.0))
let headerInset: CGFloat
if self.isSettings {
headerInset = sectionInset
} else {
headerInset = layout.safeInsets.left
}
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)
} }
let paneAreaExpansionDistance: CGFloat = 32.0 let paneAreaExpansionDistance: CGFloat = 32.0
@ -7215,12 +7262,27 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen {
super.displayNodeDidLoad() super.displayNodeDidLoad()
} }
fileprivate var movingInHierarchy = false
public override func willMove(toParent viewController: UIViewController?) {
super.willMove(toParent: parent)
if self.isSettings, viewController == nil, let tabBarController = self.parent as? TabBarController {
self.movingInHierarchy = true
tabBarController.updateBackgroundAlpha(1.0, transition: .immediate)
}
}
public override func didMove(toParent viewController: UIViewController?) { public override func didMove(toParent viewController: UIViewController?) {
super.didMove(toParent: viewController) super.didMove(toParent: viewController)
if self.isSettings && viewController == nil { if self.isSettings {
Queue.mainQueue().after(0.1) { if viewController == nil {
self.controllerNode.resetHeaderExpansion() self.movingInHierarchy = false
Queue.mainQueue().after(0.1) {
self.controllerNode.resetHeaderExpansion()
}
} else {
self.controllerNode.updateNavigation(transition: .immediate, additive: false)
} }
} }
} }
@ -7475,8 +7537,17 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig
self.headerNode.navigationTransition = PeerInfoHeaderNavigationTransition(sourceNavigationBar: bottomNavigationBar, sourceTitleView: previousTitleView, sourceTitleFrame: previousTitleFrame, sourceSubtitleFrame: previousStatusFrame, fraction: fraction) self.headerNode.navigationTransition = PeerInfoHeaderNavigationTransition(sourceNavigationBar: bottomNavigationBar, sourceTitleView: previousTitleView, sourceTitleFrame: previousTitleFrame, sourceSubtitleFrame: previousStatusFrame, fraction: fraction)
var topHeight = topNavigationBar.backgroundNode.bounds.height var topHeight = topNavigationBar.backgroundNode.bounds.height
if let (layout, _) = self.screenNode.validLayout { if let (layout, _) = self.screenNode.validLayout {
topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: layout.safeInsets.left, 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) let sectionInset = max(16.0, floor((layout.size.width - 674.0) / 2.0))
let headerInset: CGFloat
if screenNode.isSettings {
headerInset = sectionInset
} else {
headerInset = layout.safeInsets.left
}
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)
} }
let titleScale = (fraction * previousTitleNode.bounds.height + (1.0 - fraction) * self.headerNode.titleNodeRawContainer.bounds.height) / previousTitleNode.bounds.height let titleScale = (fraction * previousTitleNode.bounds.height + (1.0 - fraction) * self.headerNode.titleNodeRawContainer.bounds.height) / previousTitleNode.bounds.height

View File

@ -138,7 +138,7 @@ static const void *userInfoKey = &userInfoKey;
- (void)_ac91f40f_setBackBarButtonItem:(UIBarButtonItem *)backBarButtonItem - (void)_ac91f40f_setBackBarButtonItem:(UIBarButtonItem *)backBarButtonItem
{ {
UIBarButtonItem *previousItem = self.rightBarButtonItem; UIBarButtonItem *previousItem = self.backBarButtonItem;
[self _ac91f40f_setBackBarButtonItem:backBarButtonItem]; [self _ac91f40f_setBackBarButtonItem:backBarButtonItem];