Invite Links Fixes

This commit is contained in:
Ilya Laktyushin 2021-01-18 23:06:49 +03:00
parent a59f9e1969
commit 426e8724dc
15 changed files with 3767 additions and 3768 deletions

View File

@ -5892,3 +5892,5 @@ Sorry for the inconvenience.";
"Conversation.ChecksTooltip.Read" = "Read"; "Conversation.ChecksTooltip.Read" = "Read";
"DialogList.MultipleTypingPair" = "%@ and %@ are typing"; "DialogList.MultipleTypingPair" = "%@ and %@ are typing";
"Common.Save" = "Save";

View File

@ -50,7 +50,7 @@ func isValidNumberOfUsers(_ number: String) -> Bool {
private enum InviteLinksEditEntry: ItemListNodeEntry { private enum InviteLinksEditEntry: ItemListNodeEntry {
case timeHeader(PresentationTheme, String) case timeHeader(PresentationTheme, String)
case timePicker(PresentationTheme, InviteLinkTimeLimit) case timePicker(PresentationTheme, InviteLinkTimeLimit)
case timeExpiryDate(PresentationTheme, Int32?) case timeExpiryDate(PresentationTheme, Int32?, Bool)
case timeCustomPicker(PresentationTheme, Int32?) case timeCustomPicker(PresentationTheme, Int32?)
case timeInfo(PresentationTheme, String) case timeInfo(PresentationTheme, String)
@ -111,8 +111,8 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .timeExpiryDate(lhsTheme, lhsDate): case let .timeExpiryDate(lhsTheme, lhsDate, lhsActive):
if case let .timeExpiryDate(rhsTheme, rhsDate) = rhs, lhsTheme === rhsTheme, lhsDate == rhsDate { if case let .timeExpiryDate(rhsTheme, rhsDate, rhsActive) = rhs, lhsTheme === rhsTheme, lhsDate == rhsDate, lhsActive == rhsActive {
return true return true
} else { } else {
return false return false
@ -182,14 +182,14 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
return updatedState return updatedState
}) })
}) })
case let .timeExpiryDate(_, value): case let .timeExpiryDate(theme, value, active):
let text: String let text: String
if let value = value { if let value = value {
text = stringForFullDate(timestamp: value, strings: presentationData.strings, dateTimeFormat: PresentationDateTimeFormat(timeFormat: .regular, dateFormat: .monthFirst, dateSeparator: ".", decimalSeparator: ".", groupingSeparator: ".")) text = stringForFullDate(timestamp: value, strings: presentationData.strings, dateTimeFormat: PresentationDateTimeFormat(timeFormat: .regular, dateFormat: .monthFirst, dateSeparator: ".", decimalSeparator: ".", groupingSeparator: "."))
} else { } else {
text = presentationData.strings.InviteLink_Create_TimeLimitExpiryDateNever text = presentationData.strings.InviteLink_Create_TimeLimitExpiryDateNever
} }
return ItemListDisclosureItem(presentationData: presentationData, title: presentationData.strings.InviteLink_Create_TimeLimitExpiryDate, label: text, sectionId: self.section, style: .blocks, disclosureStyle: .none, action: { return ItemListDisclosureItem(presentationData: presentationData, title: presentationData.strings.InviteLink_Create_TimeLimitExpiryDate, label: text, labelStyle: active ? .coloredText(theme.list.itemAccentColor) : .text, sectionId: self.section, style: .blocks, disclosureStyle: .none, action: {
arguments.dismissInput() arguments.dismissInput()
arguments.updateState { state in arguments.updateState { state in
var updatedState = state var updatedState = state
@ -276,7 +276,7 @@ private func inviteLinkEditControllerEntries(invite: ExportedInvitation?, state:
} else if let value = state.time.value { } else if let value = state.time.value {
time = currentTime + value time = currentTime + value
} }
entries.append(.timeExpiryDate(presentationData.theme, time)) entries.append(.timeExpiryDate(presentationData.theme, time, state.pickingTimeLimit))
if state.pickingTimeLimit { if state.pickingTimeLimit {
entries.append(.timeCustomPicker(presentationData.theme, time ?? currentTime)) entries.append(.timeCustomPicker(presentationData.theme, time ?? currentTime))
} }
@ -327,7 +327,7 @@ public func inviteLinkEditController(context: AccountContext, peerId: PeerId, in
initialState = InviteLinkEditControllerState(usage: InviteLinkUsageLimit(value: usageLimit), time: timeLimit, pickingTimeLimit: false, pickingUsageLimit: false) initialState = InviteLinkEditControllerState(usage: InviteLinkUsageLimit(value: usageLimit), time: timeLimit, pickingTimeLimit: false, pickingUsageLimit: false)
} else { } else {
initialState = InviteLinkEditControllerState(usage: .medium, time: .week, pickingTimeLimit: false, pickingUsageLimit: false) initialState = InviteLinkEditControllerState(usage: .unlimited, time: .unlimited, pickingTimeLimit: false, pickingUsageLimit: false)
} }
let statePromise = ValuePromise(initialState, ignoreRepeated: true) let statePromise = ValuePromise(initialState, ignoreRepeated: true)
@ -376,7 +376,7 @@ public func inviteLinkEditController(context: AccountContext, peerId: PeerId, in
dismissImpl?() dismissImpl?()
}) })
let rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: { let rightNavigationButton = ItemListNavigationButton(content: .text(invite == nil ? presentationData.strings.Common_Create : presentationData.strings.Common_Save), style: .bold, enabled: true, action: {
let expireDate: Int32? let expireDate: Int32?
if case let .custom(value) = state.time { if case let .custom(value) = state.time {
expireDate = value expireDate = value

View File

@ -139,7 +139,9 @@ private enum InviteLinkInviteEntry: Comparable, Identifiable {
case let .header(theme, title, text): case let .header(theme, title, text):
return InviteLinkInviteHeaderItem(theme: theme, title: title, text: text) return InviteLinkInviteHeaderItem(theme: theme, title: title, text: text)
case let .mainLink(_, invite): case let .mainLink(_, invite):
return ItemListPermanentInviteLinkItem(context: interaction.context, presentationData: ItemListPresentationData(presentationData), invite: invite, peers: [], displayButton: true, displayImporters: false, buttonColor: nil, sectionId: 0, style: .plain, shareAction: { return ItemListPermanentInviteLinkItem(context: interaction.context, presentationData: ItemListPresentationData(presentationData), invite: invite, peers: [], displayButton: true, displayImporters: false, buttonColor: nil, sectionId: 0, style: .plain, copyAction: {
interaction.copyLink(invite)
}, shareAction: {
interaction.shareLink(invite) interaction.shareLink(invite)
}, contextAction: { node in }, contextAction: { node in
interaction.mainLinkContextAction(invite, node, nil) interaction.mainLinkContextAction(invite, node, nil)
@ -371,7 +373,7 @@ public final class InviteLinkInviteController: ViewController {
ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: { ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: {
dismissAction() dismissAction()
self?.revokeDisposable.set((ensuredExistingPeerExportedInvitation(account: context.account, peerId: peerId, revokeExisted: true) |> deliverOnMainQueue).start(completed: { self?.revokeDisposable.set((revokePersistentPeerExportedInvitation(account: context.account, peerId: peerId) |> deliverOnMainQueue).start(completed: {
})) }))
}) })
@ -585,11 +587,6 @@ public final class InviteLinkInviteController: ViewController {
if result === self.headerNode.view { if result === self.headerNode.view {
return self.view return self.view
} }
if result === self.headerNode.view {
return self.view
}
if !self.bounds.contains(point) { if !self.bounds.contains(point) {
return nil return nil
} }
@ -615,8 +612,6 @@ public final class InviteLinkInviteController: ViewController {
case .changed: case .changed:
var translation = recognizer.translation(in: self.contentNode.view).y var translation = recognizer.translation(in: self.contentNode.view).y
if let currentPanOffset = self.panGestureArguments { if let currentPanOffset = self.panGestureArguments {
if case let .known(value) = contentOffset, value <= 0.5 { if case let .known(value) = contentOffset, value <= 0.5 {
} else { } else {
translation = currentPanOffset translation = currentPanOffset

View File

@ -22,18 +22,20 @@ import ShareController
private final class InviteLinkListControllerArguments { private final class InviteLinkListControllerArguments {
let context: AccountContext let context: AccountContext
let shareMainLink: (ExportedInvitation?) -> Void let shareMainLink: (ExportedInvitation) -> Void
let openMainLink: (ExportedInvitation?) -> Void let openMainLink: (ExportedInvitation) -> Void
let copyLink: (ExportedInvitation) -> Void
let mainLinkContextAction: (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void let mainLinkContextAction: (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void
let createLink: () -> Void let createLink: () -> Void
let openLink: (ExportedInvitation) -> Void let openLink: (ExportedInvitation) -> Void
let linkContextAction: (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void let linkContextAction: (ExportedInvitation?, ASDisplayNode, ContextGesture?) -> Void
let deleteAllRevokedLinks: () -> Void let deleteAllRevokedLinks: () -> Void
init(context: AccountContext, shareMainLink: @escaping (ExportedInvitation?) -> Void, openMainLink: @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, deleteAllRevokedLinks: @escaping () -> Void) {
self.context = context self.context = context
self.shareMainLink = shareMainLink self.shareMainLink = shareMainLink
self.openMainLink = openMainLink self.openMainLink = openMainLink
self.copyLink = copyLink
self.mainLinkContextAction = mainLinkContextAction self.mainLinkContextAction = mainLinkContextAction
self.createLink = createLink self.createLink = createLink
self.openLink = openLink self.openLink = openLink
@ -178,8 +180,14 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
case let .mainLinkHeader(_, text): case let .mainLinkHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .mainLink(_, invite, peers): case let .mainLink(_, invite, peers):
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, peers: peers, displayButton: true, displayImporters: true, buttonColor: nil, sectionId: self.section, style: .blocks, shareAction: { return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, peers: peers, displayButton: true, displayImporters: true, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
if let invite = invite {
arguments.copyLink(invite)
}
}, shareAction: {
if let invite = invite {
arguments.shareMainLink(invite) arguments.shareMainLink(invite)
}
}, contextAction: { node in }, contextAction: { node in
arguments.mainLinkContextAction(invite, node, nil) arguments.mainLinkContextAction(invite, node, nil)
}, viewAction: { }, viewAction: {
@ -299,13 +307,6 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
let deleteAllRevokedLinksDisposable = MetaDisposable() let deleteAllRevokedLinksDisposable = MetaDisposable()
actionsDisposable.add(deleteAllRevokedLinksDisposable) actionsDisposable.add(deleteAllRevokedLinksDisposable)
actionsDisposable.add((context.account.viewTracker.peerView(peerId) |> filter { $0.cachedData != nil } |> take(1) |> mapToSignal { view -> Signal<String?, NoError> in
return ensuredExistingPeerExportedInvitation(account: context.account, peerId: peerId)
|> mapToSignal { _ -> Signal<String?, NoError> in
return .complete()
}
}).start())
var getControllerImpl: (() -> ViewController?)? var getControllerImpl: (() -> ViewController?)?
let invitesPromise = Promise<ExportedInvitations?>() let invitesPromise = Promise<ExportedInvitations?>()
@ -317,15 +318,15 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
|> then(peerExportedInvitations(account: context.account, peerId: peerId, revoked: true))) |> then(peerExportedInvitations(account: context.account, peerId: peerId, revoked: true)))
let arguments = InviteLinkListControllerArguments(context: context, shareMainLink: { invite in let arguments = InviteLinkListControllerArguments(context: context, shareMainLink: { invite in
if let invite = invite {
let shareController = ShareController(context: context, subject: .url(invite.link)) let shareController = ShareController(context: context, subject: .url(invite.link))
presentControllerImpl?(shareController, nil) presentControllerImpl?(shareController, nil)
}
}, openMainLink: { invite in }, openMainLink: { invite in
if let invite = invite {
let controller = InviteLinkViewController(context: context, peerId: peerId, invite: invite, importersContext: nil) let controller = InviteLinkViewController(context: context, peerId: peerId, invite: invite, importersContext: nil)
pushControllerImpl?(controller) pushControllerImpl?(controller)
} }, copyLink: { invite in
UIPasteboard.general.string = invite.link
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Username_LinkCopied, false)), nil)
}, mainLinkContextAction: { invite, node, gesture in }, mainLinkContextAction: { invite, node, gesture in
guard let node = node as? ContextExtractedContentContainingNode, let controller = getControllerImpl?() else { guard let node = node as? ContextExtractedContentContainingNode, let controller = getControllerImpl?() else {
return return
@ -383,7 +384,7 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId) ->
} }
} }
if revoke { if revoke {
revokeLinkDisposable.set((ensuredExistingPeerExportedInvitation(account: context.account, peerId: peerId, revokeExisted: true) |> deliverOnMainQueue).start(completed: { revokeLinkDisposable.set((revokePersistentPeerExportedInvitation(account: context.account, peerId: peerId) |> deliverOnMainQueue).start(completed: {
updateState { state in updateState { state in
var updatedState = state var updatedState = state
updatedState.revokingPrivateLink = false updatedState.revokingPrivateLink = false

View File

@ -24,12 +24,14 @@ import DirectionalPanGesture
class InviteLinkViewInteraction { class InviteLinkViewInteraction {
let context: AccountContext let context: AccountContext
let openPeer: (PeerId) -> Void let openPeer: (PeerId) -> Void
let copyLink: (ExportedInvitation) -> Void
let shareLink: (ExportedInvitation) -> Void let shareLink: (ExportedInvitation) -> Void
let contextAction: (ExportedInvitation, ASDisplayNode, ContextGesture?) -> Void let contextAction: (ExportedInvitation, ASDisplayNode, ContextGesture?) -> Void
init(context: AccountContext, openPeer: @escaping (PeerId) -> Void, shareLink: @escaping (ExportedInvitation) -> Void, contextAction: @escaping (ExportedInvitation, ASDisplayNode, ContextGesture?) -> Void) { init(context: AccountContext, openPeer: @escaping (PeerId) -> Void, copyLink: @escaping (ExportedInvitation) -> Void, shareLink: @escaping (ExportedInvitation) -> Void, contextAction: @escaping (ExportedInvitation, ASDisplayNode, ContextGesture?) -> Void) {
self.context = context self.context = context
self.openPeer = openPeer self.openPeer = openPeer
self.copyLink = copyLink
self.shareLink = shareLink self.shareLink = shareLink
self.contextAction = contextAction self.contextAction = contextAction
} }
@ -169,7 +171,9 @@ private enum InviteLinkViewEntry: Comparable, Identifiable {
case let .link(_, invite): case let .link(_, invite):
let buttonColor = color(for: invite) let buttonColor = color(for: invite)
let availability = invitationAvailability(invite) let availability = invitationAvailability(invite)
return ItemListPermanentInviteLinkItem(context: interaction.context, presentationData: ItemListPresentationData(presentationData), invite: invite, peers: [], displayButton: !invite.isRevoked && !availability.isZero, displayImporters: false, buttonColor: buttonColor, sectionId: 0, style: .plain, shareAction: { return ItemListPermanentInviteLinkItem(context: interaction.context, presentationData: ItemListPresentationData(presentationData), invite: invite, peers: [], displayButton: !invite.isRevoked && !availability.isZero, displayImporters: false, buttonColor: buttonColor, sectionId: 0, style: .plain, copyAction: {
interaction.copyLink(invite)
}, shareAction: {
interaction.shareLink(invite) interaction.shareLink(invite)
}, contextAction: { node in }, contextAction: { node in
interaction.contextAction(invite, node, nil) interaction.contextAction(invite, node, nil)
@ -383,6 +387,10 @@ public final class InviteLinkViewController: ViewController {
if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController { if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), keepStack: .always)) context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), keepStack: .always))
} }
}, copyLink: { [weak self] invite in
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 }, shareLink: { [weak self] invite in
let shareController = ShareController(context: context, subject: .url(invite.link)) let shareController = ShareController(context: context, subject: .url(invite.link))
self?.controller?.present(shareController, in: .window(.root)) self?.controller?.present(shareController, in: .window(.root))
@ -655,11 +663,6 @@ public final class InviteLinkViewController: ViewController {
if result === self.headerNode.view { if result === self.headerNode.view {
return self.view return self.view
} }
if result === self.headerNode.view {
return self.view
}
if !self.bounds.contains(point) { if !self.bounds.contains(point) {
return nil return nil
} }

View File

@ -35,6 +35,7 @@ public class ItemListPermanentInviteLinkItem: ListViewItem, ItemListItem {
let buttonColor: UIColor? let buttonColor: UIColor?
public let sectionId: ItemListSectionId public let sectionId: ItemListSectionId
let style: ItemListStyle let style: ItemListStyle
let copyAction: (() -> Void)?
let shareAction: (() -> Void)? let shareAction: (() -> Void)?
let contextAction: ((ASDisplayNode) -> Void)? let contextAction: ((ASDisplayNode) -> Void)?
let viewAction: (() -> Void)? let viewAction: (() -> Void)?
@ -50,6 +51,7 @@ public class ItemListPermanentInviteLinkItem: ListViewItem, ItemListItem {
buttonColor: UIColor?, buttonColor: UIColor?,
sectionId: ItemListSectionId, sectionId: ItemListSectionId,
style: ItemListStyle, style: ItemListStyle,
copyAction: (() -> Void)?,
shareAction: (() -> Void)?, shareAction: (() -> Void)?,
contextAction: ((ASDisplayNode) -> Void)?, contextAction: ((ASDisplayNode) -> Void)?,
viewAction: (() -> Void)?, viewAction: (() -> Void)?,
@ -64,6 +66,7 @@ public class ItemListPermanentInviteLinkItem: ListViewItem, ItemListItem {
self.buttonColor = buttonColor self.buttonColor = buttonColor
self.sectionId = sectionId self.sectionId = sectionId
self.style = style self.style = style
self.copyAction = copyAction
self.shareAction = shareAction self.shareAction = shareAction
self.contextAction = contextAction self.contextAction = contextAction
self.viewAction = viewAction self.viewAction = viewAction
@ -114,6 +117,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
private let fieldNode: ASImageNode private let fieldNode: ASImageNode
private let addressNode: TextNode private let addressNode: TextNode
private let fieldButtonNode: HighlightTrackingButtonNode
private let extractedContainerNode: ContextExtractedContentContainingNode private let extractedContainerNode: ContextExtractedContentContainingNode
private let containerNode: ContextControllerSourceNode private let containerNode: ContextControllerSourceNode
private let addressButtonNode: HighlightTrackingButtonNode private let addressButtonNode: HighlightTrackingButtonNode
@ -158,6 +162,8 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
self.addressNode = TextNode() self.addressNode = TextNode()
self.addressNode.isUserInteractionEnabled = false self.addressNode.isUserInteractionEnabled = false
self.fieldButtonNode = HighlightTrackingButtonNode()
self.addressButtonNode = HighlightTrackingButtonNode() self.addressButtonNode = HighlightTrackingButtonNode()
self.extractedContainerNode = ContextExtractedContentContainingNode() self.extractedContainerNode = ContextExtractedContentContainingNode()
self.containerNode = ContextControllerSourceNode() self.containerNode = ContextControllerSourceNode()
@ -177,6 +183,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
self.addSubnode(self.fieldNode) self.addSubnode(self.fieldNode)
self.addSubnode(self.addressNode) self.addSubnode(self.addressNode)
self.addSubnode(self.fieldButtonNode)
self.addSubnode(self.avatarsNode) self.addSubnode(self.avatarsNode)
self.addSubnode(self.invitedPeersNode) self.addSubnode(self.invitedPeersNode)
self.addSubnode(self.avatarsButtonNode) self.addSubnode(self.avatarsButtonNode)
@ -189,6 +196,19 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
self.addSubnode(self.activateArea) self.addSubnode(self.activateArea)
self.fieldButtonNode.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
if highlighted {
strongSelf.addressNode.layer.removeAnimation(forKey: "opacity")
strongSelf.addressNode.alpha = 0.4
} else {
strongSelf.addressNode.alpha = 1.0
strongSelf.addressNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
}
}
}
self.fieldButtonNode.addTarget(self, action: #selector(self.fieldButtonPressed), forControlEvents: .touchUpInside)
self.addressButtonNode.addTarget(self, action: #selector(self.addressButtonPressed), forControlEvents: .touchUpInside) self.addressButtonNode.addTarget(self, action: #selector(self.addressButtonPressed), forControlEvents: .touchUpInside)
self.addressButtonNode.highligthedChanged = { [weak self] highlighted in self.addressButtonNode.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self { if let strongSelf = self {
@ -224,6 +244,12 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
self.avatarsButtonNode.addTarget(self, action: #selector(self.avatarsButtonPressed), forControlEvents: .touchUpInside) self.avatarsButtonNode.addTarget(self, action: #selector(self.avatarsButtonPressed), forControlEvents: .touchUpInside)
} }
@objc private func fieldButtonPressed() {
if let item = self.item {
item.copyAction?()
}
}
@objc private func addressButtonPressed() { @objc private func addressButtonPressed() {
if let item = self.item { if let item = self.item {
item.contextAction?(self.extractedContainerNode) item.contextAction?(self.extractedContainerNode)
@ -393,6 +419,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
let fieldFrame = CGRect(origin: CGPoint(x: leftInset, y: verticalInset), size: CGSize(width: params.width - leftInset - rightInset, height: fieldHeight)) let fieldFrame = CGRect(origin: CGPoint(x: leftInset, y: verticalInset), size: CGSize(width: params.width - leftInset - rightInset, height: fieldHeight))
strongSelf.fieldNode.frame = fieldFrame strongSelf.fieldNode.frame = fieldFrame
strongSelf.fieldButtonNode.frame = fieldFrame
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.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)

View File

@ -18,6 +18,7 @@ public enum ItemListDisclosureStyle {
public enum ItemListDisclosureLabelStyle { public enum ItemListDisclosureLabelStyle {
case text case text
case detailText case detailText
case coloredText(UIColor)
case multilineDetailText case multilineDetailText
case badge(UIColor) case badge(UIColor)
case color(UIColor) case color(UIColor)
@ -277,6 +278,9 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
labelBadgeColor = item.presentationData.theme.list.itemSecondaryTextColor labelBadgeColor = item.presentationData.theme.list.itemSecondaryTextColor
labelFont = detailFont labelFont = detailFont
labelConstrain = params.width - params.rightInset - 40.0 - leftInset labelConstrain = params.width - params.rightInset - 40.0 - leftInset
case let .coloredText(color):
labelBadgeColor = color
labelFont = titleFont
default: default:
labelBadgeColor = item.presentationData.theme.list.itemSecondaryTextColor labelBadgeColor = item.presentationData.theme.list.itemSecondaryTextColor
labelFont = titleFont labelFont = titleFont

View File

@ -30,11 +30,12 @@ private final class ChannelVisibilityControllerArguments {
let displayPrivateLinkMenu: (String) -> Void let displayPrivateLinkMenu: (String) -> Void
let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void
let revokePeerId: (PeerId) -> Void let revokePeerId: (PeerId) -> Void
let shareLink: () -> Void let copyLink: (ExportedInvitation) -> Void
let shareLink: (ExportedInvitation) -> Void
let linkContextAction: (ASDisplayNode) -> Void let linkContextAction: (ASDisplayNode) -> Void
let manageInviteLinks: () -> Void let manageInviteLinks: () -> Void
init(context: AccountContext, updateCurrentType: @escaping (CurrentChannelType) -> Void, updatePublicLinkText: @escaping (String?, String) -> Void, scrollToPublicLinkText: @escaping () -> Void, displayPrivateLinkMenu: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, revokePeerId: @escaping (PeerId) -> Void, shareLink: @escaping () -> Void, linkContextAction: @escaping (ASDisplayNode) -> Void, manageInviteLinks: @escaping () -> Void) { init(context: AccountContext, updateCurrentType: @escaping (CurrentChannelType) -> Void, updatePublicLinkText: @escaping (String?, String) -> Void, scrollToPublicLinkText: @escaping () -> Void, displayPrivateLinkMenu: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, revokePeerId: @escaping (PeerId) -> Void, copyLink: @escaping (ExportedInvitation) -> Void, shareLink: @escaping (ExportedInvitation) -> Void, linkContextAction: @escaping (ASDisplayNode) -> Void, manageInviteLinks: @escaping () -> Void) {
self.context = context self.context = context
self.updateCurrentType = updateCurrentType self.updateCurrentType = updateCurrentType
self.updatePublicLinkText = updatePublicLinkText self.updatePublicLinkText = updatePublicLinkText
@ -42,6 +43,7 @@ private final class ChannelVisibilityControllerArguments {
self.displayPrivateLinkMenu = displayPrivateLinkMenu self.displayPrivateLinkMenu = displayPrivateLinkMenu
self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions
self.revokePeerId = revokePeerId self.revokePeerId = revokePeerId
self.copyLink = copyLink
self.shareLink = shareLink self.shareLink = shareLink
self.linkContextAction = linkContextAction self.linkContextAction = linkContextAction
self.manageInviteLinks = manageInviteLinks self.manageInviteLinks = manageInviteLinks
@ -291,8 +293,14 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
case let .privateLinkHeader(_, title): case let .privateLinkHeader(_, title):
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
case let .privateLink(_, invite): case let .privateLink(_, invite):
return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, peers: [], displayButton: true, displayImporters: true, buttonColor: nil, sectionId: self.section, style: .blocks, shareAction: { return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, peers: [], displayButton: true, displayImporters: true, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
arguments.shareLink() if let invite = invite {
arguments.copyLink(invite)
}
}, shareAction: {
if let invite = invite {
arguments.shareLink(invite)
}
}, contextAction: { node in }, contextAction: { node in
arguments.linkContextAction(node) arguments.linkContextAction(node)
}, viewAction: { }, viewAction: {
@ -836,13 +844,6 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
let revokeLinkDisposable = MetaDisposable() let revokeLinkDisposable = MetaDisposable()
actionsDisposable.add(revokeLinkDisposable) actionsDisposable.add(revokeLinkDisposable)
actionsDisposable.add((context.account.viewTracker.peerView(peerId) |> filter { $0.cachedData != nil } |> take(1) |> mapToSignal { view -> Signal<String?, NoError> in
return ensuredExistingPeerExportedInvitation(account: context.account, peerId: peerId)
|> mapToSignal { _ -> Signal<String?, NoError> in
return .complete()
}
}).start())
let arguments = ChannelVisibilityControllerArguments(context: context, updateCurrentType: { type in let arguments = ChannelVisibilityControllerArguments(context: context, updateCurrentType: { type in
updateState { state in updateState { state in
return state.withUpdatedSelectedType(type) return state.withUpdatedSelectedType(type)
@ -898,22 +899,13 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
} }
}) })
})) }))
}, shareLink: { }, copyLink: { invite in
let _ = (context.account.postbox.transaction { transaction -> String? in UIPasteboard.general.string = invite.link
if let cachedData = transaction.getPeerCachedData(peerId: peerId) { let presentationData = context.sharedContext.currentPresentationData.with { $0 }
if let cachedData = cachedData as? CachedChannelData { presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Username_LinkCopied, false)), nil)
return cachedData.exportedInvitation?.link }, shareLink: { invite in
} else if let cachedData = cachedData as? CachedGroupData { let shareController = ShareController(context: context, subject: .url(invite.link))
return cachedData.exportedInvitation?.link
}
}
return nil
} |> deliverOnMainQueue).start(next: { link in
if let link = link {
let shareController = ShareController(context: context, subject: .url(link))
presentControllerImpl?(shareController, nil) presentControllerImpl?(shareController, nil)
}
})
}, linkContextAction: { node in }, linkContextAction: { node in
guard let node = node as? ContextExtractedContentContainingNode, let controller = getControllerImpl?() else { guard let node = node as? ContextExtractedContentContainingNode, let controller = getControllerImpl?() else {
return return
@ -991,7 +983,7 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
} }
} }
if revoke { if revoke {
revokeLinkDisposable.set((ensuredExistingPeerExportedInvitation(account: context.account, peerId: peerId, revokeExisted: true) |> deliverOnMainQueue).start(completed: { revokeLinkDisposable.set((revokePersistentPeerExportedInvitation(account: context.account, peerId: peerId) |> deliverOnMainQueue).start(completed: {
updateState { updateState {
$0.withUpdatedRevokingPrivateLink(false) $0.withUpdatedRevokingPrivateLink(false)
} }

View File

@ -11,7 +11,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) } dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) } dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) } dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) }
dict[231260545] = { return Api.ChatFull.parse_chatFull($0) } dict[-213431562] = { return Api.ChatFull.parse_chatFull($0) }
dict[2055070967] = { return Api.ChatFull.parse_channelFull($0) } dict[2055070967] = { return Api.ChatFull.parse_channelFull($0) }
dict[-1159937629] = { return Api.PollResults.parse_pollResults($0) } dict[-1159937629] = { return Api.PollResults.parse_pollResults($0) }
dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) } dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) }

View File

@ -2206,14 +2206,14 @@ public extension Api {
} }
public enum ChatFull: TypeConstructorDescription { public enum ChatFull: TypeConstructorDescription {
case chatFull(flags: Int32, id: Int32, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?, call: Api.InputGroupCall?) case chatFull(flags: Int32, id: Int32, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?, call: Api.InputGroupCall?)
case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32, call: Api.InputGroupCall?) case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite?, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32, call: Api.InputGroupCall?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call): case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call):
if boxed { if boxed {
buffer.appendInt32(231260545) buffer.appendInt32(-213431562)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false) serializeInt32(id, buffer: buffer, boxed: false)
@ -2221,7 +2221,7 @@ public extension Api {
participants.serialize(buffer, true) participants.serialize(buffer, true)
if Int(flags) & Int(1 << 2) != 0 {chatPhoto!.serialize(buffer, true)} if Int(flags) & Int(1 << 2) != 0 {chatPhoto!.serialize(buffer, true)}
notifySettings.serialize(buffer, true) notifySettings.serialize(buffer, true)
exportedInvite.serialize(buffer, true) if Int(flags) & Int(1 << 13) != 0 {exportedInvite!.serialize(buffer, true)}
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261) if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(botInfo!.count)) buffer.appendInt32(Int32(botInfo!.count))
for item in botInfo! { for item in botInfo! {
@ -2300,9 +2300,9 @@ public extension Api {
_6 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings _6 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings
} }
var _7: Api.ExportedChatInvite? var _7: Api.ExportedChatInvite?
if let signature = reader.readInt32() { if Int(_1!) & Int(1 << 13) != 0 {if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite _7 = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite
} } }
var _8: [Api.BotInfo]? var _8: [Api.BotInfo]?
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() { if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotInfo.self) _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotInfo.self)
@ -2321,13 +2321,13 @@ public extension Api {
let _c4 = _4 != nil let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil
let _c6 = _6 != nil let _c6 = _6 != nil
let _c7 = _7 != nil let _c7 = (Int(_1!) & Int(1 << 13) == 0) || _7 != nil
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil
let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil
let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil
let _c11 = (Int(_1!) & Int(1 << 12) == 0) || _11 != nil let _c11 = (Int(_1!) & Int(1 << 12) == 0) || _11 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 { 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) 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)
} }
else { else {
return nil return nil

View File

@ -1061,24 +1061,6 @@ public final class VoiceChatController: ViewController {
strongSelf.accountPeer = accountPeer strongSelf.accountPeer = accountPeer
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set()) strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set())
if let peer = peerViewMainPeer(view) {
if let channel = peer as? TelegramChannel {
let addressName = channel.addressName ?? ""
if channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers) {
if addressName.isEmpty {
let _ = ensuredExistingPeerExportedInvitation(account: strongSelf.context.account, peerId: call.peerId).start()
}
}
} else if let group = peer as? TelegramGroup {
switch group.role {
case .creator, .admin:
let _ = ensuredExistingPeerExportedInvitation(account: strongSelf.context.account, peerId: call.peerId).start()
default:
break
}
}
}
strongSelf.didSetDataReady = true strongSelf.didSetDataReady = true
strongSelf.controller?.dataReady.set(true) strongSelf.controller?.dataReady.set(true)
} }

View File

@ -6,14 +6,11 @@ import MtProtoKit
import SyncCore import SyncCore
public func ensuredExistingPeerExportedInvitation(account: Account, peerId: PeerId, revokeExisted: Bool = false) -> Signal<ExportedInvitation?, NoError> { public func revokePersistentPeerExportedInvitation(account: Account, peerId: PeerId) -> Signal<ExportedInvitation?, NoError> {
return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, NoError> in return account.postbox.transaction { transaction -> Signal<ExportedInvitation?, NoError> in
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
let flags: Int32 = (1 << 2) let flags: Int32 = (1 << 2)
if let _ = peer as? TelegramChannel { if let _ = peer as? TelegramChannel {
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(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil)) return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil))
|> retryRequest |> retryRequest
|> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in |> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in
@ -32,11 +29,7 @@ public func ensuredExistingPeerExportedInvitation(account: Account, peerId: Peer
} }
} }
} }
}
} else if let _ = peer as? TelegramGroup { } else if let _ = peer as? TelegramGroup {
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedGroupData, cachedData.exportedInvitation != nil && !revokeExisted {
return .complete()
} else {
return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil)) return account.network.request(Api.functions.messages.exportChatInvite(flags: flags, peer: inputPeer, expireDate: nil, usageLimit: nil))
|> retryRequest |> retryRequest
|> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in |> mapToSignal { result -> Signal<ExportedInvitation?, NoError> in
@ -55,7 +48,6 @@ public func ensuredExistingPeerExportedInvitation(account: Account, peerId: Peer
} }
} }
} }
}
} else { } else {
return .complete() return .complete()
} }

View File

@ -257,7 +257,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
let photo: TelegramMediaImage? = chatFull.chatPhoto.flatMap(telegramMediaImageFromApiPhoto) let photo: TelegramMediaImage? = chatFull.chatPhoto.flatMap(telegramMediaImageFromApiPhoto)
let exportedInvitation = ExportedInvitation(apiExportedInvite: chatFull.exportedInvite) let exportedInvitation = chatFull.exportedInvite.flatMap { ExportedInvitation(apiExportedInvite: $0) }
let pinnedMessageId = chatFull.pinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }) let pinnedMessageId = chatFull.pinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })
var peers: [Peer] = [] var peers: [Peer] = []