mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Group invitation sheet
This commit is contained in:
parent
4a8a14cb9f
commit
38bc517122
@ -96,19 +96,21 @@ public final class ContactMultiselectionControllerParams {
|
||||
public let options: [ContactListAdditionalOption]
|
||||
public let filters: [ContactListFilter]
|
||||
public let onlyWriteable: Bool
|
||||
public let isGroupInvitation: Bool
|
||||
public let isPeerEnabled: ((EnginePeer) -> Bool)?
|
||||
public let attemptDisabledItemSelection: ((EnginePeer, ChatListDisabledPeerReason) -> Void)?
|
||||
public let alwaysEnabled: Bool
|
||||
public let limit: Int32?
|
||||
public let reachedLimit: ((Int32) -> Void)?
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, mode: ContactMultiselectionControllerMode, options: [ContactListAdditionalOption], filters: [ContactListFilter] = [.excludeSelf], onlyWriteable: Bool = false, isPeerEnabled: ((EnginePeer) -> Bool)? = nil, attemptDisabledItemSelection: ((EnginePeer, ChatListDisabledPeerReason) -> Void)? = nil, alwaysEnabled: Bool = false, limit: Int32? = nil, reachedLimit: ((Int32) -> Void)? = nil) {
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, mode: ContactMultiselectionControllerMode, options: [ContactListAdditionalOption], filters: [ContactListFilter] = [.excludeSelf], onlyWriteable: Bool = false, isGroupInvitation: Bool = false, isPeerEnabled: ((EnginePeer) -> Bool)? = nil, attemptDisabledItemSelection: ((EnginePeer, ChatListDisabledPeerReason) -> Void)? = nil, alwaysEnabled: Bool = false, limit: Int32? = nil, reachedLimit: ((Int32) -> Void)? = nil) {
|
||||
self.context = context
|
||||
self.updatedPresentationData = updatedPresentationData
|
||||
self.mode = mode
|
||||
self.options = options
|
||||
self.filters = filters
|
||||
self.onlyWriteable = onlyWriteable
|
||||
self.isGroupInvitation = isGroupInvitation
|
||||
self.isPeerEnabled = isPeerEnabled
|
||||
self.attemptDisabledItemSelection = attemptDisabledItemSelection
|
||||
self.alwaysEnabled = alwaysEnabled
|
||||
|
@ -1059,7 +1059,7 @@ public final class ContactListNode: ASDisplayNode {
|
||||
|
||||
private let isPeerEnabled: ((EnginePeer) -> Bool)?
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, presentation: Signal<ContactListPresentation, NoError>, filters: [ContactListFilter] = [.excludeSelf], onlyWriteable: Bool, isPeerEnabled: ((EnginePeer) -> Bool)? = nil, selectionState: ContactListNodeGroupSelectionState? = nil, displayPermissionPlaceholder: Bool = true, displaySortOptions: Bool = false, displayCallIcons: Bool = false, contextAction: ((EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?, Bool) -> Void)? = nil, isSearch: Bool = false, multipleSelection: Bool = false) {
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, presentation: Signal<ContactListPresentation, NoError>, filters: [ContactListFilter] = [.excludeSelf], onlyWriteable: Bool, isGroupInvitation: Bool, isPeerEnabled: ((EnginePeer) -> Bool)? = nil, selectionState: ContactListNodeGroupSelectionState? = nil, displayPermissionPlaceholder: Bool = true, displaySortOptions: Bool = false, displayCallIcons: Bool = false, contextAction: ((EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?, Bool) -> Void)? = nil, isSearch: Bool = false, multipleSelection: Bool = false) {
|
||||
self.context = context
|
||||
self.filters = filters
|
||||
self.displayPermissionPlaceholder = displayPermissionPlaceholder
|
||||
@ -1383,7 +1383,7 @@ public final class ContactListNode: ASDisplayNode {
|
||||
})
|
||||
|
||||
let peerRequiresPremiumForMessaging: Signal<[EnginePeer.Id: Bool], NoError>
|
||||
if onlyWriteable {
|
||||
if onlyWriteable && !isGroupInvitation {
|
||||
peerRequiresPremiumForMessaging = foundPeers.get()
|
||||
|> map { foundPeers -> Set<EnginePeer.Id> in
|
||||
var result = Set<EnginePeer.Id>()
|
||||
|
@ -114,7 +114,7 @@ final class ContactsControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
|
||||
var contextAction: ((EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?, Bool) -> Void)?
|
||||
|
||||
self.contactListNode = ContactListNode(context: context, presentation: presentation, onlyWriteable: false, displaySortOptions: true, contextAction: { peer, node, gesture, location, isStories in
|
||||
self.contactListNode = ContactListNode(context: context, presentation: presentation, onlyWriteable: false, isGroupInvitation: false, displaySortOptions: true, contextAction: { peer, node, gesture, location, isStories in
|
||||
contextAction?(peer, node, gesture, location, isStories)
|
||||
})
|
||||
|
||||
|
@ -1244,8 +1244,8 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
return current.withUpdatedUpdating(false)
|
||||
}
|
||||
|
||||
if let adminPeer {
|
||||
let inviteScreen = SendInviteLinkScreen(context: context, peer: channelPeer, link: exportedInvitation?.link, peers: [adminPeer])
|
||||
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)])
|
||||
pushControllerImpl?(inviteScreen)
|
||||
|
||||
dismissImpl?()
|
||||
@ -1433,9 +1433,9 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
return current.withUpdatedUpdating(true)
|
||||
}
|
||||
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, let admin = adminPeer {
|
||||
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: [admin])
|
||||
let inviteScreen = SendInviteLinkScreen(context: context, peer: channelPeer, link: exportedInvitation?.link, peers: [forbiddenPeer ?? TelegramForbiddenInvitePeer(peer: admin, canInviteWithPremium: false, premiumRequiredToContact: false)])
|
||||
pushControllerImpl?(inviteScreen)
|
||||
|
||||
dismissImpl?()
|
||||
|
@ -549,25 +549,25 @@ public func channelMembersController(context: AccountContext, updatedPresentatio
|
||||
contactsController?.dismiss()
|
||||
} else {
|
||||
if let chatPeer {
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataList(failedPeerIds.compactMap { item -> EnginePeer.Id? in
|
||||
return item.0
|
||||
}.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:)))
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { peerItems in
|
||||
let peers = peerItems.compactMap { $0 }
|
||||
if !peers.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: peers)
|
||||
viewControllers.remove(at: index)
|
||||
viewControllers.append(inviteScreen)
|
||||
navigationController.setViewControllers(viewControllers, animated: true)
|
||||
}
|
||||
let failedPeers = failedPeerIds.compactMap { _, error -> TelegramForbiddenInvitePeer? in
|
||||
if case let .restricted(peer) = error {
|
||||
return peer
|
||||
} else {
|
||||
contactsController?.dismiss()
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
viewControllers.remove(at: index)
|
||||
viewControllers.append(inviteScreen)
|
||||
navigationController.setViewControllers(viewControllers, animated: true)
|
||||
}
|
||||
} else {
|
||||
contactsController?.dismiss()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -4,15 +4,50 @@ import SwiftSignalKit
|
||||
import TelegramApi
|
||||
import MtProtoKit
|
||||
|
||||
|
||||
public enum AddGroupMemberError {
|
||||
case generic
|
||||
case groupFull
|
||||
case privacy
|
||||
case privacy(TelegramInvitePeersResult?)
|
||||
case notMutualContact
|
||||
case tooManyChannels
|
||||
}
|
||||
|
||||
public final class TelegramForbiddenInvitePeer: Equatable {
|
||||
public let peer: EnginePeer
|
||||
public let canInviteWithPremium: Bool
|
||||
public let premiumRequiredToContact: Bool
|
||||
|
||||
public init(peer: EnginePeer, canInviteWithPremium: Bool, premiumRequiredToContact: Bool) {
|
||||
self.peer = peer
|
||||
self.canInviteWithPremium = canInviteWithPremium
|
||||
self.premiumRequiredToContact = premiumRequiredToContact
|
||||
}
|
||||
|
||||
public static func ==(lhs: TelegramForbiddenInvitePeer, rhs: TelegramForbiddenInvitePeer) -> Bool {
|
||||
if lhs === rhs {
|
||||
return true
|
||||
}
|
||||
if lhs.peer != rhs.peer {
|
||||
return false
|
||||
}
|
||||
if lhs.canInviteWithPremium != rhs.canInviteWithPremium {
|
||||
return false
|
||||
}
|
||||
if lhs.premiumRequiredToContact != rhs.premiumRequiredToContact {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public final class TelegramInvitePeersResult {
|
||||
public let forbiddenPeers: [TelegramForbiddenInvitePeer]
|
||||
|
||||
public init(forbiddenPeers: [TelegramForbiddenInvitePeer]) {
|
||||
self.forbiddenPeers = forbiddenPeers
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_addGroupMember(account: Account, peerId: PeerId, memberId: PeerId) -> Signal<Void, AddGroupMemberError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, AddGroupMemberError> in
|
||||
if let peer = transaction.getPeer(peerId), let memberPeer = transaction.getPeer(memberId), let inputUser = apiInputUser(memberPeer) {
|
||||
@ -23,7 +58,7 @@ func _internal_addGroupMember(account: Account, peerId: PeerId, memberId: PeerId
|
||||
case "USERS_TOO_MUCH":
|
||||
return .groupFull
|
||||
case "USER_PRIVACY_RESTRICTED":
|
||||
return .privacy
|
||||
return .privacy(nil)
|
||||
case "USER_CHANNELS_TOO_MUCH":
|
||||
return .tooManyChannels
|
||||
case "USER_NOT_MUTUAL_CONTACT":
|
||||
@ -34,14 +69,16 @@ func _internal_addGroupMember(account: Account, peerId: PeerId, memberId: PeerId
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, AddGroupMemberError> in
|
||||
let updatesValue: Api.Updates
|
||||
let missingInviteesValue: [Api.MissingInvitee]
|
||||
switch result {
|
||||
case let .invitedUsers(updates, missingInvitees):
|
||||
let _ = missingInvitees
|
||||
updatesValue = updates
|
||||
missingInviteesValue = missingInvitees
|
||||
}
|
||||
|
||||
account.stateManager.addUpdates(updatesValue)
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
|
||||
return account.postbox.transaction { transaction -> TelegramInvitePeersResult in
|
||||
if let message = updatesValue.messages.first, let timestamp = message.timestamp {
|
||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
|
||||
if let cachedData = cachedData as? CachedGroupData, let participants = cachedData.participants {
|
||||
@ -62,8 +99,29 @@ func _internal_addGroupMember(account: Account, peerId: PeerId, memberId: PeerId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return TelegramInvitePeersResult(forbiddenPeers: missingInviteesValue.compactMap { invitee -> TelegramForbiddenInvitePeer? in
|
||||
switch invitee {
|
||||
case let .missingInvitee(flags, userId):
|
||||
guard let peer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))) else {
|
||||
return nil
|
||||
}
|
||||
return TelegramForbiddenInvitePeer(
|
||||
peer: EnginePeer(peer),
|
||||
canInviteWithPremium: (flags & (1 << 0)) != 0,
|
||||
premiumRequiredToContact: (flags & (1 << 1)) != 0
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|> mapError { _ -> AddGroupMemberError in }
|
||||
|> mapToSignal { result -> Signal<Void, AddGroupMemberError> in
|
||||
if result.forbiddenPeers.isEmpty {
|
||||
return .single(Void())
|
||||
} else {
|
||||
return .fail(.privacy(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
@ -76,7 +134,7 @@ func _internal_addGroupMember(account: Account, peerId: PeerId, memberId: PeerId
|
||||
|
||||
public enum AddChannelMemberError {
|
||||
case generic
|
||||
case restricted
|
||||
case restricted(TelegramForbiddenInvitePeer?)
|
||||
case notMutualContact
|
||||
case limitExceeded
|
||||
case tooMuchJoined
|
||||
@ -108,7 +166,7 @@ func _internal_addChannelMember(account: Account, peerId: PeerId, memberId: Peer
|
||||
case "USERS_TOO_MUCH":
|
||||
return .fail(.limitExceeded)
|
||||
case "USER_PRIVACY_RESTRICTED":
|
||||
return .fail(.restricted)
|
||||
return .fail(.restricted(nil))
|
||||
case "USER_NOT_MUTUAL_CONTACT":
|
||||
return .fail(.notMutualContact)
|
||||
case "USER_BOT":
|
||||
@ -127,7 +185,14 @@ func _internal_addChannelMember(account: Account, peerId: PeerId, memberId: Peer
|
||||
let updatesValue: Api.Updates
|
||||
switch result {
|
||||
case let .invitedUsers(updates, missingInvitees):
|
||||
let _ = missingInvitees
|
||||
if case let .missingInvitee(flags, _) = missingInvitees.first {
|
||||
return .fail(.restricted(TelegramForbiddenInvitePeer(
|
||||
peer: EnginePeer(memberPeer),
|
||||
canInviteWithPremium: (flags & (1 << 0)) != 0,
|
||||
premiumRequiredToContact: (flags & (1 << 1)) != 0
|
||||
)))
|
||||
}
|
||||
|
||||
updatesValue = updates
|
||||
}
|
||||
|
||||
@ -193,8 +258,8 @@ func _internal_addChannelMember(account: Account, peerId: PeerId, memberId: Peer
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_addChannelMembers(account: Account, peerId: PeerId, memberIds: [PeerId]) -> Signal<Void, AddChannelMemberError> {
|
||||
let signal = account.postbox.transaction { transaction -> Signal<Void, AddChannelMemberError> in
|
||||
func _internal_addChannelMembers(account: Account, peerId: PeerId, memberIds: [PeerId]) -> Signal<TelegramInvitePeersResult, AddChannelMemberError> {
|
||||
let signal = account.postbox.transaction { transaction -> Signal<TelegramInvitePeersResult, AddChannelMemberError> in
|
||||
var memberPeerIds: [PeerId:Peer] = [:]
|
||||
var inputUsers: [Api.InputUser] = []
|
||||
for memberId in memberIds {
|
||||
@ -207,13 +272,13 @@ func _internal_addChannelMembers(account: Account, peerId: PeerId, memberIds: [P
|
||||
}
|
||||
|
||||
if let peer = transaction.getPeer(peerId), let channel = peer as? TelegramChannel, let inputChannel = apiInputChannel(channel) {
|
||||
let signal = account.network.request(Api.functions.channels.inviteToChannel(channel: inputChannel, users: inputUsers))
|
||||
let signal: Signal<TelegramInvitePeersResult, AddChannelMemberError> = account.network.request(Api.functions.channels.inviteToChannel(channel: inputChannel, users: inputUsers))
|
||||
|> mapError { error -> AddChannelMemberError in
|
||||
switch error.errorDescription {
|
||||
case "CHANNELS_TOO_MUCH":
|
||||
return .tooMuchJoined
|
||||
case "USER_PRIVACY_RESTRICTED":
|
||||
return .restricted
|
||||
return .restricted(nil)
|
||||
case "USER_NOT_MUTUAL_CONTACT":
|
||||
return .notMutualContact
|
||||
case "USERS_TOO_MUCH":
|
||||
@ -224,21 +289,39 @@ func _internal_addChannelMembers(account: Account, peerId: PeerId, memberIds: [P
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
|> map { result in
|
||||
|> mapToQueue { result -> Signal<TelegramInvitePeersResult, AddChannelMemberError> in
|
||||
let updatesValue: Api.Updates
|
||||
let missingInviteesValue: [Api.MissingInvitee]
|
||||
switch result {
|
||||
case let .invitedUsers(updates, missingInvitees):
|
||||
let _ = missingInvitees
|
||||
updatesValue = updates
|
||||
missingInviteesValue = missingInvitees
|
||||
}
|
||||
|
||||
account.stateManager.addUpdates(updatesValue)
|
||||
account.viewTracker.forceUpdateCachedPeerData(peerId: peerId)
|
||||
|
||||
return account.postbox.transaction { transaction -> TelegramInvitePeersResult in
|
||||
return TelegramInvitePeersResult(forbiddenPeers: missingInviteesValue.compactMap { invitee -> TelegramForbiddenInvitePeer? in
|
||||
switch invitee {
|
||||
case let .missingInvitee(flags, userId):
|
||||
guard let peer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))) else {
|
||||
return nil
|
||||
}
|
||||
return TelegramForbiddenInvitePeer(
|
||||
peer: EnginePeer(peer),
|
||||
canInviteWithPremium: (flags & (1 << 0)) != 0,
|
||||
premiumRequiredToContact: (flags & (1 << 1)) != 0
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|> castError(AddChannelMemberError.self)
|
||||
}
|
||||
|
||||
return signal
|
||||
} else {
|
||||
return .single(Void())
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,14 +15,14 @@ public enum CreateGroupError {
|
||||
|
||||
public struct CreateGroupResult {
|
||||
public var peerId: EnginePeer.Id
|
||||
public var failedToInvitePeerIds: [EnginePeer.Id]
|
||||
public var result: TelegramInvitePeersResult
|
||||
|
||||
public init(
|
||||
peerId: EnginePeer.Id,
|
||||
failedToInvitePeerIds: [EnginePeer.Id]
|
||||
result: TelegramInvitePeersResult
|
||||
) {
|
||||
self.peerId = peerId
|
||||
self.failedToInvitePeerIds = failedToInvitePeerIds
|
||||
self.result = result
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,14 +50,12 @@ func _internal_createGroup(account: Account, title: String, peerIds: [PeerId], t
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<CreateGroupResult?, CreateGroupError> in
|
||||
var failedToInvitePeerIds: [EnginePeer.Id] = []
|
||||
failedToInvitePeerIds = []
|
||||
|
||||
let updatesValue: Api.Updates
|
||||
let missingInviteesValue: [Api.MissingInvitee]
|
||||
switch result {
|
||||
case let .invitedUsers(updates, missingInvitees):
|
||||
let _ = missingInvitees
|
||||
updatesValue = updates
|
||||
missingInviteesValue = missingInvitees
|
||||
}
|
||||
|
||||
account.stateManager.addUpdates(updatesValue)
|
||||
@ -68,11 +66,26 @@ func _internal_createGroup(account: Account, title: String, peerIds: [PeerId], t
|
||||
}
|
||||
|> take(1)
|
||||
|> castError(CreateGroupError.self)
|
||||
|> map { _ -> CreateGroupResult in
|
||||
return CreateGroupResult(
|
||||
peerId: peerId,
|
||||
failedToInvitePeerIds: failedToInvitePeerIds
|
||||
)
|
||||
|> mapToSignal { _ -> Signal<CreateGroupResult?, CreateGroupError> in
|
||||
return account.postbox.transaction { transaction -> CreateGroupResult in
|
||||
return CreateGroupResult(
|
||||
peerId: peerId,
|
||||
result: TelegramInvitePeersResult(forbiddenPeers: missingInviteesValue.compactMap { invitee -> TelegramForbiddenInvitePeer? in
|
||||
switch invitee {
|
||||
case let .missingInvitee(flags, userId):
|
||||
guard let peer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))) else {
|
||||
return nil
|
||||
}
|
||||
return TelegramForbiddenInvitePeer(
|
||||
peer: EnginePeer(peer),
|
||||
canInviteWithPremium: (flags & (1 << 0)) != 0,
|
||||
premiumRequiredToContact: (flags & (1 << 1)) != 0
|
||||
)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|> castError(CreateGroupError.self)
|
||||
}
|
||||
} else {
|
||||
return .single(nil)
|
||||
|
@ -78,7 +78,7 @@ func _internal_addGroupAdmin(account: Account, peerId: PeerId, adminId: PeerId)
|
||||
}
|
||||
)
|
||||
} else if error.errorDescription == "USER_PRIVACY_RESTRICTED" {
|
||||
return .fail(.addMemberError(.privacy))
|
||||
return .fail(.addMemberError(.privacy(nil)))
|
||||
} else if error.errorDescription == "ADMINS_TOO_MUCH" {
|
||||
return .fail(.adminsTooMuch)
|
||||
}
|
||||
@ -204,7 +204,7 @@ func _internal_updateChannelAdminRights(account: Account, peerId: PeerId, adminI
|
||||
} else if error.errorDescription == "USER_NOT_MUTUAL_CONTACT" {
|
||||
return .fail(.addMemberError(.notMutualContact))
|
||||
} else if error.errorDescription == "USER_PRIVACY_RESTRICTED" {
|
||||
return .fail(.addMemberError(.restricted))
|
||||
return .fail(.addMemberError(.restricted(nil)))
|
||||
} else if error.errorDescription == "USER_CHANNELS_TOO_MUCH" {
|
||||
return .fail(.addMemberError(.tooMuchJoined))
|
||||
} else if error.errorDescription == "ADMINS_TOO_MUCH" {
|
||||
|
@ -589,7 +589,7 @@ public extension TelegramEngine {
|
||||
return _internal_sendBotRequestedPeer(account: self.account, peerId: messageId.peerId, messageId: messageId, buttonId: buttonId, requestedPeerIds: requestedPeerIds)
|
||||
}
|
||||
|
||||
public func addChannelMembers(peerId: PeerId, memberIds: [PeerId]) -> Signal<Void, AddChannelMemberError> {
|
||||
public func addChannelMembers(peerId: PeerId, memberIds: [PeerId]) -> Signal<TelegramInvitePeersResult, AddChannelMemberError> {
|
||||
return _internal_addChannelMembers(account: self.account, peerId: peerId, memberIds: memberIds)
|
||||
}
|
||||
|
||||
|
@ -316,6 +316,7 @@ public enum PresentationResourceKey: Int32 {
|
||||
case sharedLinkIcon
|
||||
|
||||
case hideIconImage
|
||||
case peerStatusLockedImage
|
||||
}
|
||||
|
||||
public enum ChatExpiredStoryIndicatorType: Hashable {
|
||||
|
@ -408,4 +408,10 @@ public struct PresentationResourcesItemList {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/Archive/IconHide"), color: theme.list.itemAccentColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func peerStatusLockedImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.peerStatusLockedImage.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/SmallLock"), color: theme.list.itemSecondaryTextColor)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -274,6 +274,9 @@ private final class PeerInfoMembersContextImpl {
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
self.peerDisposable.dispose()
|
||||
for (_, disposable) in self.removingMemberIds {
|
||||
disposable.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
private func pushState() {
|
||||
@ -293,7 +296,7 @@ private final class PeerInfoMembersContextImpl {
|
||||
}
|
||||
|
||||
func removeMember(memberId: PeerId) {
|
||||
if removingMemberIds[memberId] == nil {
|
||||
if self.removingMemberIds[memberId] == nil {
|
||||
let signal: Signal<Never, NoError>
|
||||
if self.peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
signal = context.peerChannelMemberCategoriesContextsManager.updateMemberBannedRights(engine: self.context.engine, peerId: self.peerId, memberId: memberId, bannedRights: TelegramChatBannedRights(flags: [.banReadMessages], untilDate: Int32.max))
|
||||
|
@ -12424,20 +12424,8 @@ public func presentAddMembersImpl(context: AccountContext, updatedPresentationDa
|
||||
}, clearHighlightAutomatically: true))
|
||||
}
|
||||
|
||||
let contactsController: ViewController
|
||||
/*if groupPeer.id.namespace == Namespaces.Peer.CloudGroup {
|
||||
contactsController = context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, autoDismiss: false, title: { $0.GroupInfo_AddParticipantTitle }, options: options, confirmation: { peer in
|
||||
if let confirmationImpl = confirmationImpl, case let .peer(peer, _, _) = peer {
|
||||
return confirmationImpl(peer.id)
|
||||
} else {
|
||||
return .single(false)
|
||||
}
|
||||
}))
|
||||
let contactsController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, mode: .peerSelection(searchChatList: false, searchGroups: false, searchChannels: false), options: options, filters: [.excludeSelf, .disable(recentIds)], onlyWriteable: true, isGroupInvitation: true))
|
||||
contactsController.navigationPresentation = .modal
|
||||
} else {*/
|
||||
contactsController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, mode: .peerSelection(searchChatList: false, searchGroups: false, searchChannels: false), options: options, filters: [.excludeSelf, .disable(recentIds)], onlyWriteable: true))
|
||||
contactsController.navigationPresentation = .modal
|
||||
//}
|
||||
|
||||
confirmationImpl = { [weak contactsController] peerId in
|
||||
return context.account.postbox.loadedPeerWithId(peerId)
|
||||
@ -12461,162 +12449,6 @@ public func presentAddMembersImpl(context: AccountContext, updatedPresentationDa
|
||||
}
|
||||
}
|
||||
|
||||
/*let addMember: (ContactListPeer) -> Signal<Void, NoError> = { [weak contactsController] memberPeer -> Signal<Void, NoError> in
|
||||
if case let .peer(selectedPeer, _, _) = memberPeer {
|
||||
let memberId = selectedPeer.id
|
||||
if groupPeer.id.namespace == Namespaces.Peer.CloudChannel {
|
||||
return context.peerChannelMemberCategoriesContextsManager.addMember(engine: context.engine, peerId: groupPeer.id, memberId: memberId)
|
||||
|> map { _ -> Void in
|
||||
}
|
||||
|> `catch` { error -> Signal<Void, NoError> in
|
||||
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 let peer = groupPeer as? TelegramChannel, case .broadcast = peer.info {
|
||||
text = presentationData.strings.Channel_AddUserLeftError
|
||||
} else {
|
||||
text = presentationData.strings.GroupInfo_AddUserLeftError
|
||||
}
|
||||
case let .bot(memberId):
|
||||
guard let peer = groupPeer as? TelegramChannel else {
|
||||
parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
contactsController?.dismiss()
|
||||
return .complete()
|
||||
}
|
||||
|
||||
if peer.hasPermission(.addAdmins) {
|
||||
parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Channel_AddBotErrorHaveRights, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Channel_AddBotAsAdmin, action: {
|
||||
contactsController?.dismiss()
|
||||
|
||||
parentController?.push(channelAdminController(context: context, updatedPresentationData: updatedPresentationData, peerId: groupPeer.id, adminId: memberId, initialParticipant: nil, updated: { _ in
|
||||
}, upgradedToSupergroup: { _, f in f () }, transferedOwnership: { _ in }))
|
||||
})]), in: .window(.root))
|
||||
} else {
|
||||
parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Channel_AddBotErrorHaveRights, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
|
||||
contactsController?.dismiss()
|
||||
return .complete()
|
||||
case .botDoesntSupportGroups:
|
||||
text = presentationData.strings.Channel_BotDoesntSupportGroups
|
||||
case .tooMuchBots:
|
||||
text = presentationData.strings.Channel_TooMuchBots
|
||||
case .kicked:
|
||||
text = presentationData.strings.Channel_AddUserKickedError
|
||||
}
|
||||
parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
return context.engine.data.get(TelegramEngine.EngineData.Item.Peer.ExportedInvitation(id: groupPeer.id))
|
||||
|> mapToSignal { exportedInvitation in
|
||||
return context.engine.peers.addGroupMember(peerId: groupPeer.id, memberId: memberId)
|
||||
|> deliverOnMainQueue
|
||||
|> `catch` { error -> Signal<Void, NoError> in
|
||||
if let exportedInvitation, let link = exportedInvitation.link {
|
||||
let failedPeerIds: [(PeerId, AddGroupMemberError)] = [(memberId, error)]
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataList(failedPeerIds.compactMap { item -> EnginePeer.Id? in
|
||||
return item.0
|
||||
}.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:)))
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { peerItems in
|
||||
let peers = peerItems.compactMap { $0 }
|
||||
if !peers.isEmpty, let contactsController, let navigationController = contactsController.navigationController as? NavigationController {
|
||||
var viewControllers = navigationController.viewControllers
|
||||
|
||||
let inviteScreen = SendInviteLinkScreen(context: context, link: link, peers: peers)
|
||||
|
||||
if let index = viewControllers.firstIndex(where: { $0 === contactsController }) {
|
||||
viewControllers.remove(at: index)
|
||||
viewControllers.append(inviteScreen)
|
||||
navigationController.setViewControllers(viewControllers, animated: true)
|
||||
} else {
|
||||
navigationController.pushViewController(inviteScreen)
|
||||
}
|
||||
} else {
|
||||
contactsController?.dismiss()
|
||||
}
|
||||
})
|
||||
|
||||
return .complete()
|
||||
}
|
||||
|
||||
switch error {
|
||||
case .generic:
|
||||
return .complete()
|
||||
case .privacy:
|
||||
let _ = (context.account.postbox.loadedPeerWithId(memberId)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(peer).compactDisplayTitle, EnginePeer(peer).compactDisplayTitle).string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
})
|
||||
return .complete()
|
||||
case .notMutualContact:
|
||||
let _ = (context.account.postbox.loadedPeerWithId(memberId)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
let text: String
|
||||
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
|
||||
text = presentationData.strings.Channel_AddUserLeftError
|
||||
} else {
|
||||
text = presentationData.strings.GroupInfo_AddUserLeftError
|
||||
}
|
||||
parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
})
|
||||
return .complete()
|
||||
case .tooManyChannels:
|
||||
let _ = (context.account.postbox.loadedPeerWithId(memberId)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Invite_ChannelsTooMuch, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
})
|
||||
return .complete()
|
||||
case .groupFull:
|
||||
let signal = context.engine.peers.convertGroupToSupergroup(peerId: groupPeer.id)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { error -> Signal<PeerId?, NoError> in
|
||||
switch error {
|
||||
case .tooManyChannels:
|
||||
Queue.mainQueue().async {
|
||||
parentController?.push(oldChannelsController(context: context, intent: .upgrade))
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { upgradedPeerId -> Signal<PeerId?, NoError> in
|
||||
guard let upgradedPeerId = upgradedPeerId else {
|
||||
return .single(nil)
|
||||
}
|
||||
return context.peerChannelMemberCategoriesContextsManager.addMember(engine: context.engine, peerId: upgradedPeerId, memberId: memberId)
|
||||
|> `catch` { _ -> Signal<Never, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<PeerId?, NoError> in
|
||||
}
|
||||
|> then(.single(upgradedPeerId))
|
||||
}
|
||||
|> deliverOnMainQueue
|
||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
return signal
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}*/
|
||||
|
||||
let addMembers: ([ContactListPeerId]) -> Signal<[(PeerId, AddChannelMemberError)], NoError> = { members -> Signal<[(PeerId, AddChannelMemberError)], NoError> in
|
||||
let memberIds = members.compactMap { contact -> PeerId? in
|
||||
switch contact {
|
||||
@ -12652,8 +12484,8 @@ public func presentAddMembersImpl(context: AccountContext, updatedPresentationDa
|
||||
return .generic
|
||||
case .groupFull:
|
||||
return .limitExceeded
|
||||
case .privacy:
|
||||
return .restricted
|
||||
case let .privacy(privacy):
|
||||
return .restricted(privacy?.forbiddenPeers.first)
|
||||
case .notMutualContact:
|
||||
return .notMutualContact
|
||||
case .tooManyChannels:
|
||||
@ -12683,25 +12515,7 @@ public func presentAddMembersImpl(context: AccountContext, updatedPresentationDa
|
||||
}
|
||||
|
||||
parentController?.push(contactsController)
|
||||
/*if let contactsController = contactsController as? ContactSelectionController {
|
||||
selectAddMemberDisposable.set((contactsController.result
|
||||
|> deliverOnMainQueue).start(next: { [weak contactsController] result in
|
||||
guard let (peers, _, _, _, _) = result, let memberPeer = peers.first else {
|
||||
return
|
||||
}
|
||||
|
||||
contactsController?.displayProgress = true
|
||||
addMemberDisposable.set((addMember(memberPeer)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
contactsController?.dismiss()
|
||||
}))
|
||||
}))
|
||||
contactsController.dismissed = {
|
||||
selectAddMemberDisposable.set(nil)
|
||||
addMemberDisposable.set(nil)
|
||||
}
|
||||
}*/
|
||||
if let contactsController = contactsController as? ContactMultiselectionController {
|
||||
do {
|
||||
selectAddMemberDisposable.set((
|
||||
combineLatest(queue: .mainQueue(),
|
||||
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.ExportedInvitation(id: groupPeer.id)),
|
||||
@ -12743,56 +12557,25 @@ public func presentAddMembersImpl(context: AccountContext, updatedPresentationDa
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if "".isEmpty {
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataList(failedPeerIds.compactMap { item -> EnginePeer.Id? in
|
||||
return item.0
|
||||
}.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:)))
|
||||
)
|
||||
|> deliverOnMainQueue).startStandalone(next: { peerItems in
|
||||
let peers = peerItems.compactMap { $0 }
|
||||
if !peers.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: peers)
|
||||
viewControllers.remove(at: index)
|
||||
viewControllers.append(inviteScreen)
|
||||
navigationController.setViewControllers(viewControllers, animated: true)
|
||||
}
|
||||
} else {
|
||||
contactsController?.dismiss()
|
||||
}
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if peers.count == 1, case .restricted = failedPeerIds[0].1 {
|
||||
switch peers[0] {
|
||||
case let .peer(peerId):
|
||||
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> deliverOnMainQueue).startStandalone(next: { peer in
|
||||
parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(peer).compactDisplayTitle, EnginePeer(peer).compactDisplayTitle).string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
})
|
||||
default:
|
||||
break
|
||||
}
|
||||
} else if peers.count == 1, case .notMutualContact = failedPeerIds[0].1 {
|
||||
let text: String
|
||||
if let peer = groupPeer as? TelegramChannel, case .broadcast = peer.info {
|
||||
text = presentationData.strings.Channel_AddUserLeftError
|
||||
let failedPeers = failedPeerIds.compactMap { _, error -> TelegramForbiddenInvitePeer? in
|
||||
if case let .restricted(peer) = error {
|
||||
return peer
|
||||
} else {
|
||||
text = presentationData.strings.GroupInfo_AddUserLeftError
|
||||
return nil
|
||||
}
|
||||
|
||||
parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
} else if case .tooMuchJoined = failedPeerIds[0].1 {
|
||||
parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Invite_ChannelsTooMuch, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
} else if peers.count == 1, case .kicked = failedPeerIds[0].1 {
|
||||
parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Channel_AddUserKickedError, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
|
||||
contactsController?.dismiss()
|
||||
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)
|
||||
viewControllers.remove(at: index)
|
||||
viewControllers.append(inviteScreen)
|
||||
navigationController.setViewControllers(viewControllers, animated: true)
|
||||
}
|
||||
} else {
|
||||
contactsController?.dismiss()
|
||||
}
|
||||
}
|
||||
}))
|
||||
}))
|
||||
|
@ -1354,7 +1354,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
self.controller?.containerLayoutUpdated(layout, transition: .immediate)
|
||||
}
|
||||
} else {
|
||||
let contactListNode = ContactListNode(context: self.context, updatedPresentationData: self.updatedPresentationData, presentation: .single(.natural(options: [], includeChatList: false, topPeers: .none)), onlyWriteable: self.filter.contains(.onlyWriteable))
|
||||
let contactListNode = ContactListNode(context: self.context, updatedPresentationData: self.updatedPresentationData, presentation: .single(.natural(options: [], includeChatList: false, topPeers: .none)), onlyWriteable: self.filter.contains(.onlyWriteable), isGroupInvitation: false)
|
||||
self.contactListNode = contactListNode
|
||||
contactListNode.enableUpdates = true
|
||||
contactListNode.selectionStateUpdated = { [weak self] selectionState in
|
||||
|
@ -34,13 +34,22 @@ final class PeerListItemComponent: Component {
|
||||
case editing(isSelected: Bool)
|
||||
}
|
||||
|
||||
enum SubtitleIcon {
|
||||
case lock
|
||||
}
|
||||
|
||||
enum Subtitle: Equatable {
|
||||
case presence(EnginePeer.Presence?)
|
||||
case text(text: String, icon: SubtitleIcon)
|
||||
}
|
||||
|
||||
let context: AccountContext
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
let sideInset: CGFloat
|
||||
let title: String
|
||||
let subtitle: Subtitle
|
||||
let peer: EnginePeer?
|
||||
let presence: EnginePeer.Presence?
|
||||
let selectionState: SelectionState
|
||||
let hasNext: Bool
|
||||
let action: (EnginePeer) -> Void
|
||||
@ -51,8 +60,8 @@ final class PeerListItemComponent: Component {
|
||||
strings: PresentationStrings,
|
||||
sideInset: CGFloat,
|
||||
title: String,
|
||||
subtitle: Subtitle,
|
||||
peer: EnginePeer?,
|
||||
presence: EnginePeer.Presence?,
|
||||
selectionState: SelectionState,
|
||||
hasNext: Bool,
|
||||
action: @escaping (EnginePeer) -> Void
|
||||
@ -62,8 +71,8 @@ final class PeerListItemComponent: Component {
|
||||
self.strings = strings
|
||||
self.sideInset = sideInset
|
||||
self.title = title
|
||||
self.subtitle = subtitle
|
||||
self.peer = peer
|
||||
self.presence = presence
|
||||
self.selectionState = selectionState
|
||||
self.hasNext = hasNext
|
||||
self.action = action
|
||||
@ -85,10 +94,10 @@ final class PeerListItemComponent: Component {
|
||||
if lhs.title != rhs.title {
|
||||
return false
|
||||
}
|
||||
if lhs.peer != rhs.peer {
|
||||
if lhs.subtitle != rhs.subtitle {
|
||||
return false
|
||||
}
|
||||
if lhs.presence != rhs.presence {
|
||||
if lhs.peer != rhs.peer {
|
||||
return false
|
||||
}
|
||||
if lhs.selectionState != rhs.selectionState {
|
||||
@ -108,6 +117,7 @@ final class PeerListItemComponent: Component {
|
||||
private let separatorLayer: SimpleLayer
|
||||
private let avatarNode: AvatarNode
|
||||
|
||||
private var labelIconView: UIImageView?
|
||||
private var checkLayer: CheckLayer?
|
||||
|
||||
private var component: PeerListItemComponent?
|
||||
@ -165,7 +175,7 @@ final class PeerListItemComponent: Component {
|
||||
self.component = component
|
||||
self.state = state
|
||||
|
||||
if let presence = component.presence {
|
||||
if case let .presence(presence) = component.subtitle, let presence {
|
||||
let statusManager: PeerPresenceStatusManager
|
||||
if let current = self.statusManager {
|
||||
statusManager = current
|
||||
@ -240,11 +250,26 @@ final class PeerListItemComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
var labelIcon: UIImage?
|
||||
let labelData: (String, Bool)
|
||||
if let presence = component.presence {
|
||||
labelData = stringAndActivityForUserPresence(strings: component.strings, dateTimeFormat: PresentationDateTimeFormat(), presence: presence, relativeTo: Int32(Date().timeIntervalSince1970))
|
||||
} else {
|
||||
labelData = (component.strings.LastSeen_Offline, false)
|
||||
switch component.subtitle {
|
||||
case let .presence(presence):
|
||||
if let presence {
|
||||
labelData = stringAndActivityForUserPresence(strings: component.strings, dateTimeFormat: PresentationDateTimeFormat(), presence: presence, relativeTo: Int32(Date().timeIntervalSince1970))
|
||||
} else {
|
||||
labelData = (component.strings.LastSeen_Offline, false)
|
||||
}
|
||||
case let .text(text, icon):
|
||||
switch icon {
|
||||
case .lock:
|
||||
labelIcon = PresentationResourcesItemList.peerStatusLockedImage(component.theme)
|
||||
}
|
||||
labelData = (text, false)
|
||||
}
|
||||
|
||||
var maxTextSize = availableSize.width - leftInset - rightInset
|
||||
if labelIcon != nil {
|
||||
maxTextSize -= 48.0
|
||||
}
|
||||
|
||||
let labelSize = self.label.update(
|
||||
@ -253,7 +278,7 @@ final class PeerListItemComponent: Component {
|
||||
text: .plain(NSAttributedString(string: labelData.0, font: Font.regular(15.0), textColor: labelData.1 ? component.theme.list.itemAccentColor : component.theme.list.itemSecondaryTextColor))
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - leftInset - rightInset, height: 100.0)
|
||||
containerSize: CGSize(width: maxTextSize, height: 100.0)
|
||||
)
|
||||
|
||||
let previousTitleFrame = self.title.view?.frame
|
||||
@ -268,7 +293,7 @@ final class PeerListItemComponent: Component {
|
||||
text: .plain(NSAttributedString(string: component.title, font: Font.semibold(17.0), textColor: component.theme.list.itemPrimaryTextColor))
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - leftInset - rightInset, height: 100.0)
|
||||
containerSize: CGSize(width: maxTextSize, height: 100.0)
|
||||
)
|
||||
|
||||
let titleSpacing: CGFloat = 1.0
|
||||
@ -296,6 +321,27 @@ final class PeerListItemComponent: Component {
|
||||
transition.animateAlpha(view: titleView, from: 0.0, to: 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
if let labelIcon {
|
||||
let labelIconView: UIImageView
|
||||
if let current = self.labelIconView {
|
||||
labelIconView = current
|
||||
} else {
|
||||
labelIconView = UIImageView()
|
||||
self.labelIconView = labelIconView
|
||||
self.containerButton.addSubview(labelIconView)
|
||||
}
|
||||
labelIconView.image = labelIcon
|
||||
|
||||
let labelIconFrame = CGRect(origin: CGPoint(x: availableSize.width - rightInset - 48.0 + floor((48.0 - labelIcon.size.width) * 0.5), y: floor((height - verticalInset * 2.0 - labelIcon.size.height) / 2.0)), size: CGSize(width: labelIcon.size.width, height: labelIcon.size.height))
|
||||
transition.setFrame(view: labelIconView, frame: labelIconFrame)
|
||||
} else {
|
||||
if let labelIconView = self.labelIconView {
|
||||
self.labelIconView = nil
|
||||
labelIconView.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
if let labelView = self.label.view {
|
||||
if labelView.superview == nil {
|
||||
labelView.isUserInteractionEnabled = false
|
||||
|
@ -22,13 +22,13 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
|
||||
let context: AccountContext
|
||||
let link: String?
|
||||
let peers: [EnginePeer]
|
||||
let peers: [TelegramForbiddenInvitePeer]
|
||||
let peerPresences: [EnginePeer.Id: EnginePeer.Presence]
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
link: String?,
|
||||
peers: [EnginePeer],
|
||||
peers: [TelegramForbiddenInvitePeer],
|
||||
peerPresences: [EnginePeer.Id: EnginePeer.Presence]
|
||||
) {
|
||||
self.context = context
|
||||
@ -272,7 +272,9 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
|
||||
if self.component == nil {
|
||||
for peer in component.peers {
|
||||
self.selectedItems.insert(peer.id)
|
||||
if component.link != nil && !peer.premiumRequiredToContact {
|
||||
self.selectedItems.insert(peer.peer.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -280,8 +282,15 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
self.state = state
|
||||
self.environment = environment
|
||||
|
||||
let hasPremiumRestrictedUsers = "".isEmpty
|
||||
let hasInviteLink = "".isEmpty
|
||||
let premiumRestrictedUsers = component.peers.filter { peer in
|
||||
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
|
||||
}
|
||||
|
||||
if themeUpdated {
|
||||
self.dimView.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
|
||||
@ -312,12 +321,13 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
self.scrollContentView.addSubview(avatarsNode.view)
|
||||
}
|
||||
|
||||
let avatarsContent = self.avatarsContext.update(peers: component.peers.count <= 3 ? component.peers : Array(component.peers.prefix(upTo: 3)), animated: false)
|
||||
let avatarPeers = component.peers.map(\.peer)
|
||||
let avatarsContent = self.avatarsContext.update(peers: avatarPeers.count <= 3 ? avatarPeers : Array(avatarPeers.prefix(upTo: 3)), animated: false)
|
||||
let avatarsSize = avatarsNode.update(
|
||||
context: component.context,
|
||||
content: avatarsContent,
|
||||
itemSize: CGSize(width: 60.0, height: 60.0),
|
||||
customSpacing: 50.0,
|
||||
customSpacing: 30.0,
|
||||
font: avatarPlaceholderFont(size: 28.0),
|
||||
animated: false,
|
||||
synchronousLoad: true
|
||||
@ -347,7 +357,7 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
transition.setFrame(view: leftButtonView, frame: leftButtonFrame)
|
||||
}
|
||||
|
||||
if hasPremiumRestrictedUsers {
|
||||
if !premiumRestrictedUsers.isEmpty {
|
||||
var premiumItemsTransition = transition
|
||||
|
||||
let premiumTitle: ComponentView<Empty>
|
||||
@ -397,20 +407,20 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
|
||||
//TODO:localize
|
||||
let text: String
|
||||
if component.peers.count == 1 {
|
||||
text = "**\(component.peers[0].compactDisplayTitle)** accepts invitations to groups from contacts and **Premium** users."
|
||||
if premiumRestrictedUsers.count == 1 {
|
||||
text = "**\(premiumRestrictedUsers[0].peer.compactDisplayTitle)** accepts invitations to groups from contacts and **Premium** users."
|
||||
} else {
|
||||
let extraCount = component.peers.count - 3
|
||||
let extraCount = premiumRestrictedUsers.count - 3
|
||||
|
||||
var peersText = ""
|
||||
for i in 0 ..< min(3, component.peers.count) {
|
||||
if extraCount == 0 && i == component.peers.count - 1 {
|
||||
for i in 0 ..< min(3, premiumRestrictedUsers.count) {
|
||||
if extraCount == 0 && i == premiumRestrictedUsers.count - 1 {
|
||||
peersText.append(", and ")
|
||||
} else if i != 0 {
|
||||
peersText.append(", ")
|
||||
}
|
||||
peersText.append("**")
|
||||
peersText.append(component.peers[i].compactDisplayTitle)
|
||||
peersText.append(premiumRestrictedUsers[i].peer.compactDisplayTitle)
|
||||
peersText.append("**")
|
||||
}
|
||||
|
||||
@ -641,13 +651,13 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
contentHeight += 8.0
|
||||
|
||||
let text: String
|
||||
if hasPremiumRestrictedUsers {
|
||||
if !premiumRestrictedUsers.isEmpty {
|
||||
if component.link != nil {
|
||||
//TODO:localize
|
||||
text = "You can try to send an invite link instead."
|
||||
} else {
|
||||
if component.peers.count == 1 {
|
||||
text = environment.strings.SendInviteLink_TextUnavailableSingleUser(component.peers[0].displayTitle(strings: environment.strings, displayOrder: .firstLast)).string
|
||||
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))
|
||||
}
|
||||
@ -655,13 +665,13 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
} else {
|
||||
if component.link != nil {
|
||||
if component.peers.count == 1 {
|
||||
text = environment.strings.SendInviteLink_TextAvailableSingleUser(component.peers[0].displayTitle(strings: environment.strings, displayOrder: .firstLast)).string
|
||||
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 {
|
||||
if component.peers.count == 1 {
|
||||
text = environment.strings.SendInviteLink_TextUnavailableSingleUser(component.peers[0].displayTitle(strings: environment.strings, displayOrder: .firstLast)).string
|
||||
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))
|
||||
}
|
||||
@ -696,6 +706,7 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
|
||||
contentHeight += descriptionTextFrame.height
|
||||
contentHeight += 22.0
|
||||
initialContentHeight = contentHeight
|
||||
|
||||
var singleItemHeight: CGFloat = 0.0
|
||||
|
||||
@ -706,7 +717,7 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
|
||||
for _ in 0 ..< 1 {
|
||||
//let id: AnyHashable = AnyHashable("\(peer.id)_\(j)")
|
||||
let id = AnyHashable(peer.id)
|
||||
let id = AnyHashable(peer.peer.id)
|
||||
validIds.append(id)
|
||||
|
||||
let item: ComponentView<Empty>
|
||||
@ -719,6 +730,15 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
self.items[id] = item
|
||||
}
|
||||
|
||||
let itemSubtitle: PeerListItemComponent.Subtitle
|
||||
let canBeSelected = component.link != nil && !peer.premiumRequiredToContact
|
||||
if peer.premiumRequiredToContact {
|
||||
//TODO:localize
|
||||
itemSubtitle = .text(text: "Available only to premium users", icon: .lock)
|
||||
} else {
|
||||
itemSubtitle = .presence(component.peerPresences[peer.peer.id])
|
||||
}
|
||||
|
||||
let itemSize = item.update(
|
||||
transition: itemTransition,
|
||||
component: AnyComponent(PeerListItemComponent(
|
||||
@ -726,15 +746,18 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
theme: environment.theme,
|
||||
strings: environment.strings,
|
||||
sideInset: 0.0,
|
||||
title: peer.displayTitle(strings: environment.strings, displayOrder: .firstLast),
|
||||
peer: peer,
|
||||
presence: component.peerPresences[peer.id],
|
||||
selectionState: component.link == nil ? .none : .editing(isSelected: self.selectedItems.contains(peer.id)),
|
||||
title: peer.peer.displayTitle(strings: environment.strings, displayOrder: .firstLast),
|
||||
subtitle: itemSubtitle,
|
||||
peer: peer.peer,
|
||||
selectionState: !canBeSelected ? .none : .editing(isSelected: self.selectedItems.contains(peer.peer.id)),
|
||||
hasNext: i != component.peers.count - 1,
|
||||
action: { [weak self] peer in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if !canBeSelected {
|
||||
return
|
||||
}
|
||||
if self.selectedItems.contains(peer.id) {
|
||||
self.selectedItems.remove(peer.id)
|
||||
} else {
|
||||
@ -771,7 +794,6 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
}
|
||||
transition.setFrame(view: self.itemContainerView, frame: CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: CGSize(width: availableSize.width - sideInset * 2.0, height: itemsHeight)))
|
||||
|
||||
initialContentHeight += singleItemHeight + 16.0
|
||||
initialContentHeight += min(itemsHeight, floor(singleItemHeight * 2.5))
|
||||
|
||||
contentHeight += itemsHeight
|
||||
@ -805,16 +827,16 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
if self.selectedItems.isEmpty {
|
||||
controller.dismiss()
|
||||
} else if let link = component.link {
|
||||
let selectedPeers = component.peers.filter { self.selectedItems.contains($0.id) }
|
||||
let selectedPeers = component.peers.filter { self.selectedItems.contains($0.peer.id) }
|
||||
|
||||
let _ = enqueueMessagesToMultiplePeers(account: component.context.account, peerIds: Array(self.selectedItems), threadIds: [:], messages: [.message(text: link, attributes: [], inlineStickers: [:], mediaReference: nil, threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])]).start()
|
||||
let text: String
|
||||
if selectedPeers.count == 1 {
|
||||
text = environment.strings.Conversation_ShareLinkTooltip_Chat_One(selectedPeers[0].displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: "")).string
|
||||
text = environment.strings.Conversation_ShareLinkTooltip_Chat_One(selectedPeers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: "")).string
|
||||
} else if selectedPeers.count == 2 {
|
||||
text = environment.strings.Conversation_ShareLinkTooltip_TwoChats_One(selectedPeers[0].displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: ""), selectedPeers[1].displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: "")).string
|
||||
text = environment.strings.Conversation_ShareLinkTooltip_TwoChats_One(selectedPeers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: ""), selectedPeers[1].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: "")).string
|
||||
} else {
|
||||
text = environment.strings.Conversation_ShareLinkTooltip_ManyChats_One(selectedPeers[0].displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: ""), "\(selectedPeers.count - 1)").string
|
||||
text = environment.strings.Conversation_ShareLinkTooltip_ManyChats_One(selectedPeers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: ""), "\(selectedPeers.count - 1)").string
|
||||
}
|
||||
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
||||
@ -863,7 +885,7 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
|
||||
let topInset: CGFloat = max(0.0, availableSize.height - containerInset - initialContentHeight)
|
||||
|
||||
let scrollContentHeight = max(topInset + contentHeight, availableSize.height - containerInset)
|
||||
let scrollContentHeight = max(topInset + contentHeight + containerInset, availableSize.height - containerInset)
|
||||
|
||||
self.scrollContentClippingView.layer.cornerRadius = 10.0
|
||||
|
||||
@ -906,13 +928,13 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
public class SendInviteLinkScreen: ViewControllerComponentContainer {
|
||||
private let context: AccountContext
|
||||
private let link: String?
|
||||
private let peers: [EnginePeer]
|
||||
private let peers: [TelegramForbiddenInvitePeer]
|
||||
|
||||
private var isDismissed: Bool = false
|
||||
|
||||
private var presenceDisposable: Disposable?
|
||||
|
||||
public init(context: AccountContext, peer: EnginePeer, link: String?, peers: [EnginePeer]) {
|
||||
public init(context: AccountContext, peer: EnginePeer, link: String?, peers: [TelegramForbiddenInvitePeer]) {
|
||||
self.context = context
|
||||
|
||||
var link = link
|
||||
@ -920,6 +942,120 @@ public class SendInviteLinkScreen: ViewControllerComponentContainer {
|
||||
link = "https://t.me/\(addressName)"
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
var peers = peers
|
||||
|
||||
if !"".isEmpty {
|
||||
enum TestConfiguration: CaseIterable {
|
||||
case singlePeerNoPremiumLink
|
||||
case singlePeerPremiumLink
|
||||
case singlePeerNoPremiumNoLink
|
||||
case singlePeerPremiumNoLink
|
||||
case somePeersNoPremiumLink
|
||||
case somePeersOnePremiumLink
|
||||
case somePeersAllPremiumLink
|
||||
case somePeersNoPremiumNoLink
|
||||
case somePeersOnePremiumNoLink
|
||||
case somePeersAllPremiumNoLink
|
||||
case morePeersNoPremiumLink
|
||||
case morePeersOnePremiumLink
|
||||
case morePeersAllPremiumLink
|
||||
case morePeersNoPremiumNoLink
|
||||
case morePeersOnePremiumNoLink
|
||||
case morePeersAllPremiumNoLink
|
||||
}
|
||||
|
||||
var nextPeerId: Int64 = 1
|
||||
let makePeer: (Bool, Bool) -> TelegramForbiddenInvitePeer = { canInviteWithPremium, premiumRequiredToContact in
|
||||
guard case let .user(user) = peers[0].peer else {
|
||||
preconditionFailure()
|
||||
}
|
||||
let id = nextPeerId
|
||||
nextPeerId += 1
|
||||
return TelegramForbiddenInvitePeer(
|
||||
peer: .user(TelegramUser(
|
||||
id: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(id)),
|
||||
accessHash: user.accessHash,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
username: user.username,
|
||||
phone: user.phone,
|
||||
photo: user.photo,
|
||||
botInfo: user.botInfo,
|
||||
restrictionInfo: user.restrictionInfo,
|
||||
flags: user.flags,
|
||||
emojiStatus: user.emojiStatus,
|
||||
usernames: user.usernames,
|
||||
storiesHidden: user.storiesHidden,
|
||||
nameColor: user.nameColor,
|
||||
backgroundEmojiId: user.backgroundEmojiId,
|
||||
profileColor: user.profileColor,
|
||||
profileBackgroundEmojiId: user.profileBackgroundEmojiId
|
||||
)),
|
||||
canInviteWithPremium: canInviteWithPremium,
|
||||
premiumRequiredToContact: premiumRequiredToContact
|
||||
)
|
||||
}
|
||||
|
||||
let caseIndex = 9
|
||||
let configuration = TestConfiguration.allCases[caseIndex]
|
||||
do {
|
||||
switch configuration {
|
||||
case .singlePeerNoPremiumLink:
|
||||
peers = [makePeer(false, false)]
|
||||
link = "abcd"
|
||||
case .singlePeerPremiumLink:
|
||||
peers = [makePeer(true, false)]
|
||||
link = "abcd"
|
||||
case .singlePeerNoPremiumNoLink:
|
||||
peers = [makePeer(false, false)]
|
||||
link = nil
|
||||
case .singlePeerPremiumNoLink:
|
||||
peers = [makePeer(true, false)]
|
||||
link = nil
|
||||
case .somePeersNoPremiumLink:
|
||||
peers = (0 ..< 3).map { _ in makePeer(false, false) }
|
||||
link = "abcd"
|
||||
case .somePeersOnePremiumLink:
|
||||
peers = [
|
||||
makePeer(false, false),
|
||||
makePeer(true, true),
|
||||
makePeer(false, false)
|
||||
]
|
||||
link = "abcd"
|
||||
case .somePeersAllPremiumLink:
|
||||
peers = (0 ..< 3).map { _ in makePeer(true, false) }
|
||||
link = "abcd"
|
||||
case .somePeersNoPremiumNoLink:
|
||||
peers = (0 ..< 3).map { _ in makePeer(false, false) }
|
||||
link = nil
|
||||
case .somePeersOnePremiumNoLink:
|
||||
peers = [
|
||||
makePeer(false, false),
|
||||
makePeer(true, false),
|
||||
makePeer(false, false)
|
||||
]
|
||||
link = nil
|
||||
case .somePeersAllPremiumNoLink:
|
||||
peers = (0 ..< 3).map { _ in makePeer(true, false) }
|
||||
link = nil
|
||||
case .morePeersNoPremiumLink:
|
||||
preconditionFailure()
|
||||
case .morePeersOnePremiumLink:
|
||||
preconditionFailure()
|
||||
case .morePeersAllPremiumLink:
|
||||
preconditionFailure()
|
||||
case .morePeersNoPremiumNoLink:
|
||||
preconditionFailure()
|
||||
case .morePeersOnePremiumNoLink:
|
||||
preconditionFailure()
|
||||
case .morePeersAllPremiumNoLink:
|
||||
preconditionFailure()
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
self.link = link
|
||||
self.peers = peers
|
||||
|
||||
@ -930,7 +1066,7 @@ public class SendInviteLinkScreen: ViewControllerComponentContainer {
|
||||
self.blocksBackgroundWhenInOverlay = true
|
||||
|
||||
self.presenceDisposable = (context.engine.data.subscribe(EngineDataMap(
|
||||
peers.map(\.id).map(TelegramEngine.EngineData.Item.Peer.Presence.init(id:))
|
||||
peers.map(\.peer.id).map(TelegramEngine.EngineData.Item.Peer.Presence.init(id:))
|
||||
))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presences in
|
||||
guard let self else {
|
||||
|
@ -52,7 +52,7 @@ final class ComposeControllerNode: ASDisplayNode {
|
||||
ContactListAdditionalOption(title: self.presentationData.strings.Compose_NewChannel, icon: .generic(UIImage(bundleImageName: "Contact List/CreateChannelActionIcon")!), action: {
|
||||
openCreateNewChannelImpl?()
|
||||
})
|
||||
], includeChatList: false, topPeers: .none)), onlyWriteable: false, displayPermissionPlaceholder: false)
|
||||
], includeChatList: false, topPeers: .none)), onlyWriteable: false, isGroupInvitation: false, displayPermissionPlaceholder: false)
|
||||
|
||||
super.init()
|
||||
|
||||
|
@ -83,6 +83,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
private let options: [ContactListAdditionalOption]
|
||||
private let filters: [ContactListFilter]
|
||||
private let onlyWriteable: Bool
|
||||
private let isGroupInvitation: Bool
|
||||
private let limit: Int32?
|
||||
|
||||
init(_ params: ContactMultiselectionControllerParams) {
|
||||
@ -94,6 +95,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
self.options = params.options
|
||||
self.filters = params.filters
|
||||
self.onlyWriteable = params.onlyWriteable
|
||||
self.isGroupInvitation = params.isGroupInvitation
|
||||
self.limit = params.limit
|
||||
self.presentationData = params.updatedPresentationData?.initial ?? params.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
@ -302,7 +304,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
}
|
||||
|
||||
override func loadDisplayNode() {
|
||||
self.displayNode = ContactMultiselectionControllerNode(navigationBar: self.navigationBar, context: self.context, presentationData: self.presentationData, mode: self.mode, isPeerEnabled: self.isPeerEnabled, attemptDisabledItemSelection: self.attemptDisabledItemSelection, options: self.options, filters: self.filters, onlyWriteable: self.onlyWriteable, limit: self.limit, reachedSelectionLimit: self.params.reachedLimit, present: { [weak self] c, a in
|
||||
self.displayNode = ContactMultiselectionControllerNode(navigationBar: self.navigationBar, context: self.context, presentationData: self.presentationData, mode: self.mode, isPeerEnabled: self.isPeerEnabled, attemptDisabledItemSelection: self.attemptDisabledItemSelection, options: self.options, filters: self.filters, onlyWriteable: self.onlyWriteable, isGroupInvitation: self.isGroupInvitation, limit: self.limit, reachedSelectionLimit: self.params.reachedLimit, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
})
|
||||
switch self.contactsNode.contentNode {
|
||||
|
@ -78,8 +78,9 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
|
||||
private let isPeerEnabled: ((EnginePeer) -> Bool)?
|
||||
private let onlyWriteable: Bool
|
||||
private let isGroupInvitation: Bool
|
||||
|
||||
init(navigationBar: NavigationBar?, context: AccountContext, presentationData: PresentationData, mode: ContactMultiselectionControllerMode, isPeerEnabled: ((EnginePeer) -> Bool)?, attemptDisabledItemSelection: ((EnginePeer, ChatListDisabledPeerReason) -> Void)?, options: [ContactListAdditionalOption], filters: [ContactListFilter], onlyWriteable: Bool, limit: Int32?, reachedSelectionLimit: ((Int32) -> Void)?, present: @escaping (ViewController, Any?) -> Void) {
|
||||
init(navigationBar: NavigationBar?, context: AccountContext, presentationData: PresentationData, mode: ContactMultiselectionControllerMode, isPeerEnabled: ((EnginePeer) -> Bool)?, attemptDisabledItemSelection: ((EnginePeer, ChatListDisabledPeerReason) -> Void)?, options: [ContactListAdditionalOption], filters: [ContactListFilter], onlyWriteable: Bool, isGroupInvitation: Bool, limit: Int32?, reachedSelectionLimit: ((Int32) -> Void)?, present: @escaping (ViewController, Any?) -> Void) {
|
||||
self.navigationBar = navigationBar
|
||||
|
||||
self.context = context
|
||||
@ -90,6 +91,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
|
||||
self.isPeerEnabled = isPeerEnabled
|
||||
self.onlyWriteable = onlyWriteable
|
||||
self.isGroupInvitation = isGroupInvitation
|
||||
|
||||
var proceedImpl: (() -> Void)?
|
||||
|
||||
@ -231,7 +233,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
} else {
|
||||
displayTopPeers = .none
|
||||
}
|
||||
let contactListNode = ContactListNode(context: context, presentation: .single(.natural(options: options, includeChatList: includeChatList, topPeers: displayTopPeers)), filters: filters, onlyWriteable: onlyWriteable, selectionState: ContactListNodeGroupSelectionState())
|
||||
let contactListNode = ContactListNode(context: context, presentation: .single(.natural(options: options, includeChatList: includeChatList, topPeers: displayTopPeers)), filters: filters, onlyWriteable: onlyWriteable, isGroupInvitation: isGroupInvitation, selectionState: ContactListNodeGroupSelectionState())
|
||||
self.contentNode = .contacts(contactListNode)
|
||||
|
||||
if !selectedPeers.isEmpty {
|
||||
@ -359,7 +361,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
searchChannels: searchChannels,
|
||||
globalSearch: globalSearch,
|
||||
displaySavedMessages: displaySavedMessages
|
||||
))), filters: filters, onlyWriteable: strongSelf.onlyWriteable, isPeerEnabled: strongSelf.isPeerEnabled, selectionState: selectionState, isSearch: true)
|
||||
))), filters: filters, onlyWriteable: strongSelf.onlyWriteable, isGroupInvitation: strongSelf.isGroupInvitation, isPeerEnabled: strongSelf.isPeerEnabled, selectionState: selectionState, isSearch: true)
|
||||
searchResultsNode.openPeer = { peer, _ in
|
||||
self?.tokenListNode.setText("")
|
||||
self?.openPeer?(peer)
|
||||
|
@ -68,7 +68,7 @@ final class ContactSelectionControllerNode: ASDisplayNode {
|
||||
self.filters = filters
|
||||
|
||||
var contextActionImpl: ((EnginePeer, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?
|
||||
self.contactListNode = ContactListNode(context: context, updatedPresentationData: (presentationData, self.presentationDataPromise.get()), presentation: .single(.natural(options: options, includeChatList: false, topPeers: .none)), filters: filters, onlyWriteable: false, displayCallIcons: displayCallIcons, contextAction: multipleSelection ? { peer, node, gesture, _, _ in
|
||||
self.contactListNode = ContactListNode(context: context, updatedPresentationData: (presentationData, self.presentationDataPromise.get()), presentation: .single(.natural(options: options, includeChatList: false, topPeers: .none)), filters: filters, onlyWriteable: false, isGroupInvitation: false, displayCallIcons: displayCallIcons, contextAction: multipleSelection ? { peer, node, gesture, _, _ in
|
||||
contextActionImpl?(peer, node, gesture, nil)
|
||||
} : nil, multipleSelection: multipleSelection)
|
||||
|
||||
|
@ -676,7 +676,7 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
case .supergroup:
|
||||
createSignal = context.engine.peers.createSupergroup(title: title, description: nil)
|
||||
|> map { peerId -> CreateGroupResult? in
|
||||
return CreateGroupResult(peerId: peerId, failedToInvitePeerIds: [])
|
||||
return CreateGroupResult(peerId: peerId, result: TelegramInvitePeersResult(forbiddenPeers: []))
|
||||
}
|
||||
|> mapError { error -> CreateGroupError in
|
||||
switch error {
|
||||
@ -705,7 +705,7 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
}
|
||||
return context.engine.peers.createSupergroup(title: title, description: nil, location: (location.latitude, location.longitude, address))
|
||||
|> map { peerId -> CreateGroupResult? in
|
||||
return CreateGroupResult(peerId: peerId, failedToInvitePeerIds: [])
|
||||
return CreateGroupResult(peerId: peerId, result: TelegramInvitePeersResult(forbiddenPeers: []))
|
||||
}
|
||||
|> mapError { error -> CreateGroupError in
|
||||
switch error {
|
||||
@ -731,7 +731,7 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
let createGroupSignal: (Bool) -> Signal<CreateGroupResult?, CreateGroupError> = { isForum in
|
||||
return context.engine.peers.createSupergroup(title: title, description: nil, isForum: isForum)
|
||||
|> map { peerId -> CreateGroupResult? in
|
||||
return CreateGroupResult(peerId: peerId, failedToInvitePeerIds: [])
|
||||
return CreateGroupResult(peerId: peerId, result: TelegramInvitePeersResult(forbiddenPeers: []))
|
||||
}
|
||||
|> mapError { error -> CreateGroupError in
|
||||
switch error {
|
||||
@ -834,7 +834,7 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
let controller = ChatControllerImpl(context: context, chatLocation: .peer(id: result.peerId))
|
||||
replaceControllerImpl?(controller)
|
||||
|
||||
if !result.failedToInvitePeerIds.isEmpty {
|
||||
if !result.result.forbiddenPeers.isEmpty {
|
||||
context.account.viewTracker.forceUpdateCachedPeerData(peerId: result.peerId)
|
||||
let _ = (context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.ExportedInvitation(id: result.peerId)
|
||||
@ -847,26 +847,10 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: result.peerId)
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
let _ = controller
|
||||
let _ = exportedInvitation
|
||||
|
||||
if let peer, let exportedInvitation, let link = exportedInvitation.link {
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataList(result.failedToInvitePeerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:)))
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { peerItems in
|
||||
guard let controller else {
|
||||
return
|
||||
}
|
||||
let _ = controller
|
||||
let _ = peerItems
|
||||
|
||||
let peers = peerItems.compactMap { $0 }
|
||||
if !peers.isEmpty {
|
||||
let inviteScreen = SendInviteLinkScreen(context: context, peer: peer, link: link, peers: peers)
|
||||
controller.push(inviteScreen)
|
||||
}
|
||||
})
|
||||
|
||||
let inviteScreen = SendInviteLinkScreen(context: context, peer: peer, link: link, peers: result.result.forbiddenPeers)
|
||||
controller?.push(inviteScreen)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user