diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 3c508b2d67..211b5f8ab6 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -14182,3 +14182,8 @@ Sorry for the inconvenience."; "Call.IncomingGroupCallTitle.Multiple_any" = "{} and %d others"; "GroupCall.RevokeLinkText" = "Are you sure you want to revoke this link? Once you do, no one will be able to join the call using it."; + + +"SendInviteLink.TextCallsRestrictedOneUser" = "%@ does not accept calls."; +"SendInviteLink.TextCallsRestrictedMultipleUsers_1" = "{user_list}, and **%d** more person do not accept calls."; +"SendInviteLink.TextCallsRestrictedMultipleUsers_any" = "{user_list}, and **%d** more people do not accept calls."; diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 0a74b6e388..b542956c50 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -985,6 +985,11 @@ public enum OldChannelsControllerIntent { case upgrade } +public enum SendInviteLinkScreenSubject { + case chat(peer: EnginePeer, link: String?) + case groupCall(link: String) +} + public protocol SharedAccountContext: AnyObject { var sharedContainerPath: String { get } var basePath: String { get } @@ -1201,6 +1206,8 @@ public protocol SharedAccountContext: AnyObject { func makeAccountFreezeInfoScreen(context: AccountContext) -> ViewController + func makeSendInviteLinkScreen(context: AccountContext, subject: SendInviteLinkScreenSubject, peers: [TelegramForbiddenInvitePeer], theme: PresentationTheme?) -> ViewController + func makeDebugSettingsController(context: AccountContext?) -> ViewController? func openCreateGroupCallUI(context: AccountContext, peerIds: [EnginePeer.Id], parentController: ViewController) diff --git a/submodules/CallListUI/Sources/CallListController.swift b/submodules/CallListUI/Sources/CallListController.swift index 246fe5d891..80f86ad4a2 100644 --- a/submodules/CallListUI/Sources/CallListController.swift +++ b/submodules/CallListUI/Sources/CallListController.swift @@ -700,10 +700,6 @@ public final class CallListController: TelegramBaseController { guard case let .conferenceCall(conferenceCall) = action?.action else { return } - if conferenceCall.duration != nil { - self.context.sharedContext.openCreateGroupCallUI(context: self.context, peerIds: conferenceCall.otherParticipants, parentController: self) - return - } if let currentGroupCallController = self.context.sharedContext as? VoiceChatController, case let .group(groupCall) = currentGroupCallController.call, let currentCallId = groupCall.callId, currentCallId == conferenceCall.callId { self.context.sharedContext.navigateToCurrentCall() diff --git a/submodules/CallListUI/Sources/CallListControllerNode.swift b/submodules/CallListUI/Sources/CallListControllerNode.swift index cd9c6c87be..9ea4fff4be 100644 --- a/submodules/CallListUI/Sources/CallListControllerNode.swift +++ b/submodules/CallListUI/Sources/CallListControllerNode.swift @@ -126,7 +126,7 @@ private func mappedInsertEntries(context: AccountContext, presentationData: Item case let .displayTabInfo(_, text): return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: 0), directionHint: entry.directionHint) case .openNewCall: - let item = ItemListPeerActionItem(presentationData: presentationData, style: showSettings ? .blocks : .plain, icon: PresentationResourcesRootController.callListCallIcon(presentationData.theme), title: presentationData.strings.CallList_NewCall, hasSeparator: false, sectionId: 1, height: .generic, noInsets: true, editing: false, action: { + let item = ItemListPeerActionItem(presentationData: presentationData, style: showSettings ? .blocks : .plain, icon: PresentationResourcesRootController.callListCallIcon(presentationData.theme), title: presentationData.strings.CallList_NewCall, hasSeparator: false, sectionId: 1, height: .generic, noInsets: !showSettings, editing: false, action: { nodeInteraction.openNewCall() }) return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint) @@ -150,7 +150,7 @@ private func mappedUpdateEntries(context: AccountContext, presentationData: Item case let .displayTabInfo(_, text): return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: 0), directionHint: entry.directionHint) case .openNewCall: - let item = ItemListPeerActionItem(presentationData: presentationData, style: showSettings ? .blocks : .plain, icon: PresentationResourcesRootController.callListCallIcon(presentationData.theme), title: presentationData.strings.CallList_NewCall, hasSeparator: false, sectionId: 1, height: .generic, noInsets: true, editing: false, action: { + let item = ItemListPeerActionItem(presentationData: presentationData, style: showSettings ? .blocks : .plain, icon: PresentationResourcesRootController.callListCallIcon(presentationData.theme), title: presentationData.strings.CallList_NewCall, hasSeparator: false, sectionId: 1, height: .generic, noInsets: !showSettings, editing: false, action: { nodeInteraction.openNewCall() }) return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint) @@ -525,7 +525,7 @@ final class CallListControllerNode: ASDisplayNode { |> mapToQueue { (updateAndType, state, groupCalls, showCallsTab, currentGroupCallPeerId) -> Signal in let (update, type) = updateAndType - let processedView = CallListNodeView(originalView: update.view, filteredEntries: callListNodeEntriesForView(view: update.view, displayOpenNewCall: mode == .tab && type == .all, groupCalls: groupCalls, state: state, showSettings: showSettings, showCallsTab: showCallsTab, isRecentCalls: type == .all, currentGroupCallPeerId: currentGroupCallPeerId), presentationData: state.presentationData) + let processedView = CallListNodeView(originalView: update.view, filteredEntries: callListNodeEntriesForView(view: update.view, displayOpenNewCall: type == .all, groupCalls: groupCalls, state: state, showSettings: showSettings, showCallsTab: showCallsTab, isRecentCalls: type == .all, currentGroupCallPeerId: currentGroupCallPeerId), presentationData: state.presentationData) let previous = previousView.swap(processedView) let previousType = previousType.swap(type) diff --git a/submodules/CallListUI/Sources/CallListNodeEntries.swift b/submodules/CallListUI/Sources/CallListNodeEntries.swift index 37d7733834..144573f0ba 100644 --- a/submodules/CallListUI/Sources/CallListNodeEntries.swift +++ b/submodules/CallListUI/Sources/CallListNodeEntries.swift @@ -44,14 +44,14 @@ enum CallListNodeEntry: Comparable, Identifiable { case .openNewCall: switch rhs { case .displayTab, .displayTabInfo: - return false - default: return true + default: + return false } case let .groupCall(lhsPeerId, lhsTitle): switch rhs { case .displayTab, .displayTabInfo, .openNewCall: - return false + return true case let .groupCall(rhsPeerId, rhsTitle): if lhsTitle == rhsTitle { return lhsPeerId < rhsPeerId @@ -64,7 +64,7 @@ enum CallListNodeEntry: Comparable, Identifiable { case let .hole(lhsIndex): switch rhs { case .displayTab, .displayTabInfo, .groupCall, .openNewCall: - return false + return true case let .hole(rhsIndex): return lhsIndex < rhsIndex case let .message(rhsIndex): @@ -73,7 +73,7 @@ enum CallListNodeEntry: Comparable, Identifiable { case let .message(lhsIndex): switch rhs { case .displayTab, .displayTabInfo, .groupCall, .openNewCall: - return false + return true case let .hole(rhsIndex): return lhsIndex < rhsIndex case let .message(rhsIndex): diff --git a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift index 1e7012154e..1baf8ed6a5 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift @@ -306,10 +306,8 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: if conferenceCall.flags.contains(.isMissed) { messageText = strings.Chat_CallMessage_DeclinedGroupCall - } else if message.timestamp < currentTime - missedTimeout { + } else if conferenceCall.duration == nil && message.timestamp < currentTime - missedTimeout { messageText = strings.Chat_CallMessage_MissedGroupCall - } else if conferenceCall.duration != nil { - messageText = strings.Chat_CallMessage_CancelledGroupCall } else { if incoming { messageText = strings.Chat_CallMessage_IncomingGroupCall diff --git a/submodules/PeerInfoUI/Sources/ChannelAdminController.swift b/submodules/PeerInfoUI/Sources/ChannelAdminController.swift index f2ed2a2316..2bf3f99d49 100644 --- a/submodules/PeerInfoUI/Sources/ChannelAdminController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelAdminController.swift @@ -1247,7 +1247,7 @@ public func channelAdminController(context: AccountContext, updatedPresentationD } if let adminPeer, case let .restricted(forbiddenPeer) = error { - let inviteScreen = SendInviteLinkScreen(context: context, peer: channelPeer, link: exportedInvitation?.link, peers: [forbiddenPeer ?? TelegramForbiddenInvitePeer(peer: adminPeer, canInviteWithPremium: false, premiumRequiredToContact: false)]) + let inviteScreen = SendInviteLinkScreen(context: context, subject: .chat(peer: channelPeer, link: exportedInvitation?.link), peers: [forbiddenPeer ?? TelegramForbiddenInvitePeer(peer: adminPeer, canInviteWithPremium: false, premiumRequiredToContact: false)]) pushControllerImpl?(inviteScreen) dismissImpl?() @@ -1437,7 +1437,7 @@ public func channelAdminController(context: AccountContext, updatedPresentationD updateRightsDisposable.set((context.peerChannelMemberCategoriesContextsManager.updateMemberAdminRights(engine: context.engine, peerId: peerId, memberId: adminId, adminRights: TelegramChatAdminRights(rights: updateFlags), rank: updateRank) |> deliverOnMainQueue).start(error: { error in if case let .addMemberError(addMemberError) = error, case let .restricted(forbiddenPeer) = addMemberError, let admin = adminPeer { if let channelPeer { - let inviteScreen = SendInviteLinkScreen(context: context, peer: channelPeer, link: exportedInvitation?.link, peers: [forbiddenPeer ?? TelegramForbiddenInvitePeer(peer: admin, canInviteWithPremium: false, premiumRequiredToContact: false)]) + let inviteScreen = SendInviteLinkScreen(context: context, subject: .chat(peer: channelPeer, link: exportedInvitation?.link), peers: [forbiddenPeer ?? TelegramForbiddenInvitePeer(peer: admin, canInviteWithPremium: false, premiumRequiredToContact: false)]) pushControllerImpl?(inviteScreen) dismissImpl?() @@ -1519,7 +1519,7 @@ public func channelAdminController(context: AccountContext, updatedPresentationD ) |> deliverOnMainQueue).startStandalone(next: { exportedInvitation in let _ = exportedInvitation - let inviteScreen = SendInviteLinkScreen(context: context, peer: .legacyGroup(group), link: exportedInvitation?.link, peers: [failedPeer]) + let inviteScreen = SendInviteLinkScreen(context: context, subject: .chat(peer: .legacyGroup(group), link: exportedInvitation?.link), peers: [failedPeer]) pushControllerImpl?(inviteScreen) }) } else { diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersController.swift b/submodules/PeerInfoUI/Sources/ChannelMembersController.swift index 783f04db24..bd55fc4126 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersController.swift @@ -560,7 +560,7 @@ public func channelMembersController(context: AccountContext, updatedPresentatio if !failedPeers.isEmpty, let contactsController, let navigationController = contactsController.navigationController as? NavigationController { var viewControllers = navigationController.viewControllers if let index = viewControllers.firstIndex(where: { $0 === contactsController }) { - let inviteScreen = SendInviteLinkScreen(context: context, peer: chatPeer, link: exportedInvitation?.link, peers: failedPeers) + let inviteScreen = SendInviteLinkScreen(context: context, subject: .chat(peer: chatPeer, link: exportedInvitation?.link), peers: failedPeers) viewControllers.remove(at: index) viewControllers.append(inviteScreen) navigationController.setViewControllers(viewControllers, animated: true) diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index 561a94c07f..d842760168 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -3620,14 +3620,24 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { let presentationData = self.accountContext.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: defaultDarkColorPresentationTheme) var errorText = presentationData.strings.Login_UnknownError + switch error { case let .privacy(peer): if let peer { - errorText = presentationData.strings.Call_PrivacyErrorMessage(peer.compactDisplayTitle).string + if let currentInviteLinks = self.currentInviteLinks { + let inviteLinkScreen = self.accountContext.sharedContext.makeSendInviteLinkScreen(context: self.accountContext, subject: .groupCall(link: currentInviteLinks.listenerLink), peers: [TelegramForbiddenInvitePeer(peer: peer, canInviteWithPremium: false, premiumRequiredToContact: false)], theme: defaultDarkColorPresentationTheme) + if let navigationController = self.accountContext.sharedContext.mainWindow?.viewController as? NavigationController { + navigationController.pushViewController(inviteLinkScreen) + } + return + } else { + errorText = presentationData.strings.Call_PrivacyErrorMessage(peer.compactDisplayTitle).string + } } default: break } + self.accountContext.sharedContext.mainWindow?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: errorText, actions: [ TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {}) ]), on: .root, blockInteraction: false, completion: {}) @@ -3752,6 +3762,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { } } + public var currentInviteLinks: GroupCallInviteLinks? + private var currentMyAudioLevel: Float = 0.0 private var currentMyAudioLevelTimestamp: Double = 0.0 private var isSendingTyping: Bool = false diff --git a/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift b/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift index f15d3cc12f..533e13905d 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift @@ -1530,6 +1530,9 @@ final class VideoChatScreenComponent: Component { return } self.inviteLinks = value + if case let .group(groupCall) = self.currentCall, let groupCall = groupCall as? PresentationGroupCallImpl { + groupCall.currentInviteLinks = value + } }) self.reconnectedAsEventsDisposable?.dispose() diff --git a/submodules/TelegramCore/Sources/State/ConferenceCallE2EContext.swift b/submodules/TelegramCore/Sources/State/ConferenceCallE2EContext.swift index acb8efc5be..f14d7ba965 100644 --- a/submodules/TelegramCore/Sources/State/ConferenceCallE2EContext.swift +++ b/submodules/TelegramCore/Sources/State/ConferenceCallE2EContext.swift @@ -379,7 +379,7 @@ public final class ConferenceCallE2EContext { // Peer ids that are in the blockchain but not in the server list var removedPeerIds = blockchainPeerIds.filter { blockchainPeerId in return !result.participants.contains(where: { participant in - if case let .peer(id) = participant.id, id.namespace == Namespaces.Peer.CloudChannel, id.id._internalGetInt64Value() == blockchainPeerId { + if case let .peer(id) = participant.id, id.namespace == Namespaces.Peer.CloudUser, id.id._internalGetInt64Value() == blockchainPeerId { return true } else { return false diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/JoinLink.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/JoinLink.swift index e32f60f2cc..218cf05c84 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/JoinLink.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/JoinLink.swift @@ -200,7 +200,7 @@ func _internal_joinCallInvitationInformation(account: Account, messageId: Messag } var members: [EnginePeer] = [] for participant in call.topParticipants { - if let peer = participant.peer { + if let peer = participant.peer, peer.id != account.peerId { members.append(peer) } } diff --git a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift index 328d44f08a..e38a8d1eb0 100644 --- a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift @@ -625,10 +625,8 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, if conferenceCall.flags.contains(.isMissed) { titleString = strings.Chat_CallMessage_DeclinedGroupCall - } else if message.timestamp < currentTime - missedTimeout { + } else if conferenceCall.duration == nil && message.timestamp < currentTime - missedTimeout { titleString = strings.Chat_CallMessage_MissedGroupCall - } else if conferenceCall.duration != nil { - titleString = strings.Chat_CallMessage_CancelledGroupCall } else { if incoming { titleString = strings.Chat_CallMessage_IncomingGroupCall diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageCallBubbleContentNode/Sources/ChatMessageCallBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageCallBubbleContentNode/Sources/ChatMessageCallBubbleContentNode.swift index 29f242f634..60cca730c9 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageCallBubbleContentNode/Sources/ChatMessageCallBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageCallBubbleContentNode/Sources/ChatMessageCallBubbleContentNode.swift @@ -174,10 +174,8 @@ public class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode { let currentTime = Int32(Date().timeIntervalSince1970) if conferenceCall.flags.contains(.isMissed) { titleString = item.presentationData.strings.Chat_CallMessage_DeclinedGroupCall - } else if item.message.timestamp < currentTime - missedTimeout { + } else if conferenceCall.duration == nil && item.message.timestamp < currentTime - missedTimeout { titleString = item.presentationData.strings.Chat_CallMessage_MissedGroupCall - } else if conferenceCall.duration != nil { - titleString = item.presentationData.strings.Chat_CallMessage_CancelledGroupCall } else { if incoming { titleString = item.presentationData.strings.Chat_CallMessage_IncomingGroupCall diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index ebd3998789..fbb591752d 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -14182,7 +14182,7 @@ public func presentAddMembersImpl(context: AccountContext, updatedPresentationDa if !failedPeers.isEmpty, let contactsController, let navigationController = contactsController.navigationController as? NavigationController { var viewControllers = navigationController.viewControllers if let index = viewControllers.firstIndex(where: { $0 === contactsController }) { - let inviteScreen = SendInviteLinkScreen(context: context, peer: EnginePeer(groupPeer), link: exportedInvitation?.link, peers: failedPeers) + let inviteScreen = SendInviteLinkScreen(context: context, subject: .chat(peer: EnginePeer(groupPeer), link: exportedInvitation?.link), peers: failedPeers) viewControllers.remove(at: index) viewControllers.append(inviteScreen) navigationController.setViewControllers(viewControllers, animated: true) diff --git a/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift b/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift index 3dfb23c301..7190f13e27 100644 --- a/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift +++ b/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift @@ -23,23 +23,20 @@ private final class SendInviteLinkScreenComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment let context: AccountContext - let peer: EnginePeer - let link: String? + let subject: SendInviteLinkScreenSubject let peers: [TelegramForbiddenInvitePeer] let peerPresences: [EnginePeer.Id: EnginePeer.Presence] let sendPaidMessageStars: [EnginePeer.Id: StarsAmount] init( context: AccountContext, - peer: EnginePeer, - link: String?, + subject: SendInviteLinkScreenSubject, peers: [TelegramForbiddenInvitePeer], peerPresences: [EnginePeer.Id: EnginePeer.Presence], sendPaidMessageStars: [EnginePeer.Id: StarsAmount] ) { self.context = context - self.peer = peer - self.link = link + self.subject = subject self.peers = peers self.peerPresences = peerPresences self.sendPaidMessageStars = sendPaidMessageStars @@ -49,9 +46,6 @@ private final class SendInviteLinkScreenComponent: Component { if lhs.context !== rhs.context { return false } - if lhs.link != rhs.link { - return false - } if lhs.peers != rhs.peers { return false } @@ -315,7 +309,12 @@ private final class SendInviteLinkScreenComponent: Component { if self.component == nil { for peer in component.peers { - if component.link != nil && !peer.premiumRequiredToContact { + switch component.subject { + case let .chat(_, link): + if link != nil && !peer.premiumRequiredToContact { + self.selectedItems.insert(peer.peer.id) + } + case .groupCall: self.selectedItems.insert(peer.peer.id) } } @@ -329,10 +328,15 @@ private final class SendInviteLinkScreenComponent: Component { return peer.canInviteWithPremium } var hasInviteLink = true - if premiumRestrictedUsers.count == component.peers.count && component.link == nil { - hasInviteLink = false - } else if component.link != nil && !premiumRestrictedUsers.isEmpty && component.peers.allSatisfy({ $0.premiumRequiredToContact }) { - hasInviteLink = false + switch component.subject { + case let .chat(_, link): + if premiumRestrictedUsers.count == component.peers.count && link == nil { + hasInviteLink = false + } else if link != nil && !premiumRestrictedUsers.isEmpty && component.peers.allSatisfy({ $0.premiumRequiredToContact }) { + hasInviteLink = false + } + case .groupCall: + hasInviteLink = true } if themeUpdated { @@ -453,48 +457,85 @@ private final class SendInviteLinkScreenComponent: Component { contentHeight += 8.0 let text: String - if premiumRestrictedUsers.count == 1 { - if case let .channel(channel) = component.peer, case .broadcast = channel.info { - text = environment.strings.SendInviteLink_ChannelTextContactsAndPremiumOneUser(premiumRestrictedUsers[0].peer.compactDisplayTitle).string - } else { - text = environment.strings.SendInviteLink_TextContactsAndPremiumOneUser(premiumRestrictedUsers[0].peer.compactDisplayTitle).string - } - } else { - let extraCount = premiumRestrictedUsers.count - 3 - - var peersTextArray: [String] = [] - for i in 0 ..< min(3, premiumRestrictedUsers.count) { - peersTextArray.append("**\(premiumRestrictedUsers[i].peer.compactDisplayTitle)**") - } - - var peersText = "" - if #available(iOS 13.0, *) { - let listFormatter = ListFormatter() - listFormatter.locale = localeWithStrings(environment.strings) - if let value = listFormatter.string(from: peersTextArray) { - peersText = value + switch component.subject { + case let .chat(peer, _): + if premiumRestrictedUsers.count == 1 { + if case let .channel(channel) = peer, case .broadcast = channel.info { + text = environment.strings.SendInviteLink_ChannelTextContactsAndPremiumOneUser(premiumRestrictedUsers[0].peer.compactDisplayTitle).string + } else { + text = environment.strings.SendInviteLink_TextContactsAndPremiumOneUser(premiumRestrictedUsers[0].peer.compactDisplayTitle).string } - } - if peersText.isEmpty { - for i in 0 ..< peersTextArray.count { - if i != 0 { - peersText.append(", ") + } else { + let extraCount = premiumRestrictedUsers.count - 3 + + var peersTextArray: [String] = [] + for i in 0 ..< min(3, premiumRestrictedUsers.count) { + peersTextArray.append("**\(premiumRestrictedUsers[i].peer.compactDisplayTitle)**") + } + + var peersText = "" + if #available(iOS 13.0, *) { + let listFormatter = ListFormatter() + listFormatter.locale = localeWithStrings(environment.strings) + if let value = listFormatter.string(from: peersTextArray) { + peersText = value + } + } + if peersText.isEmpty { + for i in 0 ..< peersTextArray.count { + if i != 0 { + peersText.append(", ") + } + peersText.append(peersTextArray[i]) + } + } + + if extraCount >= 1 { + if case let .channel(channel) = peer, case .broadcast = channel.info { + text = environment.strings.SendInviteLink_ChannelTextContactsAndPremiumMultipleUsers(Int32(extraCount)).replacingOccurrences(of: "{user_list}", with: peersText) + } else { + text = environment.strings.SendInviteLink_TextContactsAndPremiumMultipleUsers(Int32(extraCount)).replacingOccurrences(of: "{user_list}", with: peersText) + } + } else { + if case let .channel(channel) = peer, case .broadcast = channel.info { + text = environment.strings.SendInviteLink_ChannelTextContactsAndPremiumOneUser(peersText).string + } else { + text = environment.strings.SendInviteLink_TextContactsAndPremiumOneUser(peersText).string } - peersText.append(peersTextArray[i]) } } - - if extraCount >= 1 { - if case let .channel(channel) = component.peer, case .broadcast = channel.info { - text = environment.strings.SendInviteLink_ChannelTextContactsAndPremiumMultipleUsers(Int32(extraCount)).replacingOccurrences(of: "{user_list}", with: peersText) - } else { - text = environment.strings.SendInviteLink_TextContactsAndPremiumMultipleUsers(Int32(extraCount)).replacingOccurrences(of: "{user_list}", with: peersText) - } + case .groupCall: + if premiumRestrictedUsers.count == 1 { + text = environment.strings.SendInviteLink_TextCallsRestrictedOneUser(premiumRestrictedUsers[0].peer.compactDisplayTitle).string } else { - if case let .channel(channel) = component.peer, case .broadcast = channel.info { - text = environment.strings.SendInviteLink_ChannelTextContactsAndPremiumOneUser(peersText).string + let extraCount = premiumRestrictedUsers.count - 3 + + var peersTextArray: [String] = [] + for i in 0 ..< min(3, premiumRestrictedUsers.count) { + peersTextArray.append("**\(premiumRestrictedUsers[i].peer.compactDisplayTitle)**") + } + + var peersText = "" + if #available(iOS 13.0, *) { + let listFormatter = ListFormatter() + listFormatter.locale = localeWithStrings(environment.strings) + if let value = listFormatter.string(from: peersTextArray) { + peersText = value + } + } + if peersText.isEmpty { + for i in 0 ..< peersTextArray.count { + if i != 0 { + peersText.append(", ") + } + peersText.append(peersTextArray[i]) + } + } + + if extraCount >= 1 { + text = environment.strings.SendInviteLink_TextCallsRestrictedMultipleUsers(Int32(extraCount)).replacingOccurrences(of: "{user_list}", with: peersText) } else { - text = environment.strings.SendInviteLink_TextContactsAndPremiumOneUser(peersText).string + text = environment.strings.SendInviteLink_TextCallsRestrictedOneUser(peersText).string } } } @@ -693,11 +734,19 @@ private final class SendInviteLinkScreenComponent: Component { actionButton = ComponentView() self.actionButton = actionButton } + + let titleText: String + switch component.subject { + case let .chat(_, link): + titleText = link != nil ? environment.strings.SendInviteLink_InviteTitle : environment.strings.SendInviteLink_LinkUnavailableTitle + case .groupCall: + titleText = environment.strings.SendInviteLink_InviteTitle + } let titleSize = title.update( transition: .immediate, component: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString(string: component.link != nil ? environment.strings.SendInviteLink_InviteTitle : environment.strings.SendInviteLink_LinkUnavailableTitle, font: Font.semibold(24.0), textColor: environment.theme.list.itemPrimaryTextColor)) + text: .plain(NSAttributedString(string: titleText, font: Font.semibold(24.0), textColor: environment.theme.list.itemPrimaryTextColor)) )), environment: {}, containerSize: CGSize(width: availableSize.width - leftButtonFrame.maxX * 2.0, height: 100.0) @@ -714,30 +763,35 @@ private final class SendInviteLinkScreenComponent: Component { contentHeight += 8.0 let text: String - if !premiumRestrictedUsers.isEmpty { - if component.link != nil { - text = environment.strings.SendInviteLink_TextSendInviteLink - } else { - if component.peers.count == 1 { - text = environment.strings.SendInviteLink_TextUnavailableSingleUser(component.peers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast)).string + switch component.subject { + case let .chat(_, link): + if !premiumRestrictedUsers.isEmpty { + if link != nil { + text = environment.strings.SendInviteLink_TextSendInviteLink } else { - text = environment.strings.SendInviteLink_TextUnavailableMultipleUsers(Int32(component.peers.count)) - } - } - } else { - if component.link != nil { - if component.peers.count == 1 { - text = environment.strings.SendInviteLink_TextAvailableSingleUser(component.peers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast)).string - } else { - text = environment.strings.SendInviteLink_TextAvailableMultipleUsers(Int32(component.peers.count)) + if component.peers.count == 1 { + text = environment.strings.SendInviteLink_TextUnavailableSingleUser(component.peers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast)).string + } else { + text = environment.strings.SendInviteLink_TextUnavailableMultipleUsers(Int32(component.peers.count)) + } } } else { - if component.peers.count == 1 { - text = environment.strings.SendInviteLink_TextUnavailableSingleUser(component.peers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast)).string + if link != nil { + if component.peers.count == 1 { + text = environment.strings.SendInviteLink_TextAvailableSingleUser(component.peers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast)).string + } else { + text = environment.strings.SendInviteLink_TextAvailableMultipleUsers(Int32(component.peers.count)) + } } else { - text = environment.strings.SendInviteLink_TextUnavailableMultipleUsers(Int32(component.peers.count)) + if component.peers.count == 1 { + text = environment.strings.SendInviteLink_TextUnavailableSingleUser(component.peers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast)).string + } else { + text = environment.strings.SendInviteLink_TextUnavailableMultipleUsers(Int32(component.peers.count)) + } } } + case .groupCall: + text = " " } let body = MarkdownAttributeSet(font: Font.regular(15.0), textColor: environment.theme.list.itemPrimaryTextColor) @@ -793,7 +847,13 @@ private final class SendInviteLinkScreenComponent: Component { } let itemSubtitle: PeerListItemComponent.Subtitle - let canBeSelected = component.link != nil && !peer.premiumRequiredToContact + let canBeSelected : Bool + switch component.subject { + case let .chat(_, link): + canBeSelected = link != nil && !peer.premiumRequiredToContact + case .groupCall: + canBeSelected = true + } if peer.premiumRequiredToContact { itemSubtitle = .text(text: environment.strings.SendInviteLink_StatusAvailableToPremiumOnly, icon: .lock) } else { @@ -862,16 +922,24 @@ private final class SendInviteLinkScreenComponent: Component { initialContentHeight += 24.0 let actionButtonTitle: String - if component.link != nil { - actionButtonTitle = self.selectedItems.isEmpty ? environment.strings.SendInviteLink_ActionSkip : environment.strings.SendInviteLink_ActionInvite - } else { - actionButtonTitle = environment.strings.SendInviteLink_ActionClose + let actionButtonBadge: String? + switch component.subject { + case let.chat(_, link): + if link != nil { + actionButtonTitle = self.selectedItems.isEmpty ? environment.strings.SendInviteLink_ActionSkip : environment.strings.SendInviteLink_ActionInvite + } else { + actionButtonTitle = environment.strings.SendInviteLink_ActionClose + } + actionButtonBadge = (self.selectedItems.isEmpty || link == nil) ? nil : "\(self.selectedItems.count)" + case .groupCall: + actionButtonTitle = environment.strings.SendInviteLink_ActionInvite + actionButtonBadge = self.selectedItems.isEmpty ? nil : "\(self.selectedItems.count)" } let actionButtonSize = actionButton.update( transition: transition, component: AnyComponent(SolidRoundedButtonComponent( title: actionButtonTitle, - badge: (self.selectedItems.isEmpty || component.link == nil) ? nil : "\(self.selectedItems.count)", + badge: actionButtonBadge, theme: SolidRoundedButtonComponent.Theme(theme: environment.theme), font: .bold, fontSize: 17.0, @@ -885,9 +953,18 @@ private final class SendInviteLinkScreenComponent: Component { guard let self, let component = self.component, let controller = self.environment?.controller() else { return } + + let link: String? + switch component.subject { + case let .chat(_, linkValue): + link = linkValue + case let .groupCall(linkValue): + link = linkValue + } + if self.selectedItems.isEmpty { controller.dismiss() - } else if let link = component.link { + } else if let link { let selectedPeers = component.peers.filter { self.selectedItems.contains($0.peer.id) } self.presentPaidMessageAlertIfNeeded( @@ -1012,15 +1089,21 @@ public class SendInviteLinkScreen: ViewControllerComponentContainer { private var presenceDisposable: Disposable? - public init(context: AccountContext, peer: EnginePeer, link: String?, peers: [TelegramForbiddenInvitePeer]) { + public init(context: AccountContext, subject: SendInviteLinkScreenSubject, peers: [TelegramForbiddenInvitePeer], theme: PresentationTheme? = nil) { self.context = context - var link = link - if link == nil, let addressName = peer.addressName { - link = "https://t.me/\(addressName)" + switch subject { + case let .chat(peer, link): + var link = link + if link == nil, let addressName = peer.addressName { + link = "https://t.me/\(addressName)" + } + self.link = link + case let .groupCall(link): + self.link = link } - #if DEBUG + #if DEBUG && false var peers = peers if !"".isEmpty { @@ -1136,10 +1219,9 @@ public class SendInviteLinkScreen: ViewControllerComponentContainer { } #endif - self.link = link self.peers = peers - super.init(context: context, component: SendInviteLinkScreenComponent(context: context, peer: peer, link: link, peers: peers, peerPresences: [:], sendPaidMessageStars: [:]), navigationBarAppearance: .none) + super.init(context: context, component: SendInviteLinkScreenComponent(context: context, subject: subject, peers: peers, peerPresences: [:], sendPaidMessageStars: [:]), navigationBarAppearance: .none, theme: theme.flatMap { .custom($0) } ?? .default) self.statusBar.statusBarStyle = .Ignore self.navigationPresentation = .flatModal @@ -1169,7 +1251,7 @@ public class SendInviteLinkScreen: ViewControllerComponentContainer { parsedSendPaidMessageStars[id] = sendPaidMessageStars } } - self.updateComponent(component: AnyComponent(SendInviteLinkScreenComponent(context: context, peer: peer, link: link, peers: peers, peerPresences: parsedPresences, sendPaidMessageStars: parsedSendPaidMessageStars)), transition: .immediate) + self.updateComponent(component: AnyComponent(SendInviteLinkScreenComponent(context: context, subject: subject, peers: peers, peerPresences: parsedPresences, sendPaidMessageStars: parsedSendPaidMessageStars)), transition: .immediate) }) } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index a2b9c83eb9..068d189a8a 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -2893,10 +2893,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard case let .conferenceCall(conferenceCall) = action?.action else { return } - if conferenceCall.duration != nil { - self.context.sharedContext.openCreateGroupCallUI(context: self.context, peerIds: conferenceCall.otherParticipants, parentController: self) - return - } if let currentGroupCallController = self.context.sharedContext.currentGroupCallController as? VoiceChatController, case let .group(groupCall) = currentGroupCallController.call, let currentCallId = groupCall.callId, currentCallId == conferenceCall.callId { self.context.sharedContext.navigateToCurrentCall() diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 1a45674174..89a9ef7aed 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -2733,7 +2733,6 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto var messageIdsWithUnseenPersonalMention: [MessageId] = [] var messageIdsWithUnseenReactions: [MessageId] = [] var messageIdsWithInactiveExtendedMedia = Set() - var messageIdsWithGroupCalls: [MessageId] = [] var downloadableResourceIds: [(messageId: MessageId, resourceId: String)] = [] var allVisibleAnchorMessageIds: [(MessageId, Int)] = [] var visibleAdOpaqueIds: [Data] = [] @@ -2832,13 +2831,6 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto storiesRequiredValidation = true } else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content, let _ = content.story { storiesRequiredValidation = true - } else if let media = media as? TelegramMediaAction { - if case let .conferenceCall(conferenceCall) = media.action { - if conferenceCall.duration != nil { - } else { - messageIdsWithGroupCalls.append(message.id) - } - } } } if contentRequiredValidation { @@ -3096,9 +3088,6 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto if !peerIdsWithRefreshStories.isEmpty { self.context.account.viewTracker.refreshStoryStatsForPeerIds(peerIds: peerIdsWithRefreshStories) } - if !messageIdsWithGroupCalls.isEmpty { - self.inlineGroupCallsProcessingManager.add(messageIdsWithGroupCalls.map { MessageAndThreadId(messageId: $0, threadId: nil) }) - } self.currentEarlierPrefetchMessages = toEarlierMediaMessages self.currentLaterPrefetchMessages = toLaterMediaMessages diff --git a/submodules/TelegramUI/Sources/CreateGroupController.swift b/submodules/TelegramUI/Sources/CreateGroupController.swift index 7258a66e95..80c275fda4 100644 --- a/submodules/TelegramUI/Sources/CreateGroupController.swift +++ b/submodules/TelegramUI/Sources/CreateGroupController.swift @@ -850,7 +850,7 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId] |> deliverOnMainQueue).start(next: { peer in if let peer, let exportedInvitation, let link = exportedInvitation.link { - let inviteScreen = SendInviteLinkScreen(context: context, peer: peer, link: link, peers: result.result.forbiddenPeers) + let inviteScreen = SendInviteLinkScreen(context: context, subject: .chat(peer: peer, link: link), peers: result.result.forbiddenPeers) controller?.push(inviteScreen) } }) diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 6103230f8d..97d9a3c054 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -81,6 +81,7 @@ import AccountFreezeInfoScreen import JoinSubjectScreen import OldChannelsController import InviteLinksUI +import SendInviteLinkScreen private final class AccountUserInterfaceInUseContext { let subscribers = Bag<(Bool) -> Void>() @@ -3819,6 +3820,10 @@ public final class SharedAccountContextImpl: SharedAccountContext { public func makeAccountFreezeInfoScreen(context: AccountContext) -> ViewController { return AccountFreezeInfoScreen(context: context) } + + public func makeSendInviteLinkScreen(context: AccountContext, subject: SendInviteLinkScreenSubject, peers: [TelegramForbiddenInvitePeer], theme: PresentationTheme?) -> ViewController { + return SendInviteLinkScreen(context: context, subject: subject, peers: peers, theme: theme) + } } private func peerInfoControllerImpl(context: AccountContext, updatedPresentationData: (PresentationData, Signal)?, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, requestsContext: PeerInvitationImportersContext? = nil) -> ViewController? {