mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-07 14:53:35 +00:00
Merge commit '78db6173fb9fb575f8f1a09c73109c4936e5491c' into beta
This commit is contained in:
commit
5a811112b3
@ -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";
|
||||||
|
|||||||
@ -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)))
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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?
|
||||||
|
|||||||
@ -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))
|
||||||
|
|||||||
@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()))
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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()
|
||||||
|
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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):
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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))
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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()
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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])
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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>) {
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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> {
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
12
submodules/TelegramUI/Images.xcassets/Settings/Reset.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Settings/Reset.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Icon-36.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
88
submodules/TelegramUI/Images.xcassets/Settings/Reset.imageset/Icon-36.pdf
vendored
Normal file
88
submodules/TelegramUI/Images.xcassets/Settings/Reset.imageset/Icon-36.pdf
vendored
Normal 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
|
||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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)))
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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];
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user