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.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.Read" = "Read";

View File

@ -474,7 +474,7 @@ final class InviteContactsControllerNode: ASDisplayNode {
var headerInsets = layout.insets(options: [.input])
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 {
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 {

View File

@ -12,15 +12,15 @@ final class InviteContactsCountPanelNode: ASDisplayNode {
private let separatorNode: ASDisplayNode
private let button: SolidRoundedButtonNode
private var validLayout: (CGFloat, CGFloat)?
private var validLayout: (CGFloat, CGFloat, CGFloat)?
var count: Int = 0 {
didSet {
if self.count != oldValue && self.count > 0 {
self.button.title = self.strings.Contacts_InviteContacts(Int32(self.count))
if let (width, bottomInset) = self.validLayout {
let _ = self.updateLayout(width: width, bottomInset: bottomInset, transition: .immediate)
if let (width, sideInset, bottomInset) = self.validLayout {
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 {
self.validLayout = (width, bottomInset)
func updateLayout(width: CGFloat, sideInset: CGFloat, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
self.validLayout = (width, sideInset, bottomInset)
let topInset: CGFloat = 9.0
var bottomInset = bottomInset
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 buttonHeight = self.button.updateLayout(width: buttonWidth, transition: transition)
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 TelegramStringFormatting
private let textFont = Font.regular(13.0)
private let selectedTextFont = Font.bold(13.0)
public final class DatePickerTheme: Equatable {
public let backgroundColor: UIColor
public let textColor: UIColor
@ -15,18 +12,16 @@ public final class DatePickerTheme: Equatable {
public let accentColor: UIColor
public let disabledColor: UIColor
public let selectionColor: UIColor
public let selectedCurrentTextColor: UIColor
public let secondarySelectionColor: UIColor
public let selectionTextColor: 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.textColor = textColor
self.secondaryTextColor = secondaryTextColor
self.accentColor = accentColor
self.disabledColor = disabledColor
self.selectionColor = selectionColor
self.selectedCurrentTextColor = selectedCurrentTextColor
self.secondarySelectionColor = secondarySelectionColor
self.selectionTextColor = selectionTextColor
}
public static func ==(lhs: DatePickerTheme, rhs: DatePickerTheme) -> Bool {
@ -45,31 +40,26 @@ public final class DatePickerTheme: Equatable {
if lhs.selectionColor != rhs.selectionColor {
return false
}
if lhs.selectedCurrentTextColor != rhs.selectedCurrentTextColor {
return false
}
if lhs.secondarySelectionColor != rhs.secondarySelectionColor {
if lhs.selectionTextColor != rhs.selectionTextColor {
return false
}
return true
}
}
//public extension DatePickerTheme {
// 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)
// }
//}
private class SegmentedControlItemNode: HighlightTrackingButtonNode {
public extension DatePickerTheme {
convenience init(theme: PresentationTheme) {
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 let telegramReleaseDate = Date(timeIntervalSince1970: 1376438400.0)
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 dateFont = Font.with(size: 13.0, design: .regular, traits: .monospacedNumbers)
private let selectedDateFont = Font.bold(13.0)
private let dateFont = Font.with(size: 17.0, design: .regular, traits: .monospacedNumbers)
private let selectedDateFont = Font.with(size: 17.0, design: .regular, traits: [.bold, .monospacedNumbers])
private let calendar = Calendar(identifier: .gregorian)
@ -81,12 +71,46 @@ private func monthForDate(_ date: Date) -> Date {
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 {
private let month: Date
var theme: DatePickerTheme {
didSet {
self.selectionNode.image = generateStretchableFilledCircleImage(diameter: 44.0, color: self.theme.selectionColor)
if let size = self.validSize {
self.updateLayout(size: size)
}
@ -136,6 +160,7 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
self.selectionNode = ASImageNode()
self.selectionNode.displaysAsynchronously = false
self.selectionNode.displayWithoutProcessing = true
self.selectionNode.image = generateStretchableFilledCircleImage(diameter: 44.0, color: theme.selectionColor)
self.dateNodes = (0..<42).map { _ in ImmediateTextNode() }
@ -147,7 +172,7 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
self.numberOfDays = calendar.range(of: .day, in: .month, for: month)!.count
super.init()
self.addSubnode(self.selectionNode)
self.dateNodes.forEach { self.addSubnode($0) }
}
@ -157,6 +182,10 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
var started = false
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 {
let row: Int = Int(floor(Float(i) / 7.0))
let col: Int = i % 7
@ -164,49 +193,55 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
if !started && weekday == self.startWeekday {
started = true
}
weekday += 1
if started {
count += 1
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 {
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 {
isAvailableDate = false
}
}
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 {
isAvailableDate = false
}
}
var isSelectedDate = false
var isSelectedAndCurrentDate = false
let isToday = calendar.isDateInToday(date)
let isSelected = self.date.flatMap { calendar.isDate(date, equalTo: $0, toGranularity: .day) } ?? false
let color: UIColor
if !isAvailableDate {
color = self.theme.disabledColor
} else if isSelectedAndCurrentDate {
color = .white
} else if isSelectedDate {
if isSelected {
color = self.theme.selectionTextColor
} else if isToday {
color = self.theme.accentColor
} else if !isAvailableDate {
color = self.theme.disabledColor
} else {
color = self.theme.textColor
}
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)
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 {
break
@ -232,40 +267,75 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
private let timeTitleNode: ImmediateTextNode
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 monthTextNode: ImmediateTextNode
private let monthArrowNode: ASImageNode
private let previousButtonNode: HighlightableButtonNode
private let nextButtonNode: HighlightableButtonNode
private let dayNodes: [ImmediateTextNode]
private var previousMonthNode: MonthNode?
private var currentMonthNode: MonthNode?
private var nextMonthNode: MonthNode?
private let scrollNode: ASScrollNode
private var transitionFraction: CGFloat = 0.0
private var gestureRecognizer: UIPanGestureRecognizer?
private var gestureSelectedIndex: Int?
private var validLayout: CGSize?
public var maximumDate: Date? {
didSet {
public var maximumDate: Date {
get {
return self.state.maxDate
}
}
public var minimumDate: Date = telegramReleaseDate {
didSet {
}
}
public var date: Date = Date() {
didSet {
guard self.date != oldValue else {
set {
guard newValue != self.maximumDate else {
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 {
let _ = self.updateLayout(size: size, transition: .immediate)
}
@ -282,33 +352,74 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
self.timeFieldNode.displaysAsynchronously = false
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.monthTextNode = ImmediateTextNode()
self.monthArrowNode = ASImageNode()
self.monthArrowNode.displaysAsynchronously = false
self.monthArrowNode.displayWithoutProcessing = true
self.previousButtonNode = HighlightableButtonNode()
self.previousButtonNode.hitTestSlop = UIEdgeInsets(top: -6.0, left: -10.0, bottom: -6.0, right: -10.0)
self.nextButtonNode = HighlightableButtonNode()
self.dayNodes = (0..<7).map { _ in ImmediateTextNode() }
self.scrollNode = ASScrollNode()
self.nextButtonNode.hitTestSlop = UIEdgeInsets(top: -6.0, left: -10.0, bottom: -6.0, right: -10.0)
super.init()
self.clipsToBounds = true
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.monthArrowNode)
self.addSubnode(self.monthButtonNode)
self.addSubnode(self.previousButtonNode)
self.addSubnode(self.nextButtonNode)
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)
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() {
@ -316,15 +427,62 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
self.view.disablesInteractiveTransitionGestureRecognizer = true
self.scrollNode.view.isPagingEnabled = true
self.scrollNode.view.delegate = self
self.contentNode.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:))))
self.contentNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
}
private func updateState(_ state: State, animated: Bool) {
let previousState = self.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) {
@ -334,55 +492,262 @@ public final class DatePickerNode: ASDisplayNode, UIScrollViewDelegate {
self.theme = theme
self.backgroundColor = self.theme.backgroundColor
}
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.view.window?.endEditing(true)
}
public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
if let size = self.validLayout {
self.updateLayout(size: size, transition: .immediate)
}
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)
for (_, monthNode) in self.monthNodes {
monthNode.theme = theme
}
if let size = self.validLayout {
self.updateLayout(size: size, transition: .immediate)
}
}
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if let size = self.validLayout {
self.updateLayout(size: size, transition: .immediate)
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
}
@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) {
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)
self.scrollNode.frame = CGRect(origin: CGPoint(x: 0.0, y: topInset), size: scrollSize)
self.scrollNode.view.contentSize = CGSize(width: scrollSize.width * 3.0, height: scrollSize.height)
self.scrollNode.view.contentOffset = CGPoint(x: scrollSize.width, y: 0.0)
let month = monthForDate(self.state.selectedMonth)
let components = calendar.dateComponents([.month, .year], from: month)
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 {
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)
dayNode.attributedText = NSAttributedString(string: shortStringForDayOfWeek(strings: self.strings, day: day), font: dayFont, textColor: theme.secondaryTextColor)
let size = dayNode.updateLayout(size)
dayNode.frame = CGRect(origin: CGPoint(x: CGFloat(i) * 20.0, y: 0.0), size: size)
let textSize = dayNode.updateLayout(size)
let cellFrame = CGRect(x: daysSideInset + CGFloat(i) * cellSize, y: 40.0, 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)
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)
if traits.contains(.monospacedNumbers) {
updatedDescriptor = descriptor.addingAttributes([
updatedDescriptor = updatedDescriptor?.addingAttributes([
UIFontDescriptor.AttributeName.featureSettings: [
[UIFontDescriptor.FeatureKey.featureIdentifier:
kNumberSpacingType,

View File

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

View File

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

View File

@ -149,7 +149,7 @@ private enum InviteLinkInviteEntry: Comparable, Identifiable {
}, viewAction: {
})
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)
}, contextAction: { invite, _ in
interaction.shareLink(invite)
@ -218,7 +218,7 @@ public final class InviteLinkInviteController: ViewController {
override public func loadDisplayNode() {
self.displayNode = Node(context: self.context, peerId: self.peerId, controller: self)
}
private var didAppearOnce: Bool = false
private var isDismissed: Bool = false
public override func viewDidAppear(_ animated: Bool) {
@ -288,7 +288,7 @@ public final class InviteLinkInviteController: ViewController {
self.presentationDataPromise = Promise(self.presentationData)
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.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
// return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
// }, action: { _, f in
// f(.dismissWithoutContent)
//
// if let invite = invite {
// let controller = InviteLinkQRCodeController(context: context, invite: invite)
// self?.controller?.present(controller, in: .window(.root))
// }
// })))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
f(.dismissWithoutContent)
if let invite = invite {
let controller = InviteLinkQRCodeController(context: context, invite: invite)
self?.controller?.present(controller, in: .window(.root))
}
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextRevoke, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor)
@ -395,7 +395,7 @@ public final class InviteLinkInviteController: ViewController {
let shareController = ShareController(context: context, subject: .url(invite.link))
self?.controller?.present(shareController, in: .window(.root))
}, 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?.dismiss()
})
@ -403,8 +403,7 @@ public final class InviteLinkInviteController: ViewController {
let previousEntries = Atomic<[InviteLinkInviteEntry]?>(value: nil)
let peerView = context.account.postbox.peerView(id: peerId)
let invites: Signal<PeerExportedInvitationsState, NoError> = .single(PeerExportedInvitationsState())
self.disposable = (combineLatest(self.presentationDataPromise.get(), peerView, invites)
self.disposable = (combineLatest(self.presentationDataPromise.get(), peerView, self.invitesContext.state)
|> deliverOnMainQueue).start(next: { [weak self] presentationData, view, invites in
if let strongSelf = self {
var entries: [InviteLinkInviteEntry] = []
@ -423,19 +422,19 @@ public final class InviteLinkInviteController: ViewController {
entries.append(.mainLink(presentationData.theme, mainInvite))
}
// let additionalInvites = invites.invitations.filter { $0.link != mainInvite?.link }
// var index: Int32 = 0
// for i in stride(from: 0, to: additionalInvites.endIndex, by: 2) {
// var invitesPair: [ExportedInvitation] = []
// invitesPair.append(additionalInvites[i])
// if i + 1 < additionalInvites.count {
// invitesPair.append(additionalInvites[i + 1])
// }
// entries.append(.links(index, presentationData.theme, invitesPair))
// index += 1
// }
let additionalInvites = invites.invitations.filter { $0.link != mainInvite?.link }
var index: Int32 = 0
for i in stride(from: 0, to: additionalInvites.endIndex, by: 2) {
var invitesPair: [ExportedInvitation] = []
invitesPair.append(additionalInvites[i])
if i + 1 < additionalInvites.count {
invitesPair.append(additionalInvites[i + 1])
}
entries.append(.links(index, presentationData.theme, invitesPair))
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)

View File

@ -18,6 +18,7 @@ import AppBundle
import ContextUI
import TelegramStringFormatting
import ItemListPeerActionItem
import ItemListPeerItem
import ShareController
import UndoUI
@ -30,9 +31,10 @@ private final class InviteLinkListControllerArguments {
let createLink: () -> Void
let openLink: (ExportedInvitation) -> Void
let linkContextAction: (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void
let openAdmin: (ExportedInvitationCreator) -> 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.shareMainLink = shareMainLink
self.openMainLink = openMainLink
@ -41,6 +43,7 @@ private final class InviteLinkListControllerArguments {
self.createLink = createLink
self.openLink = openLink
self.linkContextAction = linkContextAction
self.openAdmin = openAdmin
self.deleteAllRevokedLinks = deleteAllRevokedLinks
}
}
@ -49,6 +52,7 @@ private enum InviteLinksListSection: Int32 {
case header
case mainLink
case links
case admins
case revokedLinks
}
@ -57,11 +61,16 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
case mainLinkHeader(PresentationTheme, String)
case mainLink(PresentationTheme, ExportedInvitation?, [Peer], Int32, Bool)
case mainLinkOtherInfo(PresentationTheme, String)
case linksHeader(PresentationTheme, String)
case linksCreate(PresentationTheme, String)
case links(Int32, PresentationTheme, [ExportedInvitation]?)
case links(Int32, PresentationTheme, [ExportedInvitation]?, Int)
case linksInfo(PresentationTheme, String)
case adminsHeader(PresentationTheme, String)
case admin(Int32, PresentationTheme, ExportedInvitationCreator)
case revokedLinksHeader(PresentationTheme, String)
case revokedLinksDeleteAll(PresentationTheme, String)
case revokedLinks(Int32, PresentationTheme, [ExportedInvitation]?)
@ -70,10 +79,12 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
switch self {
case .header:
return InviteLinksListSection.header.rawValue
case .mainLinkHeader, .mainLink:
case .mainLinkHeader, .mainLink, .mainLinkOtherInfo:
return InviteLinksListSection.mainLink.rawValue
case .linksHeader, .linksCreate, .links, .linksInfo:
return InviteLinksListSection.links.rawValue
case .adminsHeader, .admin:
return InviteLinksListSection.admins.rawValue
case .revokedLinksHeader, .revokedLinksDeleteAll, .revokedLinks:
return InviteLinksListSection.revokedLinks.rawValue
}
@ -87,20 +98,26 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
return 1
case .mainLink:
return 2
case .linksHeader:
case .mainLinkOtherInfo:
return 3
case .linksCreate:
case .linksHeader:
return 4
case let .links(index, _, _):
return 5 + index
case .linksCreate:
return 5
case let .links(index, _, _, _):
return 6 + index
case .linksInfo:
return 10000
case .revokedLinksHeader:
case .adminsHeader:
return 10001
case let .admin(index, _, _):
return 10002 + index
case .revokedLinksHeader:
return 20001
case .revokedLinksDeleteAll:
return 10002
return 20002
case let .revokedLinks(index, _, _):
return 10003 + index
return 20003 + index
}
}
@ -124,6 +141,12 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
} else {
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):
if case let .linksHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
@ -136,8 +159,8 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
} else {
return false
}
case let .links(lhsIndex, lhsTheme, lhsLinks):
if case let .links(rhsIndex, rhsTheme, rhsLinks) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsLinks == rhsLinks {
case let .links(lhsIndex, lhsTheme, lhsLinks, lhsCount):
if case let .links(rhsIndex, rhsTheme, rhsLinks, rhsCount) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsLinks == rhsLinks, lhsCount == rhsCount {
return true
} else {
return false
@ -148,6 +171,18 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
} else {
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):
if case let .revokedLinksHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
@ -196,20 +231,28 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
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):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .linksCreate(theme, text):
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.plusIconImage(theme), title: text, hasSeparator: false, sectionId: self.section, editing: false, action: {
arguments.createLink()
})
case let .links(_, _, invites):
return ItemListInviteLinkGridItem(presentationData: presentationData, invites: invites, share: false, sectionId: self.section, style: .blocks, tapAction: { invite in
case let .links(_, _, invites, count):
return ItemListInviteLinkGridItem(presentationData: presentationData, invites: invites, count: count, share: false, sectionId: self.section, style: .blocks, tapAction: { invite in
arguments.openLink(invite)
}, contextAction: { invite, node in
arguments.linkContextAction(invite, node, nil)
})
case let .linksInfo(_, text):
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):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .revokedLinksDeleteAll(theme, text):
@ -217,7 +260,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
arguments.deleteAllRevokedLinks()
})
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)
}, contextAction: { invite, node in
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] = []
entries.append(.header(presentationData.theme, presentationData.strings.InviteLink_CreatePrivateLinkHelp))
if admin == nil {
entries.append(.header(presentationData.theme, presentationData.strings.InviteLink_CreatePrivateLinkHelp))
}
let mainInvite: ExportedInvitation?
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)
isPublic = true
} else if let invites = invites, let invite = invites.first(where: { $0.isPermanent && !$0.isRevoked }) {
mainInvite = invite
} else if let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation {
} else if let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation, admin == nil {
mainInvite = invite
} else if let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation {
} else if let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation, admin == nil {
mainInvite = invite
} else {
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))
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(.linksCreate(presentationData.theme, presentationData.strings.InviteLink_Create))
if admin == nil {
entries.append(.linksCreate(presentationData.theme, presentationData.strings.InviteLink_Create))
}
var additionalInvites: [ExportedInvitation]?
if let invites = invites {
additionalInvites = invites.filter { $0.link != mainInvite?.link }
@ -275,16 +324,34 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData,
if i + 1 < additionalInvites.count {
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
}
}
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 {
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
for i in stride(from: 0, to: revokedInvites.endIndex, by: 2) {
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 presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)?
var presentInGlobalOverlayImpl: ((ViewController) -> Void)?
@ -326,8 +393,16 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
var getControllerImpl: (() -> ViewController?)?
let invitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: false)
let revokedInvitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: true, forceUpdate: true)
let adminId = admin?.peer.peer?.id
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 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)
presentInGlobalOverlayImpl?(contextController)
}, openAdmin: { admin in
let controller = inviteLinkListController(context: context, peerId: peerId, admin: admin)
pushControllerImpl?(controller)
}, deleteAllRevokedLinks: {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let controller = ActionSheetController(presentationData: presentationData)
@ -596,9 +674,9 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
}
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
|> 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)
var crossfade = false
@ -606,8 +684,15 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
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 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)
let title: ItemListControllerTitle
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))
}

View File

@ -112,7 +112,7 @@ private class ItemNode: ASDisplayNode {
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 contextAction: ((ASDisplayNode) -> Void)?
@ -214,44 +214,50 @@ private class ItemNode: ASDisplayNode {
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 availability = invitationAvailability(invite)
let availability = invite.flatMap { invitationAvailability($0) } ?? 0.0
let transitionFraction: CGFloat
let color: 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
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
}
let previousParams = self.params
self.params = (size, wide, invite, color, presentationData)
let previousExpireDate = previousParams?.invite.expireDate
if previousExpireDate != invite.expireDate {
let previousExpireDate = previousParams?.invite?.expireDate
if previousExpireDate != invite?.expireDate {
self.updateTimer?.invalidate()
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 updateTimer = SwiftSignalKit.Timer(timeout: timeout, repeat: true, completion: { [weak self] in
if let strongSelf = self {
@ -272,8 +278,13 @@ private class ItemNode: ASDisplayNode {
let bottomColor = color.colors.bottom
let nextTopColor = nextColor.colors.top
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 previousColor != color && color == .red {
if let snapshotView = self.wrapperNode.view.snapshotContentTree() {
@ -298,7 +309,7 @@ private class ItemNode: ASDisplayNode {
let secondaryTextColor = nextColor.colors.text.mixedWith(color.colors.text, alpha: transitionFraction)
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 {
inviteLink = inviteLink.replacingOccurrences(of: "joinchat/", with: "joinchat/\n")
inviteLink = inviteLink.replacingOccurrences(of: "join/", with: "join/\n")
@ -314,65 +325,72 @@ private class ItemNode: ASDisplayNode {
self.buttonIconNode.image = share ? shareIcon : moreIcon
var subtitleText: String = ""
if let count = invite.count {
subtitleText = presentationData.strings.InviteLink_PeopleJoinedShort(count)
if let invite = invite {
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 {
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 = true
self.buttonIconNode.isHidden = true
}
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 {
private var items: [ExportedInvitation] = []
private var items: [ExportedInvitation]?
private var itemNodes: [String: ItemNode] = [:]
var action: ((ExportedInvitation) -> Void)?
@ -418,7 +436,7 @@ class InviteLinksGridNode: ASDisplayNode {
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
var contentSize: CGSize = size
@ -428,24 +446,37 @@ class InviteLinksGridNode: ASDisplayNode {
var validIds = Set<String>()
for i in 0 ..< self.items.count {
let invite = self.items[i]
validIds.insert(invite.link)
let count = items?.count ?? count
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 wasAdded = false
if let current = self.itemNodes[invite.link] {
if let current = self.itemNodes[id] {
itemNode = current
} else {
wasAdded = true
let addedItemNode = ItemNode()
itemNode = addedItemNode
self.itemNodes[invite.link] = addedItemNode
self.itemNodes[id] = addedItemNode
self.addSubnode(addedItemNode)
}
if let itemNode = itemNode {
let col = CGFloat(i % 2)
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)
var itemFrame = CGRect(origin: CGPoint(x: sideInset, y: 4.0 + row * (122.0 + itemSpacing)), size: itemSize)
if !wide && col > 0 {
@ -460,10 +491,14 @@ class InviteLinksGridNode: ASDisplayNode {
transition.updateFrame(node: itemNode, frame: itemFrame)
}
itemNode.action = { [weak self] in
self?.action?(invite)
if let invite = invite {
self?.action?(invite)
}
}
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 {
let presentationData: ItemListPresentationData
let invites: [ExportedInvitation]?
let count: Int
let share: Bool
public let sectionId: ItemListSectionId
let style: ItemListStyle
@ -20,6 +21,7 @@ public class ItemListInviteLinkGridItem: ListViewItem, ItemListItem {
public init(
presentationData: ItemListPresentationData,
invites: [ExportedInvitation]?,
count: Int,
share: Bool,
sectionId: ItemListSectionId,
style: ItemListStyle,
@ -29,6 +31,7 @@ public class ItemListInviteLinkGridItem: ListViewItem, ItemListItem {
) {
self.presentationData = presentationData
self.invites = invites
self.count = count
self.share = share
self.sectionId = sectionId
self.style = style
@ -133,13 +136,14 @@ public class ItemListInviteLinkGridItemNode: ListViewItemNode, ItemListItemNode
let topInset: CGFloat
if case .plain = item.style, case .otherSection = neighbors.top {
topInset = 16.0
} else if case .blocks = item.style, case .sameSection(true) = neighbors.top {
topInset = 16.0
} else {
topInset = 4.0
}
var height: CGFloat
let count = item.invites?.count ?? 0
let count = item.invites?.count ?? item.count
if count > 0 {
if count % 2 == 0 {
height = topInset + 122.0 + 6.0
@ -176,7 +180,7 @@ public class ItemListInviteLinkGridItemNode: ListViewItemNode, ItemListItemNode
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.action = { invite in
item.tapAction?(invite)

View File

@ -10,6 +10,7 @@ import TelegramPresentationData
import ItemListUI
import SolidRoundedButtonNode
import AnimatedAvatarSetNode
import ShimmerEffect
private func actionButtonImage(color: UIColor) -> UIImage? {
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 let avatarsNode: AnimatedAvatarSetNode
private let invitedPeersNode: TextNode
private var peersPlaceholderNode: ShimmerEffectNode?
private var absoluteLocation: (CGRect, CGSize)?
private let activateArea: AccessibilityAreaNode
@ -180,7 +183,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
self.avatarsContext = AnimatedAvatarSetContext()
self.avatarsNode = AnimatedAvatarSetNode()
self.invitedPeersNode = TextNode()
self.activateArea = AccessibilityAreaNode()
super.init(layerBacked: false, dynamicBounce: false)
@ -355,7 +358,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
strongSelf.fieldNode.image = generateStretchableFilledCircleImage(diameter: 18.0, color: item.presentationData.theme.list.itemInputField.backgroundColor)
strongSelf.addressButtonIconNode.image = actionButtonImage(color: item.presentationData.theme.list.itemInputField.controlColor)
}
let _ = addressApply()
let _ = invitedPeersApply()
@ -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.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.avatarsButtonNode.isHidden = !item.displayImporters
strongSelf.avatarsNode.isHidden = !item.displayImporters
strongSelf.invitedPeersNode.isHidden = !item.displayImporters
strongSelf.avatarsNode.isHidden = !item.displayImporters || item.invite == nil
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) {
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)
strongSelf.labelNode.frame = labelFrame
} 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)
}

View File

@ -293,7 +293,7 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
case let .privateLinkHeader(_, title):
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
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 {
arguments.copyLink(invite)
}
@ -598,13 +598,13 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
} else {
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePublicLinkHelp))
}
// switch mode {
// case .initialSetup:
// break
// case .generic, .privateLink:
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
// }
switch mode {
case .initialSetup:
break
case .generic, .privateLink:
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
}
}
case .privateChannel:
let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation
@ -615,13 +615,13 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
} else {
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePrivateLinkHelp))
}
// switch mode {
// case .initialSetup:
// break
// case .generic, .privateLink:
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
// }
switch mode {
case .initialSetup:
break
case .generic, .privateLink:
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
}
}
} else if let _ = view.peers[view.peerId] as? TelegramGroup {
switch mode {
@ -630,13 +630,13 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_InviteLink.uppercased()))
entries.append(.privateLink(presentationData.theme, invite, mode != .initialSetup))
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.GroupInfo_InviteLink_Help))
// switch mode {
// case .initialSetup:
// break
// case .generic, .privateLink:
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
// }
switch mode {
case .initialSetup:
break
case .generic, .privateLink:
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
}
case .generic, .initialSetup:
let selectedType: CurrentChannelType
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(.privateLink(presentationData.theme, invite, mode != .initialSetup))
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
// switch mode {
// case .initialSetup:
// break
// case .generic, .privateLink:
// entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
// entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
// }
switch mode {
case .initialSetup:
break
case .generic, .privateLink:
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
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
// return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
// }, action: { _, f in
// f(.dismissWithoutContent)
//
// let _ = (context.account.postbox.transaction { transaction -> ExportedInvitation? in
// if let cachedData = transaction.getPeerCachedData(peerId: peerId) {
// if let cachedData = cachedData as? CachedChannelData {
// return cachedData.exportedInvitation
// } else if let cachedData = cachedData as? CachedGroupData {
// return cachedData.exportedInvitation
// }
// }
// return nil
// } |> deliverOnMainQueue).start(next: { invite in
// if let invite = invite {
// let controller = InviteLinkQRCodeController(context: context, invite: invite)
// presentControllerImpl?(controller, nil)
// }
// })
// })))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Wallet/QrIcon"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
f(.dismissWithoutContent)
let _ = (context.account.postbox.transaction { transaction -> ExportedInvitation? in
if let cachedData = transaction.getPeerCachedData(peerId: peerId) {
if let cachedData = cachedData as? CachedChannelData {
return cachedData.exportedInvitation
} else if let cachedData = cachedData as? CachedGroupData {
return cachedData.exportedInvitation
}
}
return nil
} |> deliverOnMainQueue).start(next: { invite in
if let invite = invite {
let controller = InviteLinkQRCodeController(context: context, invite: invite)
presentControllerImpl?(controller, nil)
}
})
})))
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)
@ -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)
presentInGlobalOverlayImpl?(contextController)
}, manageInviteLinks: {
let controller = inviteLinkListController(context: context, peerId: peerId)
let controller = inviteLinkListController(context: context, peerId: peerId, admin: nil)
pushControllerImpl?(controller)
})

View File

@ -11,8 +11,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) }
dict[2055070967] = { return Api.ChatFull.parse_channelFull($0) }
dict[-213431562] = { return Api.ChatFull.parse_chatFull($0) }
dict[-1415563086] = { return Api.ChatFull.parse_channelFull($0) }
dict[-261341160] = { return Api.ChatFull.parse_chatFull($0) }
dict[-1159937629] = { return Api.PollResults.parse_pollResults($0) }
dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($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[136105807] = { return Api.RichText.parse_textImage($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[-1343524562] = { return Api.InputChannel.parse_inputChannel($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[-1160714821] = { return Api.Peer.parse_peerChat($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[164646985] = { return Api.UserStatus.parse_userStatusEmpty($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[2002815875] = { return Api.KeyboardButtonRow.parse_keyboardButtonRow($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[539045032] = { return Api.photos.Photo.parse_photo($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[-1798033689] = { return Api.ChannelMessagesFilter.parse_channelMessagesFilterEmpty($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[326715557] = { return Api.auth.PasswordRecovery.parse_passwordRecovery($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[1694474197] = { return Api.messages.Chats.parse_chats($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[482797855] = { return Api.InputSingleMedia.parse_inputSingleMedia($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[1474462241] = { return Api.account.ContentSettings.parse_contentSettings($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[-402498398] = { return Api.messages.SavedGifs.parse_savedGifsNotModified($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[42402760] = { return Api.InputStickerSet.parse_inputStickerSetAnimatedEmoji($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[-1519637954] = { return Api.updates.State.parse_state($0) }
dict[372165663] = { return Api.FoundGif.parse_foundGif($0) }
dict[-1670052855] = { return Api.FoundGif.parse_foundGifCached($0) }
dict[537022650] = { return Api.User.parse_userEmpty($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[-1868117372] = { return Api.Message.parse_messageEmpty($0) }
dict[-1125940270] = { return Api.Message.parse_message($0) }
dict[831924812] = { return Api.StatsGroupTopInviter.parse_statsGroupTopInviter($0) }
dict[186120336] = { return Api.messages.RecentStickers.parse_recentStickersNotModified($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[2047704898] = { return Api.MessageAction.parse_messageActionGroupCall($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[462375633] = { return Api.PhoneCall.parse_phoneCallWaiting($0) }
dict[-2014659757] = { return Api.PhoneCall.parse_phoneCallRequested($0) }
@ -1036,6 +1043,8 @@ public struct Api {
_1.serialize(buffer, boxed)
case let _1 as Api.Peer:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.ExportedChatInvite:
_1.serialize(buffer, boxed)
case let _1 as Api.PaymentRequestedInfo:
_1.serialize(buffer, boxed)
case let _1 as Api.UserStatus:
@ -1108,6 +1117,8 @@ public struct Api {
_1.serialize(buffer, boxed)
case let _1 as Api.StickerSet:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.ExportedChatInvites:
_1.serialize(buffer, boxed)
case let _1 as Api.SecureSecretSettings:
_1.serialize(buffer, boxed)
case let _1 as Api.photos.Photo:
@ -1120,6 +1131,8 @@ public struct Api {
_1.serialize(buffer, boxed)
case let _1 as Api.ChannelMessagesFilter:
_1.serialize(buffer, boxed)
case let _1 as Api.ChatAdminWithInvites:
_1.serialize(buffer, boxed)
case let _1 as Api.DialogFilterSuggested:
_1.serialize(buffer, boxed)
case let _1 as Api.auth.PasswordRecovery:
@ -1154,6 +1167,8 @@ public struct Api {
_1.serialize(buffer, boxed)
case let _1 as Api.messages.Chats:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.ChatInviteImporters:
_1.serialize(buffer, boxed)
case let _1 as Api.InputGroupCall:
_1.serialize(buffer, boxed)
case let _1 as Api.InputSingleMedia:
@ -1284,6 +1299,8 @@ public struct Api {
_1.serialize(buffer, boxed)
case let _1 as Api.phone.GroupParticipants:
_1.serialize(buffer, boxed)
case let _1 as Api.ChatInviteImporter:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.AffectedMessages:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.SavedGifs:
@ -1362,6 +1379,8 @@ public struct Api {
_1.serialize(buffer, boxed)
case let _1 as Api.InputStickerSet:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.ChatAdminsWithInvites:
_1.serialize(buffer, boxed)
case let _1 as Api.BotInfo:
_1.serialize(buffer, boxed)
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 {
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 {
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 {
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 {
case recentStickersNotModified
@ -2176,14 +2380,14 @@ public extension Api {
}
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 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 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?, ttlPeriod: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
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 {
buffer.appendInt32(2055070967)
buffer.appendInt32(-1415563086)
}
serializeInt32(flags, 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)}
serializeInt32(pts, buffer: buffer, boxed: false)
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
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 {
buffer.appendInt32(-213431562)
buffer.appendInt32(-261341160)
}
serializeInt32(flags, 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 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)}
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
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
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):
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)])
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let 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)])
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), ("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, 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), ("ttlPeriod", ttlPeriod)])
}
}
@ -2321,6 +2527,8 @@ public extension Api {
if Int(_1!) & Int(1 << 21) != 0 {if let signature = reader.readInt32() {
_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 _c2 = _2 != nil
let _c3 = _3 != nil
@ -2349,8 +2557,9 @@ public extension Api {
let _c26 = (Int(_1!) & Int(1 << 12) == 0) || _26 != nil
let _c27 = _27 != 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 {
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)
let _c29 = (Int(_1!) & Int(1 << 22) == 0) || _29 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 && _c28 && _c29 {
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 {
return nil
@ -2391,6 +2600,8 @@ public extension Api {
if Int(_1!) & Int(1 << 12) != 0 {if let signature = reader.readInt32() {
_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 _c2 = _2 != nil
let _c3 = _3 != nil
@ -2402,8 +2613,9 @@ public extension Api {
let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil
let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil
let _c11 = (Int(_1!) & Int(1 << 12) == 0) || _11 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 {
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)
let _c12 = (Int(_1!) & Int(1 << 14) == 0) || _12 != nil
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 {
return nil
@ -4868,13 +5080,13 @@ public extension Api {
}
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) {
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 {
buffer.appendInt32(-302941166)
buffer.appendInt32(328899191)
}
serializeInt32(flags, buffer: buffer, boxed: false)
user.serialize(buffer, true)
@ -4886,14 +5098,15 @@ public extension Api {
if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, 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 << 14) != 0 {serializeInt32(ttlPeriod!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .userFull(let flags, let user, let about, let settings, let profilePhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId):
return ("userFull", [("flags", flags), ("user", user), ("about", about), ("settings", settings), ("profilePhoto", profilePhoto), ("notifySettings", notifySettings), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("commonChatsCount", commonChatsCount), ("folderId", 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), ("ttlPeriod", ttlPeriod)])
}
}
@ -4928,6 +5141,8 @@ public extension Api {
_9 = reader.readInt32()
var _10: Int32?
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 _c2 = _2 != 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 _c9 = _9 != nil
let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 {
return Api.UserFull.userFull(flags: _1!, user: _2!, about: _3, settings: _4!, profilePhoto: _5, notifySettings: _6!, botInfo: _7, pinnedMsgId: _8, commonChatsCount: _9!, folderId: _10)
let _c11 = (Int(_1!) & Int(1 << 14) == 0) || _11 != nil
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 {
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 {
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 {
case cdnPublicKey(dcId: Int32, publicKey: String)
@ -18304,15 +18596,35 @@ public extension Api {
}
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 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) {
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 {
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(id, buffer: buffer, boxed: false)
@ -18341,41 +18653,78 @@ public extension Api {
for item in restrictionReason! {
item.serialize(buffer, true)
}}
break
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)}
if Int(flags) & Int(1 << 25) != 0 {serializeInt32(ttlPeriod!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
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):
return ("messageService", [("flags", flags), ("id", id), ("fromId", fromId), ("peerId", peerId), ("replyTo", replyTo), ("date", date), ("action", action)])
case .messageEmpty(let flags, let id, let 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? {
var _1: Int32?
_1 = reader.readInt32()
@ -18433,6 +18782,8 @@ public extension Api {
if Int(_1!) & Int(1 << 22) != 0 {if let _ = reader.readInt32() {
_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 _c2 = _2 != 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 _c18 = (Int(_1!) & Int(1 << 17) == 0) || _18 != 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 {
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)
}
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)
let _c20 = (Int(_1!) & Int(1 << 25) == 0) || _20 != nil
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
@ -21858,6 +22154,7 @@ public extension Api {
case messageActionGeoProximityReached(fromId: Api.Peer, toId: Api.Peer, distance: Int32)
case messageActionGroupCall(flags: Int32, call: Api.InputGroupCall, duration: Int32?)
case messageActionInviteToGroupCall(call: Api.InputGroupCall, users: [Int32])
case messageActionSetMessagesTTL(period: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
@ -22056,6 +22353,12 @@ public extension Api {
serializeInt32(item, buffer: buffer, boxed: false)
}
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)])
case .messageActionInviteToGroupCall(let call, let users):
return ("messageActionInviteToGroupCall", [("call", call), ("users", users)])
case .messageActionSetMessagesTTL(let period):
return ("messageActionSetMessagesTTL", [("period", period)])
}
}
@ -22439,6 +22744,17 @@ public extension Api {
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 {

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>) {
let buffer = Buffer()
buffer.appendInt32(899735650)
@ -4008,6 +3994,121 @@ public extension Api {
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 static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {

View File

@ -7,71 +7,12 @@ import MtProtoKit
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> {
return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, NoError> in
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
let flags: Int32 = (1 << 2)
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
|> mapToSignal { result -> Signal<ExportedInvitation?, NoError> 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 {
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
|> mapToSignal { result -> Signal<ExportedInvitation?, NoError> 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> {
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) {
var flags: Int32 = 0
if let _ = expireDate {
@ -146,7 +86,7 @@ public func createPeerExportedInvitation(account: Account, peerId: PeerId, expir
}
}
|> castError(CreatePeerExportedInvitationError.self)
|> switchToLatest*/
|> switchToLatest
}
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> {
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) {
var flags: Int32 = 0
if let _ = expireDate {
@ -188,7 +127,7 @@ public func editPeerExportedInvitation(account: Account, peerId: PeerId, link: S
}
}
|> castError(EditPeerExportedInvitationError.self)
|> switchToLatest*/
|> switchToLatest
}
public enum RevokePeerExportedInvitationError {
@ -196,8 +135,7 @@ public enum 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) {
let flags: Int32 = (1 << 2)
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)
|> switchToLatest*/
|> switchToLatest
}
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> {
return .single(nil)
/*return account.postbox.transaction { transaction -> Signal<ExportedInvitations?, NoError> in
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
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) {
var flags: Int32 = 0
if let _ = offsetLink {
flags |= (1 << 2)
@ -243,7 +180,7 @@ public func peerExportedInvitations(account: Account, peerId: PeerId, revoked: B
if revoked {
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)
|> `catch` { _ -> Signal<Api.messages.ExportedChatInvites?, NoError> in
return .single(nil)
@ -277,7 +214,7 @@ public func peerExportedInvitations(account: Account, peerId: PeerId, revoked: B
} else {
return .single(nil)
}
} |> switchToLatest*/
} |> switchToLatest
}
@ -286,8 +223,7 @@ public enum 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) {
return account.network.request(Api.functions.messages.deleteExportedChatInvite(peer: inputPeer, link: link))
|> mapError { _ in return DeletePeerExportedInvitationError.generic }
@ -297,12 +233,11 @@ public func deletePeerExportedInvitation(account: Account, peerId: PeerId, link:
}
}
|> castError(DeletePeerExportedInvitationError.self)
|> switchToLatest*/
|> switchToLatest
}
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) {
return account.network.request(Api.functions.messages.deleteRevokedExportedChatInvites(peer: inputPeer))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
@ -313,7 +248,7 @@ public func deleteAllRevokedPeerExportedInvitations(account: Account, peerId: Pe
return .complete()
}
}
|> switchToLatest*/
|> switchToLatest
}
private let cachedPeerExportedInvitationsCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 20)
@ -377,6 +312,7 @@ private final class PeerExportedInvitationsContextImpl {
private let queue: Queue
private let account: Account
private let peerId: PeerId
private let adminId: PeerId
private let revoked: Bool
private var forceUpdate: Bool
private let disposable = MetaDisposable()
@ -388,36 +324,41 @@ private final class PeerExportedInvitationsContextImpl {
private var results: [ExportedInvitation] = []
private var count: Int32
private var populateCache: Bool = true
private var isMainList: Bool
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.account = account
self.peerId = peerId
self.adminId = adminId ?? account.peerId
self.revoked = revoked
self.forceUpdate = forceUpdate
self.isMainList = adminId == nil
self.count = 0
self.isLoadingMore = true
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
if adminId == nil {
self.isLoadingMore = true
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()
}
@ -433,17 +374,18 @@ private final class PeerExportedInvitationsContextImpl {
}
func loadMore() {
/*if self.isLoadingMore {
if self.isLoadingMore {
return
}
self.isLoadingMore = true
let account = self.account
let peerId = self.peerId
let adminId = self.adminId
let revoked = self.revoked
var lastResult = self.results.last
if self.forceUpdate {
self.populateCache = true
self.populateCache = self.isMainList
self.forceUpdate = false
lastResult = nil
} else if self.loadedFromCache {
@ -452,11 +394,11 @@ private final class PeerExportedInvitationsContextImpl {
}
let populateCache = self.populateCache
self.disposable.set((self.account.postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
self.disposable.set((self.account.postbox.transaction { transaction -> (peerId: Api.InputPeer?, adminId: Api.InputUser?) in
return (transaction.getPeer(peerId).flatMap(apiInputPeer), transaction.getPeer(adminId).flatMap(apiInputUser))
}
|> mapToSignal { inputPeer -> Signal<([ExportedInvitation], Int32), NoError> in
if let inputPeer = inputPeer {
|> mapToSignal { inputPeer, adminId -> Signal<([ExportedInvitation], Int32), NoError> in
if let inputPeer = inputPeer, let adminId = adminId {
let offsetLink = lastResult?.link
let offsetDate = lastResult?.date
var flags: Int32 = 0
@ -466,7 +408,7 @@ private final class PeerExportedInvitationsContextImpl {
if revoked {
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)
|> `catch` { _ -> Signal<Api.messages.ExportedChatInvites?, NoError> in
return .single(nil)
@ -527,7 +469,7 @@ private final class PeerExportedInvitationsContextImpl {
strongSelf.loadMore()
}
}))
self.updateState()*/
self.updateState()
}
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
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 {
return
}
/*self.isLoadingMore = true
self.isLoadingMore = true
let account = self.account
let peerId = self.peerId
let link = self.link
@ -871,7 +813,7 @@ private final class PeerInvitationImportersContextImpl {
}
strongSelf.updateState()
}))
self.updateState()*/
self.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 func currentLayer() -> UInt {
return 123
return 124
}
public func parseMessage(_ data: Data!) -> Any! {

View File

@ -129,7 +129,7 @@ func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? {
func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
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
var result = [peerId]
@ -192,7 +192,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
}
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
case let .messageActionChannelMigrateFrom(_, 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]? {
switch message {
case let .message(_, _, _, chatPeerId, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, _, chatPeerId, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _, _):
if let replyTo = replyTo {
let peerId: PeerId = chatPeerId.peerId
@ -371,7 +371,7 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes
extension StoreMessage {
convenience init?(apiMessage: Api.Message, namespace: MessageId.Namespace = Namespaces.Message.Cloud) {
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 peerId: PeerId

View File

@ -71,6 +71,8 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
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 {
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()
if (flags & (1 << 3)) != 0 {
channelFlags.insert(.canDisplayParticipants)

View File

@ -58,7 +58,7 @@ class UpdateMessageService: NSObject, MTMessageService {
self.putNext(groups)
}
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 groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
if groups.count != 0 {
@ -74,7 +74,7 @@ class UpdateMessageService: NSObject, MTMessageService {
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 groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
if groups.count != 0 {

View File

@ -654,17 +654,17 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
discussionPeer = peer
}
// if currentInvitationsContext == nil {
// 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)) {
// canManageInvitations = true
// }
// if canManageInvitations {
// let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: true)
// invitationsContextPromise.set(.single(invitationsContext))
// invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
// }
// }
if currentInvitationsContext == nil {
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)) {
canManageInvitations = true
}
if canManageInvitations {
let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, adminId: nil, revoked: false, forceUpdate: true)
invitationsContextPromise.set(.single(invitationsContext))
invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
}
}
return PeerInfoScreenData(
peer: peerView.peers[peerId],
@ -811,19 +811,19 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
}
}
// if currentInvitationsContext == nil {
// var canManageInvitations = false
// if let group = peerViewMainPeer(peerView) as? TelegramGroup, case .creator = group.role {
// 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)) {
// canManageInvitations = true
// }
// if canManageInvitations {
// let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: true)
// invitationsContextPromise.set(.single(invitationsContext))
// invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
// }
// }
if currentInvitationsContext == nil {
var canManageInvitations = false
if let group = peerViewMainPeer(peerView) as? TelegramGroup, case .creator = group.role {
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)) {
canManageInvitations = true
}
if canManageInvitations {
let invitationsContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, adminId: nil, revoked: false, forceUpdate: true)
invitationsContextPromise.set(.single(invitationsContext))
invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
}
}
return PeerInfoScreenData(
peer: peerView.peers[groupId],

View File

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

View File

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

View File

@ -128,6 +128,13 @@ public final class TelegramRootController: NavigationController {
self.accountSettingsController = accountSettingsController
self.rootTabController = tabBarController
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) {