Convert legacy group to supergroup

This commit is contained in:
Ali 2023-03-27 18:56:27 +04:00
parent fbc393c51c
commit 1b79f229c3
4 changed files with 155 additions and 47 deletions

View File

@ -9,7 +9,7 @@ public enum ConvertGroupToSupergroupError {
case tooManyChannels
}
func _internal_convertGroupToSupergroup(account: Account, peerId: PeerId) -> Signal<PeerId, ConvertGroupToSupergroupError> {
func _internal_convertGroupToSupergroup(account: Account, peerId: PeerId, additionalProcessing: ((EnginePeer.Id) -> Signal<Never, NoError>)?) -> Signal<PeerId, ConvertGroupToSupergroupError> {
return account.network.request(Api.functions.messages.migrateChat(chatId: peerId.id._internalGetInt64Value()))
|> mapError { error -> ConvertGroupToSupergroupError in
if error.errorDescription == "CHANNELS_TOO_MUCH" {
@ -20,7 +20,6 @@ func _internal_convertGroupToSupergroup(account: Account, peerId: PeerId) -> Sig
}
|> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic))
|> mapToSignal { updates -> Signal<PeerId, ConvertGroupToSupergroupError> in
account.stateManager.addUpdates(updates)
var createdPeerId: PeerId?
for message in updates.messages {
if apiMessagePeerId(message) != peerId {
@ -30,19 +29,35 @@ func _internal_convertGroupToSupergroup(account: Account, peerId: PeerId) -> Sig
}
if let createdPeerId = createdPeerId {
return account.postbox.multiplePeersView([createdPeerId])
|> filter { view in
return view.peers[createdPeerId] != nil
let additionalProcessingValue: Signal<Never, NoError> = additionalProcessing?(createdPeerId) ?? Signal<Never, NoError>.complete()
return additionalProcessingValue
|> map { _ -> Bool in }
|> castError(ConvertGroupToSupergroupError.self)
|> then(Signal<Bool, ConvertGroupToSupergroupError>.single(true))
|> mapToSignal { _ ->Signal<PeerId, ConvertGroupToSupergroupError> in
account.stateManager.addUpdates(updates)
return _internal_fetchAndUpdateCachedPeerData(accountPeerId: account.peerId, peerId: createdPeerId, network: account.network, postbox: account.postbox)
|> castError(ConvertGroupToSupergroupError.self)
|> mapToSignal { _ -> Signal<PeerId, ConvertGroupToSupergroupError> in
return account.postbox.multiplePeersView([createdPeerId])
|> filter { view in
return view.peers[createdPeerId] != nil
}
|> take(1)
|> map { _ in
return createdPeerId
}
|> mapError { _ -> ConvertGroupToSupergroupError in
}
|> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic))
}
}
|> take(1)
|> map { _ in
return createdPeerId
}
|> mapError { _ -> ConvertGroupToSupergroupError in
}
|> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic))
} else {
account.stateManager.addUpdates(updates)
return .fail(.generic)
}
return .fail(.generic)
}
}

View File

@ -134,8 +134,8 @@ public extension TelegramEngine {
return _internal_chatOnlineMembers(postbox: self.account.postbox, network: self.account.network, peerId: peerId)
}
public func convertGroupToSupergroup(peerId: PeerId) -> Signal<PeerId, ConvertGroupToSupergroupError> {
return _internal_convertGroupToSupergroup(account: self.account, peerId: peerId)
public func convertGroupToSupergroup(peerId: PeerId, additionalProcessing: ((EnginePeer.Id) -> Signal<Never, NoError>)? = nil) -> Signal<PeerId, ConvertGroupToSupergroupError> {
return _internal_convertGroupToSupergroup(account: self.account, peerId: peerId, additionalProcessing: additionalProcessing)
}
public func createGroup(title: String, peerIds: [PeerId], ttlPeriod: Int32?) -> Signal<CreateGroupResult?, CreateGroupError> {

View File

@ -350,40 +350,42 @@ enum PeerInfoMembersData: Equatable {
}
private func peerInfoScreenInputData(context: AccountContext, peerId: EnginePeer.Id, isSettings: Bool) -> Signal<PeerInfoScreenInputData, NoError> {
return context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|> map { peer -> PeerInfoScreenInputData in
guard let peer = peer else {
return .none
}
if case let .user(user) = peer {
if isSettings && user.id == context.account.peerId {
return .settings
} else {
let kind: PeerInfoScreenInputUserKind
if user.flags.contains(.isSupport) {
kind = .support
} else if user.botInfo != nil {
kind = .bot
return `deferred` {
return context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|> mapToSignal { peer -> Signal<PeerInfoScreenInputData, NoError> in
guard let peer = peer else {
return .single(.none)
}
if case let .user(user) = peer {
if isSettings && user.id == context.account.peerId {
return .single(.settings)
} else {
kind = .user
let kind: PeerInfoScreenInputUserKind
if user.flags.contains(.isSupport) {
kind = .support
} else if user.botInfo != nil {
kind = .bot
} else {
kind = .user
}
return .single(.user(userId: user.id, secretChatId: nil, kind: kind))
}
return .user(userId: user.id, secretChatId: nil, kind: kind)
}
} else if case let .channel(channel) = peer {
if case .group = channel.info {
return .group(groupId: channel.id)
} else if case let .channel(channel) = peer {
if case .group = channel.info {
return .single(.group(groupId: channel.id))
} else {
return .single(.channel)
}
} else if case let .legacyGroup(group) = peer {
return .single(.group(groupId: group.id))
} else if case let .secretChat(secretChat) = peer {
return .single(.user(userId: secretChat.regularPeerId, secretChatId: peer.id, kind: .user))
} else {
return .channel
return .single(.none)
}
} else if case let .legacyGroup(group) = peer {
return .group(groupId: group.id)
} else if case let .secretChat(secretChat) = peer {
return .user(userId: secretChat.regularPeerId, secretChatId: peer.id, kind: .user)
} else {
return .none
}
|> distinctUntilChanged
}
|> distinctUntilChanged
}
func keepPeerInfoScreenDataHot(context: AccountContext, peerId: PeerId, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>) -> Signal<Never, NoError> {
@ -547,6 +549,8 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, isSettings: Bool, hintGroupInCommon: PeerId?, existingRequestsContext: PeerInvitationImportersContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>) -> Signal<PeerInfoScreenData, NoError> {
return peerInfoScreenInputData(context: context, peerId: peerId, isSettings: isSettings)
|> mapToSignal { inputData -> Signal<PeerInfoScreenData, NoError> in
let wasUpgradedGroup = Atomic<Bool?>(value: nil)
switch inputData {
case .none, .settings:
return .single(PeerInfoScreenData(
@ -914,7 +918,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
threadData,
context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
)
|> map { peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests, threadData, preferencesView -> PeerInfoScreenData in
|> mapToSignal { peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests, threadData, preferencesView -> Signal<PeerInfoScreenData, NoError> in
var discussionPeer: Peer?
if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] {
discussionPeer = peer
@ -931,6 +935,11 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
var canManageInvitations = false
if let group = peerViewMainPeer(peerView) as? TelegramGroup {
let previousValue = wasUpgradedGroup.swap(group.migrationReference != nil)
if group.migrationReference != nil, let previousValue, !previousValue {
return .never()
}
if case .creator = group.role {
canManageInvitations = true
} else if case let .admin(rights, _) = group.role, rights.rights.contains(.canInviteUsers) {
@ -960,7 +969,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue
return PeerInfoScreenData(
return .single(PeerInfoScreenData(
peer: peerView.peers[groupId],
chatPeer: peerView.peers[groupId],
cachedData: peerView.cachedData,
@ -981,7 +990,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
threadData: threadData,
appConfiguration: appConfiguration,
isPowerSavingEnabled: nil
)
))
}
}
}

View File

@ -1823,6 +1823,8 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
let ItemAdmins = 105
let ItemMemberRequests = 106
let ItemReactions = 107
let ItemTopics = 108
let ItemTopicsText = 109
var canViewAdminsAndBanned = false
@ -1852,6 +1854,33 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
interaction.editingOpenPreHistorySetup()
}))
var canSetupTopics = false
if case .creator = group.role {
canSetupTopics = true
}
var topicsLimitedReason: TopicsLimitedReason?
if let appConfiguration = data.appConfiguration {
var minParticipants = 200
if let data = appConfiguration.data, let value = data["forum_upgrade_participants_min"] as? Double {
minParticipants = Int(value)
}
if Int(group.participantCount) < minParticipants {
topicsLimitedReason = .participants(minParticipants)
}
}
if canSetupTopics {
items[.peerPublicSettings]!.append(PeerInfoScreenSwitchItem(id: ItemTopics, text: presentationData.strings.PeerInfo_OptionTopics, value: false, icon: UIImage(bundleImageName: "Settings/Menu/Topics"), isLocked: topicsLimitedReason != nil, toggled: { value in
if let topicsLimitedReason = topicsLimitedReason {
interaction.displayTopicsLimited(topicsLimitedReason)
} else {
interaction.toggleForumTopics(value)
}
}))
items[.peerPublicSettings]!.append(PeerInfoScreenCommentItem(id: ItemTopicsText, text: presentationData.strings.PeerInfo_OptionTopicsText))
}
let label: String
if let cachedData = data.cachedData as? CachedGroupData, case let .known(allowedReactions) = cachedData.allowedReactions {
switch allowedReactions {
@ -2228,7 +2257,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.peers.setChannelForumMode(id: strongSelf.peerId, isForum: value).start()
strongSelf.toggleForumTopics(isEnabled: value)
},
displayTopicsLimited: { [weak self] reason in
guard let self else {
@ -6515,6 +6544,61 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
self.controller?.push(peerAllowedReactionListController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: peer.id))
}
private func toggleForumTopics(isEnabled: Bool) {
guard let data = self.data, let peer = data.peer else {
return
}
if peer is TelegramGroup {
if isEnabled {
let context = self.context
let signal: Signal<EnginePeer.Id?, NoError> = self.context.engine.peers.convertGroupToSupergroup(peerId: self.peerId, additionalProcessing: { upgradedPeerId -> Signal<Never, NoError> in
return context.engine.peers.setChannelForumMode(id: upgradedPeerId, isForum: isEnabled)
})
|> map(Optional.init)
|> `catch` { [weak self] error -> Signal<PeerId?, NoError> in
switch error {
case .tooManyChannels:
Queue.mainQueue().async {
self?.controller?.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 .single(upgradedPeerId)
}
|> deliverOnMainQueue
let _ = signal.start(next: { [weak self] resultPeerId in
guard let self else {
return
}
guard let resultPeerId else {
return
}
let _ = (self.context.engine.peers.setChannelForumMode(id: resultPeerId, isForum: isEnabled)
|> deliverOnMainQueue).start(completed: { [weak self] in
guard let self, let controller = self.controller else {
return
}
/*if let navigationController = controller.navigationController as? NavigationController {
rebuildControllerStackAfterSupergroupUpgrade(controller: controller, navigationController: navigationController)
}*/
controller.dismiss()
})
})
}
} else {
let _ = self.context.engine.peers.setChannelForumMode(id: self.peerId, isForum: isEnabled).start()
}
}
private func editingToggleMessageSignatures(value: Bool) {
self.toggleShouldChannelMessagesSignaturesDisposable.set(self.context.engine.peers.toggleShouldChannelMessagesSignatures(peerId: self.peerId, enabled: value).start())
}