mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Update folders
This commit is contained in:
parent
c40b9abc69
commit
8d79979422
@ -9092,3 +9092,8 @@ Sorry for the inconvenience.";
|
|||||||
"StickerPacksSettings.SuggestAnimatedEmojiInfo" = "Each time you enter an emoji you can replace it with an animated emoji.";
|
"StickerPacksSettings.SuggestAnimatedEmojiInfo" = "Each time you enter an emoji you can replace it with an animated emoji.";
|
||||||
|
|
||||||
"DialogList.DeleteBotClearHistory" = "Clear Chat History";
|
"DialogList.DeleteBotClearHistory" = "Clear Chat History";
|
||||||
|
|
||||||
|
"ChatList.ChatFolderUpdateCount_1" = "1 new chat";
|
||||||
|
"ChatList.ChatFolderUpdateCount_any" = "%d new chats";
|
||||||
|
"ChatList.ChatFolderUpdateHintTitle" = "You can join %@";
|
||||||
|
"ChatList.ChatFolderUpdateHintText" = "Tap here to view them";
|
||||||
|
@ -89,6 +89,7 @@ swift_library(
|
|||||||
"//submodules/AvatarNode:AvatarNode",
|
"//submodules/AvatarNode:AvatarNode",
|
||||||
"//submodules/AvatarVideoNode:AvatarVideoNode",
|
"//submodules/AvatarVideoNode:AvatarVideoNode",
|
||||||
"//submodules/InviteLinksUI",
|
"//submodules/InviteLinksUI",
|
||||||
|
"//submodules/TelegramUI/Components/ChatFolderLinkPreviewScreen",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -2705,50 +2705,78 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func askForFilterRemoval(id: Int32) {
|
private func askForFilterRemoval(id: Int32) {
|
||||||
let actionSheet = ActionSheetController(presentationData: self.presentationData)
|
let apply: () -> Void = { [weak self] in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let commit: () -> Void = {
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if strongSelf.chatListDisplayNode.mainContainerNode.currentItemNode.chatListFilter?.id == id {
|
||||||
|
if strongSelf.chatListDisplayNode.mainContainerNode.currentItemNode.currentState.editing {
|
||||||
|
strongSelf.donePressed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = (strongSelf.context.engine.peers.updateChatListFiltersInteractively { filters in
|
||||||
|
return filters.filter({ $0.id != id })
|
||||||
|
}).start()
|
||||||
|
}
|
||||||
|
|
||||||
|
if strongSelf.chatListDisplayNode.mainContainerNode.currentItemNode.chatListFilter?.id == id {
|
||||||
|
strongSelf.chatListDisplayNode.mainContainerNode.switchToFilter(id: .all, completion: {
|
||||||
|
commit()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
actionSheet.setItemGroups([
|
let _ = (context.engine.peers.currentChatListFilters()
|
||||||
ActionSheetItemGroup(items: [
|
|> take(1)
|
||||||
ActionSheetTextItem(title: self.presentationData.strings.ChatList_RemoveFolderConfirmation),
|
|> deliverOnMainQueue).start(next: { [weak self] filters in
|
||||||
ActionSheetButtonItem(title: self.presentationData.strings.ChatList_RemoveFolderAction, color: .destructive, action: { [weak self, weak actionSheet] in
|
guard let self else {
|
||||||
actionSheet?.dismissAnimated()
|
return
|
||||||
|
}
|
||||||
guard let strongSelf = self else {
|
guard let filter = filters.first(where: { $0.id == id }) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let commit: () -> Void = {
|
if case let .filter(_, _, _, data) = filter, data.isShared {
|
||||||
guard let strongSelf = self else {
|
let presentationData = self.presentationData
|
||||||
return
|
|
||||||
}
|
//TODO:localize
|
||||||
|
self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Delete Folder", text: "Are you sure you want to delete this folder? This will also deactivate all the invite links used to share this folder.", actions: [
|
||||||
if strongSelf.chatListDisplayNode.mainContainerNode.currentItemNode.chatListFilter?.id == id {
|
TextAlertAction(type: .destructiveAction, title: presentationData.strings.Common_Delete, action: {
|
||||||
if strongSelf.chatListDisplayNode.mainContainerNode.currentItemNode.currentState.editing {
|
apply()
|
||||||
strongSelf.donePressed()
|
}),
|
||||||
}
|
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {
|
||||||
}
|
})
|
||||||
|
]), in: .window(.root))
|
||||||
let _ = (strongSelf.context.engine.peers.updateChatListFiltersInteractively { filters in
|
} else {
|
||||||
return filters.filter({ $0.id != id })
|
let actionSheet = ActionSheetController(presentationData: self.presentationData)
|
||||||
}).start()
|
|
||||||
}
|
actionSheet.setItemGroups([
|
||||||
|
ActionSheetItemGroup(items: [
|
||||||
if strongSelf.chatListDisplayNode.mainContainerNode.currentItemNode.chatListFilter?.id == id {
|
ActionSheetTextItem(title: self.presentationData.strings.ChatList_RemoveFolderConfirmation),
|
||||||
strongSelf.chatListDisplayNode.mainContainerNode.switchToFilter(id: .all, completion: {
|
ActionSheetButtonItem(title: self.presentationData.strings.ChatList_RemoveFolderAction, color: .destructive, action: { [weak actionSheet] in
|
||||||
commit()
|
actionSheet?.dismissAnimated()
|
||||||
|
|
||||||
|
apply()
|
||||||
})
|
})
|
||||||
} else {
|
]),
|
||||||
commit()
|
ActionSheetItemGroup(items: [
|
||||||
}
|
ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||||
})
|
actionSheet?.dismissAnimated()
|
||||||
]),
|
})
|
||||||
ActionSheetItemGroup(items: [
|
])
|
||||||
ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
])
|
||||||
actionSheet?.dismissAnimated()
|
self.present(actionSheet, in: .window(.root))
|
||||||
})
|
}
|
||||||
])
|
})
|
||||||
])
|
|
||||||
self.present(actionSheet, in: .window(.root))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public private(set) var isSearchActive: Bool = false
|
public private(set) var isSearchActive: Bool = false
|
||||||
|
@ -186,7 +186,7 @@ private final class ChatListShimmerNode: ASDisplayNode {
|
|||||||
let interaction = ChatListNodeInteraction(context: context, animationCache: animationCache, animationRenderer: animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _, _ in }, togglePeerSelected: { _, _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
let interaction = ChatListNodeInteraction(context: context, animationCache: animationCache, animationRenderer: animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _, _ in }, togglePeerSelected: { _, _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
||||||
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, setPeerThreadStopped: { _, _, _ in }, setPeerThreadPinned: { _, _, _ in }, setPeerThreadHidden: { _, _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, toggleThreadsSelection: { _, _ in }, hidePsa: { _ in }, activateChatPreview: { _, _, _, gesture, _ in
|
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, setPeerThreadStopped: { _, _, _ in }, setPeerThreadPinned: { _, _, _ in }, setPeerThreadHidden: { _, _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, toggleThreadsSelection: { _, _ in }, hidePsa: { _ in }, activateChatPreview: { _, _, _, gesture, _ in
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}, present: { _ in }, openForumThread: { _, _ in }, openStorageManagement: {}, openPasswordSetup: {}, openPremiumIntro: {})
|
}, present: { _ in }, openForumThread: { _, _ in }, openStorageManagement: {}, openPasswordSetup: {}, openPremiumIntro: {}, openChatFolderUpdates: {})
|
||||||
interaction.isInlineMode = isInlineMode
|
interaction.isInlineMode = isInlineMode
|
||||||
|
|
||||||
let items = (0 ..< 2).map { _ -> ChatListItem in
|
let items = (0 ..< 2).map { _ -> ChatListItem in
|
||||||
|
@ -380,32 +380,59 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
|
|||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
}, removePreset: { id in
|
}, removePreset: { id in
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let _ = (context.engine.peers.currentChatListFilters()
|
||||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).start(next: { filters in
|
||||||
actionSheet.setItemGroups([
|
guard let filter = filters.first(where: { $0.id == id }) else {
|
||||||
ActionSheetItemGroup(items: [
|
return
|
||||||
ActionSheetTextItem(title: presentationData.strings.ChatList_RemoveFolderConfirmation),
|
}
|
||||||
ActionSheetButtonItem(title: presentationData.strings.ChatList_RemoveFolderAction, color: .destructive, action: { [weak actionSheet] in
|
|
||||||
actionSheet?.dismissAnimated()
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
|
if case let .filter(_, _, _, data) = filter, data.isShared {
|
||||||
var filters = filters
|
//TODO:localize
|
||||||
if let index = filters.firstIndex(where: { $0.id == id }) {
|
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Delete Folder", text: "Are you sure you want to delete this folder? This will also deactivate all the invite links used to share this folder.", actions: [
|
||||||
filters.remove(at: index)
|
TextAlertAction(type: .destructiveAction, title: presentationData.strings.Common_Delete, action: {
|
||||||
|
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
|
||||||
|
var filters = filters
|
||||||
|
if let index = filters.firstIndex(where: { $0.id == id }) {
|
||||||
|
filters.remove(at: index)
|
||||||
|
}
|
||||||
|
return filters
|
||||||
}
|
}
|
||||||
return filters
|
|> deliverOnMainQueue).start()
|
||||||
}
|
}),
|
||||||
|> deliverOnMainQueue).start()
|
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {
|
||||||
})
|
})
|
||||||
]),
|
]))
|
||||||
ActionSheetItemGroup(items: [
|
} else {
|
||||||
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||||
actionSheet?.dismissAnimated()
|
|
||||||
})
|
actionSheet.setItemGroups([
|
||||||
])
|
ActionSheetItemGroup(items: [
|
||||||
])
|
ActionSheetTextItem(title: presentationData.strings.ChatList_RemoveFolderConfirmation),
|
||||||
presentControllerImpl?(actionSheet)
|
ActionSheetButtonItem(title: presentationData.strings.ChatList_RemoveFolderAction, color: .destructive, action: { [weak actionSheet] in
|
||||||
|
actionSheet?.dismissAnimated()
|
||||||
|
|
||||||
|
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
|
||||||
|
var filters = filters
|
||||||
|
if let index = filters.firstIndex(where: { $0.id == id }) {
|
||||||
|
filters.remove(at: index)
|
||||||
|
}
|
||||||
|
return filters
|
||||||
|
}
|
||||||
|
|> deliverOnMainQueue).start()
|
||||||
|
})
|
||||||
|
]),
|
||||||
|
ActionSheetItemGroup(items: [
|
||||||
|
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||||
|
actionSheet?.dismissAnimated()
|
||||||
|
})
|
||||||
|
])
|
||||||
|
])
|
||||||
|
presentControllerImpl?(actionSheet)
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
let featuredFilters = context.account.postbox.preferencesView(keys: [PreferencesKeys.chatListFiltersFeaturedState])
|
let featuredFilters = context.account.postbox.preferencesView(keys: [PreferencesKeys.chatListFiltersFeaturedState])
|
||||||
|
@ -2164,6 +2164,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
}, openStorageManagement: {
|
}, openStorageManagement: {
|
||||||
}, openPasswordSetup: {
|
}, openPasswordSetup: {
|
||||||
}, openPremiumIntro: {
|
}, openPremiumIntro: {
|
||||||
|
}, openChatFolderUpdates: {
|
||||||
})
|
})
|
||||||
chatListInteraction.isSearchMode = true
|
chatListInteraction.isSearchMode = true
|
||||||
|
|
||||||
@ -3397,7 +3398,7 @@ private final class ChatListSearchShimmerNode: ASDisplayNode {
|
|||||||
let interaction = ChatListNodeInteraction(context: context, animationCache: animationCache, animationRenderer: animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _, _ in }, togglePeerSelected: { _, _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
let interaction = ChatListNodeInteraction(context: context, animationCache: animationCache, animationRenderer: animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _, _ in }, togglePeerSelected: { _, _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
||||||
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, setPeerThreadStopped: { _, _, _ in }, setPeerThreadPinned: { _, _, _ in }, setPeerThreadHidden: { _, _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, toggleThreadsSelection: { _, _ in }, hidePsa: { _ in }, activateChatPreview: { _, _, _, gesture, _ in
|
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, setPeerThreadStopped: { _, _, _ in }, setPeerThreadPinned: { _, _, _ in }, setPeerThreadHidden: { _, _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, toggleThreadsSelection: { _, _ in }, hidePsa: { _ in }, activateChatPreview: { _, _, _, gesture, _ in
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}, present: { _ in }, openForumThread: { _, _ in }, openStorageManagement: {}, openPasswordSetup: {}, openPremiumIntro: {})
|
}, present: { _ in }, openForumThread: { _, _ in }, openStorageManagement: {}, openPasswordSetup: {}, openPremiumIntro: {}, openChatFolderUpdates: {})
|
||||||
var isInlineMode = false
|
var isInlineMode = false
|
||||||
if case .topics = key {
|
if case .topics = key {
|
||||||
isInlineMode = false
|
isInlineMode = false
|
||||||
|
@ -17,6 +17,7 @@ import PremiumUI
|
|||||||
import AnimationCache
|
import AnimationCache
|
||||||
import MultiAnimationRenderer
|
import MultiAnimationRenderer
|
||||||
import Postbox
|
import Postbox
|
||||||
|
import ChatFolderLinkPreviewScreen
|
||||||
|
|
||||||
public enum ChatListNodeMode {
|
public enum ChatListNodeMode {
|
||||||
case chatList
|
case chatList
|
||||||
@ -95,6 +96,7 @@ public final class ChatListNodeInteraction {
|
|||||||
let openStorageManagement: () -> Void
|
let openStorageManagement: () -> Void
|
||||||
let openPasswordSetup: () -> Void
|
let openPasswordSetup: () -> Void
|
||||||
let openPremiumIntro: () -> Void
|
let openPremiumIntro: () -> Void
|
||||||
|
let openChatFolderUpdates: () -> Void
|
||||||
|
|
||||||
public var searchTextHighightState: String?
|
public var searchTextHighightState: String?
|
||||||
var highlightedChatLocation: ChatListHighlightedLocation?
|
var highlightedChatLocation: ChatListHighlightedLocation?
|
||||||
@ -139,7 +141,8 @@ public final class ChatListNodeInteraction {
|
|||||||
openForumThread: @escaping (EnginePeer.Id, Int64) -> Void,
|
openForumThread: @escaping (EnginePeer.Id, Int64) -> Void,
|
||||||
openStorageManagement: @escaping () -> Void,
|
openStorageManagement: @escaping () -> Void,
|
||||||
openPasswordSetup: @escaping () -> Void,
|
openPasswordSetup: @escaping () -> Void,
|
||||||
openPremiumIntro: @escaping () -> Void
|
openPremiumIntro: @escaping () -> Void,
|
||||||
|
openChatFolderUpdates: @escaping () -> Void
|
||||||
) {
|
) {
|
||||||
self.activateSearch = activateSearch
|
self.activateSearch = activateSearch
|
||||||
self.peerSelected = peerSelected
|
self.peerSelected = peerSelected
|
||||||
@ -172,6 +175,7 @@ public final class ChatListNodeInteraction {
|
|||||||
self.openStorageManagement = openStorageManagement
|
self.openStorageManagement = openStorageManagement
|
||||||
self.openPasswordSetup = openPasswordSetup
|
self.openPasswordSetup = openPasswordSetup
|
||||||
self.openPremiumIntro = openPremiumIntro
|
self.openPremiumIntro = openPremiumIntro
|
||||||
|
self.openChatFolderUpdates = openChatFolderUpdates
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -620,6 +624,8 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
nodeInteraction?.openPasswordSetup()
|
nodeInteraction?.openPasswordSetup()
|
||||||
case .premiumUpgrade, .premiumAnnualDiscount:
|
case .premiumUpgrade, .premiumAnnualDiscount:
|
||||||
nodeInteraction?.openPremiumIntro()
|
nodeInteraction?.openPremiumIntro()
|
||||||
|
case .chatFolderUpdates:
|
||||||
|
nodeInteraction?.openChatFolderUpdates()
|
||||||
}
|
}
|
||||||
}), directionHint: entry.directionHint)
|
}), directionHint: entry.directionHint)
|
||||||
}
|
}
|
||||||
@ -873,6 +879,8 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
nodeInteraction?.openPasswordSetup()
|
nodeInteraction?.openPasswordSetup()
|
||||||
case .premiumUpgrade, .premiumAnnualDiscount:
|
case .premiumUpgrade, .premiumAnnualDiscount:
|
||||||
nodeInteraction?.openPremiumIntro()
|
nodeInteraction?.openPremiumIntro()
|
||||||
|
case .chatFolderUpdates:
|
||||||
|
nodeInteraction?.openChatFolderUpdates()
|
||||||
}
|
}
|
||||||
}), directionHint: entry.directionHint)
|
}), directionHint: entry.directionHint)
|
||||||
case .HeaderEntry:
|
case .HeaderEntry:
|
||||||
@ -1068,6 +1076,9 @@ public final class ChatListNode: ListView {
|
|||||||
|
|
||||||
let hideArhiveIntro = ValuePromise<Bool>(false, ignoreRepeated: true)
|
let hideArhiveIntro = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||||
|
|
||||||
|
private let chatFolderUpdates = Promise<ChatFolderUpdates?>(nil)
|
||||||
|
private var pollFilterUpdatesDisposable: Disposable?
|
||||||
|
|
||||||
public init(context: AccountContext, location: ChatListControllerLocation, chatListFilter: ChatListFilter? = nil, previewing: Bool, fillPreloadItems: Bool, mode: ChatListNodeMode, isPeerEnabled: ((EnginePeer) -> Bool)? = nil, theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, disableAnimations: Bool, isInlineMode: Bool) {
|
public init(context: AccountContext, location: ChatListControllerLocation, chatListFilter: ChatListFilter? = nil, previewing: Bool, fillPreloadItems: Bool, mode: ChatListNodeMode, isPeerEnabled: ((EnginePeer) -> Bool)? = nil, theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, disableAnimations: Bool, isInlineMode: Bool) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.location = location
|
self.location = location
|
||||||
@ -1389,6 +1400,19 @@ public final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
let controller = self.context.sharedContext.makePremiumIntroController(context: self.context, source: .ads)
|
let controller = self.context.sharedContext.makePremiumIntroController(context: self.context, source: .ads)
|
||||||
self.push?(controller)
|
self.push?(controller)
|
||||||
|
}, openChatFolderUpdates: { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let _ = (self.chatFolderUpdates.get()
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||||
|
guard let self, let result else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.push?(ChatFolderLinkPreviewScreen(context: self.context, subject: .updates(result), contents: result.chatFolderLinkContents))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
nodeInteraction.isInlineMode = isInlineMode
|
nodeInteraction.isInlineMode = isInlineMode
|
||||||
|
|
||||||
@ -1614,15 +1638,18 @@ public final class ChatListNode: ListView {
|
|||||||
suggestedChatListNotice,
|
suggestedChatListNotice,
|
||||||
savedMessagesPeer,
|
savedMessagesPeer,
|
||||||
chatListViewUpdate,
|
chatListViewUpdate,
|
||||||
|
self.chatFolderUpdates.get() |> distinctUntilChanged,
|
||||||
self.statePromise.get()
|
self.statePromise.get()
|
||||||
)
|
)
|
||||||
|> mapToQueue { (hideArchivedFolderByDefault, displayArchiveIntro, storageInfo, suggestedChatListNotice, savedMessagesPeer, updateAndFilter, state) -> Signal<ChatListNodeListViewTransition, NoError> in
|
|> mapToQueue { (hideArchivedFolderByDefault, displayArchiveIntro, storageInfo, suggestedChatListNotice, savedMessagesPeer, updateAndFilter, chatFolderUpdates, state) -> Signal<ChatListNodeListViewTransition, NoError> in
|
||||||
let (update, filter) = updateAndFilter
|
let (update, filter) = updateAndFilter
|
||||||
|
|
||||||
let previousHideArchivedFolderByDefaultValue = previousHideArchivedFolderByDefault.swap(hideArchivedFolderByDefault)
|
let previousHideArchivedFolderByDefaultValue = previousHideArchivedFolderByDefault.swap(hideArchivedFolderByDefault)
|
||||||
|
|
||||||
let notice: ChatListNotice?
|
let notice: ChatListNotice?
|
||||||
if let suggestedChatListNotice {
|
if let chatFolderUpdates, chatFolderUpdates.availableChatsToJoin != 0 {
|
||||||
|
notice = .chatFolderUpdates(count: chatFolderUpdates.availableChatsToJoin)
|
||||||
|
} else if let suggestedChatListNotice {
|
||||||
notice = suggestedChatListNotice
|
notice = suggestedChatListNotice
|
||||||
} else if let storageInfo {
|
} else if let storageInfo {
|
||||||
notice = .clearStorage(sizeFraction: storageInfo)
|
notice = .clearStorage(sizeFraction: storageInfo)
|
||||||
@ -2551,6 +2578,7 @@ public final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.pollFilterUpdates(shouldDelay: false)
|
||||||
self.resetFilter()
|
self.resetFilter()
|
||||||
|
|
||||||
let selectionRecognizer = ChatHistoryListSelectionRecognizer(target: self, action: #selector(self.selectionPanGesture(_:)))
|
let selectionRecognizer = ChatHistoryListSelectionRecognizer(target: self, action: #selector(self.selectionPanGesture(_:)))
|
||||||
@ -2567,6 +2595,7 @@ public final class ChatListNode: ListView {
|
|||||||
self.chatListDisposable.dispose()
|
self.chatListDisposable.dispose()
|
||||||
self.activityStatusesDisposable?.dispose()
|
self.activityStatusesDisposable?.dispose()
|
||||||
self.updatedFilterDisposable.dispose()
|
self.updatedFilterDisposable.dispose()
|
||||||
|
self.pollFilterUpdatesDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateFilter(_ filter: ChatListFilter?) {
|
func updateFilter(_ filter: ChatListFilter?) {
|
||||||
@ -2576,6 +2605,20 @@ public final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func pollFilterUpdates(shouldDelay: Bool) {
|
||||||
|
guard let chatListFilter, case let .filter(id, _, _, data) = chatListFilter, data.isShared else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.pollFilterUpdatesDisposable = (context.engine.peers.getChatFolderUpdates(folderId: id)
|
||||||
|
|> delay(shouldDelay ? 5.0 : 0.0, queue: .mainQueue())).start(next: { [weak self] result in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.chatFolderUpdates.set(.single(result))
|
||||||
|
self.pollFilterUpdates(shouldDelay: true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private func resetFilter() {
|
private func resetFilter() {
|
||||||
if let chatListFilter = self.chatListFilter {
|
if let chatListFilter = self.chatListFilter {
|
||||||
self.updatedFilterDisposable.set((self.context.engine.peers.updatedChatListFilters()
|
self.updatedFilterDisposable.set((self.context.engine.peers.updatedChatListFilters()
|
||||||
|
@ -51,6 +51,7 @@ enum ChatListNotice: Equatable {
|
|||||||
case setupPassword
|
case setupPassword
|
||||||
case premiumUpgrade(discount: Int32)
|
case premiumUpgrade(discount: Int32)
|
||||||
case premiumAnnualDiscount(discount: Int32)
|
case premiumAnnualDiscount(discount: Int32)
|
||||||
|
case chatFolderUpdates(count: Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ChatListNodeEntry: Comparable, Identifiable {
|
enum ChatListNodeEntry: Comparable, Identifiable {
|
||||||
|
@ -160,6 +160,15 @@ class ChatListStorageInfoItemNode: ListViewItemNode {
|
|||||||
titleString = titleStringValue
|
titleString = titleStringValue
|
||||||
|
|
||||||
textString = NSAttributedString(string: item.strings.ChatList_PremiumAnnualDiscountText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
|
textString = NSAttributedString(string: item.strings.ChatList_PremiumAnnualDiscountText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
|
||||||
|
case let .chatFolderUpdates(count):
|
||||||
|
let rawTitleString = item.strings.ChatList_ChatFolderUpdateHintTitle(item.strings.ChatList_ChatFolderUpdateCount(Int32(count)))
|
||||||
|
let titleStringValue = NSMutableAttributedString(attributedString: NSAttributedString(string: rawTitleString.string, font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor))
|
||||||
|
if let range = rawTitleString.ranges.first {
|
||||||
|
titleStringValue.addAttribute(.foregroundColor, value: item.theme.rootController.navigationBar.accentTextColor, range: range.range)
|
||||||
|
}
|
||||||
|
titleString = titleStringValue
|
||||||
|
|
||||||
|
textString = NSAttributedString(string: item.strings.ChatList_ChatFolderUpdateHintText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
let titleLayout = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - sideInset - rightInset, height: 100.0)))
|
let titleLayout = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - sideInset - rightInset, height: 100.0)))
|
||||||
|
@ -94,6 +94,7 @@ public final class HashtagSearchController: TelegramBaseController {
|
|||||||
}, openStorageManagement: {
|
}, openStorageManagement: {
|
||||||
}, openPasswordSetup: {
|
}, openPasswordSetup: {
|
||||||
}, openPremiumIntro: {
|
}, openPremiumIntro: {
|
||||||
|
}, openChatFolderUpdates: {
|
||||||
})
|
})
|
||||||
|
|
||||||
let previousSearchItems = Atomic<[ChatListSearchEntry]?>(value: nil)
|
let previousSearchItems = Atomic<[ChatListSearchEntry]?>(value: nil)
|
||||||
|
@ -222,7 +222,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
|||||||
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, setPeerThreadStopped: { _, _, _ in }, setPeerThreadPinned: { _, _, _ in }, setPeerThreadHidden: { _, _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, toggleThreadsSelection: { _, _ in }, hidePsa: { _ in
|
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, setPeerThreadStopped: { _, _, _ in }, setPeerThreadPinned: { _, _, _ in }, setPeerThreadHidden: { _, _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, toggleThreadsSelection: { _, _ in }, hidePsa: { _ in
|
||||||
}, activateChatPreview: { _, _, _, gesture, _ in
|
}, activateChatPreview: { _, _, _, gesture, _ in
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}, present: { _ in }, openForumThread: { _, _ in }, openStorageManagement: {}, openPasswordSetup: {}, openPremiumIntro: {})
|
}, present: { _ in }, openForumThread: { _, _ in }, openStorageManagement: {}, openPasswordSetup: {}, openPremiumIntro: {}, openChatFolderUpdates: {})
|
||||||
|
|
||||||
let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)
|
let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)
|
||||||
|
|
||||||
|
@ -843,7 +843,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
|||||||
}, activateChatPreview: { _, _, _, gesture, _ in
|
}, activateChatPreview: { _, _, _, gesture, _ in
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}, present: { _ in
|
}, present: { _ in
|
||||||
}, openForumThread: { _, _ in }, openStorageManagement: {}, openPasswordSetup: {}, openPremiumIntro: {})
|
}, openForumThread: { _, _ in }, openStorageManagement: {}, openPasswordSetup: {}, openPremiumIntro: {}, openChatFolderUpdates: {})
|
||||||
let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)
|
let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)
|
||||||
|
|
||||||
func makeChatListItem(
|
func makeChatListItem(
|
||||||
|
@ -367,7 +367,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}, activateChatPreview: { _, _, _, gesture, _ in
|
}, activateChatPreview: { _, _, _, gesture, _ in
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}, present: { _ in
|
}, present: { _ in
|
||||||
}, openForumThread: { _, _ in }, openStorageManagement: {}, openPasswordSetup: {}, openPremiumIntro: {} )
|
}, openForumThread: { _, _ in }, openStorageManagement: {}, openPasswordSetup: {}, openPremiumIntro: {}, openChatFolderUpdates: {})
|
||||||
|
|
||||||
func makeChatListItem(
|
func makeChatListItem(
|
||||||
peer: EnginePeer,
|
peer: EnginePeer,
|
||||||
|
@ -346,7 +346,7 @@ func _internal_joinChatFolderLink(account: Account, slug: String, peerIds: [Engi
|
|||||||
|> mapToSignal { inputPeers -> Signal<Never, JoinChatFolderLinkError> in
|
|> mapToSignal { inputPeers -> Signal<Never, JoinChatFolderLinkError> in
|
||||||
return account.network.request(Api.functions.communities.joinCommunityInvite(slug: slug, peers: inputPeers))
|
return account.network.request(Api.functions.communities.joinCommunityInvite(slug: slug, peers: inputPeers))
|
||||||
|> mapError { error -> JoinChatFolderLinkError in
|
|> mapError { error -> JoinChatFolderLinkError in
|
||||||
if error.errorDescription == "DIALOG_FILTERS_TOO_MUCH" {
|
if error.errorDescription.hasPrefix("DIALOG_FILTERS_TOO_MUCH") {
|
||||||
return .limitExceeded
|
return .limitExceeded
|
||||||
} else {
|
} else {
|
||||||
return .generic
|
return .generic
|
||||||
@ -360,7 +360,9 @@ func _internal_joinChatFolderLink(account: Account, slug: String, peerIds: [Engi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class ChatFolderUpdates {
|
public final class ChatFolderUpdates: Equatable {
|
||||||
|
fileprivate let folderId: Int32
|
||||||
|
fileprivate let title: String
|
||||||
fileprivate let missingPeers: [Api.Peer]
|
fileprivate let missingPeers: [Api.Peer]
|
||||||
fileprivate let chats: [Api.Chat]
|
fileprivate let chats: [Api.Chat]
|
||||||
fileprivate let users: [Api.User]
|
fileprivate let users: [Api.User]
|
||||||
@ -369,15 +371,44 @@ public final class ChatFolderUpdates {
|
|||||||
return self.missingPeers.count
|
return self.missingPeers.count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var chatFolderLinkContents: ChatFolderLinkContents {
|
||||||
|
var peers: [EnginePeer] = []
|
||||||
|
for missingPeer in self.missingPeers {
|
||||||
|
for chat in chats {
|
||||||
|
if chat.peerId == missingPeer.peerId {
|
||||||
|
if let peer = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
|
peers.append(EnginePeer(peer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChatFolderLinkContents(localFilterId: self.folderId, title: self.title, peers: peers, alreadyMemberPeerIds: Set())
|
||||||
|
}
|
||||||
|
|
||||||
fileprivate init(
|
fileprivate init(
|
||||||
|
folderId: Int32,
|
||||||
|
title: String,
|
||||||
missingPeers: [Api.Peer],
|
missingPeers: [Api.Peer],
|
||||||
chats: [Api.Chat],
|
chats: [Api.Chat],
|
||||||
users: [Api.User]
|
users: [Api.User]
|
||||||
) {
|
) {
|
||||||
|
self.folderId = folderId
|
||||||
|
self.title = title
|
||||||
self.missingPeers = missingPeers
|
self.missingPeers = missingPeers
|
||||||
self.chats = chats
|
self.chats = chats
|
||||||
self.users = users
|
self.users = users
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: ChatFolderUpdates, rhs: ChatFolderUpdates) -> Bool {
|
||||||
|
if lhs.folderId != rhs.folderId {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.missingPeers.map(\.peerId) != rhs.missingPeers.map(\.peerId) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func _internal_getChatFolderUpdates(account: Account, folderId: Int32) -> Signal<ChatFolderUpdates?, NoError> {
|
func _internal_getChatFolderUpdates(account: Account, folderId: Int32) -> Signal<ChatFolderUpdates?, NoError> {
|
||||||
@ -392,18 +423,25 @@ func _internal_getChatFolderUpdates(account: Account, folderId: Int32) -> Signal
|
|||||||
}
|
}
|
||||||
switch result {
|
switch result {
|
||||||
case let .communityUpdates(missingPeers, chats, users):
|
case let .communityUpdates(missingPeers, chats, users):
|
||||||
return .single(ChatFolderUpdates(missingPeers: missingPeers, chats: chats, users: users))
|
return account.postbox.transaction { transaction -> ChatFolderUpdates? in
|
||||||
|
for filter in _internal_currentChatListFilters(transaction: transaction) {
|
||||||
|
if case let .filter(id, title, _, _) = filter, id == folderId {
|
||||||
|
return ChatFolderUpdates(folderId: folderId, title: title, missingPeers: missingPeers, chats: chats, users: users)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func _internal_joinAvailableChatsInFolder(account: Account, folderId: Int32, peerIds: [EnginePeer.Id]) -> Signal<Never, JoinChatFolderLinkError> {
|
func _internal_joinAvailableChatsInFolder(account: Account, updates: ChatFolderUpdates, peerIds: [EnginePeer.Id]) -> Signal<Never, JoinChatFolderLinkError> {
|
||||||
return account.postbox.transaction { transaction -> [Api.InputPeer] in
|
return account.postbox.transaction { transaction -> [Api.InputPeer] in
|
||||||
return peerIds.compactMap(transaction.getPeer).compactMap(apiInputPeer)
|
return peerIds.compactMap(transaction.getPeer).compactMap(apiInputPeer)
|
||||||
}
|
}
|
||||||
|> castError(JoinChatFolderLinkError.self)
|
|> castError(JoinChatFolderLinkError.self)
|
||||||
|> mapToSignal { inputPeers -> Signal<Never, JoinChatFolderLinkError> in
|
|> mapToSignal { inputPeers -> Signal<Never, JoinChatFolderLinkError> in
|
||||||
return account.network.request(Api.functions.communities.joinCommunityUpdates(community: .inputCommunityDialogFilter(filterId: folderId), peers: inputPeers))
|
return account.network.request(Api.functions.communities.joinCommunityUpdates(community: .inputCommunityDialogFilter(filterId: updates.folderId), peers: inputPeers))
|
||||||
|> mapError { error -> JoinChatFolderLinkError in
|
|> mapError { error -> JoinChatFolderLinkError in
|
||||||
if error.errorDescription == "DIALOG_FILTERS_TOO_MUCH" {
|
if error.errorDescription == "DIALOG_FILTERS_TOO_MUCH" {
|
||||||
return .limitExceeded
|
return .limitExceeded
|
||||||
|
@ -1054,8 +1054,8 @@ public extension TelegramEngine {
|
|||||||
return _internal_getChatFolderUpdates(account: self.account, folderId: folderId)
|
return _internal_getChatFolderUpdates(account: self.account, folderId: folderId)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func joinAvailableChatsInFolder(folderId: Int32, peerIds: [EnginePeer.Id]) -> Signal<Never, JoinChatFolderLinkError> {
|
public func joinAvailableChatsInFolder(updates: ChatFolderUpdates, peerIds: [EnginePeer.Id]) -> Signal<Never, JoinChatFolderLinkError> {
|
||||||
return _internal_joinAvailableChatsInFolder(account: self.account, folderId: folderId, peerIds: peerIds)
|
return _internal_joinAvailableChatsInFolder(account: self.account, updates: updates, peerIds: peerIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func hideChatFolderUpdates(folderId: Int32) -> Signal<Never, NoError> {
|
public func hideChatFolderUpdates(folderId: Int32) -> Signal<Never, NoError> {
|
||||||
|
@ -21,16 +21,16 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
|
|||||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||||
|
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let slug: String
|
let subject: ChatFolderLinkPreviewScreen.Subject
|
||||||
let linkContents: ChatFolderLinkContents?
|
let linkContents: ChatFolderLinkContents?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
slug: String,
|
subject: ChatFolderLinkPreviewScreen.Subject,
|
||||||
linkContents: ChatFolderLinkContents?
|
linkContents: ChatFolderLinkContents?
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.slug = slug
|
self.subject = subject
|
||||||
self.linkContents = linkContents
|
self.linkContents = linkContents
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
|
|||||||
if lhs.context !== rhs.context {
|
if lhs.context !== rhs.context {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if lhs.slug != rhs.slug {
|
if lhs.subject != rhs.subject {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if lhs.linkContents !== rhs.linkContents {
|
if lhs.linkContents !== rhs.linkContents {
|
||||||
@ -660,7 +660,15 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
|
|||||||
|
|
||||||
if let _ = component.linkContents {
|
if let _ = component.linkContents {
|
||||||
if self.joinDisposable == nil, !self.selectedItems.isEmpty {
|
if self.joinDisposable == nil, !self.selectedItems.isEmpty {
|
||||||
self.joinDisposable = (component.context.engine.peers.joinChatFolderLink(slug: component.slug, peerIds: Array(self.selectedItems))
|
let joinSignal: Signal<Never, JoinChatFolderLinkError>
|
||||||
|
switch component.subject {
|
||||||
|
case let .slug(slug):
|
||||||
|
joinSignal = component.context.engine.peers.joinChatFolderLink(slug: slug, peerIds: Array(self.selectedItems))
|
||||||
|
case let .updates(updates):
|
||||||
|
joinSignal = component.context.engine.peers.joinAvailableChatsInFolder(updates: updates, peerIds: Array(self.selectedItems))
|
||||||
|
}
|
||||||
|
|
||||||
|
self.joinDisposable = (joinSignal
|
||||||
|> deliverOnMainQueue).start(error: { [weak self] error in
|
|> deliverOnMainQueue).start(error: { [weak self] error in
|
||||||
guard let self, let component = self.component, let controller = self.environment?.controller() else {
|
guard let self, let component = self.component, let controller = self.environment?.controller() else {
|
||||||
return
|
return
|
||||||
@ -782,29 +790,33 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class ChatFolderLinkPreviewScreen: ViewControllerComponentContainer {
|
public class ChatFolderLinkPreviewScreen: ViewControllerComponentContainer {
|
||||||
|
public enum Subject: Equatable {
|
||||||
|
case slug(String)
|
||||||
|
case updates(ChatFolderUpdates)
|
||||||
|
}
|
||||||
|
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private var linkContents: ChatFolderLinkContents?
|
|
||||||
private var linkContentsDisposable: Disposable?
|
private var linkContentsDisposable: Disposable?
|
||||||
|
|
||||||
private var isDismissed: Bool = false
|
private var isDismissed: Bool = false
|
||||||
|
|
||||||
public init(context: AccountContext, slug: String) {
|
public init(context: AccountContext, subject: Subject, contents: ChatFolderLinkContents) {
|
||||||
self.context = context
|
self.context = context
|
||||||
|
|
||||||
super.init(context: context, component: ChatFolderLinkPreviewScreenComponent(context: context, slug: slug, linkContents: nil), navigationBarAppearance: .none)
|
super.init(context: context, component: ChatFolderLinkPreviewScreenComponent(context: context, subject: subject, linkContents: contents), navigationBarAppearance: .none)
|
||||||
|
|
||||||
self.statusBar.statusBarStyle = .Ignore
|
self.statusBar.statusBarStyle = .Ignore
|
||||||
self.navigationPresentation = .flatModal
|
self.navigationPresentation = .flatModal
|
||||||
self.blocksBackgroundWhenInOverlay = true
|
self.blocksBackgroundWhenInOverlay = true
|
||||||
|
self.automaticallyControlPresentationContextLayout = false
|
||||||
|
|
||||||
self.linkContentsDisposable = (context.engine.peers.checkChatFolderLink(slug: slug)
|
/*self.linkContentsDisposable = (context.engine.peers.checkChatFolderLink(subject: subject)
|
||||||
|> delay(0.2, queue: .mainQueue())
|
|> delay(0.2, queue: .mainQueue())
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.linkContents = result
|
self.updateComponent(component: AnyComponent(ChatFolderLinkPreviewScreenComponent(context: context, subject: subject, linkContents: result)), transition: Transition(animation: .curve(duration: 0.2, curve: .easeInOut)).withUserData(ChatFolderLinkPreviewScreenComponent.AnimationHint()))
|
||||||
self.updateComponent(component: AnyComponent(ChatFolderLinkPreviewScreenComponent(context: context, slug: slug, linkContents: result)), transition: Transition(animation: .curve(duration: 0.2, curve: .easeInOut)).withUserData(ChatFolderLinkPreviewScreenComponent.AnimationHint()))
|
|
||||||
}, error: { [weak self] _ in
|
}, error: { [weak self] _ in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
@ -812,9 +824,7 @@ public class ChatFolderLinkPreviewScreen: ViewControllerComponentContainer {
|
|||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
self.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: "The folder link has expired."), elevatedLayout: false, action: { _ in true }), in: .window(.root))
|
self.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: "The folder link has expired."), elevatedLayout: false, action: { _ in true }), in: .window(.root))
|
||||||
self.dismiss()
|
self.dismiss()
|
||||||
})
|
})*/
|
||||||
|
|
||||||
self.automaticallyControlPresentationContextLayout = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(coder aDecoder: NSCoder) {
|
required public init(coder aDecoder: NSCoder) {
|
||||||
|
@ -265,6 +265,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
|
|||||||
}, openStorageManagement: {
|
}, openStorageManagement: {
|
||||||
}, openPasswordSetup: {
|
}, openPasswordSetup: {
|
||||||
}, openPremiumIntro: {
|
}, openPremiumIntro: {
|
||||||
|
}, openChatFolderUpdates: {
|
||||||
})
|
})
|
||||||
interaction.searchTextHighightState = searchQuery
|
interaction.searchTextHighightState = searchQuery
|
||||||
self.interaction = interaction
|
self.interaction = interaction
|
||||||
|
@ -753,7 +753,48 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
|||||||
}
|
}
|
||||||
case let .chatFolder(slug):
|
case let .chatFolder(slug):
|
||||||
if let navigationController = navigationController {
|
if let navigationController = navigationController {
|
||||||
navigationController.pushViewController(ChatFolderLinkPreviewScreen(context: context, slug: slug))
|
let signal = context.engine.peers.checkChatFolderLink(slug: slug)
|
||||||
|
|
||||||
|
var cancelImpl: (() -> Void)?
|
||||||
|
let progressSignal = Signal<Never, NoError> { subscriber in
|
||||||
|
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
|
||||||
|
cancelImpl?()
|
||||||
|
}))
|
||||||
|
present(controller, nil)
|
||||||
|
return ActionDisposable { [weak controller] in
|
||||||
|
Queue.mainQueue().async() {
|
||||||
|
controller?.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> runOn(Queue.mainQueue())
|
||||||
|
|> delay(0.35, queue: Queue.mainQueue())
|
||||||
|
|
||||||
|
let disposable = MetaDisposable()
|
||||||
|
let progressDisposable = progressSignal.start()
|
||||||
|
cancelImpl = {
|
||||||
|
disposable.set(nil)
|
||||||
|
}
|
||||||
|
disposable.set((signal
|
||||||
|
|> afterDisposed {
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
progressDisposable.dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak navigationController] result in
|
||||||
|
guard let navigationController else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
navigationController.pushViewController(ChatFolderLinkPreviewScreen(context: context, subject: .slug(slug), contents: result))
|
||||||
|
}, error: { error in
|
||||||
|
let errorText: String
|
||||||
|
switch error {
|
||||||
|
case .generic:
|
||||||
|
errorText = "The folder link has expired."
|
||||||
|
}
|
||||||
|
present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||||
|
}))
|
||||||
|
dismissInput()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user