Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
overtake 2021-01-19 18:16:03 +03:00
commit d66a80670a
15 changed files with 212 additions and 137 deletions

View File

@ -55,7 +55,7 @@ private enum InviteLinkInviteEntry: Comparable, Identifiable {
case header(PresentationTheme, String, String)
case mainLink(PresentationTheme, ExportedInvitation)
case links(Int32, PresentationTheme, [ExportedInvitation])
case manage(PresentationTheme, String)
case manage(PresentationTheme, String, Bool)
var stableId: InviteLinkInviteEntryId {
switch self {
@ -90,8 +90,8 @@ private enum InviteLinkInviteEntry: Comparable, Identifiable {
} else {
return false
}
case let .manage(lhsTheme, lhsText):
if case let .manage(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
case let .manage(lhsTheme, lhsText, lhsStandalone):
if case let .manage(rhsTheme, rhsText, rhsStandalone) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsStandalone == rhsStandalone {
return true
} else {
return false
@ -148,13 +148,13 @@ private enum InviteLinkInviteEntry: Comparable, Identifiable {
}, viewAction: {
})
case let .links(_, _, invites):
return ItemListInviteLinkGridItem(presentationData: ItemListPresentationData(presentationData), invites: invites, share: true, sectionId: 0, style: .plain, tapAction: { invite in
return ItemListInviteLinkGridItem(presentationData: ItemListPresentationData(presentationData), invites: invites, share: true, sectionId: 1, style: .plain, tapAction: { invite in
interaction.copyLink(invite)
}, contextAction: { invite, _ in
interaction.shareLink(invite)
})
case let .manage(theme, text):
return InviteLinkInviteManageItem(theme: theme, text: text, action: {
case let .manage(theme, text, standalone):
return InviteLinkInviteManageItem(theme: theme, text: text, standalone: standalone, action: {
interaction.manageLinks()
})
}
@ -257,6 +257,7 @@ public final class InviteLinkInviteController: ViewController {
private let context: AccountContext
private let peerId: PeerId
private let invitesContext: PeerExportedInvitationsContext
private var interaction: InviteLinkInviteInteraction?
@ -289,6 +290,8 @@ public final class InviteLinkInviteController: ViewController {
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationDataPromise = Promise(self.presentationData)
self.controller = controller
self.invitesContext = PeerExportedInvitationsContext(account: context.account, peerId: peerId, revoked: false, forceUpdate: false)
self.dimNode = ASDisplayNode()
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
@ -386,8 +389,9 @@ public final class InviteLinkInviteController: ViewController {
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture)
self?.controller?.presentInGlobalOverlay(contextController)
}, copyLink: { [weak self] invite in
let shareController = ShareController(context: context, subject: .url(invite.link))
self?.controller?.present(shareController, in: .window(.root))
UIPasteboard.general.string = invite.link
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self?.controller?.present(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Username_LinkCopied, false)), in: .window(.root))
}, shareLink: { [weak self] invite in
let shareController = ShareController(context: context, subject: .url(invite.link))
self?.controller?.present(shareController, in: .window(.root))
@ -400,20 +404,38 @@ public final class InviteLinkInviteController: ViewController {
let previousEntries = Atomic<[InviteLinkInviteEntry]?>(value: nil)
let peerView = context.account.postbox.peerView(id: peerId)
self.disposable = (combineLatest(self.presentationDataPromise.get(), peerView)
|> deliverOnMainQueue).start(next: { [weak self] presentationData, view in
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] = []
entries.append(.header(presentationData.theme, presentationData.strings.InviteLink_InviteLink, presentationData.strings.InviteLink_CreatePrivateLinkHelp))
let mainInvite: ExportedInvitation?
if let cachedData = view.cachedData as? CachedGroupData, let invite = cachedData.exportedInvitation {
entries.append(.mainLink(presentationData.theme, invite))
mainInvite = invite
} else if let cachedData = view.cachedData as? CachedChannelData, let invite = cachedData.exportedInvitation {
entries.append(.mainLink(presentationData.theme, invite))
mainInvite = invite
} else {
mainInvite = nil
}
if let mainInvite = mainInvite {
entries.append(.mainLink(presentationData.theme, mainInvite))
}
entries.append(.manage(presentationData.theme, presentationData.strings.InviteLink_Manage))
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))
let previousEntries = previousEntries.swap(entries)

View File

@ -14,12 +14,13 @@ class InviteLinkInviteManageItem: ListViewItem, ItemListItem {
let theme: PresentationTheme
let text: String
let standalone: Bool
let action: () -> Void
init(theme: PresentationTheme, text: String, action: @escaping () -> Void) {
init(theme: PresentationTheme, text: String, standalone: Bool, action: @escaping () -> Void) {
self.theme = theme
self.text = text
self.standalone = standalone
self.action = action
}
@ -94,7 +95,11 @@ class InviteLinkInviteManageItemNode: ListViewItemNode {
if let strongSelf = self {
strongSelf.item = item
strongSelf.backgroundNode.backgroundColor = item.standalone ? .clear : item.theme.list.blocksBackgroundColor
strongSelf.buttonNode.setTitle(item.text, with: Font.regular(17.0), with: item.theme.actionSheet.controlAccentColor, for: .normal)
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: params.width, height: 1000.0))
let size = strongSelf.buttonNode.measure(layout.contentSize)
strongSelf.buttonNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.contentSize.width - size.width) / 2.0), y: floorToScreenPixels((layout.contentSize.height - size.height) / 2.0)), size: size)

View File

@ -316,7 +316,7 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
let shareController = ShareController(context: context, subject: .url(invite.link))
presentControllerImpl?(shareController, nil)
}, openMainLink: { invite in
let controller = InviteLinkViewController(context: context, peerId: peerId, invite: invite, invitationsContext: nil, importersContext: nil)
let controller = InviteLinkViewController(context: context, peerId: peerId, invite: invite, invitationsContext: nil, revokedInvitationsContext: revokedInvitesContext, importersContext: nil)
pushControllerImpl?(controller)
}, copyLink: { invite in
UIPasteboard.general.string = invite.link
@ -409,7 +409,7 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
pushControllerImpl?(controller)
}, openLink: { invite in
if let invite = invite {
let controller = InviteLinkViewController(context: context, peerId: peerId, invite: invite, invitationsContext: invitesContext, importersContext: nil)
let controller = InviteLinkViewController(context: context, peerId: peerId, invite: invite, invitationsContext: invitesContext, revokedInvitationsContext: revokedInvitesContext, importersContext: nil)
pushControllerImpl?(controller)
}
}, linkContextAction: { invite, node, gesture in
@ -449,7 +449,7 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
if let invite = invite {
if invite.isRevoked {
invitesContext.remove(invite)
revokedInvitesContext.add(invite)
revokedInvitesContext.add(invite.withUpdated(isRevoked: true))
} else {
invitesContext.update(invite)
}
@ -508,7 +508,7 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
}))
invitesContext.remove(invite)
revokedInvitesContext.add(invite)
revokedInvitesContext.add(invite.withUpdated(isRevoked: true))
})
]),
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])

View File

@ -218,15 +218,17 @@ public final class InviteLinkViewController: ViewController {
private let peerId: PeerId
private let invite: ExportedInvitation
private let invitationsContext: PeerExportedInvitationsContext?
private let revokedInvitationsContext: PeerExportedInvitationsContext?
private let importersContext: PeerInvitationImportersContext?
private var presentationDataDisposable: Disposable?
public init(context: AccountContext, peerId: PeerId, invite: ExportedInvitation, invitationsContext: PeerExportedInvitationsContext?, importersContext: PeerInvitationImportersContext?) {
public init(context: AccountContext, peerId: PeerId, invite: ExportedInvitation, invitationsContext: PeerExportedInvitationsContext?, revokedInvitationsContext: PeerExportedInvitationsContext?, importersContext: PeerInvitationImportersContext?) {
self.context = context
self.peerId = peerId
self.invite = invite
self.invitationsContext = invitationsContext
self.revokedInvitationsContext = revokedInvitationsContext
self.importersContext = importersContext
super.init(navigationBarPresentationData: nil)
@ -299,12 +301,16 @@ public final class InviteLinkViewController: ViewController {
private let peerId: PeerId
private let invite: ExportedInvitation
private let importersContext: PeerInvitationImportersContext
private var interaction: InviteLinkViewInteraction?
private var presentationData: PresentationData
private let presentationDataPromise: Promise<PresentationData>
private var presentationDataDisposable: Disposable?
private var disposable: Disposable?
private let actionDisposable = MetaDisposable()
private let dimNode: ASDisplayNode
private let contentNode: ASDisplayNode
@ -323,10 +329,6 @@ public final class InviteLinkViewController: ViewController {
private var validLayout: ContainerViewLayout?
private var presentationDataDisposable: Disposable?
private let importersContext: PeerInvitationImportersContext
init(context: AccountContext, peerId: PeerId, invite: ExportedInvitation, importersContext: PeerInvitationImportersContext?, controller: InviteLinkViewController) {
self.context = context
self.peerId = peerId
@ -420,7 +422,24 @@ public final class InviteLinkViewController: ViewController {
}, action: { [weak self] _, f in
f(.dismissWithoutContent)
let controller = InviteLinkQRCodeController(context: context, invite: invite)
let controller = ActionSheetController(presentationData: presentationData)
let dismissAction: () -> Void = { [weak controller] in
controller?.dismissAnimated()
}
controller.setItemGroups([
ActionSheetItemGroup(items: [
ActionSheetTextItem(title: presentationData.strings.InviteLink_DeleteLinkAlert_Text),
ActionSheetButtonItem(title: presentationData.strings.InviteLink_DeleteLinkAlert_Action, color: .destructive, action: {
dismissAction()
self?.actionDisposable.set((deletePeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(completed: {
}))
self?.controller?.revokedInvitationsContext?.remove(invite)
})
]),
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
])
self?.controller?.present(controller, in: .window(.root))
})))
} else {

View File

@ -63,11 +63,36 @@ private enum ItemBackgroundColor: Equatable {
case .red:
return (UIColor(rgb: 0xf2656a), UIColor(rgb: 0xf25f65), UIColor(rgb: 0xffd3de))
case .gray:
return (UIColor(rgb: 0xd4d8db), UIColor(rgb: 0xced2d5), UIColor(rgb: 0xf8f9f9))
return (UIColor(rgb: 0xa8b2bb), UIColor(rgb: 0xa2abb4), UIColor(rgb: 0xe3e6e8))
}
}
}
private let moreIcon = generateImage(CGSize(width: 26.0, height: 26.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor.white.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
context.setBlendMode(.clear)
context.fillEllipse(in: CGRect(origin: CGPoint(x: 4.0, y: 11.0), size: CGSize(width: 4.0, height: 4.0)))
context.fillEllipse(in: CGRect(origin: CGPoint(x: 11.0, y: 11.0), size: CGSize(width: 4.0, height: 4.0)))
context.fillEllipse(in: CGRect(origin: CGPoint(x: 18.0, y: 11.0), size: CGSize(width: 4.0, height: 4.0)))
})
private let shareIcon = generateImage(CGSize(width: 26.0, height: 26.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor.white.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
if let maskImage = UIImage(bundleImageName: "Chat/Links/Share") {
context.clip(to: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - maskImage.size.width) / 2.0), y: floorToScreenPixels((size.height - maskImage.size.height) / 2.0)), size: maskImage.size), mask: maskImage.cgImage!)
context.setBlendMode(.clear)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
}
})
private class ItemNode: ASDisplayNode {
private let selectionNode: HighlightTrackingButtonNode
private let wrapperNode: ASDisplayNode
@ -114,17 +139,6 @@ private class ItemNode: ASDisplayNode {
self.buttonIconNode = ASImageNode()
self.buttonIconNode.displaysAsynchronously = false
self.buttonIconNode.displayWithoutProcessing = true
self.buttonIconNode.image = generateImage(CGSize(width: 26.0, height: 26.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor.white.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
context.setBlendMode(.clear)
context.fillEllipse(in: CGRect(origin: CGPoint(x: 4.0, y: 11.0), size: CGSize(width: 4.0, height: 4.0)))
context.fillEllipse(in: CGRect(origin: CGPoint(x: 11.0, y: 11.0), size: CGSize(width: 4.0, height: 4.0)))
context.fillEllipse(in: CGRect(origin: CGPoint(x: 18.0, y: 11.0), size: CGSize(width: 4.0, height: 4.0)))
})
self.titleNode = ImmediateTextNode()
self.titleNode.maximumNumberOfLines = 2
@ -264,6 +278,8 @@ private class ItemNode: ASDisplayNode {
}
self.titleNode.attributedText = title
self.buttonIconNode.image = share ? shareIcon : moreIcon
var subtitleText: String = ""
if let count = invite.count {
subtitleText = presentationData.strings.InviteLink_PeopleJoinedShort(count)
@ -282,7 +298,11 @@ private class ItemNode: ASDisplayNode {
if !subtitleText.isEmpty {
subtitleText += ""
}
subtitleText += presentationData.strings.InviteLink_Expired
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
@ -290,7 +310,11 @@ private class ItemNode: ASDisplayNode {
if !subtitleText.isEmpty {
subtitleText += ""
}
subtitleText += presentationData.strings.InviteLink_UsageLimitReached
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
@ -306,10 +330,16 @@ private class ItemNode: ASDisplayNode {
self.addSubnode(timerNode)
}
timerNode.update(color: UIColor.white, creationTimestamp: invite.date, deadlineTimestamp: expireDate)
if share {
subtitleText = presentationData.strings.InviteLink_TapToCopy
}
} else {
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Links/Link"), color: .white)
self.timerNode?.removeFromSupernode()
self.timerNode = nil
if share {
subtitleText = presentationData.strings.InviteLink_TapToCopy
}
}
self.iconNode.frame = CGRect(x: 10.0, y: 10.0, width: 30.0, height: 30.0)

View File

@ -130,14 +130,21 @@ public class ItemListInviteLinkGridItemNode: ListViewItemNode, ItemListItemNode
let itemSeparatorColor: UIColor
let leftInset = 16.0 + params.leftInset
let topInset: CGFloat
if case .plain = item.style, case .otherSection = neighbors.top {
topInset = 16.0
} else {
topInset = 4.0
}
var height: CGFloat
let count = item.invites?.count ?? 0
if count > 0 {
if count % 2 == 0 {
height = 4.0 + 122.0 + 6.0
height = topInset + 122.0 + 6.0
} else {
height = 4.0 + 102.0 + 6.0
height = topInset + 102.0 + 6.0
}
} else {
height = 0.001
@ -145,9 +152,9 @@ public class ItemListInviteLinkGridItemNode: ListViewItemNode, ItemListItemNode
switch item.style {
case .plain:
itemBackgroundColor = item.presentationData.theme.list.plainBackgroundColor
itemSeparatorColor = item.presentationData.theme.list.itemPlainSeparatorColor
insets = itemListNeighborsPlainInsets(neighbors)
itemBackgroundColor = item.presentationData.theme.list.blocksBackgroundColor
itemSeparatorColor = item.presentationData.theme.list.blocksBackgroundColor
insets = UIEdgeInsets()
case .blocks:
itemBackgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor
itemSeparatorColor = item.presentationData.theme.list.itemBlocksSeparatorColor
@ -155,7 +162,7 @@ public class ItemListInviteLinkGridItemNode: ListViewItemNode, ItemListItemNode
}
if case .sameSection(false) = neighbors.bottom {
} else {
height += 6.0
height += 10.0
}
contentSize = CGSize(width: params.width, height: height)
@ -170,7 +177,7 @@ public class ItemListInviteLinkGridItemNode: ListViewItemNode, ItemListItemNode
}
let gridSize = strongSelf.gridNode.update(size: contentSize, safeInset: params.leftInset, items: item.invites ?? [], share: item.share, presentationData: item.presentationData, transition: .immediate)
strongSelf.gridNode.frame = CGRect(origin: CGPoint(), size: gridSize)
strongSelf.gridNode.frame = CGRect(origin: CGPoint(x: 0.0, y: topInset - 4.0), size: gridSize)
strongSelf.gridNode.action = { invite in
item.tapAction?(invite)
}
@ -180,18 +187,19 @@ public class ItemListInviteLinkGridItemNode: ListViewItemNode, ItemListItemNode
switch item.style {
case .plain:
if strongSelf.backgroundNode.supernode != nil {
strongSelf.backgroundNode.removeFromSupernode()
if strongSelf.backgroundNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0)
}
if strongSelf.topStripeNode.supernode != nil {
strongSelf.topStripeNode.removeFromSupernode()
}
if strongSelf.bottomStripeNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
if strongSelf.bottomStripeNode.supernode != nil {
strongSelf.bottomStripeNode.removeFromSupernode()
}
if strongSelf.maskNode.supernode != nil {
strongSelf.maskNode.removeFromSupernode()
}
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: params.width, height: contentSize.height))
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
case .blocks:
if strongSelf.backgroundNode.supernode == nil {

View File

@ -169,6 +169,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
self.containerNode = ContextControllerSourceNode()
self.containerNode.isGestureEnabled = false
self.addressButtonIconNode = ASImageNode()
self.addressButtonIconNode.contentMode = .center
self.addressButtonIconNode.displaysAsynchronously = false
self.addressButtonIconNode.displayWithoutProcessing = true
@ -423,7 +424,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
strongSelf.addressNode.frame = CGRect(origin: CGPoint(x: fieldFrame.minX + floorToScreenPixels((fieldFrame.width - addressLayout.size.width) / 2.0), y: fieldFrame.minY + floorToScreenPixels((fieldFrame.height - addressLayout.size.height) / 2.0) + 1.0), size: addressLayout.size)
strongSelf.addressButtonNode.frame = CGRect(origin: CGPoint(x: params.width - rightInset - 38.0, y: verticalInset + 14.0), size: CGSize(width: 24.0, height: 24.0))
strongSelf.addressButtonNode.frame = CGRect(origin: CGPoint(x: params.width - rightInset - 38.0 - 14.0, y: verticalInset), size: CGSize(width: 52.0, height: 52.0))
strongSelf.extractedContainerNode.frame = strongSelf.addressButtonNode.bounds
strongSelf.extractedContainerNode.contentRect = strongSelf.addressButtonNode.bounds
strongSelf.addressButtonIconNode.frame = strongSelf.addressButtonNode.bounds

View File

@ -125,18 +125,18 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
return 8
case .privateLinkInfo:
return 9
case .privateLinkManage:
return 10
case .privateLinkManageInfo:
return 11
case .publicLinkStatus:
return 12
return 10
case .publicLinkInfo:
return 13
return 11
case .existingLinksInfo:
return 14
return 12
case let .existingLinkPeerItem(index, _, _, _, _, _, _, _):
return 15 + index
return 13 + index
case .privateLinkManage:
return 1000
case .privateLinkManageInfo:
return 1001
}
}
@ -594,10 +594,17 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Group_PublicLink_Info))
} else {
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePublicLinkHelp))
}
}
} 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))
}
}
case .privateChannel:
let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation

View File

@ -66,4 +66,8 @@ public struct ExportedInvitation: PostboxCoding, Equatable {
public static func ==(lhs: ExportedInvitation, rhs: ExportedInvitation) -> Bool {
return lhs.link == rhs.link && lhs.isPermanent == rhs.isPermanent && lhs.isRevoked == rhs.isRevoked && lhs.adminId == rhs.adminId && lhs.date == rhs.date && lhs.startDate == rhs.startDate && lhs.expireDate == rhs.expireDate && lhs.usageLimit == rhs.usageLimit && lhs.count == rhs.count
}
public func withUpdated(isRevoked: Bool) -> ExportedInvitation {
return ExportedInvitation(link: self.link, isPermanent: self.isPermanent, isRevoked: isRevoked, adminId: self.adminId, date: self.date, startDate: self.startDate, expireDate: self.expireDate, usageLimit: self.usageLimit, count: self.count)
}
}

View File

@ -3942,15 +3942,16 @@ public extension Api {
})
}
public static func getExportedChatInvites(flags: Int32, peer: Api.InputPeer, adminId: Api.InputUser?, offsetLink: String?, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ExportedChatInvites>) {
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(1838984707)
buffer.appendInt32(1785900140)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {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), ("offsetLink", offsetLink), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ExportedChatInvites? in
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() {

View File

@ -88,58 +88,6 @@ public func createPeerExportedInvitation(account: Account, peerId: PeerId, expir
|> switchToLatest
}
public struct ExportedInvitations : Equatable {
public let list: [ExportedInvitation]?
public let totalCount: Int32
}
public func peerExportedInvitations(account: Account, peerId: PeerId, revoked: Bool, offsetLink: String? = nil) -> Signal<ExportedInvitations?, NoError> {
return account.postbox.transaction { transaction -> Signal<ExportedInvitations?, NoError> in
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
var flags: Int32 = 0
if let _ = offsetLink {
flags |= (1 << 2)
}
if revoked {
flags |= (1 << 3)
}
return account.network.request(Api.functions.messages.getExportedChatInvites(flags: flags, peer: inputPeer, adminId: nil, offsetLink: offsetLink, limit: 50))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.ExportedChatInvites?, NoError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<ExportedInvitations?, NoError> in
return account.postbox.transaction { transaction -> ExportedInvitations? in
if let result = result, case let .exportedChatInvites(count, apiInvites, users) = result {
var peers: [Peer] = []
var peersMap: [PeerId: Peer] = [:]
for user in users {
let telegramUser = TelegramUser(user: user)
peers.append(telegramUser)
peersMap[telegramUser.id] = telegramUser
}
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
return updated
})
var invites: [ExportedInvitation] = []
for apiInvite in apiInvites {
if let invite = ExportedInvitation(apiExportedInvite: apiInvite) {
invites.append(invite)
}
}
return ExportedInvitations(list: invites, totalCount: count)
} else {
return nil
}
}
}
} else {
return .single(nil)
}
} |> switchToLatest
}
public enum EditPeerExportedInvitationError {
case generic
}
@ -375,6 +323,7 @@ private final class PeerExportedInvitationsContextImpl {
|> mapToSignal { inputPeer -> Signal<([ExportedInvitation], Int32), NoError> in
if let inputPeer = inputPeer {
let offsetLink = lastResult?.link
let offsetDate = lastResult?.date
var flags: Int32 = 0
if let _ = offsetLink {
flags |= (1 << 2)
@ -382,7 +331,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, offsetLink: offsetLink, limit: lastResult == nil ? 50 : 100))
let signal = account.network.request(Api.functions.messages.getExportedChatInvites(flags: flags, peer: inputPeer, adminId: nil, offsetDate: offsetDate, offsetLink: offsetLink, limit: lastResult == nil ? 50 : 100))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.ExportedChatInvites?, NoError> in
return .single(nil)

View File

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

View File

@ -615,7 +615,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
case .channel:
let status = context.account.viewTracker.peerView(peerId, updateData: false)
|> map { peerView -> PeerInfoStatusData? in
guard let channel = peerView.peers[peerId] as? TelegramChannel else {
guard let _ = peerView.peers[peerId] as? TelegramChannel else {
return PeerInfoStatusData(text: strings.Channel_Status, isActivity: false)
}
if let cachedChannelData = peerView.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount, memberCount != 0 {
@ -654,12 +654,18 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
discussionPeer = peer
}
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)), currentInvitationsContext == nil {
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, revoked: false, forceUpdate: true)
invitationsContextPromise.set(.single(invitationsContext))
invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
}
}
return PeerInfoScreenData(
peer: peerView.peers[peerId],
cachedData: peerView.cachedData,
@ -805,12 +811,20 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
}
}
if let group = peerViewMainPeer(peerView) as? TelegramGroup, case .creator = group.role, currentInvitationsContext == nil {
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, revoked: false, forceUpdate: true)
invitationsContextPromise.set(.single(invitationsContext))
invitationsStatePromise.set(invitationsContext.state |> map(Optional.init))
}
}
return PeerInfoScreenData(
peer: peerView.peers[groupId],
cachedData: peerView.cachedData,

View File

@ -1185,6 +1185,17 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
discussionGroupTitle = "..."
}
let invitesText: String
if let count = data.invitations?.count, count > 0 {
invitesText = "\(count)"
} else {
invitesText = ""
}
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()
}))
@ -4559,15 +4570,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
return
}
strongSelf.view.endEditing(true)
let mode: ChannelVisibilityControllerMode
if groupPeer.addressName != nil {
let visibilityController = channelVisibilityController(context: strongSelf.context, peerId: groupPeer.id, mode: .generic, upgradedToSupergroup: { _, f in f() }, onDismissRemoveController: contactsController)
//visibilityController.navigationPresentation = .modal
contactsController?.push(visibilityController)
} else {
contactsController?.present(InviteLinkInviteController(context: context, peerId: groupPeer.id, parentNavigationController: contactsController?.navigationController as? NavigationController), in: .window(.root))
}
contactsController?.present(InviteLinkInviteController(context: context, peerId: groupPeer.id, parentNavigationController: contactsController?.navigationController as? NavigationController), in: .window(.root))
}
strongSelf.controller?.push(contactsController)