Invite Links Improvements

This commit is contained in:
Ilya Laktyushin 2021-02-03 19:26:30 +04:00
parent ec5b5173e0
commit 2aa619502c
29 changed files with 4522 additions and 3535 deletions

View File

@ -5902,6 +5902,9 @@ Sorry for the inconvenience.";
"InviteLink.InviteLinkCopiedText" = "Invite link copied to clipboard"; "InviteLink.InviteLinkCopiedText" = "Invite link copied to clipboard";
"InviteLink.OtherAdminsLinks" = "Invite Links Created By Other Admins";
"InviteLink.OtherPermanentLinkInfo" = "**%1$@** can see this link and use it to invite new members to **%2$@**.";
"Conversation.ChecksTooltip.Delivered" = "Delivered"; "Conversation.ChecksTooltip.Delivered" = "Delivered";
"Conversation.ChecksTooltip.Read" = "Read"; "Conversation.ChecksTooltip.Read" = "Read";

View File

@ -474,7 +474,7 @@ final class InviteContactsControllerNode: ASDisplayNode {
var headerInsets = layout.insets(options: [.input]) var headerInsets = layout.insets(options: [.input])
headerInsets.top += actualNavigationBarHeight headerInsets.top += actualNavigationBarHeight
let countPanelHeight = self.countPanelNode.updateLayout(width: layout.size.width, bottomInset: layout.intrinsicInsets.bottom, transition: transition) let countPanelHeight = self.countPanelNode.updateLayout(width: layout.size.width, sideInset: layout.safeInsets.left, bottomInset: layout.intrinsicInsets.bottom, transition: transition)
if self.selectionState.selectedContactIndices.isEmpty { if self.selectionState.selectedContactIndices.isEmpty {
transition.updateFrame(node: self.countPanelNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height), size: CGSize(width: layout.size.width, height: countPanelHeight))) transition.updateFrame(node: self.countPanelNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height), size: CGSize(width: layout.size.width, height: countPanelHeight)))
} else { } else {

View File

@ -12,15 +12,15 @@ final class InviteContactsCountPanelNode: ASDisplayNode {
private let separatorNode: ASDisplayNode private let separatorNode: ASDisplayNode
private let button: SolidRoundedButtonNode private let button: SolidRoundedButtonNode
private var validLayout: (CGFloat, CGFloat)? private var validLayout: (CGFloat, CGFloat, CGFloat)?
var count: Int = 0 { var count: Int = 0 {
didSet { didSet {
if self.count != oldValue && self.count > 0 { if self.count != oldValue && self.count > 0 {
self.button.title = self.strings.Contacts_InviteContacts(Int32(self.count)) self.button.title = self.strings.Contacts_InviteContacts(Int32(self.count))
if let (width, bottomInset) = self.validLayout { if let (width, sideInset, bottomInset) = self.validLayout {
let _ = self.updateLayout(width: width, bottomInset: bottomInset, transition: .immediate) let _ = self.updateLayout(width: width, sideInset: sideInset, bottomInset: bottomInset, transition: .immediate)
} }
} }
} }
@ -47,13 +47,13 @@ final class InviteContactsCountPanelNode: ASDisplayNode {
} }
} }
func updateLayout(width: CGFloat, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat { func updateLayout(width: CGFloat, sideInset: CGFloat, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
self.validLayout = (width, bottomInset) self.validLayout = (width, sideInset, bottomInset)
let topInset: CGFloat = 9.0 let topInset: CGFloat = 9.0
var bottomInset = bottomInset var bottomInset = bottomInset
bottomInset += topInset - (bottomInset.isZero ? 0.0 : 4.0) bottomInset += topInset - (bottomInset.isZero ? 0.0 : 4.0)
let buttonInset: CGFloat = 16.0 let buttonInset: CGFloat = 16.0 + sideInset
let buttonWidth = width - buttonInset * 2.0 let buttonWidth = width - buttonInset * 2.0
let buttonHeight = self.button.updateLayout(width: buttonWidth, transition: transition) let buttonHeight = self.button.updateLayout(width: buttonWidth, transition: transition)
transition.updateFrame(node: self.button, frame: CGRect(x: buttonInset, y: topInset, width: buttonWidth, height: buttonHeight)) transition.updateFrame(node: self.button, frame: CGRect(x: buttonInset, y: topInset, width: buttonWidth, height: buttonHeight))

View File

@ -5,9 +5,6 @@ import AsyncDisplayKit
import TelegramPresentationData import TelegramPresentationData
import TelegramStringFormatting import TelegramStringFormatting
private let textFont = Font.regular(13.0)
private let selectedTextFont = Font.bold(13.0)
public final class DatePickerTheme: Equatable { public final class DatePickerTheme: Equatable {
public let backgroundColor: UIColor public let backgroundColor: UIColor
public let textColor: UIColor public let textColor: UIColor
@ -15,18 +12,16 @@ public final class DatePickerTheme: Equatable {
public let accentColor: UIColor public let accentColor: UIColor
public let disabledColor: UIColor public let disabledColor: UIColor
public let selectionColor: UIColor public let selectionColor: UIColor
public let selectedCurrentTextColor: UIColor public let selectionTextColor: UIColor
public let secondarySelectionColor: UIColor
public init(backgroundColor: UIColor, textColor: UIColor, secondaryTextColor: UIColor, accentColor: UIColor, disabledColor: UIColor, selectionColor: UIColor, selectedCurrentTextColor: UIColor, secondarySelectionColor: UIColor) { public init(backgroundColor: UIColor, textColor: UIColor, secondaryTextColor: UIColor, accentColor: UIColor, disabledColor: UIColor, selectionColor: UIColor, selectionTextColor: UIColor) {
self.backgroundColor = backgroundColor self.backgroundColor = backgroundColor
self.textColor = textColor self.textColor = textColor
self.secondaryTextColor = secondaryTextColor self.secondaryTextColor = secondaryTextColor
self.accentColor = accentColor self.accentColor = accentColor
self.disabledColor = disabledColor self.disabledColor = disabledColor
self.selectionColor = selectionColor self.selectionColor = selectionColor
self.selectedCurrentTextColor = selectedCurrentTextColor self.selectionTextColor = selectionTextColor
self.secondarySelectionColor = secondarySelectionColor
} }
public static func ==(lhs: DatePickerTheme, rhs: DatePickerTheme) -> Bool { public static func ==(lhs: DatePickerTheme, rhs: DatePickerTheme) -> Bool {
@ -45,31 +40,26 @@ public final class DatePickerTheme: Equatable {
if lhs.selectionColor != rhs.selectionColor { if lhs.selectionColor != rhs.selectionColor {
return false return false
} }
if lhs.selectedCurrentTextColor != rhs.selectedCurrentTextColor { if lhs.selectionTextColor != rhs.selectionTextColor {
return false
}
if lhs.secondarySelectionColor != rhs.secondarySelectionColor {
return false return false
} }
return true return true
} }
} }
//public extension DatePickerTheme { public extension DatePickerTheme {
// convenience init(theme: PresentationTheme) { convenience init(theme: PresentationTheme) {
// self.init(backgroundColor: theme.rootController.navigationBar.segmentedBackgroundColor, foregroundColor: theme.rootController.navigationBar.segmentedForegroundColor, shadowColor: .black, textColor: theme.rootController.navigationBar.segmentedTextColor, dividerColor: theme.rootController.navigationBar.segmentedDividerColor) self.init(backgroundColor: theme.list.itemBlocksBackgroundColor, textColor: theme.list.itemPrimaryTextColor, secondaryTextColor: theme.list.itemSecondaryTextColor, accentColor: theme.list.itemAccentColor, disabledColor: theme.list.itemDisabledTextColor, selectionColor: theme.list.itemCheckColors.fillColor, selectionTextColor: theme.list.itemCheckColors.foregroundColor)
// } }
//}
private class SegmentedControlItemNode: HighlightTrackingButtonNode {
} }
private let telegramReleaseDate = Date(timeIntervalSince1970: 1376438400.0) private let telegramReleaseDate = Date(timeIntervalSince1970: 1376438400.0)
private let upperLimitDate = Date(timeIntervalSince1970: Double(Int32.max - 1)) private let upperLimitDate = Date(timeIntervalSince1970: Double(Int32.max - 1))
private let controlFont = Font.regular(17.0)
private let dayFont = Font.regular(13.0) private let dayFont = Font.regular(13.0)
private let dateFont = Font.with(size: 13.0, design: .regular, traits: .monospacedNumbers) private let dateFont = Font.with(size: 17.0, design: .regular, traits: .monospacedNumbers)
private let selectedDateFont = Font.bold(13.0) private let selectedDateFont = Font.with(size: 17.0, design: .regular, traits: [.bold, .monospacedNumbers])
private let calendar = Calendar(identifier: .gregorian) private let calendar = Calendar(identifier: .gregorian)
@ -81,12 +71,46 @@ private func monthForDate(_ date: Date) -> Date {
return calendar.date(from: components)! return calendar.date(from: components)!
} }
public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate { private func generateSmallArrowImage(color: UIColor) -> UIImage? {
return generateImage(CGSize(width: 7.0, height: 12.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setStrokeColor(color.cgColor)
context.setLineWidth(2.0)
context.setLineCap(.round)
context.beginPath()
context.move(to: CGPoint(x: 1.0, y: 1.0))
context.addLine(to: CGPoint(x: size.width - 1.0, y: size.height / 2.0))
context.addLine(to: CGPoint(x: 1.0, y: size.height - 1.0))
context.strokePath()
})
}
private func generateNavigationArrowImage(color: UIColor, mirror: Bool) -> UIImage? {
return generateImage(CGSize(width: 10.0, height: 17.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setStrokeColor(color.cgColor)
context.setLineWidth(2.0)
context.setLineCap(.round)
context.beginPath()
if mirror {
context.translateBy(x: 5.0, y: 8.5)
context.scaleBy(x: -1.0, y: 1.0)
context.translateBy(x: -5.0, y: -8.5)
}
context.move(to: CGPoint(x: 1.0, y: 1.0))
context.addLine(to: CGPoint(x: size.width - 1.0, y: size.height / 2.0))
context.addLine(to: CGPoint(x: 1.0, y: size.height - 1.0))
context.strokePath()
})
}
public final class DatePickerNode: ASDisplayNode {
class MonthNode: ASDisplayNode { class MonthNode: ASDisplayNode {
private let month: Date private let month: Date
var theme: DatePickerTheme { var theme: DatePickerTheme {
didSet { didSet {
self.selectionNode.image = generateStretchableFilledCircleImage(diameter: 44.0, color: self.theme.selectionColor)
if let size = self.validSize { if let size = self.validSize {
self.updateLayout(size: size) self.updateLayout(size: size)
} }
@ -136,6 +160,7 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
self.selectionNode = ASImageNode() self.selectionNode = ASImageNode()
self.selectionNode.displaysAsynchronously = false self.selectionNode.displaysAsynchronously = false
self.selectionNode.displayWithoutProcessing = true self.selectionNode.displayWithoutProcessing = true
self.selectionNode.image = generateStretchableFilledCircleImage(diameter: 44.0, color: theme.selectionColor)
self.dateNodes = (0..<42).map { _ in ImmediateTextNode() } self.dateNodes = (0..<42).map { _ in ImmediateTextNode() }
@ -157,6 +182,10 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
var started = false var started = false
var count = 0 var count = 0
let sideInset: CGFloat = 12.0
let cellSize: CGFloat = floor((size.width - sideInset * 2.0) / 7.0)
self.selectionNode.isHidden = true
for i in 0 ..< 42 { for i in 0 ..< 42 {
let row: Int = Int(floor(Float(i) / 7.0)) let row: Int = Int(floor(Float(i) / 7.0))
let col: Int = i % 7 let col: Int = i % 7
@ -164,49 +193,55 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
if !started && weekday == self.startWeekday { if !started && weekday == self.startWeekday {
started = true started = true
} }
weekday += 1
if started { if started {
count += 1 count += 1
var isAvailableDate = true var isAvailableDate = true
var components = calendar.dateComponents([.year, .month], from: self.month)
components.day = count
components.hour = 0
components.minute = 0
let date = calendar.date(from: components)!
if let minimumDate = self.minimumDate { if let minimumDate = self.minimumDate {
var components = calendar.dateComponents([.year, .month], from: self.month)
components.day = count
components.hour = 0
components.minute = 0
let date = calendar.date(from: components)!
if date < minimumDate { if date < minimumDate {
isAvailableDate = false isAvailableDate = false
} }
} }
if let maximumDate = self.maximumDate { if let maximumDate = self.maximumDate {
var components = calendar.dateComponents([.year, .month], from: self.month)
components.day = count
components.hour = 0
components.minute = 0
let date = calendar.date(from: components)!
if date > maximumDate { if date > maximumDate {
isAvailableDate = false isAvailableDate = false
} }
} }
var isSelectedDate = false let isToday = calendar.isDateInToday(date)
var isSelectedAndCurrentDate = false let isSelected = self.date.flatMap { calendar.isDate(date, equalTo: $0, toGranularity: .day) } ?? false
let color: UIColor let color: UIColor
if !isAvailableDate { if isSelected {
color = self.theme.disabledColor color = self.theme.selectionTextColor
} else if isSelectedAndCurrentDate { } else if isToday {
color = .white
} else if isSelectedDate {
color = self.theme.accentColor color = self.theme.accentColor
} else if !isAvailableDate {
color = self.theme.disabledColor
} else { } else {
color = self.theme.textColor color = self.theme.textColor
} }
let textNode = self.dateNodes[i] let textNode = self.dateNodes[i]
textNode.attributedText = NSAttributedString(string: "\(count)", font: dateFont, textColor: color) textNode.attributedText = NSAttributedString(string: "\(count)", font: isSelected ? selectedDateFont : dateFont, textColor: color)
let textSize = textNode.updateLayout(size) let textSize = textNode.updateLayout(size)
textNode.frame = CGRect(origin: CGPoint(x: CGFloat(col) * 20.0, y: CGFloat(row) * 20.0), size: textSize)
let cellFrame = CGRect(x: sideInset + CGFloat(col) * cellSize, y: 0.0 + CGFloat(row) * cellSize, width: cellSize, height: cellSize)
let textFrame = CGRect(origin: CGPoint(x: cellFrame.minX + floor((cellFrame.width - textSize.width) / 2.0), y: cellFrame.minY + floor((cellFrame.height - textSize.height) / 2.0)), size: textSize)
textNode.frame = textFrame
if isSelected {
self.selectionNode.isHidden = false
let selectionSize = CGSize(width: 44.0, height: 44.0)
self.selectionNode.frame = CGRect(origin: CGPoint(x: cellFrame.minX + floor((cellFrame.width - selectionSize.width) / 2.0), y: cellFrame.minY + floor((cellFrame.height - selectionSize.height) / 2.0)), size: selectionSize)
}
if count == self.numberOfDays { if count == self.numberOfDays {
break break
@ -233,39 +268,74 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
private let timeTitleNode: ImmediateTextNode private let timeTitleNode: ImmediateTextNode
private let timeFieldNode: ASImageNode private let timeFieldNode: ASImageNode
private let dayNodes: [ImmediateTextNode]
private var currentIndex = 0
private var months: [Date] = []
private var monthNodes: [Date: MonthNode] = [:]
private let contentNode: ASDisplayNode
private let pickerBackgroundNode: ASDisplayNode
private var pickerNode: MonthPickerNode
private let monthButtonNode: HighlightTrackingButtonNode private let monthButtonNode: HighlightTrackingButtonNode
private let monthTextNode: ImmediateTextNode private let monthTextNode: ImmediateTextNode
private let monthArrowNode: ASImageNode private let monthArrowNode: ASImageNode
private let previousButtonNode: HighlightableButtonNode private let previousButtonNode: HighlightableButtonNode
private let nextButtonNode: HighlightableButtonNode private let nextButtonNode: HighlightableButtonNode
private let dayNodes: [ImmediateTextNode] private var transitionFraction: CGFloat = 0.0
private var previousMonthNode: MonthNode?
private var currentMonthNode: MonthNode?
private var nextMonthNode: MonthNode?
private let scrollNode: ASScrollNode
private var gestureRecognizer: UIPanGestureRecognizer? private var gestureRecognizer: UIPanGestureRecognizer?
private var gestureSelectedIndex: Int? private var gestureSelectedIndex: Int?
private var validLayout: CGSize? private var validLayout: CGSize?
public var maximumDate: Date? { public var maximumDate: Date {
didSet { get {
return self.state.maxDate
} }
} set {
public var minimumDate: Date = telegramReleaseDate { guard newValue != self.maximumDate else {
didSet {
}
}
public var date: Date = Date() {
didSet {
guard self.date != oldValue else {
return return
} }
let updatedState = State(minDate: self.state.minDate, maxDate: newValue, date: self.state.date, displayingMonthSelection: self.state.displayingMonthSelection, selectedMonth: self.state.selectedMonth)
self.updateState(updatedState, animated: false)
if let size = self.validLayout {
let _ = self.updateLayout(size: size, transition: .immediate)
}
}
}
public var minimumDate: Date {
get {
return self.state.minDate
}
set {
guard newValue != self.minimumDate else {
return
}
let updatedState = State(minDate: newValue, maxDate: self.state.maxDate, date: self.state.date, displayingMonthSelection: self.state.displayingMonthSelection, selectedMonth: self.state.selectedMonth)
self.updateState(updatedState, animated: false)
if let size = self.validLayout {
let _ = self.updateLayout(size: size, transition: .immediate)
}
}
}
public var date: Date {
get {
return self.state.date
}
set {
guard newValue != self.date else {
return
}
let updatedState = State(minDate: self.state.minDate, maxDate: self.state.maxDate, date: newValue, displayingMonthSelection: self.state.displayingMonthSelection, selectedMonth: self.state.selectedMonth)
self.updateState(updatedState, animated: false)
if let size = self.validLayout { if let size = self.validLayout {
let _ = self.updateLayout(size: size, transition: .immediate) let _ = self.updateLayout(size: size, transition: .immediate)
} }
@ -282,33 +352,74 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
self.timeFieldNode.displaysAsynchronously = false self.timeFieldNode.displaysAsynchronously = false
self.timeFieldNode.displayWithoutProcessing = true self.timeFieldNode.displayWithoutProcessing = true
self.dayNodes = (0..<7).map { _ in ImmediateTextNode() }
self.contentNode = ASDisplayNode()
self.pickerBackgroundNode = ASDisplayNode()
self.pickerBackgroundNode.alpha = 0.0
self.pickerBackgroundNode.backgroundColor = theme.backgroundColor
self.pickerBackgroundNode.isUserInteractionEnabled = false
self.pickerNode = MonthPickerNode(theme: theme, strings: strings, date: self.state.date, yearRange: 2013 ..< 2038, valueChanged: { date in
})
self.monthButtonNode = HighlightTrackingButtonNode() self.monthButtonNode = HighlightTrackingButtonNode()
self.monthTextNode = ImmediateTextNode() self.monthTextNode = ImmediateTextNode()
self.monthArrowNode = ASImageNode() self.monthArrowNode = ASImageNode()
self.monthArrowNode.displaysAsynchronously = false self.monthArrowNode.displaysAsynchronously = false
self.monthArrowNode.displayWithoutProcessing = true self.monthArrowNode.displayWithoutProcessing = true
self.previousButtonNode = HighlightableButtonNode() self.previousButtonNode = HighlightableButtonNode()
self.previousButtonNode.hitTestSlop = UIEdgeInsets(top: -6.0, left: -10.0, bottom: -6.0, right: -10.0)
self.nextButtonNode = HighlightableButtonNode() self.nextButtonNode = HighlightableButtonNode()
self.nextButtonNode.hitTestSlop = UIEdgeInsets(top: -6.0, left: -10.0, bottom: -6.0, right: -10.0)
self.dayNodes = (0..<7).map { _ in ImmediateTextNode() }
self.scrollNode = ASScrollNode()
super.init() super.init()
self.clipsToBounds = true
self.backgroundColor = theme.backgroundColor self.backgroundColor = theme.backgroundColor
self.addSubnode(self.contentNode)
self.dayNodes.forEach { self.addSubnode($0) }
self.addSubnode(self.previousButtonNode)
self.addSubnode(self.nextButtonNode)
self.addSubnode(self.pickerBackgroundNode)
self.pickerBackgroundNode.addSubnode(self.pickerNode)
self.addSubnode(self.monthTextNode) self.addSubnode(self.monthTextNode)
self.addSubnode(self.monthArrowNode) self.addSubnode(self.monthArrowNode)
self.addSubnode(self.monthButtonNode) self.addSubnode(self.monthButtonNode)
self.addSubnode(self.previousButtonNode) self.monthArrowNode.image = generateSmallArrowImage(color: theme.accentColor)
self.addSubnode(self.nextButtonNode) self.previousButtonNode.setImage(generateNavigationArrowImage(color: theme.accentColor, mirror: true), for: .normal)
self.nextButtonNode.setImage(generateNavigationArrowImage(color: theme.accentColor, mirror: false), for: .normal)
self.addSubnode(self.scrollNode) self.setupItems()
self.monthButtonNode.addTarget(self, action: #selector(self.monthButtonPressed), forControlEvents: .touchUpInside)
self.monthButtonNode.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
if highlighted {
strongSelf.monthTextNode.layer.removeAnimation(forKey: "opacity")
strongSelf.monthTextNode.alpha = 0.4
strongSelf.monthArrowNode.layer.removeAnimation(forKey: "opacity")
strongSelf.monthArrowNode.alpha = 0.4
} else {
strongSelf.monthTextNode.alpha = 1.0
strongSelf.monthTextNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
strongSelf.monthArrowNode.alpha = 1.0
strongSelf.monthArrowNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
}
}
}
self.previousButtonNode.addTarget(self, action: #selector(self.previousButtonPressed), forControlEvents: .touchUpInside)
self.nextButtonNode.addTarget(self, action: #selector(self.nextButtonPressed), forControlEvents: .touchUpInside)
} }
override public func didLoad() { override public func didLoad() {
@ -316,15 +427,62 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
self.view.disablesInteractiveTransitionGestureRecognizer = true self.view.disablesInteractiveTransitionGestureRecognizer = true
self.scrollNode.view.isPagingEnabled = true self.contentNode.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:))))
self.scrollNode.view.delegate = self self.contentNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
} }
private func updateState(_ state: State, animated: Bool) { private func updateState(_ state: State, animated: Bool) {
let previousState = self.state
self.state = state self.state = state
if let size = self.validLayout {
self.updateLayout(size: size, transition: animated ? .animated(duration: 0.3, curve: .easeInOut) : .immediate) if previousState.minDate != state.minDate || previousState.maxDate != state.maxDate {
self.setupItems()
} else if previousState.selectedMonth != state.selectedMonth {
for i in 0 ..< self.months.count {
if self.months[i].timeIntervalSince1970 > state.selectedMonth.timeIntervalSince1970 {
self.currentIndex = max(0, min(self.months.count - 1, i - 1))
break
}
}
} }
if let size = self.validLayout {
self.updateLayout(size: size, transition: animated ? .animated(duration: 0.3, curve: .spring) : .immediate)
}
}
private func setupItems() {
let startMonth = monthForDate(self.state.minDate)
let endMonth = monthForDate(self.state.maxDate)
let selectedMonth = monthForDate(self.state.selectedMonth)
let calendar = Calendar.current
var currentIndex = 0
var months: [Date] = [startMonth]
var index = 1
var nextMonth = startMonth
while true {
if let month = calendar.date(byAdding: .month, value: 1, to: nextMonth) {
nextMonth = month
if nextMonth == selectedMonth {
currentIndex = index
}
if nextMonth >= endMonth {
break
} else {
months.append(nextMonth)
}
index += 1
} else {
break
}
}
self.months = months
self.currentIndex = currentIndex
} }
public func updateTheme(_ theme: DatePickerTheme) { public func updateTheme(_ theme: DatePickerTheme) {
@ -334,55 +492,262 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
self.theme = theme self.theme = theme
self.backgroundColor = self.theme.backgroundColor self.backgroundColor = self.theme.backgroundColor
} self.monthArrowNode.image = generateSmallArrowImage(color: theme.accentColor)
self.previousButtonNode.setImage(generateNavigationArrowImage(color: theme.accentColor, mirror: true), for: .normal)
self.nextButtonNode.setImage(generateNavigationArrowImage(color: theme.accentColor, mirror: false), for: .normal)
public func scrollViewDidScroll(_ scrollView: UIScrollView) { for (_, monthNode) in self.monthNodes {
self.view.window?.endEditing(true) monthNode.theme = theme
} }
public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { if let size = self.validLayout {
if !decelerate { self.updateLayout(size: size, transition: .immediate)
if let size = self.validLayout {
self.updateLayout(size: size, transition: .immediate)
}
} }
} }
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { @objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
if let size = self.validLayout {
self.updateLayout(size: size, transition: .immediate) }
@objc private func panGesture(_ recognizer: UIPanGestureRecognizer) {
switch recognizer.state {
case .began:
self.view.window?.endEditing(true)
case .changed:
let translation = recognizer.translation(in: self.view)
var transitionFraction = translation.x / self.bounds.width
if self.currentIndex <= 0 {
transitionFraction = min(0.0, transitionFraction)
}
if self.currentIndex >= self.months.count - 1 {
transitionFraction = max(0.0, transitionFraction)
}
self.transitionFraction = transitionFraction
if let size = self.validLayout {
let topInset: CGFloat = 78.0
let containerSize = CGSize(width: size.width, height: size.height - topInset)
self.updateItems(size: containerSize, transition: .animated(duration: 0.3, curve: .spring))
}
case .cancelled, .ended:
let velocity = recognizer.velocity(in: self.view)
var directionIsToRight: Bool?
if abs(velocity.x) > 10.0 {
directionIsToRight = velocity.x < 0.0
} else if abs(self.transitionFraction) > 0.5 {
directionIsToRight = self.transitionFraction < 0.0
}
var updatedIndex = self.currentIndex
if let directionIsToRight = directionIsToRight {
if directionIsToRight {
updatedIndex = min(updatedIndex + 1, self.months.count - 1)
} else {
updatedIndex = max(updatedIndex - 1, 0)
}
}
self.currentIndex = updatedIndex
self.transitionFraction = 0.0
let updatedState = State(minDate: self.state.minDate, maxDate: self.state.maxDate, date: self.state.date, displayingMonthSelection: self.state.displayingMonthSelection, selectedMonth: self.months[updatedIndex])
self.updateState(updatedState, animated: true)
default:
break
}
}
private func updateItems(size: CGSize, update: Bool = false, transition: ContainedViewLayoutTransition) {
var validIds: [Date] = []
if self.currentIndex >= 0 && self.currentIndex < self.months.count {
let preloadSpan: Int = 1
for i in max(0, self.currentIndex - preloadSpan) ... min(self.currentIndex + preloadSpan, self.months.count - 1) {
validIds.append(self.months[i])
var itemNode: MonthNode?
var wasAdded = false
if let current = self.monthNodes[self.months[i]] {
itemNode = current
current.updateLayout(size: size)
} else {
wasAdded = true
let addedItemNode = MonthNode(theme: self.theme, month: self.months[i], minimumDate: self.minimumDate, maximumDate: self.maximumDate, date: self.date)
itemNode = addedItemNode
self.monthNodes[self.months[i]] = addedItemNode
self.contentNode.addSubnode(addedItemNode)
}
if let itemNode = itemNode {
let indexOffset = CGFloat(i - self.currentIndex)
let itemFrame = CGRect(origin: CGPoint(x: indexOffset * size.width + self.transitionFraction * size.width, y: 0.0), size: size)
if wasAdded {
itemNode.frame = itemFrame
itemNode.updateLayout(size: size)
} else {
transition.updateFrame(node: itemNode, frame: itemFrame)
itemNode.updateLayout(size: size)
}
}
}
}
var removeIds: [Date] = []
for (id, _) in self.monthNodes {
if !validIds.contains(id) {
removeIds.append(id)
}
}
for id in removeIds {
if let itemNode = self.monthNodes.removeValue(forKey: id) {
itemNode.removeFromSupernode()
}
} }
} }
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) { public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
self.validLayout = size self.validLayout = size
let topInset: CGFloat = 60.0 let topInset: CGFloat = 78.0
let sideInset: CGFloat = 16.0
let scrollSize = CGSize(width: size.width, height: size.height - topInset) let month = monthForDate(self.state.selectedMonth)
self.scrollNode.frame = CGRect(origin: CGPoint(x: 0.0, y: topInset), size: scrollSize) let components = calendar.dateComponents([.month, .year], from: month)
self.scrollNode.view.contentSize = CGSize(width: scrollSize.width * 3.0, height: scrollSize.height)
self.scrollNode.view.contentOffset = CGPoint(x: scrollSize.width, y: 0.0) self.monthTextNode.attributedText = NSAttributedString(string: stringForMonth(strings: self.strings, month: components.month.flatMap { Int32($0) - 1 } ?? 0, ofYear: components.year.flatMap { Int32($0) - 1900 } ?? 100), font: controlFont, textColor: theme.textColor)
let monthSize = self.monthTextNode.updateLayout(size)
let monthTextFrame = CGRect(x: sideInset, y: 10.0, width: monthSize.width, height: monthSize.height)
self.monthTextNode.frame = monthTextFrame
self.monthArrowNode.frame = CGRect(x: monthTextFrame.maxX + 10.0, y: monthTextFrame.minY + 4.0, width: 7.0, height: 12.0)
self.monthButtonNode.frame = monthTextFrame.inset(by: UIEdgeInsets(top: -6.0, left: -6.0, bottom: -6.0, right: -30.0))
self.previousButtonNode.frame = CGRect(x: size.width - sideInset - 54.0, y: monthTextFrame.minY + 1.0, width: 10.0, height: 17.0)
self.nextButtonNode.frame = CGRect(x: size.width - sideInset - 13.0, y: monthTextFrame.minY + 1.0, width: 10.0, height: 17.0)
let daysSideInset: CGFloat = 12.0
let cellSize: CGFloat = floor((size.width - daysSideInset * 2.0) / 7.0)
for i in 0 ..< self.dayNodes.count { for i in 0 ..< self.dayNodes.count {
let dayNode = self.dayNodes[i] let dayNode = self.dayNodes[i]
dayNode.attributedText = NSAttributedString(string: shortStringForDayOfWeek(strings: self.strings, day: Int32(i)).uppercased(), font: dayFont, textColor: theme.secondaryTextColor)
let day = Int32(i) let textSize = dayNode.updateLayout(size)
dayNode.attributedText = NSAttributedString(string: shortStringForDayOfWeek(strings: self.strings, day: day), font: dayFont, textColor: theme.secondaryTextColor) let cellFrame = CGRect(x: daysSideInset + CGFloat(i) * cellSize, y: 40.0, width: cellSize, height: cellSize)
let size = dayNode.updateLayout(size) let textFrame = CGRect(origin: CGPoint(x: cellFrame.minX + floor((cellFrame.width - textSize.width) / 2.0), y: cellFrame.minY + floor((cellFrame.height - textSize.height) / 2.0)), size: textSize)
dayNode.frame = CGRect(origin: CGPoint(x: CGFloat(i) * 20.0, y: 0.0), size: size)
dayNode.frame = textFrame
}
let containerSize = CGSize(width: size.width, height: size.height - topInset)
self.contentNode.frame = CGRect(origin: CGPoint(x: 0.0, y: topInset), size: containerSize)
self.updateItems(size: containerSize, transition: transition)
self.pickerBackgroundNode.frame = CGRect(origin: CGPoint(), size: size)
self.pickerBackgroundNode.isUserInteractionEnabled = self.state.displayingMonthSelection
transition.updateAlpha(node: self.pickerBackgroundNode, alpha: self.state.displayingMonthSelection ? 1.0 : 0.0)
self.pickerNode.frame = CGRect(x: sideInset, y: topInset, width: size.width - sideInset * 2.0, height: 180.0)
}
@objc private func monthButtonPressed() {
let updatedState = State(minDate: self.state.minDate, maxDate: self.state.maxDate, date: self.state.date, displayingMonthSelection: !self.state.displayingMonthSelection, selectedMonth: self.state.selectedMonth)
self.updateState(updatedState, animated: true)
}
@objc private func previousButtonPressed() {
guard let month = calendar.date(byAdding: .month, value: -1, to: self.state.selectedMonth), let size = self.validLayout else {
return
}
let updatedState = State(minDate: self.state.minDate, maxDate: self.state.maxDate, date: self.state.date, displayingMonthSelection: self.state.displayingMonthSelection, selectedMonth: month)
self.updateState(updatedState, animated: false)
self.contentNode.layer.animatePosition(from: CGPoint(x: -size.width, y: 0.0), to: CGPoint(), duration: 0.3, additive: true)
}
@objc private func nextButtonPressed() {
guard let month = calendar.date(byAdding: .month, value: 1, to: self.state.selectedMonth), let size = self.validLayout else {
return
}
let updatedState = State(minDate: self.state.minDate, maxDate: self.state.maxDate, date: self.state.date, displayingMonthSelection: self.state.displayingMonthSelection, selectedMonth: month)
self.updateState(updatedState, animated: false)
self.contentNode.layer.animatePosition(from: CGPoint(x: size.width, y: 0.0), to: CGPoint(), duration: 0.3, additive: true)
}
}
private final class MonthPickerNode: ASDisplayNode, UIPickerViewDelegate, UIPickerViewDataSource {
private let theme: DatePickerTheme
private let strings: PresentationStrings
private var date: Date
private var yearRange: Range<Int> {
didSet {
self.pickerView.reloadAllComponents()
} }
} }
@objc private func monthButtonPressed(_ button: SegmentedControlItemNode) { private let valueChanged: (Date) -> Void
private let pickerView: UIPickerView
init(theme: DatePickerTheme, strings: PresentationStrings, date: Date, yearRange: Range<Int>, valueChanged: @escaping (Date) -> Void) {
self.theme = theme
self.strings = strings
self.date = date
self.yearRange = yearRange
self.valueChanged = valueChanged
self.pickerView = UIPickerView()
super.init()
self.pickerView.delegate = self
self.pickerView.dataSource = self
self.view.addSubview(self.pickerView)
self.pickerView.reloadAllComponents()
// self.pickerView.selectRow(index, inComponent: 0, animated: false)
} }
@objc private func previousButtonPressed(_ button: SegmentedControlItemNode) { override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 180.0)
} }
@objc private func nextButtonPressed(_ button: SegmentedControlItemNode) { func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 2
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if component == 1 {
return self.yearRange.count
} else {
return 12
}
}
func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
return 40.0
}
func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? {
let string: String
if component == 1 {
string = "\(self.yearRange.startIndex + row)"
} else {
string = stringForMonth(strings: self.strings, month: Int32(row))
}
return NSAttributedString(string: string, font: Font.medium(15.0), textColor: self.theme.textColor)
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
// self.valueChanged(timeoutValues[row])
}
override func layout() {
super.layout()
self.pickerView.frame = CGRect(origin: CGPoint(), size: CGSize(width: self.bounds.size.width, height: 180.0))
} }
} }

View File

@ -45,7 +45,7 @@ public struct Font {
} }
var updatedDescriptor: UIFontDescriptor? = descriptor.withSymbolicTraits(symbolicTraits) var updatedDescriptor: UIFontDescriptor? = descriptor.withSymbolicTraits(symbolicTraits)
if traits.contains(.monospacedNumbers) { if traits.contains(.monospacedNumbers) {
updatedDescriptor = descriptor.addingAttributes([ updatedDescriptor = updatedDescriptor?.addingAttributes([
UIFontDescriptor.AttributeName.featureSettings: [ UIFontDescriptor.AttributeName.featureSettings: [
[UIFontDescriptor.FeatureKey.featureIdentifier: [UIFontDescriptor.FeatureKey.featureIdentifier:
kNumberSpacingType, kNumberSpacingType,

View File

@ -49,6 +49,7 @@ swift_library(
"//submodules/RadialStatusNode:RadialStatusNode", "//submodules/RadialStatusNode:RadialStatusNode",
"//submodules/SectionHeaderItem:SectionHeaderItem", "//submodules/SectionHeaderItem:SectionHeaderItem",
"//submodules/DirectionalPanGesture:DirectionalPanGesture", "//submodules/DirectionalPanGesture:DirectionalPanGesture",
"//submodules/ShimmerEffect:ShimmerEffect",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -193,7 +193,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
arguments.dismissInput() arguments.dismissInput()
arguments.updateState { state in arguments.updateState { state in
var updatedState = state var updatedState = state
updatedState.pickingTimeLimit = !state.pickingTimeLimit // updatedState.pickingTimeLimit = !state.pickingTimeLimit
return updatedState return updatedState
} }
}) })

View File

@ -149,7 +149,7 @@ private enum InviteLinkInviteEntry: Comparable, Identifiable {
}, viewAction: { }, viewAction: {
}) })
case let .links(_, _, invites): case let .links(_, _, invites):
return ItemListInviteLinkGridItem(presentationData: ItemListPresentationData(presentationData), invites: invites, share: true, sectionId: 1, style: .plain, tapAction: { invite in return ItemListInviteLinkGridItem(presentationData: ItemListPresentationData(presentationData), invites: invites, count: 0, share: true, sectionId: 1, style: .plain, tapAction: { invite in
interaction.copyLink(invite) interaction.copyLink(invite)
}, contextAction: { invite, _ in }, contextAction: { invite, _ in
interaction.shareLink(invite) interaction.shareLink(invite)
@ -288,7 +288,7 @@ public final class InviteLinkInviteController: ViewController {
self.presentationDataPromise = Promise(self.presentationData) self.presentationDataPromise = Promise(self.presentationData)
self.controller = controller self.controller = controller
self.invitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: false) self.invitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, adminId: nil, revoked: false, forceUpdate: false)
self.dimNode = ASDisplayNode() self.dimNode = ASDisplayNode()
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5) self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
@ -348,16 +348,16 @@ public final class InviteLinkInviteController: ViewController {
} }
}))) })))
// items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
// return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor) return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
// }, action: { _, f in }, action: { _, f in
// f(.dismissWithoutContent) f(.dismissWithoutContent)
//
// if let invite = invite { if let invite = invite {
// let controller = InviteLinkQRCodeController(context: context, invite: invite) let controller = InviteLinkQRCodeController(context: context, invite: invite)
// self?.controller?.present(controller, in: .window(.root)) self?.controller?.present(controller, in: .window(.root))
// } }
// }))) })))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextRevoke, textColor: .destructive, icon: { theme in items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextRevoke, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor)
@ -395,7 +395,7 @@ public final class InviteLinkInviteController: ViewController {
let shareController = ShareController(context: context, subject: .url(invite.link)) let shareController = ShareController(context: context, subject: .url(invite.link))
self?.controller?.present(shareController, in: .window(.root)) self?.controller?.present(shareController, in: .window(.root))
}, manageLinks: { [weak self] in }, manageLinks: { [weak self] in
let controller = inviteLinkListController(context: context, peerId: peerId) let controller = inviteLinkListController(context: context, peerId: peerId, admin: nil)
self?.controller?.parentNavigationController?.pushViewController(controller) self?.controller?.parentNavigationController?.pushViewController(controller)
self?.controller?.dismiss() self?.controller?.dismiss()
}) })
@ -403,8 +403,7 @@ public final class InviteLinkInviteController: ViewController {
let previousEntries = Atomic<[InviteLinkInviteEntry]?>(value: nil) let previousEntries = Atomic<[InviteLinkInviteEntry]?>(value: nil)
let peerView = context.account.postbox.peerView(id: peerId) let peerView = context.account.postbox.peerView(id: peerId)
let invites: Signal<PeerExportedInvitationsState, NoError> = .single(PeerExportedInvitationsState()) self.disposable = (combineLatest(self.presentationDataPromise.get(), peerView, self.invitesContext.state)
self.disposable = (combineLatest(self.presentationDataPromise.get(), peerView, invites)
|> deliverOnMainQueue).start(next: { [weak self] presentationData, view, invites in |> deliverOnMainQueue).start(next: { [weak self] presentationData, view, invites in
if let strongSelf = self { if let strongSelf = self {
var entries: [InviteLinkInviteEntry] = [] var entries: [InviteLinkInviteEntry] = []
@ -423,19 +422,19 @@ public final class InviteLinkInviteController: ViewController {
entries.append(.mainLink(presentationData.theme, mainInvite)) entries.append(.mainLink(presentationData.theme, mainInvite))
} }
// let additionalInvites = invites.invitations.filter { $0.link != mainInvite?.link } let additionalInvites = invites.invitations.filter { $0.link != mainInvite?.link }
// var index: Int32 = 0 var index: Int32 = 0
// for i in stride(from: 0, to: additionalInvites.endIndex, by: 2) { for i in stride(from: 0, to: additionalInvites.endIndex, by: 2) {
// var invitesPair: [ExportedInvitation] = [] var invitesPair: [ExportedInvitation] = []
// invitesPair.append(additionalInvites[i]) invitesPair.append(additionalInvites[i])
// if i + 1 < additionalInvites.count { if i + 1 < additionalInvites.count {
// invitesPair.append(additionalInvites[i + 1]) invitesPair.append(additionalInvites[i + 1])
// } }
// entries.append(.links(index, presentationData.theme, invitesPair)) entries.append(.links(index, presentationData.theme, invitesPair))
// index += 1 index += 1
// } }
// entries.append(.manage(presentationData.theme, presentationData.strings.InviteLink_Manage, additionalInvites.isEmpty)) entries.append(.manage(presentationData.theme, presentationData.strings.InviteLink_Manage, additionalInvites.isEmpty))
let previousEntries = previousEntries.swap(entries) let previousEntries = previousEntries.swap(entries)

View File

@ -18,6 +18,7 @@ import AppBundle
import ContextUI import ContextUI
import TelegramStringFormatting import TelegramStringFormatting
import ItemListPeerActionItem import ItemListPeerActionItem
import ItemListPeerItem
import ShareController import ShareController
import UndoUI import UndoUI
@ -30,9 +31,10 @@ private final class InviteLinkListControllerArguments {
let createLink: () -> Void let createLink: () -> Void
let openLink: (ExportedInvitation) -> Void let openLink: (ExportedInvitation) -> Void
let linkContextAction: (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void let linkContextAction: (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void
let openAdmin: (ExportedInvitationCreator) -> Void
let deleteAllRevokedLinks: () -> Void let deleteAllRevokedLinks: () -> Void
init(context: AccountContext, shareMainLink: @escaping (ExportedInvitation) -> Void, openMainLink: @escaping (ExportedInvitation) -> Void, copyLink: @escaping (ExportedInvitation) -> Void, mainLinkContextAction: @escaping (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void, createLink: @escaping () -> Void, openLink: @escaping (ExportedInvitation?) -> Void, linkContextAction: @escaping (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void, deleteAllRevokedLinks: @escaping () -> Void) { init(context: AccountContext, shareMainLink: @escaping (ExportedInvitation) -> Void, openMainLink: @escaping (ExportedInvitation) -> Void, copyLink: @escaping (ExportedInvitation) -> Void, mainLinkContextAction: @escaping (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void, createLink: @escaping () -> Void, openLink: @escaping (ExportedInvitation?) -> Void, linkContextAction: @escaping (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void, openAdmin: @escaping (ExportedInvitationCreator) -> Void, deleteAllRevokedLinks: @escaping () -> Void) {
self.context = context self.context = context
self.shareMainLink = shareMainLink self.shareMainLink = shareMainLink
self.openMainLink = openMainLink self.openMainLink = openMainLink
@ -41,6 +43,7 @@ private final class InviteLinkListControllerArguments {
self.createLink = createLink self.createLink = createLink
self.openLink = openLink self.openLink = openLink
self.linkContextAction = linkContextAction self.linkContextAction = linkContextAction
self.openAdmin = openAdmin
self.deleteAllRevokedLinks = deleteAllRevokedLinks self.deleteAllRevokedLinks = deleteAllRevokedLinks
} }
} }
@ -49,6 +52,7 @@ private enum InviteLinksListSection: Int32 {
case header case header
case mainLink case mainLink
case links case links
case admins
case revokedLinks case revokedLinks
} }
@ -57,11 +61,16 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
case mainLinkHeader(PresentationTheme, String) case mainLinkHeader(PresentationTheme, String)
case mainLink(PresentationTheme, ExportedInvitation?, [Peer], Int32, Bool) case mainLink(PresentationTheme, ExportedInvitation?, [Peer], Int32, Bool)
case mainLinkOtherInfo(PresentationTheme, String)
case linksHeader(PresentationTheme, String) case linksHeader(PresentationTheme, String)
case linksCreate(PresentationTheme, String) case linksCreate(PresentationTheme, String)
case links(Int32, PresentationTheme, [ExportedInvitation]?) case links(Int32, PresentationTheme, [ExportedInvitation]?, Int)
case linksInfo(PresentationTheme, String) case linksInfo(PresentationTheme, String)
case adminsHeader(PresentationTheme, String)
case admin(Int32, PresentationTheme, ExportedInvitationCreator)
case revokedLinksHeader(PresentationTheme, String) case revokedLinksHeader(PresentationTheme, String)
case revokedLinksDeleteAll(PresentationTheme, String) case revokedLinksDeleteAll(PresentationTheme, String)
case revokedLinks(Int32, PresentationTheme, [ExportedInvitation]?) case revokedLinks(Int32, PresentationTheme, [ExportedInvitation]?)
@ -70,10 +79,12 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
switch self { switch self {
case .header: case .header:
return InviteLinksListSection.header.rawValue return InviteLinksListSection.header.rawValue
case .mainLinkHeader, .mainLink: case .mainLinkHeader, .mainLink, .mainLinkOtherInfo:
return InviteLinksListSection.mainLink.rawValue return InviteLinksListSection.mainLink.rawValue
case .linksHeader, .linksCreate, .links, .linksInfo: case .linksHeader, .linksCreate, .links, .linksInfo:
return InviteLinksListSection.links.rawValue return InviteLinksListSection.links.rawValue
case .adminsHeader, .admin:
return InviteLinksListSection.admins.rawValue
case .revokedLinksHeader, .revokedLinksDeleteAll, .revokedLinks: case .revokedLinksHeader, .revokedLinksDeleteAll, .revokedLinks:
return InviteLinksListSection.revokedLinks.rawValue return InviteLinksListSection.revokedLinks.rawValue
} }
@ -87,20 +98,26 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
return 1 return 1
case .mainLink: case .mainLink:
return 2 return 2
case .linksHeader: case .mainLinkOtherInfo:
return 3 return 3
case .linksCreate: case .linksHeader:
return 4 return 4
case let .links(index, _, _): case .linksCreate:
return 5 + index return 5
case let .links(index, _, _, _):
return 6 + index
case .linksInfo: case .linksInfo:
return 10000 return 10000
case .revokedLinksHeader: case .adminsHeader:
return 10001 return 10001
case let .admin(index, _, _):
return 10002 + index
case .revokedLinksHeader:
return 20001
case .revokedLinksDeleteAll: case .revokedLinksDeleteAll:
return 10002 return 20002
case let .revokedLinks(index, _, _): case let .revokedLinks(index, _, _):
return 10003 + index return 20003 + index
} }
} }
@ -124,6 +141,12 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .mainLinkOtherInfo(lhsTheme, lhsText):
if case let .mainLinkOtherInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .linksHeader(lhsTheme, lhsText): case let .linksHeader(lhsTheme, lhsText):
if case let .linksHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .linksHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true return true
@ -136,8 +159,8 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .links(lhsIndex, lhsTheme, lhsLinks): case let .links(lhsIndex, lhsTheme, lhsLinks, lhsCount):
if case let .links(rhsIndex, rhsTheme, rhsLinks) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsLinks == rhsLinks { if case let .links(rhsIndex, rhsTheme, rhsLinks, rhsCount) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsLinks == rhsLinks, lhsCount == rhsCount {
return true return true
} else { } else {
return false return false
@ -148,6 +171,18 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .adminsHeader(lhsTheme, lhsText):
if case let .adminsHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .admin(lhsIndex, lhsTheme, lhsCreator):
if case let .admin(rhsIndex, rhsTheme, rhsCreator) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsCreator == rhsCreator {
return true
} else {
return false
}
case let .revokedLinksHeader(lhsTheme, lhsText): case let .revokedLinksHeader(lhsTheme, lhsText):
if case let .revokedLinksHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .revokedLinksHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true return true
@ -196,20 +231,28 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
arguments.openLink(invite) arguments.openLink(invite)
} }
}) })
case let .mainLinkOtherInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section, linkAction: nil, style: .blocks, tag: nil)
case let .linksHeader(_, text): case let .linksHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .linksCreate(theme, text): case let .linksCreate(theme, text):
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.plusIconImage(theme), title: text, hasSeparator: false, sectionId: self.section, editing: false, action: { return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.plusIconImage(theme), title: text, hasSeparator: false, sectionId: self.section, editing: false, action: {
arguments.createLink() arguments.createLink()
}) })
case let .links(_, _, invites): case let .links(_, _, invites, count):
return ItemListInviteLinkGridItem(presentationData: presentationData, invites: invites, share: false, sectionId: self.section, style: .blocks, tapAction: { invite in return ItemListInviteLinkGridItem(presentationData: presentationData, invites: invites, count: count, share: false, sectionId: self.section, style: .blocks, tapAction: { invite in
arguments.openLink(invite) arguments.openLink(invite)
}, contextAction: { invite, node in }, contextAction: { invite, node in
arguments.linkContextAction(invite, node, nil) arguments.linkContextAction(invite, node, nil)
}) })
case let .linksInfo(_, text): case let .linksInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
case let .adminsHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .admin(_, _, creator):
return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(timeFormat: .regular, dateFormat: .monthFirst, dateSeparator: ".", decimalSeparator: ".", groupingSeparator: "."), nameDisplayOrder: .firstLast, context: arguments.context, peer: creator.peer.peer!, height: .peerList, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .none, label: .disclosure("\(creator.count)"), editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: nil), revealOptions: nil, switchValue: nil, enabled: true, highlighted: false, selectable: true, sectionId: self.section, action: {
arguments.openAdmin(creator)
}, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: nil)
case let .revokedLinksHeader(_, text): case let .revokedLinksHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .revokedLinksDeleteAll(theme, text): case let .revokedLinksDeleteAll(theme, text):
@ -217,7 +260,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
arguments.deleteAllRevokedLinks() arguments.deleteAllRevokedLinks()
}) })
case let .revokedLinks(_, _, invites): case let .revokedLinks(_, _, invites):
return ItemListInviteLinkGridItem(presentationData: presentationData, invites: invites, share: false, sectionId: self.section, style: .blocks, tapAction: { invite in return ItemListInviteLinkGridItem(presentationData: presentationData, invites: invites, count: 0, share: false, sectionId: self.section, style: .blocks, tapAction: { invite in
arguments.openLink(invite) arguments.openLink(invite)
}, contextAction: { invite, node in }, contextAction: { invite, node in
arguments.linkContextAction(invite, node, nil) arguments.linkContextAction(invite, node, nil)
@ -226,22 +269,23 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
} }
} }
private func inviteLinkListControllerEntries(presentationData: PresentationData, view: PeerView, invites: [ExportedInvitation]?, revokedInvites: [ExportedInvitation]?, importers: PeerInvitationImportersState?) -> [InviteLinksListEntry] { private func inviteLinkListControllerEntries(presentationData: PresentationData, view: PeerView, invites: [ExportedInvitation]?, revokedInvites: [ExportedInvitation]?, importers: PeerInvitationImportersState?, creators: [ExportedInvitationCreator], admin: ExportedInvitationCreator?) -> [InviteLinksListEntry] {
var entries: [InviteLinksListEntry] = [] var entries: [InviteLinksListEntry] = []
entries.append(.header(presentationData.theme, presentationData.strings.InviteLink_CreatePrivateLinkHelp)) if admin == nil {
entries.append(.header(presentationData.theme, presentationData.strings.InviteLink_CreatePrivateLinkHelp))
}
let mainInvite: ExportedInvitation? let mainInvite: ExportedInvitation?
var isPublic = false var isPublic = false
if let peer = peerViewMainPeer(view), let address = peer.addressName, !address.isEmpty { if let peer = peerViewMainPeer(view), let address = peer.addressName, !address.isEmpty && admin == nil {
mainInvite = ExportedInvitation(link: "t.me/\(address)", isPermanent: true, isRevoked: false, adminId: PeerId(0), date: 0, startDate: nil, expireDate: nil, usageLimit: nil, count: nil) mainInvite = ExportedInvitation(link: "t.me/\(address)", isPermanent: true, isRevoked: false, adminId: PeerId(0), date: 0, startDate: nil, expireDate: nil, usageLimit: nil, count: 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
} else if let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation { } else if let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation, admin == nil {
mainInvite = invite mainInvite = invite
} else if let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation { } else if let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation, admin == nil {
mainInvite = invite mainInvite = invite
} else { } else {
mainInvite = nil mainInvite = nil
@ -259,10 +303,15 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData,
} }
entries.append(.mainLink(presentationData.theme, mainInvite, importers?.importers.prefix(3).compactMap { $0.peer.peer } ?? [], importersCount, isPublic)) entries.append(.mainLink(presentationData.theme, mainInvite, importers?.importers.prefix(3).compactMap { $0.peer.peer } ?? [], importersCount, isPublic))
if let adminPeer = admin?.peer.peer, let peer = peerViewMainPeer(view) {
let string = presentationData.strings.InviteLink_OtherPermanentLinkInfo(adminPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))
entries.append(.mainLinkOtherInfo(presentationData.theme, string.0))
}
entries.append(.linksHeader(presentationData.theme, presentationData.strings.InviteLink_AdditionalLinks.uppercased())) entries.append(.linksHeader(presentationData.theme, presentationData.strings.InviteLink_AdditionalLinks.uppercased()))
entries.append(.linksCreate(presentationData.theme, presentationData.strings.InviteLink_Create)) if admin == nil {
entries.append(.linksCreate(presentationData.theme, presentationData.strings.InviteLink_Create))
}
var additionalInvites: [ExportedInvitation]? var additionalInvites: [ExportedInvitation]?
if let invites = invites { if let invites = invites {
additionalInvites = invites.filter { $0.link != mainInvite?.link } additionalInvites = invites.filter { $0.link != mainInvite?.link }
@ -275,16 +324,34 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData,
if i + 1 < additionalInvites.count { if i + 1 < additionalInvites.count {
invitesPair.append(additionalInvites[i + 1]) invitesPair.append(additionalInvites[i + 1])
} }
entries.append(.links(index, presentationData.theme, invitesPair)) entries.append(.links(index, presentationData.theme, invitesPair, invitesPair.count))
index += 1
}
} else if let admin = admin {
var index: Int32 = 0
for _ in stride(from: 0, to: admin.count, by: 2) {
entries.append(.links(index, presentationData.theme, nil, 1))
index += 1 index += 1
} }
} }
entries.append(.linksInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo)) entries.append(.linksInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
if !creators.isEmpty {
entries.append(.adminsHeader(presentationData.theme, presentationData.strings.InviteLink_OtherAdminsLinks.uppercased()))
var index: Int32 = 0
for creator in creators {
if let _ = creator.peer.peer {
entries.append(.admin(index, presentationData.theme, creator))
index += 1
}
}
}
if let revokedInvites = revokedInvites, !revokedInvites.isEmpty { if let revokedInvites = revokedInvites, !revokedInvites.isEmpty {
entries.append(.revokedLinksHeader(presentationData.theme, presentationData.strings.InviteLink_RevokedLinks.uppercased())) entries.append(.revokedLinksHeader(presentationData.theme, presentationData.strings.InviteLink_RevokedLinks.uppercased()))
entries.append(.revokedLinksDeleteAll(presentationData.theme, presentationData.strings.InviteLink_DeleteAllRevokedLinks)) if admin == nil {
entries.append(.revokedLinksDeleteAll(presentationData.theme, presentationData.strings.InviteLink_DeleteAllRevokedLinks))
}
var index: Int32 = 0 var index: Int32 = 0
for i in stride(from: 0, to: revokedInvites.endIndex, by: 2) { for i in stride(from: 0, to: revokedInvites.endIndex, by: 2) {
var invitesPair: [ExportedInvitation] = [] var invitesPair: [ExportedInvitation] = []
@ -305,7 +372,7 @@ private struct InviteLinkListControllerState: Equatable {
} }
public func inviteLinkListController(context: AccountContext, peerId: PeerId) -> ViewController { public func inviteLinkListController(context: AccountContext, peerId: PeerId, admin: ExportedInvitationCreator?) -> ViewController {
var pushControllerImpl: ((ViewController) -> Void)? var pushControllerImpl: ((ViewController) -> Void)?
var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)? var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)?
var presentInGlobalOverlayImpl: ((ViewController) -> Void)? var presentInGlobalOverlayImpl: ((ViewController) -> Void)?
@ -326,8 +393,16 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
var getControllerImpl: (() -> ViewController?)? var getControllerImpl: (() -> ViewController?)?
let invitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: false) let adminId = admin?.peer.peer?.id
let revokedInvitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: true, forceUpdate: true) let invitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, adminId: adminId, revoked: false, forceUpdate: false)
let revokedInvitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, adminId: adminId, revoked: true, forceUpdate: true)
let creators: Signal<[ExportedInvitationCreator], NoError>
if adminId == nil {
creators = .single([]) |> then(peerExportedInvitationsCreators(account: context.account, peerId: peerId))
} else {
creators = .single([])
}
let arguments = InviteLinkListControllerArguments(context: context, shareMainLink: { invite in let arguments = InviteLinkListControllerArguments(context: context, shareMainLink: { invite in
let shareController = ShareController(context: context, subject: .url(invite.link)) let shareController = ShareController(context: context, subject: .url(invite.link))
@ -546,6 +621,9 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture) let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture)
presentInGlobalOverlayImpl?(contextController) presentInGlobalOverlayImpl?(contextController)
}, openAdmin: { admin in
let controller = inviteLinkListController(context: context, peerId: peerId, admin: admin)
pushControllerImpl?(controller)
}, deleteAllRevokedLinks: { }, deleteAllRevokedLinks: {
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let controller = ActionSheetController(presentationData: presentationData) let controller = ActionSheetController(presentationData: presentationData)
@ -596,9 +674,9 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
} }
let previousRevokedInvites = Atomic<PeerExportedInvitationsState?>(value: nil) let previousRevokedInvites = Atomic<PeerExportedInvitationsState?>(value: nil)
let signal = combineLatest(context.sharedContext.presentationData, peerView, importersContext, importersState.get(), invitesContext.state, revokedInvitesContext.state) let signal = combineLatest(context.sharedContext.presentationData, peerView, importersContext, importersState.get(), invitesContext.state, revokedInvitesContext.state, creators)
|> deliverOnMainQueue |> deliverOnMainQueue
|> map { presentationData, view, importersContext, importers, invites, revokedInvites -> (ItemListControllerState, (ItemListNodeState, Any)) in |> map { presentationData, view, importersContext, importers, invites, revokedInvites, creators -> (ItemListControllerState, (ItemListNodeState, Any)) in
let previousRevokedInvites = previousRevokedInvites.swap(invites) let previousRevokedInvites = previousRevokedInvites.swap(invites)
var crossfade = false var crossfade = false
@ -606,8 +684,15 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
crossfade = true crossfade = true
} }
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.InviteLink_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) let title: ItemListControllerTitle
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: inviteLinkListControllerEntries(presentationData: presentationData, view: view, invites: invites.invitations, revokedInvites: revokedInvites.invitations, importers: importers), style: .blocks, emptyStateItem: nil, crossfadeState: crossfade, animateChanges: false) if let admin = admin, let peer = admin.peer.peer {
title = .textWithSubtitle(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), "\(admin.count) invite links")
} else {
title = .text(presentationData.strings.InviteLink_Title)
}
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: title, leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: inviteLinkListControllerEntries(presentationData: presentationData, view: view, invites: invites.hasLoadedOnce ? invites.invitations : nil, revokedInvites: revokedInvites.invitations, importers: importers, creators: creators, admin: admin), style: .blocks, emptyStateItem: nil, crossfadeState: crossfade, animateChanges: false)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} }

View File

@ -112,7 +112,7 @@ private class ItemNode: ASDisplayNode {
private var updateTimer: SwiftSignalKit.Timer? private var updateTimer: SwiftSignalKit.Timer?
private var params: (size: CGSize, wide: Bool, invite: ExportedInvitation, color: ItemBackgroundColor, presentationData: ItemListPresentationData)? private var params: (size: CGSize, wide: Bool, invite: ExportedInvitation?, color: ItemBackgroundColor, presentationData: ItemListPresentationData)?
var action: (() -> Void)? var action: (() -> Void)?
var contextAction: ((ASDisplayNode) -> Void)? var contextAction: ((ASDisplayNode) -> Void)?
@ -214,44 +214,50 @@ private class ItemNode: ASDisplayNode {
self.contextAction?(self.extractedContainerNode) self.contextAction?(self.extractedContainerNode)
} }
func update(size: CGSize, wide: Bool, share: Bool, invite: ExportedInvitation, presentationData: ItemListPresentationData, transition: ContainedViewLayoutTransition) -> CGSize { func update(size: CGSize, wide: Bool, share: Bool, invite: ExportedInvitation?, presentationData: ItemListPresentationData, transition: ContainedViewLayoutTransition) -> CGSize {
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
let availability = invitationAvailability(invite) let availability = invite.flatMap { invitationAvailability($0) } ?? 0.0
let transitionFraction: CGFloat let transitionFraction: CGFloat
let color: ItemBackgroundColor let color: ItemBackgroundColor
let nextColor: ItemBackgroundColor let nextColor: ItemBackgroundColor
if invite.isRevoked { if let invite = invite {
if invite.isRevoked {
color = .gray
nextColor = .gray
transitionFraction = 0.0
} else if invite.expireDate == nil && invite.usageLimit == nil {
color = .blue
nextColor = .blue
transitionFraction = 0.0
} else if availability >= 0.5 {
color = .green
nextColor = .yellow
transitionFraction = (availability - 0.5) / 0.5
} else if availability > 0.0 {
color = .yellow
nextColor = .red
transitionFraction = availability / 0.5
} else {
color = .red
nextColor = .red
transitionFraction = 0.0
}
} else {
color = .gray color = .gray
nextColor = .gray nextColor = .gray
transitionFraction = 0.0 transitionFraction = 0.0
} else if invite.expireDate == nil && invite.usageLimit == nil {
color = .blue
nextColor = .blue
transitionFraction = 0.0
} else if availability >= 0.5 {
color = .green
nextColor = .yellow
transitionFraction = (availability - 0.5) / 0.5
} else if availability > 0.0 {
color = .yellow
nextColor = .red
transitionFraction = availability / 0.5
} else {
color = .red
nextColor = .red
transitionFraction = 0.0
} }
let previousParams = self.params let previousParams = self.params
self.params = (size, wide, invite, color, presentationData) self.params = (size, wide, invite, color, presentationData)
let previousExpireDate = previousParams?.invite.expireDate let previousExpireDate = previousParams?.invite?.expireDate
if previousExpireDate != invite.expireDate { if previousExpireDate != invite?.expireDate {
self.updateTimer?.invalidate() self.updateTimer?.invalidate()
self.updateTimer = nil self.updateTimer = nil
if let expireDate = invite.expireDate, availability > 0.0 { if let expireDate = invite?.expireDate, availability > 0.0 {
let timeout = min(2.0, max(0.001, Double(expireDate - currentTime))) let timeout = min(2.0, max(0.001, Double(expireDate - currentTime)))
let updateTimer = SwiftSignalKit.Timer(timeout: timeout, repeat: true, completion: { [weak self] in let updateTimer = SwiftSignalKit.Timer(timeout: timeout, repeat: true, completion: { [weak self] in
if let strongSelf = self { if let strongSelf = self {
@ -272,7 +278,12 @@ private class ItemNode: ASDisplayNode {
let bottomColor = color.colors.bottom let bottomColor = color.colors.bottom
let nextTopColor = nextColor.colors.top let nextTopColor = nextColor.colors.top
let nextBottomColor = nextColor.colors.bottom let nextBottomColor = nextColor.colors.bottom
let colors: NSArray = [nextTopColor.mixedWith(topColor, alpha: transitionFraction).cgColor, nextBottomColor.mixedWith(bottomColor, alpha: transitionFraction).cgColor] let colors: NSArray
if let invite = invite {
colors = [nextTopColor.mixedWith(topColor, alpha: transitionFraction).cgColor, nextBottomColor.mixedWith(bottomColor, alpha: transitionFraction).cgColor]
} else {
colors = [UIColor(rgb: 0xf2f2f7).cgColor, UIColor(rgb: 0xf2f2f7).cgColor]
}
if let (_, _, previousInvite, previousColor, _) = previousParams, previousInvite == invite { if let (_, _, previousInvite, previousColor, _) = previousParams, previousInvite == invite {
if previousColor != color && color == .red { if previousColor != color && color == .red {
@ -298,7 +309,7 @@ private class ItemNode: ASDisplayNode {
let secondaryTextColor = nextColor.colors.text.mixedWith(color.colors.text, alpha: transitionFraction) let secondaryTextColor = nextColor.colors.text.mixedWith(color.colors.text, alpha: transitionFraction)
let itemWidth = wide ? size.width : floor((size.width - itemSpacing) / 2.0) let itemWidth = wide ? size.width : floor((size.width - itemSpacing) / 2.0)
var inviteLink = invite.link.replacingOccurrences(of: "https://", with: "") var inviteLink = invite?.link.replacingOccurrences(of: "https://", with: "") ?? ""
if !wide { if !wide {
inviteLink = inviteLink.replacingOccurrences(of: "joinchat/", with: "joinchat/\n") inviteLink = inviteLink.replacingOccurrences(of: "joinchat/", with: "joinchat/\n")
inviteLink = inviteLink.replacingOccurrences(of: "join/", with: "join/\n") inviteLink = inviteLink.replacingOccurrences(of: "join/", with: "join/\n")
@ -314,65 +325,72 @@ private class ItemNode: ASDisplayNode {
self.buttonIconNode.image = share ? shareIcon : moreIcon self.buttonIconNode.image = share ? shareIcon : moreIcon
var subtitleText: String = "" var subtitleText: String = ""
if let count = invite.count { if let invite = invite {
subtitleText = presentationData.strings.InviteLink_PeopleJoinedShort(count) if let count = invite.count {
subtitleText = presentationData.strings.InviteLink_PeopleJoinedShort(count)
} else {
subtitleText = [.red, .gray].contains(color) ? presentationData.strings.InviteLink_PeopleJoinedShortNoneExpired : presentationData.strings.InviteLink_PeopleJoinedShortNone
}
if invite.isRevoked {
if !subtitleText.isEmpty {
subtitleText += ""
}
subtitleText += presentationData.strings.InviteLink_Revoked
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Expired"), color: .white)
self.timerNode?.removeFromSupernode()
self.timerNode = nil
} else if let expireDate = invite.expireDate, currentTime >= expireDate {
if !subtitleText.isEmpty {
subtitleText += ""
}
if share {
subtitleText = presentationData.strings.InviteLink_Expired
} else {
subtitleText += presentationData.strings.InviteLink_Expired
}
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Expired"), color: .white)
self.timerNode?.removeFromSupernode()
self.timerNode = nil
} else if let usageLimit = invite.usageLimit, let count = invite.count, count >= usageLimit {
if !subtitleText.isEmpty {
subtitleText += ""
}
if share {
subtitleText = presentationData.strings.InviteLink_UsageLimitReached
} else {
subtitleText += presentationData.strings.InviteLink_UsageLimitReached
}
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Expired"), color: .white)
self.timerNode?.removeFromSupernode()
self.timerNode = nil
} else if let expireDate = invite.expireDate {
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Flame"), color: .white)
let timerNode: TimerNode
if let current = self.timerNode {
timerNode = current
} else {
timerNode = TimerNode()
timerNode.isUserInteractionEnabled = false
self.timerNode = timerNode
self.addSubnode(timerNode)
}
timerNode.update(color: UIColor.white, creationTimestamp: invite.startDate ?? invite.date, deadlineTimestamp: expireDate)
if share {
subtitleText = presentationData.strings.InviteLink_TapToCopy
}
} else {
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Link"), color: .white)
self.timerNode?.removeFromSupernode()
self.timerNode = nil
if share {
subtitleText = presentationData.strings.InviteLink_TapToCopy
}
}
self.iconNode.isHidden = false
self.buttonIconNode.isHidden = false
} else { } else {
subtitleText = [.red, .gray].contains(color) ? presentationData.strings.InviteLink_PeopleJoinedShortNoneExpired : presentationData.strings.InviteLink_PeopleJoinedShortNone self.iconNode.isHidden = true
} self.buttonIconNode.isHidden = true
if invite.isRevoked {
if !subtitleText.isEmpty {
subtitleText += ""
}
subtitleText += presentationData.strings.InviteLink_Revoked
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Expired"), color: .white)
self.timerNode?.removeFromSupernode()
self.timerNode = nil
} else if let expireDate = invite.expireDate, currentTime >= expireDate {
if !subtitleText.isEmpty {
subtitleText += ""
}
if share {
subtitleText = presentationData.strings.InviteLink_Expired
} else {
subtitleText += presentationData.strings.InviteLink_Expired
}
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Expired"), color: .white)
self.timerNode?.removeFromSupernode()
self.timerNode = nil
} else if let usageLimit = invite.usageLimit, let count = invite.count, count >= usageLimit {
if !subtitleText.isEmpty {
subtitleText += ""
}
if share {
subtitleText = presentationData.strings.InviteLink_UsageLimitReached
} else {
subtitleText += presentationData.strings.InviteLink_UsageLimitReached
}
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Expired"), color: .white)
self.timerNode?.removeFromSupernode()
self.timerNode = nil
} else if let expireDate = invite.expireDate {
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Flame"), color: .white)
let timerNode: TimerNode
if let current = self.timerNode {
timerNode = current
} else {
timerNode = TimerNode()
timerNode.isUserInteractionEnabled = false
self.timerNode = timerNode
self.addSubnode(timerNode)
}
timerNode.update(color: UIColor.white, creationTimestamp: invite.startDate ?? invite.date, deadlineTimestamp: expireDate)
if share {
subtitleText = presentationData.strings.InviteLink_TapToCopy
}
} else {
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Link"), color: .white)
self.timerNode?.removeFromSupernode()
self.timerNode = nil
if share {
subtitleText = presentationData.strings.InviteLink_TapToCopy
}
} }
self.iconNode.frame = CGRect(x: 10.0, y: 10.0, width: 30.0, height: 30.0) self.iconNode.frame = CGRect(x: 10.0, y: 10.0, width: 30.0, height: 30.0)
@ -407,7 +425,7 @@ private class ItemNode: ASDisplayNode {
} }
class InviteLinksGridNode: ASDisplayNode { class InviteLinksGridNode: ASDisplayNode {
private var items: [ExportedInvitation] = [] private var items: [ExportedInvitation]?
private var itemNodes: [String: ItemNode] = [:] private var itemNodes: [String: ItemNode] = [:]
var action: ((ExportedInvitation) -> Void)? var action: ((ExportedInvitation) -> Void)?
@ -418,7 +436,7 @@ class InviteLinksGridNode: ASDisplayNode {
return result return result
} }
func update(size: CGSize, safeInset: CGFloat, items: [ExportedInvitation], share: Bool, presentationData: ItemListPresentationData, transition: ContainedViewLayoutTransition) -> CGSize { func update(size: CGSize, safeInset: CGFloat, items: [ExportedInvitation]?, count: Int, share: Bool, presentationData: ItemListPresentationData, transition: ContainedViewLayoutTransition) -> CGSize {
self.items = items self.items = items
var contentSize: CGSize = size var contentSize: CGSize = size
@ -428,24 +446,37 @@ class InviteLinksGridNode: ASDisplayNode {
var validIds = Set<String>() var validIds = Set<String>()
for i in 0 ..< self.items.count { let count = items?.count ?? count
let invite = self.items[i]
validIds.insert(invite.link) for i in 0 ..< count {
let invite: ExportedInvitation?
let id: String
if let items = items, i < items.count {
invite = items[i]
id = invite!.link
} else {
invite = nil
id = "placeholder_\(i)"
}
validIds.insert(id)
var itemNode: ItemNode? var itemNode: ItemNode?
var wasAdded = false var wasAdded = false
if let current = self.itemNodes[invite.link] {
if let current = self.itemNodes[id] {
itemNode = current itemNode = current
} else { } else {
wasAdded = true wasAdded = true
let addedItemNode = ItemNode() let addedItemNode = ItemNode()
itemNode = addedItemNode itemNode = addedItemNode
self.itemNodes[invite.link] = addedItemNode self.itemNodes[id] = addedItemNode
self.addSubnode(addedItemNode) self.addSubnode(addedItemNode)
} }
if let itemNode = itemNode { if let itemNode = itemNode {
let col = CGFloat(i % 2) let col = CGFloat(i % 2)
let row = floor(CGFloat(i) / 2.0) let row = floor(CGFloat(i) / 2.0)
let wide = (i == self.items.count - 1 && (self.items.count % 2) != 0) let wide = (i == count - 1 && (count % 2) != 0)
let itemSize = itemNode.update(size: CGSize(width: size.width - sideInset * 2.0, height: size.height), wide: wide, share: share, invite: invite, presentationData: presentationData, transition: transition) let itemSize = itemNode.update(size: CGSize(width: size.width - sideInset * 2.0, height: size.height), wide: wide, share: share, invite: invite, presentationData: presentationData, transition: transition)
var itemFrame = CGRect(origin: CGPoint(x: sideInset, y: 4.0 + row * (122.0 + itemSpacing)), size: itemSize) var itemFrame = CGRect(origin: CGPoint(x: sideInset, y: 4.0 + row * (122.0 + itemSpacing)), size: itemSize)
if !wide && col > 0 { if !wide && col > 0 {
@ -460,10 +491,14 @@ class InviteLinksGridNode: ASDisplayNode {
transition.updateFrame(node: itemNode, frame: itemFrame) transition.updateFrame(node: itemNode, frame: itemFrame)
} }
itemNode.action = { [weak self] in itemNode.action = { [weak self] in
self?.action?(invite) if let invite = invite {
self?.action?(invite)
}
} }
itemNode.contextAction = { [weak self] node in itemNode.contextAction = { [weak self] node in
self?.contextAction?(node, invite) if let invite = invite {
self?.contextAction?(node, invite)
}
} }
} }
} }

View File

@ -10,6 +10,7 @@ import ItemListUI
public class ItemListInviteLinkGridItem: ListViewItem, ItemListItem { public class ItemListInviteLinkGridItem: ListViewItem, ItemListItem {
let presentationData: ItemListPresentationData let presentationData: ItemListPresentationData
let invites: [ExportedInvitation]? let invites: [ExportedInvitation]?
let count: Int
let share: Bool let share: Bool
public let sectionId: ItemListSectionId public let sectionId: ItemListSectionId
let style: ItemListStyle let style: ItemListStyle
@ -20,6 +21,7 @@ public class ItemListInviteLinkGridItem: ListViewItem, ItemListItem {
public init( public init(
presentationData: ItemListPresentationData, presentationData: ItemListPresentationData,
invites: [ExportedInvitation]?, invites: [ExportedInvitation]?,
count: Int,
share: Bool, share: Bool,
sectionId: ItemListSectionId, sectionId: ItemListSectionId,
style: ItemListStyle, style: ItemListStyle,
@ -29,6 +31,7 @@ public class ItemListInviteLinkGridItem: ListViewItem, ItemListItem {
) { ) {
self.presentationData = presentationData self.presentationData = presentationData
self.invites = invites self.invites = invites
self.count = count
self.share = share self.share = share
self.sectionId = sectionId self.sectionId = sectionId
self.style = style self.style = style
@ -133,13 +136,14 @@ public class ItemListInviteLinkGridItemNode: ListViewItemNode, ItemListItemNode
let topInset: CGFloat let topInset: CGFloat
if case .plain = item.style, case .otherSection = neighbors.top { if case .plain = item.style, case .otherSection = neighbors.top {
topInset = 16.0 topInset = 16.0
} else if case .blocks = item.style, case .sameSection(true) = neighbors.top {
topInset = 16.0
} else { } else {
topInset = 4.0 topInset = 4.0
} }
var height: CGFloat var height: CGFloat
let count = item.invites?.count ?? 0 let count = item.invites?.count ?? item.count
if count > 0 { if count > 0 {
if count % 2 == 0 { if count % 2 == 0 {
height = topInset + 122.0 + 6.0 height = topInset + 122.0 + 6.0
@ -176,7 +180,7 @@ public class ItemListInviteLinkGridItemNode: ListViewItemNode, ItemListItemNode
strongSelf.backgroundNode.backgroundColor = itemBackgroundColor strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
} }
let gridSize = strongSelf.gridNode.update(size: contentSize, safeInset: params.leftInset, items: item.invites ?? [], share: item.share, presentationData: item.presentationData, transition: .immediate) let gridSize = strongSelf.gridNode.update(size: contentSize, safeInset: params.leftInset, items: item.invites, count: item.count, share: item.share, presentationData: item.presentationData, transition: .immediate)
strongSelf.gridNode.frame = CGRect(origin: CGPoint(x: 0.0, y: topInset - 4.0), size: gridSize) strongSelf.gridNode.frame = CGRect(origin: CGPoint(x: 0.0, y: topInset - 4.0), size: gridSize)
strongSelf.gridNode.action = { invite in strongSelf.gridNode.action = { invite in
item.tapAction?(invite) item.tapAction?(invite)

View File

@ -10,6 +10,7 @@ import TelegramPresentationData
import ItemListUI import ItemListUI
import SolidRoundedButtonNode import SolidRoundedButtonNode
import AnimatedAvatarSetNode import AnimatedAvatarSetNode
import ShimmerEffect
private func actionButtonImage(color: UIColor) -> UIImage? { private func actionButtonImage(color: UIColor) -> UIImage? {
return generateImage(CGSize(width: 24.0, height: 24.0), contextGenerator: { size, context in return generateImage(CGSize(width: 24.0, height: 24.0), contextGenerator: { size, context in
@ -132,6 +133,8 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
private var avatarsContent: AnimatedAvatarSetContext.Content? private var avatarsContent: AnimatedAvatarSetContext.Content?
private let avatarsNode: AnimatedAvatarSetNode private let avatarsNode: AnimatedAvatarSetNode
private let invitedPeersNode: TextNode private let invitedPeersNode: TextNode
private var peersPlaceholderNode: ShimmerEffectNode?
private var absoluteLocation: (CGRect, CGSize)?
private let activateArea: AccessibilityAreaNode private let activateArea: AccessibilityAreaNode
@ -470,12 +473,45 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
strongSelf.invitedPeersNode.frame = CGRect(origin: CGPoint(x: leftOrigin, y: fieldFrame.maxY + 92.0), size: invitedPeersLayout.size) strongSelf.invitedPeersNode.frame = CGRect(origin: CGPoint(x: leftOrigin, y: fieldFrame.maxY + 92.0), size: invitedPeersLayout.size)
strongSelf.avatarsButtonNode.frame = CGRect(x: floorToScreenPixels((params.width - totalWidth) / 2.0), y: fieldFrame.maxY + 87.0, width: totalWidth, height: 32.0) strongSelf.avatarsButtonNode.frame = CGRect(x: floorToScreenPixels((params.width - totalWidth) / 2.0), y: fieldFrame.maxY + 87.0, width: totalWidth, height: 32.0)
strongSelf.avatarsButtonNode.isUserInteractionEnabled = !item.peers.isEmpty strongSelf.avatarsButtonNode.isUserInteractionEnabled = !item.peers.isEmpty && item.invite != nil
strongSelf.addressButtonNode.isUserInteractionEnabled = item.invite != nil
strongSelf.fieldButtonNode.isUserInteractionEnabled = item.invite != nil
strongSelf.addressButtonIconNode.alpha = item.invite != nil ? 1.0 : 0.0
strongSelf.shareButtonNode?.isUserInteractionEnabled = item.invite != nil
strongSelf.shareButtonNode?.alpha = item.invite != nil ? 1.0 : 0.4
strongSelf.shareButtonNode?.isHidden = !item.displayButton strongSelf.shareButtonNode?.isHidden = !item.displayButton
strongSelf.avatarsButtonNode.isHidden = !item.displayImporters strongSelf.avatarsButtonNode.isHidden = !item.displayImporters
strongSelf.avatarsNode.isHidden = !item.displayImporters strongSelf.avatarsNode.isHidden = !item.displayImporters || item.invite == nil
strongSelf.invitedPeersNode.isHidden = !item.displayImporters strongSelf.invitedPeersNode.isHidden = !item.displayImporters || item.invite == nil
if item.invite == nil {
let shimmerNode: ShimmerEffectNode
if let current = strongSelf.peersPlaceholderNode {
shimmerNode = current
} else {
shimmerNode = ShimmerEffectNode()
strongSelf.peersPlaceholderNode = shimmerNode
strongSelf.insertSubnode(shimmerNode, belowSubnode: strongSelf.fieldNode)
}
shimmerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
if let (rect, size) = strongSelf.absoluteLocation {
shimmerNode.updateAbsoluteRect(rect, within: size)
}
var shapes: [ShimmerEffectNode.Shape] = []
let lineWidth: CGFloat = 180.0
let lineDiameter: CGFloat = 10.0
let titleFrame = strongSelf.invitedPeersNode.frame
shapes.append(.roundedRectLine(startPoint: CGPoint(x: floor(titleFrame.center.x - lineWidth / 2.0), y: titleFrame.minY + floor((titleFrame.height - lineDiameter) / 2.0)), width: lineWidth, diameter: lineDiameter))
shimmerNode.update(backgroundColor: item.presentationData.theme.list.itemBlocksBackgroundColor, foregroundColor: item.presentationData.theme.list.mediaPlaceholderColor, shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: shapes, size: layout.contentSize)
} else if let shimmerNode = strongSelf.peersPlaceholderNode {
strongSelf.peersPlaceholderNode = nil
shimmerNode.removeFromSupernode()
}
} }
}) })
} }
@ -492,4 +528,13 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) { override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
} }
override public func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
var rect = rect
rect.origin.y += self.insets.top
self.absoluteLocation = (rect, containerSize)
if let shimmerNode = self.peersPlaceholderNode {
shimmerNode.updateAbsoluteRect(rect, within: containerSize)
}
}
} }

View File

@ -1086,7 +1086,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
labelFrame = CGRect(origin: CGPoint(x: revealOffset + params.width - rightLabelInset - badgeWidth + (badgeWidth - labelLayout.size.width) / 2.0, y: floor((contentSize.height - labelLayout.size.height) / 2.0) + 1.0), size: labelLayout.size) labelFrame = CGRect(origin: CGPoint(x: revealOffset + params.width - rightLabelInset - badgeWidth + (badgeWidth - labelLayout.size.width) / 2.0, y: floor((contentSize.height - labelLayout.size.height) / 2.0) + 1.0), size: labelLayout.size)
strongSelf.labelNode.frame = labelFrame strongSelf.labelNode.frame = labelFrame
} else { } else {
labelFrame = CGRect(origin: CGPoint(x: revealOffset + params.width - labelLayout.size.width - rightLabelInset - rightInset, y: floor((contentSize.height - labelLayout.size.height) / 2.0) + 1.0), size: labelLayout.size) labelFrame = CGRect(origin: CGPoint(x: revealOffset + params.width - labelLayout.size.width - rightLabelInset, y: floor((contentSize.height - labelLayout.size.height) / 2.0) + 1.0), size: labelLayout.size)
transition.updateFrame(node: strongSelf.labelNode, frame: labelFrame) transition.updateFrame(node: strongSelf.labelNode, frame: labelFrame)
} }

View File

@ -293,7 +293,7 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
case let .privateLinkHeader(_, title): case let .privateLinkHeader(_, title):
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
case let .privateLink(_, invite, displayImporters): case let .privateLink(_, invite, displayImporters):
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, count: 0, peers: [], displayButton: true, displayImporters: false, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: { return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, count: 0, peers: [], displayButton: true, displayImporters: displayImporters, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
if let invite = invite { if let invite = invite {
arguments.copyLink(invite) arguments.copyLink(invite)
} }
@ -598,13 +598,13 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
} else { } else {
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePublicLinkHelp)) entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePublicLinkHelp))
} }
// switch mode { switch mode {
// case .initialSetup: case .initialSetup:
// break break
// case .generic, .privateLink: case .generic, .privateLink:
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage)) entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo)) entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
// } }
} }
case .privateChannel: case .privateChannel:
let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation
@ -615,13 +615,13 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
} else { } else {
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePrivateLinkHelp)) entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePrivateLinkHelp))
} }
// switch mode { switch mode {
// case .initialSetup: case .initialSetup:
// break break
// case .generic, .privateLink: case .generic, .privateLink:
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage)) entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo)) entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
// } }
} }
} else if let _ = view.peers[view.peerId] as? TelegramGroup { } else if let _ = view.peers[view.peerId] as? TelegramGroup {
switch mode { switch mode {
@ -630,13 +630,13 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_InviteLink.uppercased())) entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_InviteLink.uppercased()))
entries.append(.privateLink(presentationData.theme, invite, mode != .initialSetup)) entries.append(.privateLink(presentationData.theme, invite, mode != .initialSetup))
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.GroupInfo_InviteLink_Help)) entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.GroupInfo_InviteLink_Help))
// switch mode { switch mode {
// case .initialSetup: case .initialSetup:
// break break
// case .generic, .privateLink: case .generic, .privateLink:
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage)) entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo)) entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
// } }
case .generic, .initialSetup: case .generic, .initialSetup:
let selectedType: CurrentChannelType let selectedType: CurrentChannelType
if let current = state.selectedType { if let current = state.selectedType {
@ -729,13 +729,13 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_InviteLink.uppercased())) entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_InviteLink.uppercased()))
entries.append(.privateLink(presentationData.theme, invite, mode != .initialSetup)) entries.append(.privateLink(presentationData.theme, invite, mode != .initialSetup))
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp)) entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
// switch mode { switch mode {
// case .initialSetup: case .initialSetup:
// break break
// case .generic, .privateLink: case .generic, .privateLink:
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage)) entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo)) entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
// } }
} }
} }
} }
@ -943,27 +943,27 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
}) })
}))) })))
// items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
// return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor) return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
// }, action: { _, f in }, action: { _, f in
// f(.dismissWithoutContent) f(.dismissWithoutContent)
//
// let _ = (context.account.postbox.transaction { transaction -> ExportedInvitation? in let _ = (context.account.postbox.transaction { transaction -> ExportedInvitation? in
// if let cachedData = transaction.getPeerCachedData(peerId: peerId) { if let cachedData = transaction.getPeerCachedData(peerId: peerId) {
// if let cachedData = cachedData as? CachedChannelData { if let cachedData = cachedData as? CachedChannelData {
// return cachedData.exportedInvitation return cachedData.exportedInvitation
// } else if let cachedData = cachedData as? CachedGroupData { } else if let cachedData = cachedData as? CachedGroupData {
// return cachedData.exportedInvitation return cachedData.exportedInvitation
// } }
// } }
// return nil return nil
// } |> deliverOnMainQueue).start(next: { invite in } |> deliverOnMainQueue).start(next: { invite in
// if let invite = invite { if let invite = invite {
// let controller = InviteLinkQRCodeController(context: context, invite: invite) let controller = InviteLinkQRCodeController(context: context, invite: invite)
// presentControllerImpl?(controller, nil) presentControllerImpl?(controller, nil)
// } }
// }) })
// }))) })))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextRevoke, textColor: .destructive, icon: { theme in items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextRevoke, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor)
@ -1006,7 +1006,7 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node)), items: .single(items), reactionItems: [], gesture: nil) let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node)), items: .single(items), reactionItems: [], gesture: nil)
presentInGlobalOverlayImpl?(contextController) presentInGlobalOverlayImpl?(contextController)
}, manageInviteLinks: { }, manageInviteLinks: {
let controller = inviteLinkListController(context: context, peerId: peerId) let controller = inviteLinkListController(context: context, peerId: peerId, admin: nil)
pushControllerImpl?(controller) pushControllerImpl?(controller)
}) })

View File

@ -11,8 +11,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) } dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) } dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) } dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) }
dict[2055070967] = { return Api.ChatFull.parse_channelFull($0) } dict[-1415563086] = { return Api.ChatFull.parse_channelFull($0) }
dict[-213431562] = { return Api.ChatFull.parse_chatFull($0) } dict[-261341160] = { return Api.ChatFull.parse_chatFull($0) }
dict[-1159937629] = { return Api.PollResults.parse_pollResults($0) } dict[-1159937629] = { return Api.PollResults.parse_pollResults($0) }
dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) } dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) }
dict[-636267638] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) } dict[-636267638] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) }
@ -106,7 +106,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[483104362] = { return Api.RichText.parse_textPhone($0) } dict[483104362] = { return Api.RichText.parse_textPhone($0) }
dict[136105807] = { return Api.RichText.parse_textImage($0) } dict[136105807] = { return Api.RichText.parse_textImage($0) }
dict[894777186] = { return Api.RichText.parse_textAnchor($0) } dict[894777186] = { return Api.RichText.parse_textAnchor($0) }
dict[-302941166] = { return Api.UserFull.parse_userFull($0) } dict[328899191] = { return Api.UserFull.parse_userFull($0) }
dict[-292807034] = { return Api.InputChannel.parse_inputChannelEmpty($0) } dict[-292807034] = { return Api.InputChannel.parse_inputChannelEmpty($0) }
dict[-1343524562] = { return Api.InputChannel.parse_inputChannel($0) } dict[-1343524562] = { return Api.InputChannel.parse_inputChannel($0) }
dict[414687501] = { return Api.DcOption.parse_dcOption($0) } dict[414687501] = { return Api.DcOption.parse_dcOption($0) }
@ -150,6 +150,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1649296275] = { return Api.Peer.parse_peerUser($0) } dict[-1649296275] = { return Api.Peer.parse_peerUser($0) }
dict[-1160714821] = { return Api.Peer.parse_peerChat($0) } dict[-1160714821] = { return Api.Peer.parse_peerChat($0) }
dict[-1109531342] = { return Api.Peer.parse_peerChannel($0) } dict[-1109531342] = { return Api.Peer.parse_peerChannel($0) }
dict[410107472] = { return Api.messages.ExportedChatInvite.parse_exportedChatInvite($0) }
dict[-1868808300] = { return Api.PaymentRequestedInfo.parse_paymentRequestedInfo($0) } dict[-1868808300] = { return Api.PaymentRequestedInfo.parse_paymentRequestedInfo($0) }
dict[164646985] = { return Api.UserStatus.parse_userStatusEmpty($0) } dict[164646985] = { return Api.UserStatus.parse_userStatusEmpty($0) }
dict[-306628279] = { return Api.UserStatus.parse_userStatusOnline($0) } dict[-306628279] = { return Api.UserStatus.parse_userStatusOnline($0) }
@ -349,6 +350,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1768777083] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaGeo($0) } dict[-1768777083] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaGeo($0) }
dict[2002815875] = { return Api.KeyboardButtonRow.parse_keyboardButtonRow($0) } dict[2002815875] = { return Api.KeyboardButtonRow.parse_keyboardButtonRow($0) }
dict[1088567208] = { return Api.StickerSet.parse_stickerSet($0) } dict[1088567208] = { return Api.StickerSet.parse_stickerSet($0) }
dict[-1111085620] = { return Api.messages.ExportedChatInvites.parse_exportedChatInvites($0) }
dict[354925740] = { return Api.SecureSecretSettings.parse_secureSecretSettings($0) } dict[354925740] = { return Api.SecureSecretSettings.parse_secureSecretSettings($0) }
dict[539045032] = { return Api.photos.Photo.parse_photo($0) } dict[539045032] = { return Api.photos.Photo.parse_photo($0) }
dict[-208488460] = { return Api.InputContact.parse_inputPhoneContact($0) } dict[-208488460] = { return Api.InputContact.parse_inputPhoneContact($0) }
@ -364,6 +366,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-353862078] = { return Api.contacts.Contacts.parse_contacts($0) } dict[-353862078] = { return Api.contacts.Contacts.parse_contacts($0) }
dict[-1798033689] = { return Api.ChannelMessagesFilter.parse_channelMessagesFilterEmpty($0) } dict[-1798033689] = { return Api.ChannelMessagesFilter.parse_channelMessagesFilterEmpty($0) }
dict[-847783593] = { return Api.ChannelMessagesFilter.parse_channelMessagesFilter($0) } dict[-847783593] = { return Api.ChannelMessagesFilter.parse_channelMessagesFilter($0) }
dict[-559275508] = { return Api.ChatAdminWithInvites.parse_chatAdminWithInvites($0) }
dict[2004110666] = { return Api.DialogFilterSuggested.parse_dialogFilterSuggested($0) } dict[2004110666] = { return Api.DialogFilterSuggested.parse_dialogFilterSuggested($0) }
dict[326715557] = { return Api.auth.PasswordRecovery.parse_passwordRecovery($0) } dict[326715557] = { return Api.auth.PasswordRecovery.parse_passwordRecovery($0) }
dict[-1803769784] = { return Api.messages.BotResults.parse_botResults($0) } dict[-1803769784] = { return Api.messages.BotResults.parse_botResults($0) }
@ -405,6 +408,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-666824391] = { return Api.payments.PaymentResult.parse_paymentVerificationNeeded($0) } dict[-666824391] = { return Api.payments.PaymentResult.parse_paymentVerificationNeeded($0) }
dict[1694474197] = { return Api.messages.Chats.parse_chats($0) } dict[1694474197] = { return Api.messages.Chats.parse_chats($0) }
dict[-1663561404] = { return Api.messages.Chats.parse_chatsSlice($0) } dict[-1663561404] = { return Api.messages.Chats.parse_chatsSlice($0) }
dict[-2118733814] = { return Api.messages.ChatInviteImporters.parse_chatInviteImporters($0) }
dict[-659913713] = { return Api.InputGroupCall.parse_inputGroupCall($0) } dict[-659913713] = { return Api.InputGroupCall.parse_inputGroupCall($0) }
dict[482797855] = { return Api.InputSingleMedia.parse_inputSingleMedia($0) } dict[482797855] = { return Api.InputSingleMedia.parse_inputSingleMedia($0) }
dict[1163625789] = { return Api.MessageViews.parse_messageViews($0) } dict[1163625789] = { return Api.MessageViews.parse_messageViews($0) }
@ -546,6 +550,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1032140601] = { return Api.BotCommand.parse_botCommand($0) } dict[-1032140601] = { return Api.BotCommand.parse_botCommand($0) }
dict[1474462241] = { return Api.account.ContentSettings.parse_contentSettings($0) } dict[1474462241] = { return Api.account.ContentSettings.parse_contentSettings($0) }
dict[-1661028051] = { return Api.phone.GroupParticipants.parse_groupParticipants($0) } dict[-1661028051] = { return Api.phone.GroupParticipants.parse_groupParticipants($0) }
dict[507405952] = { return Api.ChatInviteImporter.parse_chatInviteImporter($0) }
dict[-2066640507] = { return Api.messages.AffectedMessages.parse_affectedMessages($0) } dict[-2066640507] = { return Api.messages.AffectedMessages.parse_affectedMessages($0) }
dict[-402498398] = { return Api.messages.SavedGifs.parse_savedGifsNotModified($0) } dict[-402498398] = { return Api.messages.SavedGifs.parse_savedGifsNotModified($0) }
dict[772213157] = { return Api.messages.SavedGifs.parse_savedGifs($0) } dict[772213157] = { return Api.messages.SavedGifs.parse_savedGifs($0) }
@ -628,15 +633,16 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-2044933984] = { return Api.InputStickerSet.parse_inputStickerSetShortName($0) } dict[-2044933984] = { return Api.InputStickerSet.parse_inputStickerSetShortName($0) }
dict[42402760] = { return Api.InputStickerSet.parse_inputStickerSetAnimatedEmoji($0) } dict[42402760] = { return Api.InputStickerSet.parse_inputStickerSetAnimatedEmoji($0) }
dict[-427863538] = { return Api.InputStickerSet.parse_inputStickerSetDice($0) } dict[-427863538] = { return Api.InputStickerSet.parse_inputStickerSetDice($0) }
dict[-1231326505] = { return Api.messages.ChatAdminsWithInvites.parse_chatAdminsWithInvites($0) }
dict[-1729618630] = { return Api.BotInfo.parse_botInfo($0) } dict[-1729618630] = { return Api.BotInfo.parse_botInfo($0) }
dict[-1519637954] = { return Api.updates.State.parse_state($0) } dict[-1519637954] = { return Api.updates.State.parse_state($0) }
dict[372165663] = { return Api.FoundGif.parse_foundGif($0) } dict[372165663] = { return Api.FoundGif.parse_foundGif($0) }
dict[-1670052855] = { return Api.FoundGif.parse_foundGifCached($0) } dict[-1670052855] = { return Api.FoundGif.parse_foundGifCached($0) }
dict[537022650] = { return Api.User.parse_userEmpty($0) } dict[537022650] = { return Api.User.parse_userEmpty($0) }
dict[-1820043071] = { return Api.User.parse_user($0) } dict[-1820043071] = { return Api.User.parse_user($0) }
dict[1487813065] = { return Api.Message.parse_message($0) }
dict[678405636] = { return Api.Message.parse_messageService($0) } dict[678405636] = { return Api.Message.parse_messageService($0) }
dict[-1868117372] = { return Api.Message.parse_messageEmpty($0) } dict[-1868117372] = { return Api.Message.parse_messageEmpty($0) }
dict[-1125940270] = { return Api.Message.parse_message($0) }
dict[831924812] = { return Api.StatsGroupTopInviter.parse_statsGroupTopInviter($0) } dict[831924812] = { return Api.StatsGroupTopInviter.parse_statsGroupTopInviter($0) }
dict[186120336] = { return Api.messages.RecentStickers.parse_recentStickersNotModified($0) } dict[186120336] = { return Api.messages.RecentStickers.parse_recentStickersNotModified($0) }
dict[586395571] = { return Api.messages.RecentStickers.parse_recentStickers($0) } dict[586395571] = { return Api.messages.RecentStickers.parse_recentStickers($0) }
@ -803,6 +809,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1730095465] = { return Api.MessageAction.parse_messageActionGeoProximityReached($0) } dict[-1730095465] = { return Api.MessageAction.parse_messageActionGeoProximityReached($0) }
dict[2047704898] = { return Api.MessageAction.parse_messageActionGroupCall($0) } dict[2047704898] = { return Api.MessageAction.parse_messageActionGroupCall($0) }
dict[1991897370] = { return Api.MessageAction.parse_messageActionInviteToGroupCall($0) } dict[1991897370] = { return Api.MessageAction.parse_messageActionInviteToGroupCall($0) }
dict[-1441072131] = { return Api.MessageAction.parse_messageActionSetMessagesTTL($0) }
dict[1399245077] = { return Api.PhoneCall.parse_phoneCallEmpty($0) } dict[1399245077] = { return Api.PhoneCall.parse_phoneCallEmpty($0) }
dict[462375633] = { return Api.PhoneCall.parse_phoneCallWaiting($0) } dict[462375633] = { return Api.PhoneCall.parse_phoneCallWaiting($0) }
dict[-2014659757] = { return Api.PhoneCall.parse_phoneCallRequested($0) } dict[-2014659757] = { return Api.PhoneCall.parse_phoneCallRequested($0) }
@ -1036,6 +1043,8 @@ public struct Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.Peer: case let _1 as Api.Peer:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.messages.ExportedChatInvite:
_1.serialize(buffer, boxed)
case let _1 as Api.PaymentRequestedInfo: case let _1 as Api.PaymentRequestedInfo:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.UserStatus: case let _1 as Api.UserStatus:
@ -1108,6 +1117,8 @@ public struct Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.StickerSet: case let _1 as Api.StickerSet:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.messages.ExportedChatInvites:
_1.serialize(buffer, boxed)
case let _1 as Api.SecureSecretSettings: case let _1 as Api.SecureSecretSettings:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.photos.Photo: case let _1 as Api.photos.Photo:
@ -1120,6 +1131,8 @@ public struct Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.ChannelMessagesFilter: case let _1 as Api.ChannelMessagesFilter:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.ChatAdminWithInvites:
_1.serialize(buffer, boxed)
case let _1 as Api.DialogFilterSuggested: case let _1 as Api.DialogFilterSuggested:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.auth.PasswordRecovery: case let _1 as Api.auth.PasswordRecovery:
@ -1154,6 +1167,8 @@ public struct Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.messages.Chats: case let _1 as Api.messages.Chats:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.messages.ChatInviteImporters:
_1.serialize(buffer, boxed)
case let _1 as Api.InputGroupCall: case let _1 as Api.InputGroupCall:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.InputSingleMedia: case let _1 as Api.InputSingleMedia:
@ -1284,6 +1299,8 @@ public struct Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.phone.GroupParticipants: case let _1 as Api.phone.GroupParticipants:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.ChatInviteImporter:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.AffectedMessages: case let _1 as Api.messages.AffectedMessages:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.messages.SavedGifs: case let _1 as Api.messages.SavedGifs:
@ -1362,6 +1379,8 @@ public struct Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.InputStickerSet: case let _1 as Api.InputStickerSet:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.messages.ChatAdminsWithInvites:
_1.serialize(buffer, boxed)
case let _1 as Api.BotInfo: case let _1 as Api.BotInfo:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.updates.State: case let _1 as Api.updates.State:

View File

@ -219,6 +219,52 @@ public struct messages {
} }
} }
}
public enum ExportedChatInvite: TypeConstructorDescription {
case exportedChatInvite(invite: Api.ExportedChatInvite, users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .exportedChatInvite(let invite, let users):
if boxed {
buffer.appendInt32(410107472)
}
invite.serialize(buffer, true)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .exportedChatInvite(let invite, let users):
return ("exportedChatInvite", [("invite", invite), ("users", users)])
}
}
public static func parse_exportedChatInvite(_ reader: BufferReader) -> ExportedChatInvite? {
var _1: Api.ExportedChatInvite?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite
}
var _2: [Api.User]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.messages.ExportedChatInvite.exportedChatInvite(invite: _1!, users: _2!)
}
else {
return nil
}
}
} }
public enum VotesList: TypeConstructorDescription { public enum VotesList: TypeConstructorDescription {
case votesList(flags: Int32, count: Int32, votes: [Api.MessageUserVote], users: [Api.User], nextOffset: String?) case votesList(flags: Int32, count: Int32, votes: [Api.MessageUserVote], users: [Api.User], nextOffset: String?)
@ -437,6 +483,60 @@ public struct messages {
} }
} }
}
public enum ExportedChatInvites: TypeConstructorDescription {
case exportedChatInvites(count: Int32, invites: [Api.ExportedChatInvite], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .exportedChatInvites(let count, let invites, let users):
if boxed {
buffer.appendInt32(-1111085620)
}
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(invites.count))
for item in invites {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .exportedChatInvites(let count, let invites, let users):
return ("exportedChatInvites", [("count", count), ("invites", invites), ("users", users)])
}
}
public static func parse_exportedChatInvites(_ reader: BufferReader) -> ExportedChatInvites? {
var _1: Int32?
_1 = reader.readInt32()
var _2: [Api.ExportedChatInvite]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ExportedChatInvite.self)
}
var _3: [Api.User]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.messages.ExportedChatInvites.exportedChatInvites(count: _1!, invites: _2!, users: _3!)
}
else {
return nil
}
}
} }
public enum BotResults: TypeConstructorDescription { public enum BotResults: TypeConstructorDescription {
case botResults(flags: Int32, queryId: Int64, nextOffset: String?, switchPm: Api.InlineBotSwitchPM?, results: [Api.BotInlineResult], cacheTime: Int32, users: [Api.User]) case botResults(flags: Int32, queryId: Int64, nextOffset: String?, switchPm: Api.InlineBotSwitchPM?, results: [Api.BotInlineResult], cacheTime: Int32, users: [Api.User])
@ -625,6 +725,60 @@ public struct messages {
} }
} }
}
public enum ChatInviteImporters: TypeConstructorDescription {
case chatInviteImporters(count: Int32, importers: [Api.ChatInviteImporter], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .chatInviteImporters(let count, let importers, let users):
if boxed {
buffer.appendInt32(-2118733814)
}
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(importers.count))
for item in importers {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .chatInviteImporters(let count, let importers, let users):
return ("chatInviteImporters", [("count", count), ("importers", importers), ("users", users)])
}
}
public static func parse_chatInviteImporters(_ reader: BufferReader) -> ChatInviteImporters? {
var _1: Int32?
_1 = reader.readInt32()
var _2: [Api.ChatInviteImporter]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ChatInviteImporter.self)
}
var _3: [Api.User]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.messages.ChatInviteImporters.chatInviteImporters(count: _1!, importers: _2!, users: _3!)
}
else {
return nil
}
}
} }
public enum DhConfig: TypeConstructorDescription { public enum DhConfig: TypeConstructorDescription {
case dhConfigNotModified(random: Buffer) case dhConfigNotModified(random: Buffer)
@ -1553,6 +1707,56 @@ public struct messages {
} }
} }
}
public enum ChatAdminsWithInvites: TypeConstructorDescription {
case chatAdminsWithInvites(admins: [Api.ChatAdminWithInvites], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .chatAdminsWithInvites(let admins, let users):
if boxed {
buffer.appendInt32(-1231326505)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(admins.count))
for item in admins {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .chatAdminsWithInvites(let admins, let users):
return ("chatAdminsWithInvites", [("admins", admins), ("users", users)])
}
}
public static func parse_chatAdminsWithInvites(_ reader: BufferReader) -> ChatAdminsWithInvites? {
var _1: [Api.ChatAdminWithInvites]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ChatAdminWithInvites.self)
}
var _2: [Api.User]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.messages.ChatAdminsWithInvites.chatAdminsWithInvites(admins: _1!, users: _2!)
}
else {
return nil
}
}
} }
public enum RecentStickers: TypeConstructorDescription { public enum RecentStickers: TypeConstructorDescription {
case recentStickersNotModified case recentStickersNotModified
@ -2176,14 +2380,14 @@ public extension Api {
} }
public enum ChatFull: TypeConstructorDescription { public enum ChatFull: TypeConstructorDescription {
case channelFull(flags: Int32, id: Int32, 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: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32, call: Api.InputGroupCall?) case channelFull(flags: Int32, id: Int32, 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: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32, call: Api.InputGroupCall?, ttlPeriod: Int32?)
case chatFull(flags: Int32, id: Int32, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?, call: Api.InputGroupCall?) case chatFull(flags: Int32, id: Int32, 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?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
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): 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):
if boxed { if boxed {
buffer.appendInt32(2055070967) buffer.appendInt32(-1415563086)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false) serializeInt32(id, buffer: buffer, boxed: false)
@ -2217,10 +2421,11 @@ public extension Api {
if Int(flags) & Int(1 << 12) != 0 {serializeInt32(statsDc!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 12) != 0 {serializeInt32(statsDc!, buffer: buffer, boxed: false)}
serializeInt32(pts, buffer: buffer, boxed: false) serializeInt32(pts, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 21) != 0 {call!.serialize(buffer, true)} if Int(flags) & Int(1 << 21) != 0 {call!.serialize(buffer, true)}
if Int(flags) & Int(1 << 22) != 0 {serializeInt32(ttlPeriod!, buffer: buffer, boxed: false)}
break break
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call): 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):
if boxed { if boxed {
buffer.appendInt32(-213431562) buffer.appendInt32(-261341160)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false) serializeInt32(id, buffer: buffer, boxed: false)
@ -2237,16 +2442,17 @@ public extension Api {
if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 12) != 0 {call!.serialize(buffer, true)} if Int(flags) & Int(1 << 12) != 0 {call!.serialize(buffer, true)}
if Int(flags) & Int(1 << 14) != 0 {serializeInt32(ttlPeriod!, buffer: buffer, boxed: false)}
break break
} }
} }
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
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): 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):
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)]) 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)])
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call): 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):
return ("chatFull", [("flags", flags), ("id", id), ("about", about), ("participants", participants), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("folderId", folderId), ("call", call)]) 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)])
} }
} }
@ -2321,6 +2527,8 @@ public extension Api {
if Int(_1!) & Int(1 << 21) != 0 {if let signature = reader.readInt32() { if Int(_1!) & Int(1 << 21) != 0 {if let signature = reader.readInt32() {
_28 = Api.parse(reader, signature: signature) as? Api.InputGroupCall _28 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
} } } }
var _29: Int32?
if Int(_1!) & Int(1 << 22) != 0 {_29 = reader.readInt32() }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
@ -2349,8 +2557,9 @@ public extension Api {
let _c26 = (Int(_1!) & Int(1 << 12) == 0) || _26 != nil let _c26 = (Int(_1!) & Int(1 << 12) == 0) || _26 != nil
let _c27 = _27 != nil let _c27 = _27 != nil
let _c28 = (Int(_1!) & Int(1 << 21) == 0) || _28 != nil let _c28 = (Int(_1!) & Int(1 << 21) == 0) || _28 != 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 { let _c29 = (Int(_1!) & Int(1 << 22) == 0) || _29 != 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) 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 {
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)
} }
else { else {
return nil return nil
@ -2391,6 +2600,8 @@ public extension Api {
if Int(_1!) & Int(1 << 12) != 0 {if let signature = reader.readInt32() { if Int(_1!) & Int(1 << 12) != 0 {if let signature = reader.readInt32() {
_11 = Api.parse(reader, signature: signature) as? Api.InputGroupCall _11 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
} } } }
var _12: Int32?
if Int(_1!) & Int(1 << 14) != 0 {_12 = reader.readInt32() }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
@ -2402,8 +2613,9 @@ public extension Api {
let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil
let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil
let _c11 = (Int(_1!) & Int(1 << 12) == 0) || _11 != nil let _c11 = (Int(_1!) & Int(1 << 12) == 0) || _11 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 { let _c12 = (Int(_1!) & Int(1 << 14) == 0) || _12 != 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) if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 {
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)
} }
else { else {
return nil return nil
@ -4868,13 +5080,13 @@ public extension Api {
} }
public enum UserFull: TypeConstructorDescription { public enum UserFull: TypeConstructorDescription {
case userFull(flags: Int32, user: Api.User, about: String?, settings: Api.PeerSettings, profilePhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, botInfo: Api.BotInfo?, pinnedMsgId: Int32?, commonChatsCount: Int32, folderId: Int32?) case userFull(flags: Int32, user: Api.User, about: String?, settings: Api.PeerSettings, profilePhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, botInfo: Api.BotInfo?, pinnedMsgId: Int32?, commonChatsCount: Int32, folderId: Int32?, ttlPeriod: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .userFull(let flags, let user, let about, let settings, let profilePhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId): case .userFull(let flags, let user, let about, let settings, let profilePhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod):
if boxed { if boxed {
buffer.appendInt32(-302941166) buffer.appendInt32(328899191)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
user.serialize(buffer, true) user.serialize(buffer, true)
@ -4886,14 +5098,15 @@ public extension Api {
if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)}
serializeInt32(commonChatsCount, buffer: buffer, boxed: false) serializeInt32(commonChatsCount, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 14) != 0 {serializeInt32(ttlPeriod!, buffer: buffer, boxed: false)}
break break
} }
} }
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .userFull(let flags, let user, let about, let settings, let profilePhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId): case .userFull(let flags, let user, let about, let settings, let profilePhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod):
return ("userFull", [("flags", flags), ("user", user), ("about", about), ("settings", settings), ("profilePhoto", profilePhoto), ("notifySettings", notifySettings), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("commonChatsCount", commonChatsCount), ("folderId", folderId)]) return ("userFull", [("flags", flags), ("user", user), ("about", about), ("settings", settings), ("profilePhoto", profilePhoto), ("notifySettings", notifySettings), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("commonChatsCount", commonChatsCount), ("folderId", folderId), ("ttlPeriod", ttlPeriod)])
} }
} }
@ -4928,6 +5141,8 @@ public extension Api {
_9 = reader.readInt32() _9 = reader.readInt32()
var _10: Int32? var _10: Int32?
if Int(_1!) & Int(1 << 11) != 0 {_10 = reader.readInt32() } if Int(_1!) & Int(1 << 11) != 0 {_10 = reader.readInt32() }
var _11: Int32?
if Int(_1!) & Int(1 << 14) != 0 {_11 = reader.readInt32() }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
@ -4938,8 +5153,9 @@ public extension Api {
let _c8 = (Int(_1!) & Int(1 << 6) == 0) || _8 != nil let _c8 = (Int(_1!) & Int(1 << 6) == 0) || _8 != nil
let _c9 = _9 != nil let _c9 = _9 != nil
let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { let _c11 = (Int(_1!) & Int(1 << 14) == 0) || _11 != nil
return Api.UserFull.userFull(flags: _1!, user: _2!, about: _3, settings: _4!, profilePhoto: _5, notifySettings: _6!, botInfo: _7, pinnedMsgId: _8, commonChatsCount: _9!, folderId: _10) if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 {
return Api.UserFull.userFull(flags: _1!, user: _2!, about: _3, settings: _4!, profilePhoto: _5, notifySettings: _6!, botInfo: _7, pinnedMsgId: _8, commonChatsCount: _9!, folderId: _10, ttlPeriod: _11)
} }
else { else {
return nil return nil
@ -11494,6 +11710,44 @@ public extension Api {
} }
} }
}
public enum ChatAdminWithInvites: TypeConstructorDescription {
case chatAdminWithInvites(adminId: Int32, invitesCount: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .chatAdminWithInvites(let adminId, let invitesCount):
if boxed {
buffer.appendInt32(-559275508)
}
serializeInt32(adminId, buffer: buffer, boxed: false)
serializeInt32(invitesCount, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .chatAdminWithInvites(let adminId, let invitesCount):
return ("chatAdminWithInvites", [("adminId", adminId), ("invitesCount", invitesCount)])
}
}
public static func parse_chatAdminWithInvites(_ reader: BufferReader) -> ChatAdminWithInvites? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.ChatAdminWithInvites.chatAdminWithInvites(adminId: _1!, invitesCount: _2!)
}
else {
return nil
}
}
} }
public enum DialogFilterSuggested: TypeConstructorDescription { public enum DialogFilterSuggested: TypeConstructorDescription {
case dialogFilterSuggested(filter: Api.DialogFilter, description: String) case dialogFilterSuggested(filter: Api.DialogFilter, description: String)
@ -16016,6 +16270,44 @@ public extension Api {
} }
} }
}
public enum ChatInviteImporter: TypeConstructorDescription {
case chatInviteImporter(userId: Int32, date: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .chatInviteImporter(let userId, let date):
if boxed {
buffer.appendInt32(507405952)
}
serializeInt32(userId, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .chatInviteImporter(let userId, let date):
return ("chatInviteImporter", [("userId", userId), ("date", date)])
}
}
public static func parse_chatInviteImporter(_ reader: BufferReader) -> ChatInviteImporter? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.ChatInviteImporter.chatInviteImporter(userId: _1!, date: _2!)
}
else {
return nil
}
}
} }
public enum CdnPublicKey: TypeConstructorDescription { public enum CdnPublicKey: TypeConstructorDescription {
case cdnPublicKey(dcId: Int32, publicKey: String) case cdnPublicKey(dcId: Int32, publicKey: String)
@ -18304,15 +18596,35 @@ public extension Api {
} }
public enum Message: TypeConstructorDescription { public enum Message: TypeConstructorDescription {
case message(flags: Int32, id: Int32, fromId: Api.Peer?, peerId: Api.Peer, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int32?, replyTo: Api.MessageReplyHeader?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, forwards: Int32?, replies: Api.MessageReplies?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, restrictionReason: [Api.RestrictionReason]?)
case messageService(flags: Int32, id: Int32, fromId: Api.Peer?, peerId: Api.Peer, replyTo: Api.MessageReplyHeader?, date: Int32, action: Api.MessageAction) case messageService(flags: Int32, id: Int32, fromId: Api.Peer?, peerId: Api.Peer, replyTo: Api.MessageReplyHeader?, date: Int32, action: Api.MessageAction)
case messageEmpty(flags: Int32, id: Int32, peerId: Api.Peer?) case messageEmpty(flags: Int32, id: Int32, peerId: Api.Peer?)
case message(flags: Int32, id: Int32, fromId: Api.Peer?, peerId: Api.Peer, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int32?, replyTo: Api.MessageReplyHeader?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, forwards: Int32?, replies: Api.MessageReplies?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, restrictionReason: [Api.RestrictionReason]?, ttlPeriod: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .message(let flags, let id, let fromId, let peerId, let fwdFrom, let viaBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let restrictionReason): case .messageService(let flags, let id, let fromId, let peerId, let replyTo, let date, let action):
if boxed { if boxed {
buffer.appendInt32(1487813065) buffer.appendInt32(678405636)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 8) != 0 {fromId!.serialize(buffer, true)}
peerId.serialize(buffer, true)
if Int(flags) & Int(1 << 3) != 0 {replyTo!.serialize(buffer, true)}
serializeInt32(date, buffer: buffer, boxed: false)
action.serialize(buffer, true)
break
case .messageEmpty(let flags, let id, let peerId):
if boxed {
buffer.appendInt32(-1868117372)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {peerId!.serialize(buffer, true)}
break
case .message(let flags, let id, let fromId, let peerId, let fwdFrom, let viaBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let restrictionReason, let ttlPeriod):
if boxed {
buffer.appendInt32(-1125940270)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false) serializeInt32(id, buffer: buffer, boxed: false)
@ -18341,41 +18653,78 @@ public extension Api {
for item in restrictionReason! { for item in restrictionReason! {
item.serialize(buffer, true) item.serialize(buffer, true)
}} }}
break if Int(flags) & Int(1 << 25) != 0 {serializeInt32(ttlPeriod!, buffer: buffer, boxed: false)}
case .messageService(let flags, let id, let fromId, let peerId, let replyTo, let date, let action):
if boxed {
buffer.appendInt32(678405636)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 8) != 0 {fromId!.serialize(buffer, true)}
peerId.serialize(buffer, true)
if Int(flags) & Int(1 << 3) != 0 {replyTo!.serialize(buffer, true)}
serializeInt32(date, buffer: buffer, boxed: false)
action.serialize(buffer, true)
break
case .messageEmpty(let flags, let id, let peerId):
if boxed {
buffer.appendInt32(-1868117372)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {peerId!.serialize(buffer, true)}
break break
} }
} }
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .message(let flags, let id, let fromId, let peerId, let fwdFrom, let viaBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let restrictionReason):
return ("message", [("flags", flags), ("id", id), ("fromId", fromId), ("peerId", peerId), ("fwdFrom", fwdFrom), ("viaBotId", viaBotId), ("replyTo", replyTo), ("date", date), ("message", message), ("media", media), ("replyMarkup", replyMarkup), ("entities", entities), ("views", views), ("forwards", forwards), ("replies", replies), ("editDate", editDate), ("postAuthor", postAuthor), ("groupedId", groupedId), ("restrictionReason", restrictionReason)])
case .messageService(let flags, let id, let fromId, let peerId, let replyTo, let date, let action): case .messageService(let flags, let id, let fromId, let peerId, let replyTo, let date, let action):
return ("messageService", [("flags", flags), ("id", id), ("fromId", fromId), ("peerId", peerId), ("replyTo", replyTo), ("date", date), ("action", action)]) return ("messageService", [("flags", flags), ("id", id), ("fromId", fromId), ("peerId", peerId), ("replyTo", replyTo), ("date", date), ("action", action)])
case .messageEmpty(let flags, let id, let peerId): case .messageEmpty(let flags, let id, let peerId):
return ("messageEmpty", [("flags", flags), ("id", id), ("peerId", peerId)]) return ("messageEmpty", [("flags", flags), ("id", id), ("peerId", peerId)])
case .message(let flags, let id, let fromId, let peerId, let fwdFrom, let viaBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let restrictionReason, let ttlPeriod):
return ("message", [("flags", flags), ("id", id), ("fromId", fromId), ("peerId", peerId), ("fwdFrom", fwdFrom), ("viaBotId", viaBotId), ("replyTo", replyTo), ("date", date), ("message", message), ("media", media), ("replyMarkup", replyMarkup), ("entities", entities), ("views", views), ("forwards", forwards), ("replies", replies), ("editDate", editDate), ("postAuthor", postAuthor), ("groupedId", groupedId), ("restrictionReason", restrictionReason), ("ttlPeriod", ttlPeriod)])
} }
} }
public static func parse_messageService(_ reader: BufferReader) -> Message? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Api.Peer?
if Int(_1!) & Int(1 << 8) != 0 {if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.Peer
} }
var _4: Api.Peer?
if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _5: Api.MessageReplyHeader?
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
_5 = Api.parse(reader, signature: signature) as? Api.MessageReplyHeader
} }
var _6: Int32?
_6 = reader.readInt32()
var _7: Api.MessageAction?
if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.MessageAction
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 8) == 0) || _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.Message.messageService(flags: _1!, id: _2!, fromId: _3, peerId: _4!, replyTo: _5, date: _6!, action: _7!)
}
else {
return nil
}
}
public static func parse_messageEmpty(_ reader: BufferReader) -> Message? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Api.Peer?
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.Peer
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
if _c1 && _c2 && _c3 {
return Api.Message.messageEmpty(flags: _1!, id: _2!, peerId: _3)
}
else {
return nil
}
}
public static func parse_message(_ reader: BufferReader) -> Message? { public static func parse_message(_ reader: BufferReader) -> Message? {
var _1: Int32? var _1: Int32?
_1 = reader.readInt32() _1 = reader.readInt32()
@ -18433,6 +18782,8 @@ public extension Api {
if Int(_1!) & Int(1 << 22) != 0 {if let _ = reader.readInt32() { if Int(_1!) & Int(1 << 22) != 0 {if let _ = reader.readInt32() {
_19 = Api.parseVector(reader, elementSignature: 0, elementType: Api.RestrictionReason.self) _19 = Api.parseVector(reader, elementSignature: 0, elementType: Api.RestrictionReason.self)
} } } }
var _20: Int32?
if Int(_1!) & Int(1 << 25) != 0 {_20 = reader.readInt32() }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 8) == 0) || _3 != nil let _c3 = (Int(_1!) & Int(1 << 8) == 0) || _3 != nil
@ -18452,64 +18803,9 @@ public extension Api {
let _c17 = (Int(_1!) & Int(1 << 16) == 0) || _17 != nil let _c17 = (Int(_1!) & Int(1 << 16) == 0) || _17 != nil
let _c18 = (Int(_1!) & Int(1 << 17) == 0) || _18 != nil let _c18 = (Int(_1!) & Int(1 << 17) == 0) || _18 != nil
let _c19 = (Int(_1!) & Int(1 << 22) == 0) || _19 != nil let _c19 = (Int(_1!) & Int(1 << 22) == 0) || _19 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 { let _c20 = (Int(_1!) & Int(1 << 25) == 0) || _20 != nil
return Api.Message.message(flags: _1!, id: _2!, fromId: _3, peerId: _4!, fwdFrom: _5, viaBotId: _6, replyTo: _7, date: _8!, message: _9!, media: _10, replyMarkup: _11, entities: _12, views: _13, forwards: _14, replies: _15, editDate: _16, postAuthor: _17, groupedId: _18, restrictionReason: _19) if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 {
} return Api.Message.message(flags: _1!, id: _2!, fromId: _3, peerId: _4!, fwdFrom: _5, viaBotId: _6, replyTo: _7, date: _8!, message: _9!, media: _10, replyMarkup: _11, entities: _12, views: _13, forwards: _14, replies: _15, editDate: _16, postAuthor: _17, groupedId: _18, restrictionReason: _19, ttlPeriod: _20)
else {
return nil
}
}
public static func parse_messageService(_ reader: BufferReader) -> Message? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Api.Peer?
if Int(_1!) & Int(1 << 8) != 0 {if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.Peer
} }
var _4: Api.Peer?
if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _5: Api.MessageReplyHeader?
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
_5 = Api.parse(reader, signature: signature) as? Api.MessageReplyHeader
} }
var _6: Int32?
_6 = reader.readInt32()
var _7: Api.MessageAction?
if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.MessageAction
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 8) == 0) || _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.Message.messageService(flags: _1!, id: _2!, fromId: _3, peerId: _4!, replyTo: _5, date: _6!, action: _7!)
}
else {
return nil
}
}
public static func parse_messageEmpty(_ reader: BufferReader) -> Message? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Api.Peer?
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.Peer
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
if _c1 && _c2 && _c3 {
return Api.Message.messageEmpty(flags: _1!, id: _2!, peerId: _3)
} }
else { else {
return nil return nil
@ -21858,6 +22154,7 @@ public extension Api {
case messageActionGeoProximityReached(fromId: Api.Peer, toId: Api.Peer, distance: Int32) case messageActionGeoProximityReached(fromId: Api.Peer, toId: Api.Peer, distance: Int32)
case messageActionGroupCall(flags: Int32, call: Api.InputGroupCall, duration: Int32?) case messageActionGroupCall(flags: Int32, call: Api.InputGroupCall, duration: Int32?)
case messageActionInviteToGroupCall(call: Api.InputGroupCall, users: [Int32]) case messageActionInviteToGroupCall(call: Api.InputGroupCall, users: [Int32])
case messageActionSetMessagesTTL(period: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -22056,6 +22353,12 @@ public extension Api {
serializeInt32(item, buffer: buffer, boxed: false) serializeInt32(item, buffer: buffer, boxed: false)
} }
break break
case .messageActionSetMessagesTTL(let period):
if boxed {
buffer.appendInt32(-1441072131)
}
serializeInt32(period, buffer: buffer, boxed: false)
break
} }
} }
@ -22113,6 +22416,8 @@ public extension Api {
return ("messageActionGroupCall", [("flags", flags), ("call", call), ("duration", duration)]) return ("messageActionGroupCall", [("flags", flags), ("call", call), ("duration", duration)])
case .messageActionInviteToGroupCall(let call, let users): case .messageActionInviteToGroupCall(let call, let users):
return ("messageActionInviteToGroupCall", [("call", call), ("users", users)]) return ("messageActionInviteToGroupCall", [("call", call), ("users", users)])
case .messageActionSetMessagesTTL(let period):
return ("messageActionSetMessagesTTL", [("period", period)])
} }
} }
@ -22439,6 +22744,17 @@ public extension Api {
return nil return nil
} }
} }
public static func parse_messageActionSetMessagesTTL(_ reader: BufferReader) -> MessageAction? {
var _1: Int32?
_1 = reader.readInt32()
let _c1 = _1 != nil
if _c1 {
return Api.MessageAction.messageActionSetMessagesTTL(period: _1!)
}
else {
return nil
}
}
} }
public enum PhoneCall: TypeConstructorDescription { public enum PhoneCall: TypeConstructorDescription {

View File

@ -3190,20 +3190,6 @@ public extension Api {
}) })
} }
public static func exportChatInvite(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ExportedChatInvite>) {
let buffer = Buffer()
buffer.appendInt32(234312524)
peer.serialize(buffer, true)
return (FunctionDescription(name: "messages.exportChatInvite", parameters: [("peer", peer)]), 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 getEmojiKeywords(langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.EmojiKeywordsDifference>) { public static func getEmojiKeywords(langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.EmojiKeywordsDifference>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(899735650) buffer.appendInt32(899735650)
@ -4008,6 +3994,121 @@ public extension Api {
return result return result
}) })
} }
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 getExportedChatInvites(flags: Int32, peer: Api.InputPeer, adminId: Api.InputUser, offsetDate: Int32?, offsetLink: String?, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ExportedChatInvites>) {
let buffer = Buffer()
buffer.appendInt32(-1565154314)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
adminId.serialize(buffer, true)
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(offsetDate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {serializeString(offsetLink!, buffer: buffer, boxed: false)}
serializeInt32(limit, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.getExportedChatInvites", parameters: [("flags", flags), ("peer", peer), ("adminId", adminId), ("offsetDate", offsetDate), ("offsetLink", offsetLink), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ExportedChatInvites? in
let reader = BufferReader(buffer)
var result: Api.messages.ExportedChatInvites?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.ExportedChatInvites
}
return result
})
}
public static func editExportedChatInvite(flags: Int32, peer: Api.InputPeer, link: String, expireDate: Int32?, usageLimit: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ExportedChatInvite>) {
let buffer = Buffer()
buffer.appendInt32(48562110)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeString(link, 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)}
return (FunctionDescription(name: "messages.editExportedChatInvite", parameters: [("flags", flags), ("peer", peer), ("link", link), ("expireDate", expireDate), ("usageLimit", usageLimit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ExportedChatInvite? in
let reader = BufferReader(buffer)
var result: Api.messages.ExportedChatInvite?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.ExportedChatInvite
}
return result
})
}
public static func deleteRevokedExportedChatInvites(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(1375999075)
peer.serialize(buffer, true)
return (FunctionDescription(name: "messages.deleteRevokedExportedChatInvites", parameters: [("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
public static func deleteExportedChatInvite(peer: Api.InputPeer, link: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-731601877)
peer.serialize(buffer, true)
serializeString(link, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.deleteExportedChatInvite", parameters: [("peer", peer), ("link", link)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
public static func getChatInviteImporters(peer: Api.InputPeer, link: String, offsetDate: Int32, offsetUser: Api.InputUser, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ChatInviteImporters>) {
let buffer = Buffer()
buffer.appendInt32(654013065)
peer.serialize(buffer, true)
serializeString(link, buffer: buffer, boxed: false)
serializeInt32(offsetDate, buffer: buffer, boxed: false)
offsetUser.serialize(buffer, true)
serializeInt32(limit, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.getChatInviteImporters", parameters: [("peer", peer), ("link", link), ("offsetDate", offsetDate), ("offsetUser", offsetUser), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ChatInviteImporters? in
let reader = BufferReader(buffer)
var result: Api.messages.ChatInviteImporters?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.ChatInviteImporters
}
return result
})
}
public static func getAdminsWithInvites(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ChatAdminsWithInvites>) {
let buffer = Buffer()
buffer.appendInt32(958457583)
peer.serialize(buffer, true)
return (FunctionDescription(name: "messages.getAdminsWithInvites", parameters: [("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ChatAdminsWithInvites? in
let reader = BufferReader(buffer)
var result: Api.messages.ChatAdminsWithInvites?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.ChatAdminsWithInvites
}
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>) {

View File

@ -7,71 +7,12 @@ import MtProtoKit
import SyncCore import SyncCore
public func ensuredExistingPeerExportedInvitation(account: Account, peerId: PeerId, revokeExisted: Bool = false) -> Signal<ExportedInvitation?, NoError> {
return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, NoError> in
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
if let _ = peer as? TelegramChannel {
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, cachedData.exportedInvitation != nil && !revokeExisted {
return .single(cachedData.exportedInvitation)
} else {
return account.network.request(Api.functions.messages.exportChatInvite(peer: inputPeer))
|> retryRequest
|> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in
return account.postbox.transaction { transaction -> ExportedInvitation? in
if let invitation = ExportedInvitation(apiExportedInvite: result) {
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedChannelData {
return current.withUpdatedExportedInvitation(invitation)
} else {
return CachedChannelData().withUpdatedExportedInvitation(invitation)
}
})
return invitation
} else {
return nil
}
}
}
}
} else if let _ = peer as? TelegramGroup {
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedGroupData, cachedData.exportedInvitation != nil && !revokeExisted {
return .single(cachedData.exportedInvitation)
} else {
return account.network.request(Api.functions.messages.exportChatInvite(peer: inputPeer))
|> retryRequest
|> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in
return account.postbox.transaction { transaction -> ExportedInvitation? in
if let invitation = ExportedInvitation(apiExportedInvite: result) {
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedGroupData {
return current.withUpdatedExportedInvitation(invitation)
} else {
return current
}
})
return invitation
} else {
return nil
}
}
}
}
} else {
return .complete()
}
} else {
return .complete()
}
} |> switchToLatest
}
public func revokePersistentPeerExportedInvitation(account: Account, peerId: PeerId) -> Signal<ExportedInvitation?, NoError> { public func revokePersistentPeerExportedInvitation(account: Account, peerId: PeerId) -> Signal<ExportedInvitation?, NoError> {
return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, NoError> in return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, NoError> 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)
if let _ = peer as? TelegramChannel { if let _ = peer as? TelegramChannel {
return account.network.request(Api.functions.messages.exportChatInvite(peer: inputPeer)) return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: 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
@ -90,7 +31,7 @@ public func revokePersistentPeerExportedInvitation(account: Account, peerId: Pee
} }
} }
} else if let _ = peer as? TelegramGroup { } else if let _ = peer as? TelegramGroup {
return account.network.request(Api.functions.messages.exportChatInvite(peer: inputPeer)) return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: 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
@ -122,8 +63,7 @@ public enum CreatePeerExportedInvitationError {
} }
public func createPeerExportedInvitation(account: Account, peerId: PeerId, expireDate: Int32?, usageLimit: Int32?) -> Signal<ExportedInvitation?, CreatePeerExportedInvitationError> { public func createPeerExportedInvitation(account: Account, peerId: PeerId, expireDate: Int32?, usageLimit: Int32?) -> Signal<ExportedInvitation?, CreatePeerExportedInvitationError> {
return .fail(.generic) 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
if let _ = expireDate { if let _ = expireDate {
@ -146,7 +86,7 @@ public func createPeerExportedInvitation(account: Account, peerId: PeerId, expir
} }
} }
|> castError(CreatePeerExportedInvitationError.self) |> castError(CreatePeerExportedInvitationError.self)
|> switchToLatest*/ |> switchToLatest
} }
public enum EditPeerExportedInvitationError { public enum EditPeerExportedInvitationError {
@ -154,8 +94,7 @@ public enum EditPeerExportedInvitationError {
} }
public func editPeerExportedInvitation(account: Account, peerId: PeerId, link: String, expireDate: Int32?, usageLimit: Int32?) -> Signal<ExportedInvitation?, EditPeerExportedInvitationError> { public func editPeerExportedInvitation(account: Account, peerId: PeerId, link: String, expireDate: Int32?, usageLimit: Int32?) -> Signal<ExportedInvitation?, EditPeerExportedInvitationError> {
return .fail(.generic) 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
if let _ = expireDate { if let _ = expireDate {
@ -188,7 +127,7 @@ public func editPeerExportedInvitation(account: Account, peerId: PeerId, link: S
} }
} }
|> castError(EditPeerExportedInvitationError.self) |> castError(EditPeerExportedInvitationError.self)
|> switchToLatest*/ |> switchToLatest
} }
public enum RevokePeerExportedInvitationError { public enum RevokePeerExportedInvitationError {
@ -196,8 +135,7 @@ public enum RevokePeerExportedInvitationError {
} }
public func revokePeerExportedInvitation(account: Account, peerId: PeerId, link: String) -> Signal<ExportedInvitation?, RevokePeerExportedInvitationError> { public func revokePeerExportedInvitation(account: Account, peerId: PeerId, link: String) -> Signal<ExportedInvitation?, RevokePeerExportedInvitationError> {
return .fail(.generic) return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, RevokePeerExportedInvitationError> in
/*return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, 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)) return account.network.request(Api.functions.messages.editExportedChatInvite(flags: flags, peer: inputPeer, link: link, expireDate: nil, usageLimit: nil))
@ -224,7 +162,7 @@ public func revokePeerExportedInvitation(account: Account, peerId: PeerId, link:
} }
} }
|> castError(RevokePeerExportedInvitationError.self) |> castError(RevokePeerExportedInvitationError.self)
|> switchToLatest*/ |> switchToLatest
} }
public struct ExportedInvitations : Equatable { public struct ExportedInvitations : Equatable {
@ -233,9 +171,8 @@ public struct ExportedInvitations : Equatable {
} }
public func peerExportedInvitations(account: Account, peerId: PeerId, revoked: Bool, offsetLink: ExportedInvitation? = nil) -> Signal<ExportedInvitations?, NoError> { public func peerExportedInvitations(account: Account, peerId: PeerId, revoked: Bool, offsetLink: ExportedInvitation? = nil) -> Signal<ExportedInvitations?, NoError> {
return .single(nil) return account.postbox.transaction { transaction -> Signal<ExportedInvitations?, NoError> in
/*return account.postbox.transaction { transaction -> Signal<ExportedInvitations?, NoError> in if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer), let accountPeer = transaction.getPeer(account.peerId), let adminId = apiInputUser(accountPeer) {
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
var flags: Int32 = 0 var flags: Int32 = 0
if let _ = offsetLink { if let _ = offsetLink {
flags |= (1 << 2) flags |= (1 << 2)
@ -243,7 +180,7 @@ public func peerExportedInvitations(account: Account, peerId: PeerId, revoked: B
if revoked { if revoked {
flags |= (1 << 3) flags |= (1 << 3)
} }
return account.network.request(Api.functions.messages.getExportedChatInvites(flags: flags, peer: inputPeer, adminId: nil, offsetDate: offsetLink?.date, offsetLink: offsetLink?.link, limit: 50)) return account.network.request(Api.functions.messages.getExportedChatInvites(flags: flags, peer: inputPeer, adminId: adminId, offsetDate: offsetLink?.date, offsetLink: offsetLink?.link, limit: 50))
|> map(Optional.init) |> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.ExportedChatInvites?, NoError> in |> `catch` { _ -> Signal<Api.messages.ExportedChatInvites?, NoError> in
return .single(nil) return .single(nil)
@ -277,7 +214,7 @@ public func peerExportedInvitations(account: Account, peerId: PeerId, revoked: B
} else { } else {
return .single(nil) return .single(nil)
} }
} |> switchToLatest*/ } |> switchToLatest
} }
@ -286,8 +223,7 @@ public enum DeletePeerExportedInvitationError {
} }
public func deletePeerExportedInvitation(account: Account, peerId: PeerId, link: String) -> Signal<Never, DeletePeerExportedInvitationError> { public func deletePeerExportedInvitation(account: Account, peerId: PeerId, link: String) -> Signal<Never, DeletePeerExportedInvitationError> {
return .fail(.generic) return account.postbox.transaction { transaction -> Signal<Never, DeletePeerExportedInvitationError> in
/*return account.postbox.transaction { transaction -> Signal<Never, DeletePeerExportedInvitationError> in
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
return account.network.request(Api.functions.messages.deleteExportedChatInvite(peer: inputPeer, link: link)) return account.network.request(Api.functions.messages.deleteExportedChatInvite(peer: inputPeer, link: link))
|> mapError { _ in return DeletePeerExportedInvitationError.generic } |> mapError { _ in return DeletePeerExportedInvitationError.generic }
@ -297,12 +233,11 @@ public func deletePeerExportedInvitation(account: Account, peerId: PeerId, link:
} }
} }
|> castError(DeletePeerExportedInvitationError.self) |> castError(DeletePeerExportedInvitationError.self)
|> switchToLatest*/ |> switchToLatest
} }
public func deleteAllRevokedPeerExportedInvitations(account: Account, peerId: PeerId) -> Signal<Never, NoError> { public func deleteAllRevokedPeerExportedInvitations(account: Account, peerId: PeerId) -> Signal<Never, NoError> {
return .complete() return account.postbox.transaction { transaction -> Signal<Never, NoError> in
/*return account.postbox.transaction { transaction -> Signal<Never, NoError> in
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
return account.network.request(Api.functions.messages.deleteRevokedExportedChatInvites(peer: inputPeer)) return account.network.request(Api.functions.messages.deleteRevokedExportedChatInvites(peer: inputPeer))
|> `catch` { _ -> Signal<Api.Bool, NoError> in |> `catch` { _ -> Signal<Api.Bool, NoError> in
@ -313,7 +248,7 @@ public func deleteAllRevokedPeerExportedInvitations(account: Account, peerId: Pe
return .complete() return .complete()
} }
} }
|> switchToLatest*/ |> switchToLatest
} }
private let cachedPeerExportedInvitationsCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 20) private let cachedPeerExportedInvitationsCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 20)
@ -377,6 +312,7 @@ private final class PeerExportedInvitationsContextImpl {
private let queue: Queue private let queue: Queue
private let account: Account private let account: Account
private let peerId: PeerId private let peerId: PeerId
private let adminId: PeerId
private let revoked: Bool private let revoked: Bool
private var forceUpdate: Bool private var forceUpdate: Bool
private let disposable = MetaDisposable() private let disposable = MetaDisposable()
@ -388,36 +324,41 @@ private final class PeerExportedInvitationsContextImpl {
private var results: [ExportedInvitation] = [] private var results: [ExportedInvitation] = []
private var count: Int32 private var count: Int32
private var populateCache: Bool = true private var populateCache: Bool = true
private var isMainList: Bool
let state = Promise<PeerExportedInvitationsState>() let state = Promise<PeerExportedInvitationsState>()
init(queue: Queue, account: Account, peerId: PeerId, revoked: Bool, forceUpdate: Bool) { init(queue: Queue, account: Account, peerId: PeerId, adminId: PeerId?, revoked: Bool, forceUpdate: Bool) {
self.queue = queue self.queue = queue
self.account = account self.account = account
self.peerId = peerId self.peerId = peerId
self.adminId = adminId ?? account.peerId
self.revoked = revoked self.revoked = revoked
self.forceUpdate = forceUpdate self.forceUpdate = forceUpdate
self.isMainList = adminId == nil
self.count = 0 self.count = 0
self.isLoadingMore = true if adminId == nil {
self.disposable.set((account.postbox.transaction { transaction -> CachedPeerExportedInvitations? in self.isLoadingMore = true
return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked))) as? CachedPeerExportedInvitations self.disposable.set((account.postbox.transaction { transaction -> CachedPeerExportedInvitations? in
return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked))) as? CachedPeerExportedInvitations
}
|> deliverOn(self.queue)).start(next: { [weak self] cachedResult in
guard let strongSelf = self else {
return
}
strongSelf.isLoadingMore = false
if let cachedResult = cachedResult {
strongSelf.results = cachedResult.invitations
strongSelf.count = cachedResult.count
strongSelf.hasLoadedOnce = true
strongSelf.canLoadMore = cachedResult.canLoadMore
strongSelf.loadedFromCache = true
}
strongSelf.loadMore()
}))
} }
|> deliverOn(self.queue)).start(next: { [weak self] cachedResult in
guard let strongSelf = self else {
return
}
strongSelf.isLoadingMore = false
if let cachedResult = cachedResult {
strongSelf.results = cachedResult.invitations
strongSelf.count = cachedResult.count
strongSelf.hasLoadedOnce = true
strongSelf.canLoadMore = cachedResult.canLoadMore
strongSelf.loadedFromCache = true
}
strongSelf.loadMore()
}))
self.loadMore() self.loadMore()
} }
@ -433,17 +374,18 @@ private final class PeerExportedInvitationsContextImpl {
} }
func loadMore() { func loadMore() {
/*if self.isLoadingMore { if self.isLoadingMore {
return return
} }
self.isLoadingMore = true self.isLoadingMore = true
let account = self.account let account = self.account
let peerId = self.peerId let peerId = self.peerId
let adminId = self.adminId
let revoked = self.revoked let revoked = self.revoked
var lastResult = self.results.last var lastResult = self.results.last
if self.forceUpdate { if self.forceUpdate {
self.populateCache = true self.populateCache = self.isMainList
self.forceUpdate = false self.forceUpdate = false
lastResult = nil lastResult = nil
} else if self.loadedFromCache { } else if self.loadedFromCache {
@ -452,11 +394,11 @@ private final class PeerExportedInvitationsContextImpl {
} }
let populateCache = self.populateCache let populateCache = self.populateCache
self.disposable.set((self.account.postbox.transaction { transaction -> Api.InputPeer? in self.disposable.set((self.account.postbox.transaction { transaction -> (peerId: Api.InputPeer?, adminId: Api.InputUser?) in
return transaction.getPeer(peerId).flatMap(apiInputPeer) return (transaction.getPeer(peerId).flatMap(apiInputPeer), transaction.getPeer(adminId).flatMap(apiInputUser))
} }
|> mapToSignal { inputPeer -> Signal<([ExportedInvitation], Int32), NoError> in |> mapToSignal { inputPeer, adminId -> Signal<([ExportedInvitation], Int32), NoError> in
if let inputPeer = inputPeer { if let inputPeer = inputPeer, let adminId = adminId {
let offsetLink = lastResult?.link let offsetLink = lastResult?.link
let offsetDate = lastResult?.date let offsetDate = lastResult?.date
var flags: Int32 = 0 var flags: Int32 = 0
@ -466,7 +408,7 @@ private final class PeerExportedInvitationsContextImpl {
if revoked { if revoked {
flags |= (1 << 3) flags |= (1 << 3)
} }
let signal = account.network.request(Api.functions.messages.getExportedChatInvites(flags: flags, peer: inputPeer, adminId: nil, offsetDate: offsetDate, offsetLink: offsetLink, limit: lastResult == nil ? 50 : 100)) let signal = account.network.request(Api.functions.messages.getExportedChatInvites(flags: flags, peer: inputPeer, adminId: adminId, offsetDate: offsetDate, offsetLink: offsetLink, limit: lastResult == nil ? 50 : 100))
|> map(Optional.init) |> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.ExportedChatInvites?, NoError> in |> `catch` { _ -> Signal<Api.messages.ExportedChatInvites?, NoError> in
return .single(nil) return .single(nil)
@ -527,7 +469,7 @@ private final class PeerExportedInvitationsContextImpl {
strongSelf.loadMore() strongSelf.loadMore()
} }
})) }))
self.updateState()*/ self.updateState()
} }
public func add(_ invite: ExportedInvitation) { public func add(_ invite: ExportedInvitation) {
@ -600,10 +542,10 @@ public final class PeerExportedInvitationsContext {
} }
} }
public init(account: Account, peerId: PeerId, revoked: Bool, forceUpdate: Bool) { public init(account: Account, peerId: PeerId, adminId: PeerId?, revoked: Bool, forceUpdate: Bool) {
let queue = self.queue let queue = self.queue
self.impl = QueueLocalObject(queue: queue, generate: { self.impl = QueueLocalObject(queue: queue, generate: {
return PeerExportedInvitationsContextImpl(queue: queue, account: account, peerId: peerId, revoked: revoked, forceUpdate: forceUpdate) return PeerExportedInvitationsContextImpl(queue: queue, account: account, peerId: peerId, adminId: adminId, revoked: revoked, forceUpdate: forceUpdate)
}) })
} }
@ -783,7 +725,7 @@ private final class PeerInvitationImportersContextImpl {
if self.isLoadingMore { if self.isLoadingMore {
return return
} }
/*self.isLoadingMore = true self.isLoadingMore = true
let account = self.account let account = self.account
let peerId = self.peerId let peerId = self.peerId
let link = self.link let link = self.link
@ -871,7 +813,7 @@ private final class PeerInvitationImportersContextImpl {
} }
strongSelf.updateState() strongSelf.updateState()
})) }))
self.updateState()*/ self.updateState()
} }
private func updateState() { private func updateState() {
@ -908,3 +850,62 @@ public final class PeerInvitationImportersContext {
} }
} }
} }
public struct ExportedInvitationCreator : Equatable {
public let peer: RenderedPeer
public let count: Int32
}
public func peerExportedInvitationsCreators(account: Account, peerId: PeerId) -> Signal<[ExportedInvitationCreator], NoError> {
return account.postbox.transaction { transaction -> Signal<[ExportedInvitationCreator], NoError> in
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
var isCreator = false
if let peer = peer as? TelegramGroup, case .creator = peer.role {
isCreator = true
} else if let peer = peer as? TelegramChannel, peer.flags.contains(.isCreator) {
isCreator = true
}
if !isCreator {
return .single([])
} else {
return account.network.request(Api.functions.messages.getAdminsWithInvites(peer: inputPeer))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.ChatAdminsWithInvites?, NoError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<[ExportedInvitationCreator], NoError> in
return account.postbox.transaction { transaction -> [ExportedInvitationCreator] in
if let result = result, case let .chatAdminsWithInvites(admins, users) = result {
var creators: [ExportedInvitationCreator] = []
var peers: [Peer] = []
var peersMap: [PeerId: Peer] = [:]
for user in users {
let telegramUser = TelegramUser(user: user)
peers.append(telegramUser)
peersMap[telegramUser.id] = telegramUser
}
for case let .chatAdminWithInvites(adminId, invitesCount) in admins {
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: adminId)
if let peer = peersMap[peerId], peerId != account.peerId {
creators.append(ExportedInvitationCreator(peer: RenderedPeer(peer: peer), count: invitesCount))
}
}
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
return updated
})
return creators
} else {
return []
}
}
}
}
} else {
return .single([])
}
} |> switchToLatest
}

View File

@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization { public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt { public func currentLayer() -> UInt {
return 123 return 124
} }
public func parseMessage(_ data: Data!) -> Any! { public func parseMessage(_ data: Data!) -> Any! {

View File

@ -129,7 +129,7 @@ func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? {
func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] { func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
switch message { switch message {
case let .message(flags, _, fromId, chatPeerId, fwdHeader, viaBotId, _, _, _, media, _, entities, _, _, _, _, _, _, _): case let .message(flags, _, fromId, chatPeerId, fwdHeader, viaBotId, _, _, _, media, _, entities, _, _, _, _, _, _, _, _):
let peerId: PeerId = chatPeerId.peerId let peerId: PeerId = chatPeerId.peerId
var result = [peerId] var result = [peerId]
@ -192,7 +192,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
} }
switch action { switch action {
case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp, .messageActionGroupCall: case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp, .messageActionGroupCall, .messageActionSetMessagesTTL:
break break
case let .messageActionChannelMigrateFrom(_, chatId): case let .messageActionChannelMigrateFrom(_, chatId):
result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)) result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId))
@ -225,7 +225,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
func apiMessageAssociatedMessageIds(_ message: Api.Message) -> [MessageId]? { func apiMessageAssociatedMessageIds(_ message: Api.Message) -> [MessageId]? {
switch message { switch message {
case let .message(_, _, _, chatPeerId, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _): case let .message(_, _, _, chatPeerId, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _, _):
if let replyTo = replyTo { if let replyTo = replyTo {
let peerId: PeerId = chatPeerId.peerId let peerId: PeerId = chatPeerId.peerId
@ -371,7 +371,7 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes
extension StoreMessage { extension StoreMessage {
convenience init?(apiMessage: Api.Message, namespace: MessageId.Namespace = Namespaces.Message.Cloud) { convenience init?(apiMessage: Api.Message, namespace: MessageId.Namespace = Namespaces.Message.Cloud) {
switch apiMessage { switch apiMessage {
case let .message(flags, id, fromId, chatPeerId, fwdFrom, viaBotId, replyTo, date, message, media, replyMarkup, entities, views, forwards, replies, editDate, postAuthor, groupingId, restrictionReason): case let .message(flags, id, fromId, chatPeerId, fwdFrom, viaBotId, replyTo, date, message, media, replyMarkup, entities, views, forwards, replies, editDate, postAuthor, groupingId, restrictionReason, _):
let resolvedFromId = fromId?.peerId ?? chatPeerId.peerId let resolvedFromId = fromId?.peerId ?? chatPeerId.peerId
let peerId: PeerId let peerId: PeerId

View File

@ -71,6 +71,8 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
})) }))
} }
case .messageActionSetMessagesTTL(period: let period):
return nil
} }
} }

View File

@ -352,7 +352,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
} }
switch fullChat { switch fullChat {
case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, chatPhoto, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, folderId, linkedChatId, location, slowmodeSeconds, slowmodeNextSendDate, statsDc, pts, inputCall): case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, chatPhoto, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, folderId, linkedChatId, location, slowmodeSeconds, slowmodeNextSendDate, statsDc, pts, inputCall, _):
var channelFlags = CachedChannelFlags() var channelFlags = CachedChannelFlags()
if (flags & (1 << 3)) != 0 { if (flags & (1 << 3)) != 0 {
channelFlags.insert(.canDisplayParticipants) channelFlags.insert(.canDisplayParticipants)

View File

@ -58,7 +58,7 @@ class UpdateMessageService: NSObject, MTMessageService {
self.putNext(groups) self.putNext(groups)
} }
case let .updateShortChatMessage(flags, id, fromId, chatId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyHeader, entities): case let .updateShortChatMessage(flags, id, fromId, chatId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyHeader, entities):
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: .peerUser(userId: fromId), peerId: Api.Peer.peerChat(chatId: chatId), fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, restrictionReason: nil) let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: .peerUser(userId: fromId), peerId: Api.Peer.peerChat(chatId: chatId), fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, restrictionReason: nil, ttlPeriod: nil)
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount) let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil) let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
if groups.count != 0 { if groups.count != 0 {
@ -74,7 +74,7 @@ class UpdateMessageService: NSObject, MTMessageService {
let generatedPeerId = Api.Peer.peerUser(userId: userId) let generatedPeerId = Api.Peer.peerUser(userId: userId)
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: generatedFromId, peerId: generatedPeerId, fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, restrictionReason: nil) let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: generatedFromId, peerId: generatedPeerId, fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, restrictionReason: nil, ttlPeriod: nil)
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount) let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil) let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
if groups.count != 0 { if groups.count != 0 {

View File

@ -654,17 +654,17 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
discussionPeer = peer discussionPeer = peer
} }
// if currentInvitationsContext == nil { if currentInvitationsContext == nil {
// var canManageInvitations = false var canManageInvitations = false
// if let channel = peerViewMainPeer(peerView) as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData, channel.flags.contains(.isCreator) || ((channel.adminRights != nil && channel.hasPermission(.pinMessages)) && cachedData.flags.contains(.canChangeUsername)) { if let channel = peerViewMainPeer(peerView) as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData, channel.flags.contains(.isCreator) || ((channel.adminRights != nil && channel.hasPermission(.pinMessages)) && cachedData.flags.contains(.canChangeUsername)) {
// canManageInvitations = true canManageInvitations = true
// } }
// if canManageInvitations { if canManageInvitations {
// let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: true) let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, adminId: nil, revoked: false, forceUpdate: true)
// invitationsContextPromise.set(.single(invitationsContext)) invitationsContextPromise.set(.single(invitationsContext))
// invitationsStatePromise.set(invitationsContext.state |> map(Optional.init)) invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
// } }
// } }
return PeerInfoScreenData( return PeerInfoScreenData(
peer: peerView.peers[peerId], peer: peerView.peers[peerId],
@ -811,19 +811,19 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
} }
} }
// if currentInvitationsContext == nil { if currentInvitationsContext == nil {
// var canManageInvitations = false var canManageInvitations = false
// if let group = peerViewMainPeer(peerView) as? TelegramGroup, case .creator = group.role { if let group = peerViewMainPeer(peerView) as? TelegramGroup, case .creator = group.role {
// canManageInvitations = true canManageInvitations = true
// } else if let channel = peerViewMainPeer(peerView) as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData, channel.flags.contains(.isCreator) || ((channel.adminRights != nil && channel.hasPermission(.pinMessages)) && cachedData.flags.contains(.canChangeUsername)) { } else if let channel = peerViewMainPeer(peerView) as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData, channel.flags.contains(.isCreator) || ((channel.adminRights != nil && channel.hasPermission(.pinMessages)) && cachedData.flags.contains(.canChangeUsername)) {
// canManageInvitations = true canManageInvitations = true
// } }
// if canManageInvitations { if canManageInvitations {
// let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: true) let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, adminId: nil, revoked: false, forceUpdate: true)
// invitationsContextPromise.set(.single(invitationsContext)) invitationsContextPromise.set(.single(invitationsContext))
// invitationsStatePromise.set(invitationsContext.state |> map(Optional.init)) invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
// } }
// } }
return PeerInfoScreenData( return PeerInfoScreenData(
peer: peerView.peers[groupId], peer: peerView.peers[groupId],

View File

@ -931,8 +931,8 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
var directionIsToRight: Bool? var directionIsToRight: Bool?
if abs(velocity.x) > 10.0 { if abs(velocity.x) > 10.0 {
directionIsToRight = velocity.x < 0.0 directionIsToRight = velocity.x < 0.0
} else if abs(transitionFraction) > 0.5 { } else if abs(self.transitionFraction) > 0.5 {
directionIsToRight = transitionFraction < 0.0 directionIsToRight = self.transitionFraction < 0.0
} }
var updatedIndex = self.currentIndex var updatedIndex = self.currentIndex
if let directionIsToRight = directionIsToRight { if let directionIsToRight = directionIsToRight {

View File

@ -1220,9 +1220,9 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
invitesText = "" invitesText = ""
} }
// items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: { items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
// interaction.editingOpenInviteLinksSetup() interaction.editingOpenInviteLinksSetup()
// })) }))
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemDiscussionGroup, label: .text(discussionGroupTitle), text: presentationData.strings.Channel_DiscussionGroup, action: { items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemDiscussionGroup, label: .text(discussionGroupTitle), text: presentationData.strings.Channel_DiscussionGroup, action: {
interaction.editingOpenDiscussionGroupSetup() interaction.editingOpenDiscussionGroupSetup()
@ -1304,9 +1304,9 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
invitesText = "" invitesText = ""
} }
// items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: { items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
// interaction.editingOpenInviteLinksSetup() interaction.editingOpenInviteLinksSetup()
// })) }))
} }
if cachedData.flags.contains(.canChangeUsername) { if cachedData.flags.contains(.canChangeUsername) {
@ -1388,9 +1388,9 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
invitesText = "" invitesText = ""
} }
// items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: { items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemInviteLinks, label: .text(invitesText), text: presentationData.strings.GroupInfo_InviteLinks, action: {
// interaction.editingOpenInviteLinksSetup() interaction.editingOpenInviteLinksSetup()
// })) }))
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPreHistory, label: .text(presentationData.strings.GroupInfo_GroupHistoryHidden), text: presentationData.strings.GroupInfo_GroupHistory, action: { items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPreHistory, label: .text(presentationData.strings.GroupInfo_GroupHistoryHidden), text: presentationData.strings.GroupInfo_GroupHistory, action: {
interaction.editingOpenPreHistorySetup() interaction.editingOpenPreHistorySetup()
@ -3746,7 +3746,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
} }
private func editingOpenInviteLinksSetup() { private func editingOpenInviteLinksSetup() {
self.controller?.push(inviteLinkListController(context: self.context, peerId: self.peerId)) self.controller?.push(inviteLinkListController(context: self.context, peerId: self.peerId, admin: nil))
} }
private func editingOpenDiscussionGroupSetup() { private func editingOpenDiscussionGroupSetup() {

View File

@ -128,6 +128,13 @@ public final class TelegramRootController: NavigationController {
self.accountSettingsController = accountSettingsController self.accountSettingsController = accountSettingsController
self.rootTabController = tabBarController self.rootTabController = tabBarController
self.pushViewController(tabBarController, animated: false) self.pushViewController(tabBarController, animated: false)
Queue.mainQueue().after(1.0) {
let datepicker = DatePickerNode(theme: DatePickerTheme(theme: self.presentationData.theme), strings: self.presentationData.strings)
datepicker.frame = CGRect(origin: CGPoint(x: 0.0, y: 60.0), size: CGSize(width: 390.0, height: 390.0))
datepicker.updateLayout(size: datepicker.frame.size, transition: .immediate)
self.rootTabController?.displayNode.addSubnode(datepicker)
}
} }
public func updateRootControllers(showCallsTab: Bool) { public func updateRootControllers(showCallsTab: Bool) {