Add voice chat invite link sharing for non-participants in public groups

This commit is contained in:
Ilya Laktyushin 2021-03-25 00:13:08 +05:00
parent 5f3bab6261
commit 1fd84c653b
4 changed files with 3830 additions and 3806 deletions

View File

@ -6317,3 +6317,6 @@ Sorry for the inconvenience.";
"VoiceChat.EditBioText" = "Any details such as age, occupation or city."; "VoiceChat.EditBioText" = "Any details such as age, occupation or city.";
"VoiceChat.EditBioPlaceholder" = "Bio"; "VoiceChat.EditBioPlaceholder" = "Bio";
"VoiceChat.EditBioSave" = "Save"; "VoiceChat.EditBioSave" = "Save";
"VoiceChat.SendPublicLinkText" = "%1$@ isn't a member of \"%2$@\" yet. Send them a public invite link instead?";
"VoiceChat.SendPublicLinkSend" = "Send";

View File

@ -945,12 +945,11 @@ public final class VoiceChatController: ViewController {
} }
if let groupPeer = groupPeer as? TelegramChannel { if let groupPeer = groupPeer as? TelegramChannel {
var canInvite = true var canInviteMembers = true
if case .broadcast = groupPeer.info, !(groupPeer.addressName?.isEmpty ?? true) { if case .broadcast = groupPeer.info, !(groupPeer.addressName?.isEmpty ?? true) {
canInvite = false canInviteMembers = false
} }
if !canInviteMembers {
if !canInvite {
if let inviteLinks = inviteLinks { if let inviteLinks = inviteLinks {
strongSelf.presentShare(inviteLinks) strongSelf.presentShare(inviteLinks)
} }
@ -963,7 +962,7 @@ public final class VoiceChatController: ViewController {
filters.append(.disable(Array(currentCallMembers.map { $0.peer.id }))) filters.append(.disable(Array(currentCallMembers.map { $0.peer.id })))
} }
if let groupPeer = groupPeer as? TelegramChannel { if let groupPeer = groupPeer as? TelegramChannel {
if !groupPeer.hasPermission(.inviteMembers) { if !groupPeer.hasPermission(.inviteMembers) && inviteLinks?.listenerLink == nil {
filters.append(.excludeNonMembers) filters.append(.excludeNonMembers)
} }
} else if let groupPeer = groupPeer as? TelegramGroup { } else if let groupPeer = groupPeer as? TelegramGroup {
@ -981,7 +980,6 @@ public final class VoiceChatController: ViewController {
} }
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
if peer.id == strongSelf.callState?.myPeerId { if peer.id == strongSelf.callState?.myPeerId {
return return
} }
@ -992,154 +990,171 @@ public final class VoiceChatController: ViewController {
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: participant.peer, text: strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0), action: { _ in return false }) strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: participant.peer, text: strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0), action: { _ in return false })
} }
} else { } else {
let text: String if let groupPeer = groupPeer as? TelegramChannel, let listenerLink = inviteLinks?.listenerLink, !groupPeer.hasPermission(.inviteMembers) {
if let groupPeer = groupPeer as? TelegramChannel, case .broadcast = groupPeer.info { let text = strongSelf.presentationData.strings.VoiceChat_SendPublicLinkText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), groupPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0
text = strongSelf.presentationData.strings.VoiceChat_InviteMemberToChannelFirstText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), groupPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0
strongSelf.controller?.present(textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: nil, text: text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.VoiceChat_SendPublicLinkSend, action: { [weak self] in
dismissController?()
if let strongSelf = self {
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: [.message(text: listenerLink, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)])
|> deliverOnMainQueue).start(next: { [weak self] _ in
if let strongSelf = self {
strongSelf.presentUndoOverlay(content: .forward(savedMessages: false, text: strongSelf.presentationData.strings.UserInfo_LinkForwardTooltip_Chat_One(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0), action: { _ in return true })
}
})
}
})]), in: .window(.root))
} else { } else {
text = strongSelf.presentationData.strings.VoiceChat_InviteMemberToGroupFirstText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), groupPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0 let text: String
} if let groupPeer = groupPeer as? TelegramChannel, case .broadcast = groupPeer.info {
text = strongSelf.presentationData.strings.VoiceChat_InviteMemberToChannelFirstText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), groupPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0
strongSelf.controller?.present(textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: nil, text: text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.VoiceChat_InviteMemberToGroupFirstAdd, action: { } else {
guard let strongSelf = self else { text = strongSelf.presentationData.strings.VoiceChat_InviteMemberToGroupFirstText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), groupPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0
return
} }
if let groupPeer = groupPeer as? TelegramChannel { strongSelf.controller?.present(textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: nil, text: text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.VoiceChat_InviteMemberToGroupFirstAdd, action: {
let selfController = strongSelf.controller guard let strongSelf = self else {
let inviteDisposable = strongSelf.inviteDisposable return
var inviteSignal = strongSelf.context.peerChannelMemberCategoriesContextsManager.addMembers(account: strongSelf.context.account, peerId: groupPeer.id, memberIds: [peer.id])
var cancelImpl: (() -> Void)?
let progressSignal = Signal<Never, NoError> { [weak selfController] subscriber in
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
cancelImpl?()
}))
selfController?.present(controller, in: .window(.root))
return ActionDisposable { [weak controller] in
Queue.mainQueue().async() {
controller?.dismiss()
}
}
}
|> runOn(Queue.mainQueue())
|> delay(0.15, queue: Queue.mainQueue())
let progressDisposable = progressSignal.start()
inviteSignal = inviteSignal
|> afterDisposed {
Queue.mainQueue().async {
progressDisposable.dispose()
}
}
cancelImpl = {
inviteDisposable.set(nil)
} }
inviteDisposable.set((inviteSignal |> deliverOnMainQueue).start(error: { error in if let groupPeer = groupPeer as? TelegramChannel {
dismissController?() let selfController = strongSelf.controller
guard let strongSelf = self else { let inviteDisposable = strongSelf.inviteDisposable
return var inviteSignal = strongSelf.context.peerChannelMemberCategoriesContextsManager.addMembers(account: strongSelf.context.account, peerId: groupPeer.id, memberIds: [peer.id])
} var cancelImpl: (() -> Void)?
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } let progressSignal = Signal<Never, NoError> { [weak selfController] subscriber in
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
let text: String cancelImpl?()
switch error { }))
case .limitExceeded: selfController?.present(controller, in: .window(.root))
text = presentationData.strings.Channel_ErrorAddTooMuch return ActionDisposable { [weak controller] in
case .tooMuchJoined: Queue.mainQueue().async() {
text = presentationData.strings.Invite_ChannelsTooMuch controller?.dismiss()
case .generic:
text = presentationData.strings.Login_UnknownError
case .restricted:
text = presentationData.strings.Channel_ErrorAddBlocked
case .notMutualContact:
if case .broadcast = groupPeer.info {
text = presentationData.strings.Channel_AddUserLeftError
} else {
text = presentationData.strings.GroupInfo_AddUserLeftError
} }
case .botDoesntSupportGroups:
text = presentationData.strings.Channel_BotDoesntSupportGroups
case .tooMuchBots:
text = presentationData.strings.Channel_TooMuchBots
case .bot:
text = presentationData.strings.Login_UnknownError
}
strongSelf.controller?.present(textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
}, completed: {
guard let strongSelf = self else {
dismissController?()
return
}
dismissController?()
if strongSelf.call.invitePeer(peer.id) {
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0), action: { _ in return false })
}
}))
} else if let groupPeer = groupPeer as? TelegramGroup {
let selfController = strongSelf.controller
let inviteDisposable = strongSelf.inviteDisposable
var inviteSignal = addGroupMember(account: strongSelf.context.account, peerId: groupPeer.id, memberId: peer.id)
var cancelImpl: (() -> Void)?
let progressSignal = Signal<Never, NoError> { [weak selfController] subscriber in
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
cancelImpl?()
}))
selfController?.present(controller, in: .window(.root))
return ActionDisposable { [weak controller] in
Queue.mainQueue().async() {
controller?.dismiss()
} }
} }
} |> runOn(Queue.mainQueue())
|> runOn(Queue.mainQueue()) |> delay(0.15, queue: Queue.mainQueue())
|> delay(0.15, queue: Queue.mainQueue()) let progressDisposable = progressSignal.start()
let progressDisposable = progressSignal.start()
inviteSignal = inviteSignal
|> afterDisposed {
Queue.mainQueue().async {
progressDisposable.dispose()
}
}
cancelImpl = {
inviteDisposable.set(nil)
}
inviteDisposable.set((inviteSignal |> deliverOnMainQueue).start(error: { error in
dismissController?()
guard let strongSelf = self else {
return
}
let context = strongSelf.context
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
switch error { inviteSignal = inviteSignal
case .privacy: |> afterDisposed {
let _ = (strongSelf.context.account.postbox.loadedPeerWithId(peer.id) Queue.mainQueue().async {
|> deliverOnMainQueue).start(next: { peer in progressDisposable.dispose()
self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(peer.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) }
})
case .notMutualContact:
strongSelf.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.GroupInfo_AddUserLeftError, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
case .tooManyChannels:
strongSelf.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.Invite_ChannelsTooMuch, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
case .groupFull, .generic:
strongSelf.controller?.present(textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
} }
}, completed: { cancelImpl = {
guard let strongSelf = self else { inviteDisposable.set(nil)
}
inviteDisposable.set((inviteSignal |> deliverOnMainQueue).start(error: { error in
dismissController?() dismissController?()
return guard let strongSelf = self else {
return
}
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let text: String
switch error {
case .limitExceeded:
text = presentationData.strings.Channel_ErrorAddTooMuch
case .tooMuchJoined:
text = presentationData.strings.Invite_ChannelsTooMuch
case .generic:
text = presentationData.strings.Login_UnknownError
case .restricted:
text = presentationData.strings.Channel_ErrorAddBlocked
case .notMutualContact:
if case .broadcast = groupPeer.info {
text = presentationData.strings.Channel_AddUserLeftError
} else {
text = presentationData.strings.GroupInfo_AddUserLeftError
}
case .botDoesntSupportGroups:
text = presentationData.strings.Channel_BotDoesntSupportGroups
case .tooMuchBots:
text = presentationData.strings.Channel_TooMuchBots
case .bot:
text = presentationData.strings.Login_UnknownError
}
strongSelf.controller?.present(textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
}, completed: {
guard let strongSelf = self else {
dismissController?()
return
}
dismissController?()
if strongSelf.call.invitePeer(peer.id) {
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0), action: { _ in return false })
}
}))
} else if let groupPeer = groupPeer as? TelegramGroup {
let selfController = strongSelf.controller
let inviteDisposable = strongSelf.inviteDisposable
var inviteSignal = addGroupMember(account: strongSelf.context.account, peerId: groupPeer.id, memberId: peer.id)
var cancelImpl: (() -> Void)?
let progressSignal = Signal<Never, NoError> { [weak selfController] subscriber in
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
cancelImpl?()
}))
selfController?.present(controller, in: .window(.root))
return ActionDisposable { [weak controller] in
Queue.mainQueue().async() {
controller?.dismiss()
}
}
} }
dismissController?() |> runOn(Queue.mainQueue())
|> delay(0.15, queue: Queue.mainQueue())
let progressDisposable = progressSignal.start()
if strongSelf.call.invitePeer(peer.id) { inviteSignal = inviteSignal
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0), action: { _ in return false }) |> afterDisposed {
Queue.mainQueue().async {
progressDisposable.dispose()
}
} }
})) cancelImpl = {
} inviteDisposable.set(nil)
})]), in: .window(.root)) }
inviteDisposable.set((inviteSignal |> deliverOnMainQueue).start(error: { error in
dismissController?()
guard let strongSelf = self else {
return
}
let context = strongSelf.context
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
switch error {
case .privacy:
let _ = (strongSelf.context.account.postbox.loadedPeerWithId(peer.id)
|> deliverOnMainQueue).start(next: { peer in
self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(peer.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
})
case .notMutualContact:
strongSelf.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.GroupInfo_AddUserLeftError, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
case .tooManyChannels:
strongSelf.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.Invite_ChannelsTooMuch, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
case .groupFull, .generic:
strongSelf.controller?.present(textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
}
}, completed: {
guard let strongSelf = self else {
dismissController?()
return
}
dismissController?()
if strongSelf.call.invitePeer(peer.id) {
strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0), action: { _ in return false })
}
}))
}
})]), in: .window(.root))
}
} }
}) })
controller.copyInviteLink = { controller.copyInviteLink = {
@ -1151,7 +1166,9 @@ public final class VoiceChatController: ViewController {
let callPeerId = strongSelf.call.peerId let callPeerId = strongSelf.call.peerId
let _ = (strongSelf.context.account.postbox.transaction { transaction -> String? in let _ = (strongSelf.context.account.postbox.transaction { transaction -> String? in
if let peer = transaction.getPeer(callPeerId), let addressName = peer.addressName, !addressName.isEmpty { if let link = inviteLinks?.listenerLink {
return link
} else if let peer = transaction.getPeer(callPeerId), let addressName = peer.addressName, !addressName.isEmpty {
return "https://t.me/\(addressName)" return "https://t.me/\(addressName)"
} else if let cachedData = transaction.getPeerCachedData(peerId: callPeerId) { } else if let cachedData = transaction.getPeerCachedData(peerId: callPeerId) {
if let cachedData = cachedData as? CachedChannelData { if let cachedData = cachedData as? CachedChannelData {