Folder updates

This commit is contained in:
Ali
2023-03-31 19:28:06 +04:00
parent 33ffaffc8d
commit dfdde96d63
38 changed files with 738 additions and 209 deletions

View File

@@ -73,7 +73,7 @@ public enum AdminLogEventAction {
case deleteExportedInvitation(ExportedInvitation)
case revokeExportedInvitation(ExportedInvitation)
case editExportedInvitation(previous: ExportedInvitation, updated: ExportedInvitation)
case participantJoinedViaInvite(ExportedInvitation)
case participantJoinedViaInvite(invitation: ExportedInvitation, joinedViaFolderLink: Bool)
case changeHistoryTTL(previousValue: Int32?, updatedValue: Int32?)
case changeTheme(previous: String?, updated: String?)
case participantJoinByRequest(invitation: ExportedInvitation, approvedBy: PeerId)
@@ -268,8 +268,8 @@ func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: PeerId, m
action = .revokeExportedInvitation(ExportedInvitation(apiExportedInvite: invite))
case let .channelAdminLogEventActionExportedInviteEdit(prevInvite, newInvite):
action = .editExportedInvitation(previous: ExportedInvitation(apiExportedInvite: prevInvite), updated: ExportedInvitation(apiExportedInvite: newInvite))
case let .channelAdminLogEventActionParticipantJoinByInvite(invite):
action = .participantJoinedViaInvite(ExportedInvitation(apiExportedInvite: invite))
case let .channelAdminLogEventActionParticipantJoinByInvite(flags, invite):
action = .participantJoinedViaInvite(invitation: ExportedInvitation(apiExportedInvite: invite), joinedViaFolderLink: (flags & (1 << 0)) != 0)
case let .channelAdminLogEventActionParticipantVolume(participant):
let parsedParticipant = GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate(participant)
action = .groupCallUpdateParticipantVolume(peerId: parsedParticipant.peerId, volume: parsedParticipant.volume ?? 10000)

View File

@@ -389,30 +389,46 @@ extension ChatListFilter {
case .allChats:
return nil
case let .filter(id, title, emoticon, data):
var flags: Int32 = 0
if data.excludeMuted {
flags |= 1 << 11
}
if data.excludeRead {
flags |= 1 << 12
}
if data.excludeArchived {
flags |= 1 << 13
}
flags |= data.categories.apiFlags
if emoticon != nil {
flags |= 1 << 25
}
return .dialogFilter(flags: flags, id: id, title: title, emoticon: emoticon, pinnedPeers: data.includePeers.pinnedPeers.compactMap { peerId -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}, includePeers: data.includePeers.peers.compactMap { peerId -> Api.InputPeer? in
if data.includePeers.pinnedPeers.contains(peerId) {
return nil
if data.isShared {
var flags: Int32 = 0
if emoticon != nil {
flags |= 1 << 25
}
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}, excludePeers: data.excludePeers.compactMap { peerId -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
})
return .dialogFilterCommunity(flags: flags, id: id, title: title, emoticon: emoticon, pinnedPeers: data.includePeers.pinnedPeers.compactMap { peerId -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}, includePeers: data.includePeers.peers.compactMap { peerId -> Api.InputPeer? in
if data.includePeers.pinnedPeers.contains(peerId) {
return nil
}
return transaction.getPeer(peerId).flatMap(apiInputPeer)
})
} else {
var flags: Int32 = 0
if data.excludeMuted {
flags |= 1 << 11
}
if data.excludeRead {
flags |= 1 << 12
}
if data.excludeArchived {
flags |= 1 << 13
}
flags |= data.categories.apiFlags
if emoticon != nil {
flags |= 1 << 25
}
return .dialogFilter(flags: flags, id: id, title: title, emoticon: emoticon, pinnedPeers: data.includePeers.pinnedPeers.compactMap { peerId -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}, includePeers: data.includePeers.peers.compactMap { peerId -> Api.InputPeer? in
if data.includePeers.pinnedPeers.contains(peerId) {
return nil
}
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}, excludePeers: data.excludePeers.compactMap { peerId -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
})
}
}
}
}
@@ -873,14 +889,21 @@ private func loadAndStorePeerChatInfos(accountPeerId: PeerId, postbox: Postbox,
struct ChatListFiltersState: Codable, Equatable {
struct ChatListFilterUpdates: Codable, Equatable {
struct MemberCount: Codable, Equatable {
var id: PeerId
var count: Int32
}
var folderId: Int32
var timestamp: Int32
var peerIds: [PeerId]
var memberCounts: [MemberCount]
init(folderId: Int32, timestamp: Int32, peerIds: [PeerId]) {
init(folderId: Int32, timestamp: Int32, peerIds: [PeerId], memberCounts: [MemberCount]) {
self.folderId = folderId
self.timestamp = timestamp
self.peerIds = peerIds
self.memberCounts = memberCounts
}
}

View File

@@ -7,7 +7,7 @@ public func canShareLinkToPeer(peer: EnginePeer) -> Bool {
var isEnabled = false
switch peer {
case let .channel(channel):
if channel.adminRights != nil && channel.hasPermission(.inviteMembers) {
if channel.flags.contains(.isCreator) || (channel.adminRights?.rights.contains(.canInviteUsers) == true) {
isEnabled = true
} else if channel.username != nil {
isEnabled = true
@@ -237,17 +237,20 @@ public final class ChatFolderLinkContents {
public let title: String?
public let peers: [EnginePeer]
public let alreadyMemberPeerIds: Set<EnginePeer.Id>
public let memberCounts: [EnginePeer.Id: Int]
public init(
localFilterId: Int32?,
title: String?,
peers: [EnginePeer],
alreadyMemberPeerIds: Set<EnginePeer.Id>
alreadyMemberPeerIds: Set<EnginePeer.Id>,
memberCounts: [EnginePeer.Id: Int]
) {
self.localFilterId = localFilterId
self.title = title
self.peers = peers
self.alreadyMemberPeerIds = alreadyMemberPeerIds
self.memberCounts = memberCounts
}
}
@@ -264,6 +267,7 @@ func _internal_checkChatFolderLink(account: Account, slug: String) -> Signal<Cha
var allPeers: [Peer] = []
var peerPresences: [PeerId: Api.User] = [:]
var memberCounts: [PeerId: Int] = [:]
for user in users {
let telegramUser = TelegramUser(user: user)
@@ -274,6 +278,11 @@ func _internal_checkChatFolderLink(account: Account, slug: String) -> Signal<Cha
if let peer = parseTelegramGroupOrChannel(chat: chat) {
allPeers.append(peer)
}
if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _) = chat {
if let participantsCount = participantsCount {
memberCounts[chat.peerId] = Int(participantsCount)
}
}
}
updatePeers(transaction: transaction, peers: allPeers, update: { _, updated -> Peer in
@@ -294,12 +303,13 @@ func _internal_checkChatFolderLink(account: Account, slug: String) -> Signal<Cha
}
alreadyMemberPeerIds.removeAll()
return ChatFolderLinkContents(localFilterId: nil, title: title, peers: resultPeers, alreadyMemberPeerIds: alreadyMemberPeerIds)
return ChatFolderLinkContents(localFilterId: nil, title: title, peers: resultPeers, alreadyMemberPeerIds: alreadyMemberPeerIds, memberCounts: memberCounts)
case let .communityInviteAlready(filterId, missingPeers, alreadyPeers, chats, users):
let _ = alreadyPeers
var allPeers: [Peer] = []
var peerPresences: [PeerId: Api.User] = [:]
var memberCounts: [PeerId: Int] = [:]
for user in users {
let telegramUser = TelegramUser(user: user)
@@ -310,6 +320,11 @@ func _internal_checkChatFolderLink(account: Account, slug: String) -> Signal<Cha
if let peer = parseTelegramGroupOrChannel(chat: chat) {
allPeers.append(peer)
}
if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _) = chat {
if let participantsCount = participantsCount {
memberCounts[chat.peerId] = Int(participantsCount)
}
}
}
updatePeers(transaction: transaction, peers: allPeers, update: { _, updated -> Peer in
@@ -356,7 +371,7 @@ func _internal_checkChatFolderLink(account: Account, slug: String) -> Signal<Cha
}
}
return ChatFolderLinkContents(localFilterId: filterId, title: currentFilterTitle, peers: resultPeers, alreadyMemberPeerIds: alreadyMemberPeerIds)
return ChatFolderLinkContents(localFilterId: filterId, title: currentFilterTitle, peers: resultPeers, alreadyMemberPeerIds: alreadyMemberPeerIds, memberCounts: memberCounts)
}
}
|> castError(CheckChatFolderLinkError.self)
@@ -370,12 +385,31 @@ public enum JoinChatFolderLinkError {
case tooManyChannels(limit: Int32, premiumLimit: Int32)
}
func _internal_joinChatFolderLink(account: Account, slug: String, peerIds: [EnginePeer.Id]) -> Signal<Never, JoinChatFolderLinkError> {
return account.postbox.transaction { transaction -> [Api.InputPeer] in
return peerIds.compactMap(transaction.getPeer).compactMap(apiInputPeer)
public final class JoinChatFolderResult {
public let folderId: Int32
public let title: String
public let newChatCount: Int
public init(folderId: Int32, title: String, newChatCount: Int) {
self.folderId = folderId
self.title = title
self.newChatCount = newChatCount
}
}
func _internal_joinChatFolderLink(account: Account, slug: String, peerIds: [EnginePeer.Id]) -> Signal<JoinChatFolderResult, JoinChatFolderLinkError> {
return account.postbox.transaction { transaction -> ([Api.InputPeer], Int) in
var newChatCount = 0
for peerId in peerIds {
if transaction.getPeerChatListIndex(peerId) != nil {
newChatCount += 1
}
}
return (peerIds.compactMap(transaction.getPeer).compactMap(apiInputPeer), newChatCount)
}
|> castError(JoinChatFolderLinkError.self)
|> mapToSignal { inputPeers -> Signal<Never, JoinChatFolderLinkError> in
|> mapToSignal { inputPeers, newChatCount -> Signal<JoinChatFolderResult, JoinChatFolderLinkError> in
return account.network.request(Api.functions.communities.joinCommunityInvite(slug: slug, peers: inputPeers))
|> `catch` { error -> Signal<Api.Updates, JoinChatFolderLinkError> in
if error.errorDescription == "USER_CHANNELS_TOO_MUCH" {
@@ -427,10 +461,36 @@ func _internal_joinChatFolderLink(account: Account, slug: String, peerIds: [Engi
return .fail(.generic)
}
}
|> mapToSignal { result -> Signal<Never, JoinChatFolderLinkError> in
|> mapToSignal { result -> Signal<JoinChatFolderResult, JoinChatFolderLinkError> in
account.stateManager.addUpdates(result)
return .complete()
var folderResult: JoinChatFolderResult?
for update in result.allUpdates {
if case let .updateDialogFilter(_, id, data) = update {
if let data = data, case let .filter(_, title, _, _) = ChatListFilter(apiFilter: data) {
folderResult = JoinChatFolderResult(folderId: id, title: title, newChatCount: newChatCount)
}
break
}
}
if let folderResult = folderResult {
return _internal_updatedChatListFilters(postbox: account.postbox)
|> castError(JoinChatFolderLinkError.self)
|> filter { filters -> Bool in
if filters.contains(where: { $0.id == folderResult.folderId }) {
return true
} else {
return false
}
}
|> take(1)
|> map { _ -> JoinChatFolderResult in
return folderResult
}
} else {
return .fail(.generic)
}
}
}
}
@@ -439,23 +499,26 @@ public final class ChatFolderUpdates: Equatable {
fileprivate let folderId: Int32
fileprivate let title: String
fileprivate let missingPeers: [EnginePeer]
fileprivate let memberCounts: [EnginePeer.Id: Int]
public var availableChatsToJoin: Int {
return self.missingPeers.count
}
public var chatFolderLinkContents: ChatFolderLinkContents {
return ChatFolderLinkContents(localFilterId: self.folderId, title: self.title, peers: self.missingPeers, alreadyMemberPeerIds: Set())
return ChatFolderLinkContents(localFilterId: self.folderId, title: self.title, peers: self.missingPeers, alreadyMemberPeerIds: Set(), memberCounts: self.memberCounts)
}
fileprivate init(
folderId: Int32,
title: String,
missingPeers: [EnginePeer]
missingPeers: [EnginePeer],
memberCounts: [EnginePeer.Id: Int]
) {
self.folderId = folderId
self.title = title
self.missingPeers = missingPeers
self.memberCounts = memberCounts
}
public static func ==(lhs: ChatFolderUpdates, rhs: ChatFolderUpdates) -> Bool {
@@ -513,7 +576,7 @@ func _internal_pollChatFolderUpdatesOnce(account: Account, folderId: Int32) -> S
var state = state
state.updates.removeAll(where: { $0.folderId == folderId })
state.updates.append(ChatListFiltersState.ChatListFilterUpdates(folderId: folderId, timestamp: Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970), peerIds: []))
state.updates.append(ChatListFiltersState.ChatListFilterUpdates(folderId: folderId, timestamp: Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970), peerIds: [], memberCounts: []))
return state
})
@@ -525,6 +588,7 @@ func _internal_pollChatFolderUpdatesOnce(account: Account, folderId: Int32) -> S
return account.postbox.transaction { transaction -> Void in
var peers: [Peer] = []
var peerPresences: [PeerId: Api.User] = [:]
var memberCounts: [ChatListFiltersState.ChatListFilterUpdates.MemberCount] = []
for user in users {
let telegramUser = TelegramUser(user: user)
@@ -535,6 +599,11 @@ func _internal_pollChatFolderUpdatesOnce(account: Account, folderId: Int32) -> S
if let peer = parseTelegramGroupOrChannel(chat: chat) {
peers.append(peer)
}
if case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _) = chat {
if let participantsCount = participantsCount {
memberCounts.append(ChatListFiltersState.ChatListFilterUpdates.MemberCount(id: chat.peerId, count: participantsCount))
}
}
}
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
@@ -546,7 +615,7 @@ func _internal_pollChatFolderUpdatesOnce(account: Account, folderId: Int32) -> S
var state = state
state.updates.removeAll(where: { $0.folderId == folderId })
state.updates.append(ChatListFiltersState.ChatListFilterUpdates(folderId: folderId, timestamp: Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970), peerIds: missingPeers.map(\.peerId)))
state.updates.append(ChatListFiltersState.ChatListFilterUpdates(folderId: folderId, timestamp: Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970), peerIds: missingPeers.map(\.peerId), memberCounts: memberCounts))
return state
})
@@ -561,6 +630,7 @@ func _internal_subscribedChatFolderUpdates(account: Account, folderId: Int32) ->
struct InternalData: Equatable {
var title: String
var peerIds: [EnginePeer.Id]
var memberCounts: [EnginePeer.Id: Int]
}
return _internal_updatedChatListFiltersState(postbox: account.postbox)
@@ -575,7 +645,11 @@ func _internal_subscribedChatFolderUpdates(account: Account, folderId: Int32) ->
return nil
}
let filteredPeerIds: [PeerId] = update.peerIds.filter { !data.includePeers.peers.contains($0) }
return InternalData(title: title, peerIds: filteredPeerIds)
var memberCounts: [PeerId: Int] = [:]
for item in update.memberCounts {
memberCounts[item.id] = Int(item.count)
}
return InternalData(title: title, peerIds: filteredPeerIds, memberCounts: memberCounts)
}
|> distinctUntilChanged
|> mapToSignal { internalData -> Signal<ChatFolderUpdates?, NoError> in
@@ -592,7 +666,7 @@ func _internal_subscribedChatFolderUpdates(account: Account, folderId: Int32) ->
peers.append(EnginePeer(peer))
}
}
return ChatFolderUpdates(folderId: folderId, title: internalData.title, missingPeers: peers)
return ChatFolderUpdates(folderId: folderId, title: internalData.title, missingPeers: peers, memberCounts: internalData.memberCounts)
}
}
}

View File

@@ -664,6 +664,7 @@ public struct PeerInvitationImportersState: Equatable {
public var date: Int32
public var about: String?
public var approvedBy: PeerId?
public var joinedViaFolderLink: Bool
}
public var importers: [Importer]
public var isLoadingMore: Bool
@@ -708,6 +709,7 @@ final class CachedPeerInvitationImporters: Codable {
let peerIds: [PeerId]
let dates: [PeerId: Int32]
let abouts: [PeerId: String]
let joinedViaFolderLink: [PeerId: Bool]
let count: Int32
static func key(peerId: PeerId, link: String, requested: Bool) -> ValueBoxKey {
@@ -727,13 +729,17 @@ final class CachedPeerInvitationImporters: Codable {
$0[$1.peer.peerId] = about
}
}
self.joinedViaFolderLink = importers.reduce(into: [PeerId: Bool]()) {
$0[$1.peer.peerId] = $1.joinedViaFolderLink
}
self.count = count
}
init(peerIds: [PeerId], dates: [PeerId: Int32], abouts: [PeerId: String], count: Int32) {
init(peerIds: [PeerId], dates: [PeerId: Int32], abouts: [PeerId: String], joinedViaFolderLink: [PeerId: Bool], count: Int32) {
self.peerIds = peerIds
self.dates = dates
self.abouts = abouts
self.joinedViaFolderLink = joinedViaFolderLink
self.count = count
}
@@ -752,6 +758,16 @@ final class CachedPeerInvitationImporters: Codable {
}
self.dates = dates
var joinedViaFolderLink: [PeerId: Bool] = [:]
let joinedViaFolderLinkArray = try container.decode([Int64].self, forKey: "joinedViaFolderLink")
for index in stride(from: 0, to: joinedViaFolderLinkArray.endIndex, by: 2) {
let userId = datesArray[index]
let value = datesArray[index + 1]
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
joinedViaFolderLink[peerId] = value != 0
}
self.joinedViaFolderLink = joinedViaFolderLink
var abouts: [PeerId: String] = [:]
let aboutsArray = try container.decodeIfPresent([DictionaryPair].self, forKey: "abouts")
if let aboutsArray = aboutsArray {
@@ -777,6 +793,13 @@ final class CachedPeerInvitationImporters: Codable {
}
try container.encode(dates, forKey: "dates")
var joinedViaFolderLink: [Int64] = []
for (peerId, value) in self.joinedViaFolderLink {
joinedViaFolderLink.append(peerId.id._internalGetInt64Value())
joinedViaFolderLink.append(Int64(value ? 1 : 0))
}
try container.encode(joinedViaFolderLink, forKey: "joinedViaFolderLink")
var abouts: [DictionaryPair] = []
for (peerId, about) in self.abouts {
abouts.append(DictionaryPair(peerId.id._internalGetInt64Value(), value: about))
@@ -847,7 +870,7 @@ private final class PeerInvitationImportersContextImpl {
var result: [PeerInvitationImportersState.Importer] = []
for peerId in cachedResult.peerIds {
if let peer = transaction.getPeer(peerId), let date = cachedResult.dates[peerId] {
result.append(PeerInvitationImportersState.Importer(peer: RenderedPeer(peer: peer), date: date, about: cachedResult.abouts[peerId]))
result.append(PeerInvitationImportersState.Importer(peer: RenderedPeer(peer: peer), date: date, about: cachedResult.abouts[peerId], joinedViaFolderLink: cachedResult.joinedViaFolderLink[peerId] ?? false))
} else {
return nil
}
@@ -958,15 +981,17 @@ private final class PeerInvitationImportersContextImpl {
let date: Int32
let about: String?
let approvedBy: PeerId?
let joinedViaFolderLink: Bool
switch importer {
case let .chatInviteImporter(_, userId, dateValue, aboutValue, approvedByValue):
case let .chatInviteImporter(flags, userId, dateValue, aboutValue, approvedByValue):
joinedViaFolderLink = (flags & (1 << 3)) != 0
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
date = dateValue
about = aboutValue
approvedBy = approvedByValue.flatMap { PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value($0)) }
}
if let peer = transaction.getPeer(peerId) {
resultImporters.append(PeerInvitationImportersState.Importer(peer: RenderedPeer(peer: peer), date: date, about: about, approvedBy: approvedBy))
resultImporters.append(PeerInvitationImportersState.Importer(peer: RenderedPeer(peer: peer), date: date, about: about, approvedBy: approvedBy, joinedViaFolderLink: joinedViaFolderLink))
}
}
if populateCache && query == nil {

View File

@@ -1054,7 +1054,7 @@ public extension TelegramEngine {
return _internal_checkChatFolderLink(account: self.account, slug: slug)
}
public func joinChatFolderLink(slug: String, peerIds: [EnginePeer.Id]) -> Signal<Never, JoinChatFolderLinkError> {
public func joinChatFolderLink(slug: String, peerIds: [EnginePeer.Id]) -> Signal<JoinChatFolderResult, JoinChatFolderLinkError> {
return _internal_joinChatFolderLink(account: self.account, slug: slug, peerIds: peerIds)
}