Invite Links Fixes

This commit is contained in:
Ilya Laktyushin 2021-02-15 08:01:11 +04:00
parent eabc08372b
commit 1777f6465a
12 changed files with 4146 additions and 4069 deletions

View File

@ -2689,6 +2689,7 @@ Unused sets are archived when you add more.";
"Channel.AdminLogFilter.EventsPinned" = "Pinned Messages"; "Channel.AdminLogFilter.EventsPinned" = "Pinned Messages";
"Channel.AdminLogFilter.EventsLeaving" = "Members Removed"; "Channel.AdminLogFilter.EventsLeaving" = "Members Removed";
"Channel.AdminLogFilter.EventsCalls" = "Voice Chats"; "Channel.AdminLogFilter.EventsCalls" = "Voice Chats";
"Channel.AdminLogFilter.EventsInviteLinks" = "Invite Links";
"Channel.AdminLogFilter.AdminsTitle" = "ADMINS"; "Channel.AdminLogFilter.AdminsTitle" = "ADMINS";
"Channel.AdminLogFilter.AdminsAll" = "All Admins"; "Channel.AdminLogFilter.AdminsAll" = "All Admins";

View File

@ -716,21 +716,31 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId, ad
]) ])
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}) })
let peerView = context.account.viewTracker.peerView(peerId) let peerView = context.account.viewTracker.peerView(peerId)
|> deliverOnMainQueue |> deliverOnMainQueue
let importersState = Promise<PeerInvitationImportersState?>(nil) let mainLink: Signal<ExportedInvitation?, NoError>
let importersContext: Signal<PeerInvitationImportersContext?, NoError> = peerView if let _ = admin {
|> mapToSignal { view -> Signal<ExportedInvitation?, NoError> in mainLink = invitesContext.state
if let cachedData = view.cachedData as? CachedGroupData, let exportedInvitation = cachedData.exportedInvitation { |> mapToSignal { state -> Signal<ExportedInvitation?, NoError> in
return .single(exportedInvitation) return .single(state.invitations.first(where: { $0.isPermanent && !$0.isRevoked }))
} else if let cachedData = view.cachedData as? CachedChannelData, let exportedInvitation = cachedData.exportedInvitation { }
return .single(exportedInvitation) } else {
} else { mainLink = peerView
return .single(nil) |> mapToSignal { view -> Signal<ExportedInvitation?, NoError> in
if let cachedData = view.cachedData as? CachedGroupData, let exportedInvitation = cachedData.exportedInvitation {
return .single(exportedInvitation)
} else if let cachedData = view.cachedData as? CachedChannelData, let exportedInvitation = cachedData.exportedInvitation {
return .single(exportedInvitation)
} else {
return .single(nil)
}
} }
} }
let importersState = Promise<PeerInvitationImportersState?>(nil)
let importersContext: Signal<PeerInvitationImportersContext?, NoError> = mainLink
|> distinctUntilChanged |> distinctUntilChanged
|> deliverOnMainQueue |> deliverOnMainQueue
|> map { invite -> PeerInvitationImportersContext? in |> map { invite -> PeerInvitationImportersContext? in
@ -749,16 +759,21 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId, ad
}, queue: Queue.mainQueue()) }, queue: Queue.mainQueue())
timer.start() timer.start()
let previousInvites = Atomic<PeerExportedInvitationsState?>(value: nil)
let previousRevokedInvites = Atomic<PeerExportedInvitationsState?>(value: nil) let previousRevokedInvites = Atomic<PeerExportedInvitationsState?>(value: nil)
let previousCreators = Atomic<[ExportedInvitationCreator]?>(value: nil) let previousCreators = Atomic<[ExportedInvitationCreator]?>(value: nil)
let signal = combineLatest(context.sharedContext.presentationData, peerView, importersContext, importersState.get(), invitesContext.state, revokedInvitesContext.state, creators, timerPromise.get()) let signal = combineLatest(context.sharedContext.presentationData, peerView, importersContext, importersState.get(), invitesContext.state, revokedInvitesContext.state, creators, timerPromise.get())
|> deliverOnMainQueue |> deliverOnMainQueue
|> map { presentationData, view, importersContext, importers, invites, revokedInvites, creators, tick -> (ItemListControllerState, (ItemListNodeState, Any)) in |> map { presentationData, view, importersContext, importers, invites, revokedInvites, creators, tick -> (ItemListControllerState, (ItemListNodeState, Any)) in
let previousRevokedInvites = previousRevokedInvites.swap(invites) let previousInvites = previousInvites.swap(invites)
let previousRevokedInvites = previousRevokedInvites.swap(revokedInvites)
let previousCreators = previousCreators.swap(creators) let previousCreators = previousCreators.swap(creators)
var crossfade = false var crossfade = false
if (previousInvites?.hasLoadedOnce ?? false) != (invites.hasLoadedOnce) {
crossfade = true
}
if (previousRevokedInvites?.hasLoadedOnce ?? false) != (revokedInvites.hasLoadedOnce) { if (previousRevokedInvites?.hasLoadedOnce ?? false) != (revokedInvites.hasLoadedOnce) {
crossfade = true crossfade = true
} }
@ -766,6 +781,11 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId, ad
crossfade = true crossfade = true
} }
var animateChanges = false
if !crossfade && previousInvites?.hasLoadedOnce == true && previousRevokedInvites?.hasLoadedOnce == true && previousCreators != nil {
animateChanges = true
}
let title: ItemListControllerTitle let title: ItemListControllerTitle
if let admin = admin, let peer = admin.peer.peer { if let admin = admin, let peer = admin.peer.peer {
title = .textWithSubtitle(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), presentationData.strings.InviteLink_InviteLinks(admin.count)) title = .textWithSubtitle(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), presentationData.strings.InviteLink_InviteLinks(admin.count))
@ -774,7 +794,7 @@ public func inviteLinkListController(context: AccountContext, peerId: PeerId, ad
} }
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: title, leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) 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, tick: tick), style: .blocks, emptyStateItem: nil, crossfadeState: crossfade, animateChanges: false) 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, tick: tick), style: .blocks, emptyStateItem: nil, crossfadeState: crossfade, animateChanges: animateChanges)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} }

View File

@ -531,9 +531,12 @@ public final class InviteLinkViewController: ViewController {
self?.controller?.dismiss() self?.controller?.dismiss()
let _ = (revokePeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(completed: { let _ = (revokePeerExportedInvitation(account: context.account, peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(completed: {
}) })
self?.controller?.revokedInvitationsContext?.remove(invite) self?.controller?.invitationsContext?.remove(invite)
let revokedInvite = invite.withUpdated(isRevoked: true)
self?.controller?.revokedInvitationsContext?.add(revokedInvite)
}) })
]), ]),
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])

View File

@ -126,6 +126,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
private let containerNode: ContextControllerSourceNode private let containerNode: ContextControllerSourceNode
private let addressButtonNode: HighlightTrackingButtonNode private let addressButtonNode: HighlightTrackingButtonNode
private let addressButtonIconNode: ASImageNode private let addressButtonIconNode: ASImageNode
private var addressShimmerNode: ShimmerEffectNode?
private var shareButtonNode: SolidRoundedButtonNode? private var shareButtonNode: SolidRoundedButtonNode?
private let avatarsButtonNode: HighlightTrackingButtonNode private let avatarsButtonNode: HighlightTrackingButtonNode
@ -133,7 +134,7 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
private var avatarsContent: AnimatedAvatarSetContext.Content? private var avatarsContent: AnimatedAvatarSetContext.Content?
private let avatarsNode: AnimatedAvatarSetNode private let avatarsNode: AnimatedAvatarSetNode
private let invitedPeersNode: TextNode private let invitedPeersNode: TextNode
private var peersPlaceholderNode: ShimmerEffectNode? private var shimmerNode: ShimmerEffectNode?
private var absoluteLocation: (CGRect, CGSize)? private var absoluteLocation: (CGRect, CGSize)?
private let activateArea: AccessibilityAreaNode private let activateArea: AccessibilityAreaNode
@ -492,11 +493,11 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
if item.invite == nil { if item.invite == nil {
let shimmerNode: ShimmerEffectNode let shimmerNode: ShimmerEffectNode
if let current = strongSelf.peersPlaceholderNode { if let current = strongSelf.shimmerNode {
shimmerNode = current shimmerNode = current
} else { } else {
shimmerNode = ShimmerEffectNode() shimmerNode = ShimmerEffectNode()
strongSelf.peersPlaceholderNode = shimmerNode strongSelf.shimmerNode = shimmerNode
strongSelf.insertSubnode(shimmerNode, belowSubnode: strongSelf.fieldNode) strongSelf.insertSubnode(shimmerNode, belowSubnode: strongSelf.fieldNode)
} }
shimmerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize) shimmerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
@ -504,17 +505,41 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
shimmerNode.updateAbsoluteRect(rect, within: size) shimmerNode.updateAbsoluteRect(rect, within: size)
} }
var shapes: [ShimmerEffectNode.Shape] = []
let lineWidth: CGFloat = 180.0 let lineWidth: CGFloat = 180.0
let lineDiameter: CGFloat = 10.0 let lineDiameter: CGFloat = 12.0
let titleFrame = strongSelf.invitedPeersNode.frame let titleFrame = strongSelf.invitedPeersNode.frame
var shapes: [ShimmerEffectNode.Shape] = []
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)) 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) 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 let addressShimmerNode: ShimmerEffectNode
shimmerNode.removeFromSupernode() if let current = strongSelf.addressShimmerNode {
addressShimmerNode = current
} else {
addressShimmerNode = ShimmerEffectNode()
strongSelf.addressShimmerNode = addressShimmerNode
strongSelf.insertSubnode(addressShimmerNode, aboveSubnode: strongSelf.fieldNode)
}
addressShimmerNode.frame = strongSelf.fieldNode.frame.insetBy(dx: 18.0, dy: 0.0)
if let (rect, size) = strongSelf.absoluteLocation {
addressShimmerNode.updateAbsoluteRect(CGRect(x: rect.minX + strongSelf.fieldNode.frame.minX + 18.0, y: rect.minY + strongSelf.fieldNode.frame.minY, width: strongSelf.fieldNode.frame.width - 18.0 * 2.0, height: strongSelf.fieldNode.frame.height), within: size)
}
let addressLineWidth: CGFloat = strongSelf.fieldNode.frame.width - 100.0
var addressShapes: [ShimmerEffectNode.Shape] = []
addressShapes.append(.roundedRectLine(startPoint: CGPoint(x: floor(addressShimmerNode.frame.width / 2.0 - addressLineWidth / 2.0), y: 16.0 + floor((22.0 - lineDiameter) / 2.0)), width: addressLineWidth, diameter: lineDiameter))
addressShimmerNode.update(backgroundColor: item.presentationData.theme.list.itemInputField.backgroundColor, foregroundColor: item.presentationData.theme.list.itemInputField.controlColor.mixedWith(item.presentationData.theme.list.itemInputField.backgroundColor, alpha: 0.7), shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: addressShapes, size: addressShimmerNode.frame.size)
} else {
if let shimmerNode = strongSelf.shimmerNode {
strongSelf.shimmerNode = nil
shimmerNode.removeFromSupernode()
}
if let shimmerNode = strongSelf.addressShimmerNode {
strongSelf.shimmerNode = nil
shimmerNode.removeFromSupernode()
}
} }
} }
}) })
@ -537,7 +562,10 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
var rect = rect var rect = rect
rect.origin.y += self.insets.top rect.origin.y += self.insets.top
self.absoluteLocation = (rect, containerSize) self.absoluteLocation = (rect, containerSize)
if let shimmerNode = self.peersPlaceholderNode { if let shimmerNode = self.addressShimmerNode {
shimmerNode.updateAbsoluteRect(CGRect(x: rect.minX + self.fieldNode.frame.minX + 18.0, y: rect.minY + self.fieldNode.frame.minY, width: self.fieldNode.frame.width - 18.0 * 2.0, height: self.fieldNode.frame.height), within: containerSize)
}
if let shimmerNode = self.shimmerNode {
shimmerNode.updateAbsoluteRect(rect, within: containerSize) shimmerNode.updateAbsoluteRect(rect, within: containerSize)
} }
} }

View File

@ -18,6 +18,7 @@ import ItemListPeerItem
import TelegramPermissionsUI import TelegramPermissionsUI
import ItemListPeerActionItem import ItemListPeerActionItem
import Markdown import Markdown
import UndoUI
private final class ChannelPermissionsControllerArguments { private final class ChannelPermissionsControllerArguments {
let context: AccountContext let context: AccountContext
@ -770,7 +771,8 @@ public func channelPermissionsController(context: AccountContext, peerId origina
let _ = (convertGroupToGigagroup(account: context.account, peerId: originalPeerId) let _ = (convertGroupToGigagroup(account: context.account, peerId: originalPeerId)
|> deliverOnMainQueue).start(completed: { |> deliverOnMainQueue).start(completed: {
let participantsLimit = context.currentLimitsConfiguration.with { $0 }.maxSupergroupMemberCount
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.BroadcastGroups_Success(presentationStringsFormattedNumber(participantsLimit, presentationData.dateTimeFormat.decimalSeparator)).0), elevatedLayout: false, action: { _ in return false }), nil)
}) })
})]) })])
presentControllerImpl?(alertController, nil) presentControllerImpl?(alertController, nil)

View File

@ -75,6 +75,7 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese
super.init(navigationBarPresentationData: nil) super.init(navigationBarPresentationData: nil)
self.blocksBackgroundWhenInOverlay = true
self.acceptsFocusWhenInOverlay = true self.acceptsFocusWhenInOverlay = true
self.statusBar.statusBarStyle = .Ignore self.statusBar.statusBarStyle = .Ignore

View File

@ -144,6 +144,11 @@ public final class ChannelAdminEventLogContext {
} }
} }
public func reload() {
self.entries = ([], self.filter)
self.loadMoreEntries()
}
public func loadMoreEntries() { public func loadMoreEntries() {
assert(self.queue.isCurrent()) assert(self.queue.isCurrent())

View File

@ -7098,7 +7098,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let _ = (convertGroupToGigagroup(account: context.account, peerId: peerId) let _ = (convertGroupToGigagroup(account: context.account, peerId: peerId)
|> deliverOnMainQueue).start(completed: { |> deliverOnMainQueue).start(completed: {
let participantsLimit = context.currentLimitsConfiguration.with { $0 }.maxSupergroupMemberCount
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.BroadcastGroups_Success(presentationStringsFormattedNumber(participantsLimit, presentationData.dateTimeFormat.decimalSeparator)).0), elevatedLayout: false, action: { _ in return false }), in: .current)
}) })
})]) })])
strongSelf.present(alertController, in: .window(.root)) strongSelf.present(alertController, in: .window(.root))

View File

@ -20,6 +20,7 @@ import StickerPackPreviewUI
import JoinLinkPreviewUI import JoinLinkPreviewUI
import LanguageLinkPreviewUI import LanguageLinkPreviewUI
import PeerInfoUI import PeerInfoUI
import InviteLinksUI
private final class ChatRecentActionsListOpaqueState { private final class ChatRecentActionsListOpaqueState {
let entries: [ChatRecentActionsEntry] let entries: [ChatRecentActionsEntry]
@ -150,6 +151,15 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
strongSelf.presentController(StickerPackScreen(context: strongSelf.context, mainStickerPack: new, stickerPacks: [new], parentNavigationController: strongSelf.getNavigationController()), nil) strongSelf.presentController(StickerPackScreen(context: strongSelf.context, mainStickerPack: new, stickerPacks: [new], parentNavigationController: strongSelf.getNavigationController()), nil)
return true return true
} }
case let .editExportedInvitation(_, invite), let .revokeExportedInvitation(invite), let .deleteExportedInvitation(invite), let .participantJoinedViaInvite(invite):
if !invite.link.hasSuffix("...") {
let controller = inviteLinkEditController(context: strongSelf.context, peerId: peer.id, invite: invite, completion: { [weak self] _ in
self?.eventLogContext.reload()
})
controller.navigationPresentation = .modal
strongSelf.pushController(controller)
return true
}
default: default:
break break
} }

View File

@ -289,6 +289,7 @@ private func channelRecentActionsFilterControllerEntries(presentationData: Prese
([.promote, .demote], presentationData.strings.Channel_AdminLogFilter_EventsAdmins), ([.promote, .demote], presentationData.strings.Channel_AdminLogFilter_EventsAdmins),
([.invite, .join], presentationData.strings.Channel_AdminLogFilter_EventsNewMembers), ([.invite, .join], presentationData.strings.Channel_AdminLogFilter_EventsNewMembers),
([.info, .settings], isGroup ? presentationData.strings.Channel_AdminLogFilter_EventsInfo : presentationData.strings.Channel_AdminLogFilter_ChannelEventsInfo), ([.info, .settings], isGroup ? presentationData.strings.Channel_AdminLogFilter_EventsInfo : presentationData.strings.Channel_AdminLogFilter_ChannelEventsInfo),
([.invites], presentationData.strings.Channel_AdminLogFilter_EventsInviteLinks),
([.deleteMessages], presentationData.strings.Channel_AdminLogFilter_EventsDeletedMessages), ([.deleteMessages], presentationData.strings.Channel_AdminLogFilter_EventsDeletedMessages),
([.editMessages], presentationData.strings.Channel_AdminLogFilter_EventsEditedMessages), ([.editMessages], presentationData.strings.Channel_AdminLogFilter_EventsEditedMessages),
([.pinnedMessages], presentationData.strings.Channel_AdminLogFilter_EventsPinned), ([.pinnedMessages], presentationData.strings.Channel_AdminLogFilter_EventsPinned),
@ -300,6 +301,7 @@ private func channelRecentActionsFilterControllerEntries(presentationData: Prese
([.promote, .demote], presentationData.strings.Channel_AdminLogFilter_EventsAdmins), ([.promote, .demote], presentationData.strings.Channel_AdminLogFilter_EventsAdmins),
([.invite, .join], presentationData.strings.Channel_AdminLogFilter_EventsNewMembers), ([.invite, .join], presentationData.strings.Channel_AdminLogFilter_EventsNewMembers),
([.info, .settings], isGroup ? presentationData.strings.Channel_AdminLogFilter_EventsInfo : presentationData.strings.Channel_AdminLogFilter_ChannelEventsInfo), ([.info, .settings], isGroup ? presentationData.strings.Channel_AdminLogFilter_EventsInfo : presentationData.strings.Channel_AdminLogFilter_ChannelEventsInfo),
([.invites], presentationData.strings.Channel_AdminLogFilter_EventsInviteLinks),
([.deleteMessages], presentationData.strings.Channel_AdminLogFilter_EventsDeletedMessages), ([.deleteMessages], presentationData.strings.Channel_AdminLogFilter_EventsDeletedMessages),
([.editMessages], presentationData.strings.Channel_AdminLogFilter_EventsEditedMessages), ([.editMessages], presentationData.strings.Channel_AdminLogFilter_EventsEditedMessages),
([.pinnedMessages], presentationData.strings.Channel_AdminLogFilter_EventsPinned), ([.pinnedMessages], presentationData.strings.Channel_AdminLogFilter_EventsPinned),