mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Saved messages view as chats
This commit is contained in:
parent
ea9c9ae777
commit
4bd4884887
@ -881,7 +881,8 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
hasUnseenCloseFriends: stats.hasUnseenCloseFriends
|
||||
)
|
||||
},
|
||||
requiresPremiumForMessaging: requiresPremiumForMessaging
|
||||
requiresPremiumForMessaging: requiresPremiumForMessaging,
|
||||
displayAsTopicList: false
|
||||
)), editing: false, hasActiveRevealControls: false, selected: false, header: tagMask == nil ? header : nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||
}
|
||||
case let .addContact(phoneNumber, theme, strings):
|
||||
@ -3743,7 +3744,8 @@ public final class ChatListSearchShimmerNode: ASDisplayNode {
|
||||
topForumTopicItems: [],
|
||||
autoremoveTimeout: nil,
|
||||
storyState: nil,
|
||||
requiresPremiumForMessaging: false
|
||||
requiresPremiumForMessaging: false,
|
||||
displayAsTopicList: false
|
||||
)), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||
case .media:
|
||||
return nil
|
||||
|
@ -208,7 +208,8 @@ public final class ChatListShimmerNode: ASDisplayNode {
|
||||
topForumTopicItems: [],
|
||||
autoremoveTimeout: nil,
|
||||
storyState: nil,
|
||||
requiresPremiumForMessaging: false
|
||||
requiresPremiumForMessaging: false,
|
||||
displayAsTopicList: false
|
||||
)), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||
}
|
||||
|
||||
|
@ -97,6 +97,7 @@ public enum ChatListItemContent {
|
||||
public var autoremoveTimeout: Int32?
|
||||
public var storyState: StoryState?
|
||||
public var requiresPremiumForMessaging: Bool
|
||||
public var displayAsTopicList: Bool
|
||||
|
||||
public init(
|
||||
messages: [EngineMessage],
|
||||
@ -117,7 +118,8 @@ public enum ChatListItemContent {
|
||||
topForumTopicItems: [EngineChatList.ForumTopicData],
|
||||
autoremoveTimeout: Int32?,
|
||||
storyState: StoryState?,
|
||||
requiresPremiumForMessaging: Bool
|
||||
requiresPremiumForMessaging: Bool,
|
||||
displayAsTopicList: Bool
|
||||
) {
|
||||
self.messages = messages
|
||||
self.peer = peer
|
||||
@ -138,6 +140,7 @@ public enum ChatListItemContent {
|
||||
self.autoremoveTimeout = autoremoveTimeout
|
||||
self.storyState = storyState
|
||||
self.requiresPremiumForMessaging = requiresPremiumForMessaging
|
||||
self.displayAsTopicList = displayAsTopicList
|
||||
}
|
||||
}
|
||||
|
||||
@ -1417,11 +1420,17 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
} else if peer.isDeleted {
|
||||
overrideImage = .deletedIcon
|
||||
}
|
||||
var isForum = false
|
||||
var isForumAvatar = false
|
||||
if case let .channel(channel) = peer, channel.flags.contains(.isForum) {
|
||||
isForum = true
|
||||
isForumAvatar = true
|
||||
}
|
||||
self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, clipStyle: isForum ? .roundedRect : .round, synchronousLoad: synchronousLoads, displayDimensions: CGSize(width: 60.0, height: 60.0))
|
||||
if case let .peer(data) = item.content {
|
||||
if data.displayAsTopicList {
|
||||
isForumAvatar = true
|
||||
}
|
||||
}
|
||||
|
||||
self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, clipStyle: isForumAvatar ? .roundedRect : .round, synchronousLoad: synchronousLoads, displayDimensions: CGSize(width: 60.0, height: 60.0))
|
||||
|
||||
if peer.isPremium && peer.id != item.context.account.peerId {
|
||||
let context = item.context
|
||||
|
@ -427,7 +427,8 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
||||
hasUnseenCloseFriends: storyState.hasUnseenCloseFriends
|
||||
)
|
||||
},
|
||||
requiresPremiumForMessaging: peerEntry.requiresPremiumForMessaging
|
||||
requiresPremiumForMessaging: peerEntry.requiresPremiumForMessaging,
|
||||
displayAsTopicList: peerEntry.displayAsTopicList
|
||||
)),
|
||||
editing: editing,
|
||||
hasActiveRevealControls: hasActiveRevealControls,
|
||||
@ -796,7 +797,8 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
||||
hasUnseenCloseFriends: storyState.hasUnseenCloseFriends
|
||||
)
|
||||
},
|
||||
requiresPremiumForMessaging: peerEntry.requiresPremiumForMessaging
|
||||
requiresPremiumForMessaging: peerEntry.requiresPremiumForMessaging,
|
||||
displayAsTopicList: peerEntry.displayAsTopicList
|
||||
)),
|
||||
editing: editing,
|
||||
hasActiveRevealControls: hasActiveRevealControls,
|
||||
@ -1278,6 +1280,8 @@ public final class ChatListNode: ListView {
|
||||
public let isMainTab = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||
private let suggestedChatListNotice = Promise<ChatListNotice?>(nil)
|
||||
|
||||
public var synchronousDrawingWhenNotAnimated: Bool = false
|
||||
|
||||
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, autoSetReady: Bool, isMainTab: Bool?) {
|
||||
self.context = context
|
||||
self.location = location
|
||||
@ -1977,39 +1981,6 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
|
||||
let currentPeerId: EnginePeer.Id = context.account.peerId
|
||||
|
||||
/*let contactList: Signal<EngineContactList?, NoError>
|
||||
if case let .chatList(appendContacts) = mode, appendContacts {
|
||||
contactList = self.context.engine.data.subscribe(TelegramEngine.EngineData.Item.Contacts.List(includePresences: true))
|
||||
|> map(Optional.init)
|
||||
} else {
|
||||
contactList = .single(nil)
|
||||
}
|
||||
let _ = contactList*/
|
||||
|
||||
|
||||
/*let emptyInitialView = ChatListNodeView(
|
||||
originalList: EngineChatList(
|
||||
items: [],
|
||||
groupItems: [],
|
||||
additionalItems: [],
|
||||
hasEarlier: false,
|
||||
hasLater: false,
|
||||
isLoading: false
|
||||
),
|
||||
filteredEntries: [ChatListNodeEntry.HeaderEntry],
|
||||
isLoading: false,
|
||||
filter: nil
|
||||
)
|
||||
let _ = previousView.swap(emptyInitialView)
|
||||
|
||||
let _ = (preparedChatListNodeViewTransition(from: nil, to: emptyInitialView, reason: .initial, previewing: previewing, disableAnimations: disableAnimations, account: context.account, scrollPosition: nil, searchMode: false)
|
||||
|> map { mappedChatListNodeViewListTransition(context: context, nodeInteraction: nodeInteraction, location: location, filterData: nil, mode: mode, isPeerEnabled: nil, transition: $0) }).start(next: { [weak self] value in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = self.enqueueTransition(value).start()
|
||||
})*/
|
||||
|
||||
let contacts: Signal<[ChatListContactPeer], NoError>
|
||||
if case .chatList(groupId: .root) = location, chatListFilter == nil, case .chatList = mode {
|
||||
@ -3414,7 +3385,7 @@ public final class ChatListNode: ListView {
|
||||
|
||||
var options = transition.options
|
||||
//options.insert(.Synchronous)
|
||||
if self.view.window != nil {
|
||||
if self.view.window != nil || self.synchronousDrawingWhenNotAnimated {
|
||||
if !options.contains(.AnimateInsertion) {
|
||||
options.insert(.PreferSynchronousDrawing)
|
||||
options.insert(.PreferSynchronousResourceLoading)
|
||||
|
@ -115,6 +115,7 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
||||
var revealed: Bool
|
||||
var storyState: ChatListNodeState.StoryState?
|
||||
var requiresPremiumForMessaging: Bool
|
||||
var displayAsTopicList: Bool
|
||||
|
||||
init(
|
||||
index: EngineChatList.Item.Index,
|
||||
@ -140,7 +141,8 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
||||
topForumTopicItems: [EngineChatList.ForumTopicData],
|
||||
revealed: Bool,
|
||||
storyState: ChatListNodeState.StoryState?,
|
||||
requiresPremiumForMessaging: Bool
|
||||
requiresPremiumForMessaging: Bool,
|
||||
displayAsTopicList: Bool
|
||||
) {
|
||||
self.index = index
|
||||
self.presentationData = presentationData
|
||||
@ -166,6 +168,7 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
||||
self.revealed = revealed
|
||||
self.storyState = storyState
|
||||
self.requiresPremiumForMessaging = requiresPremiumForMessaging
|
||||
self.displayAsTopicList = displayAsTopicList
|
||||
}
|
||||
|
||||
static func ==(lhs: PeerEntryData, rhs: PeerEntryData) -> Bool {
|
||||
@ -281,6 +284,9 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
||||
if lhs.requiresPremiumForMessaging != rhs.requiresPremiumForMessaging {
|
||||
return false
|
||||
}
|
||||
if lhs.displayAsTopicList != rhs.displayAsTopicList {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -708,7 +714,8 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState,
|
||||
hasUnseenCloseFriends: stats.hasUnseenCloseFriends
|
||||
)
|
||||
},
|
||||
requiresPremiumForMessaging: false
|
||||
requiresPremiumForMessaging: false,
|
||||
displayAsTopicList: entry.displayAsTopicList
|
||||
))
|
||||
|
||||
if let threadInfo, threadInfo.isHidden {
|
||||
@ -759,7 +766,8 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState,
|
||||
topForumTopicItems: [],
|
||||
revealed: false,
|
||||
storyState: nil,
|
||||
requiresPremiumForMessaging: false
|
||||
requiresPremiumForMessaging: false,
|
||||
displayAsTopicList: false
|
||||
)))
|
||||
if foundPinningIndex != 0 {
|
||||
foundPinningIndex -= 1
|
||||
@ -791,7 +799,8 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState,
|
||||
topForumTopicItems: [],
|
||||
revealed: false,
|
||||
storyState: nil,
|
||||
requiresPremiumForMessaging: false
|
||||
requiresPremiumForMessaging: false,
|
||||
displayAsTopicList: false
|
||||
)))
|
||||
} else {
|
||||
if !filteredAdditionalItemEntries.isEmpty {
|
||||
@ -843,7 +852,8 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState,
|
||||
topForumTopicItems: item.item.topForumTopicItems,
|
||||
revealed: state.hiddenItemShouldBeTemporaryRevealed || state.editing,
|
||||
storyState: nil,
|
||||
requiresPremiumForMessaging: false
|
||||
requiresPremiumForMessaging: false,
|
||||
displayAsTopicList: false
|
||||
)))
|
||||
if pinningIndex != 0 {
|
||||
pinningIndex -= 1
|
||||
|
@ -114,6 +114,8 @@ public func chatListFilterPredicate(filter: ChatListFilterData, accountPeerId: E
|
||||
}
|
||||
|
||||
func chatListViewForLocation(chatListLocation: ChatListControllerLocation, location: ChatListNodeLocation, account: Account) -> Signal<ChatListNodeViewUpdate, NoError> {
|
||||
let accountPeerId = account.peerId
|
||||
|
||||
switch chatListLocation {
|
||||
case let .chatList(groupId):
|
||||
let filterPredicate: ChatListFilterPredicate?
|
||||
@ -129,7 +131,7 @@ func chatListViewForLocation(chatListLocation: ChatListControllerLocation, locat
|
||||
signal = account.viewTracker.tailChatListView(groupId: groupId._asGroup(), filterPredicate: filterPredicate, count: count)
|
||||
return signal
|
||||
|> map { view, updateType -> ChatListNodeViewUpdate in
|
||||
return ChatListNodeViewUpdate(list: EngineChatList(view), type: updateType, scrollPosition: nil)
|
||||
return ChatListNodeViewUpdate(list: EngineChatList(view, accountPeerId: accountPeerId), type: updateType, scrollPosition: nil)
|
||||
}
|
||||
case let .navigation(index, _):
|
||||
guard case let .chatList(index) = index else {
|
||||
@ -145,7 +147,7 @@ func chatListViewForLocation(chatListLocation: ChatListControllerLocation, locat
|
||||
} else {
|
||||
genericType = updateType
|
||||
}
|
||||
return ChatListNodeViewUpdate(list: EngineChatList(view), type: genericType, scrollPosition: nil)
|
||||
return ChatListNodeViewUpdate(list: EngineChatList(view, accountPeerId: accountPeerId), type: genericType, scrollPosition: nil)
|
||||
}
|
||||
case let .scroll(index, sourceIndex, scrollPosition, animated, _):
|
||||
guard case let .chatList(index) = index else {
|
||||
@ -165,7 +167,7 @@ func chatListViewForLocation(chatListLocation: ChatListControllerLocation, locat
|
||||
} else {
|
||||
genericType = updateType
|
||||
}
|
||||
return ChatListNodeViewUpdate(list: EngineChatList(view), type: genericType, scrollPosition: scrollPosition)
|
||||
return ChatListNodeViewUpdate(list: EngineChatList(view, accountPeerId: accountPeerId), type: genericType, scrollPosition: scrollPosition)
|
||||
}
|
||||
}
|
||||
case let .forum(peerId):
|
||||
@ -292,7 +294,8 @@ func chatListViewForLocation(chatListLocation: ChatListControllerLocation, locat
|
||||
hasFailed: false,
|
||||
isContact: false,
|
||||
autoremoveTimeout: nil,
|
||||
storyStats: nil
|
||||
storyStats: nil,
|
||||
displayAsTopicList: false
|
||||
))
|
||||
}
|
||||
|
||||
@ -356,7 +359,8 @@ func chatListViewForLocation(chatListLocation: ChatListControllerLocation, locat
|
||||
hasFailed: false,
|
||||
isContact: false,
|
||||
autoremoveTimeout: nil,
|
||||
storyStats: nil
|
||||
storyStats: nil,
|
||||
displayAsTopicList: false
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -500,7 +500,7 @@ public final class NavigationButtonNode: ContextControllerSourceNode {
|
||||
var totalHeight: CGFloat = 0.0
|
||||
for i in 0 ..< self.nodes.count {
|
||||
if i != 0 {
|
||||
nodeOrigin.x += 10.0
|
||||
nodeOrigin.x += 15.0
|
||||
}
|
||||
|
||||
let node = self.nodes[i]
|
||||
|
@ -566,6 +566,9 @@ final class MutableChatListView {
|
||||
|
||||
private var currentHiddenPeerIds = Set<PeerId>()
|
||||
|
||||
private let displaySavedMessagesAsTopicListPreferencesKey: ValueBoxKey
|
||||
private(set) var displaySavedMessagesAsTopicList: PreferencesEntry?
|
||||
|
||||
init(postbox: PostboxImpl, currentTransaction: Transaction, groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?, aroundIndex: ChatListIndex, count: Int, summaryComponents: ChatListEntrySummaryComponents) {
|
||||
self.groupId = groupId
|
||||
self.filterPredicate = filterPredicate
|
||||
@ -574,6 +577,8 @@ final class MutableChatListView {
|
||||
|
||||
self.currentHiddenPeerIds = postbox.hiddenChatIds
|
||||
|
||||
self.displaySavedMessagesAsTopicListPreferencesKey = postbox.seedConfiguration.displaySavedMessagesAsTopicListPreferencesKey
|
||||
|
||||
var spaces: [ChatListViewSpace] = [
|
||||
.group(groupId: self.groupId, pinned: .notPinned, predicate: filterPredicate)
|
||||
]
|
||||
@ -612,6 +617,8 @@ final class MutableChatListView {
|
||||
} else {
|
||||
self.groupEntries = []
|
||||
}
|
||||
|
||||
self.displaySavedMessagesAsTopicList = postbox.preferencesTable.get(key: self.displaySavedMessagesAsTopicListPreferencesKey)
|
||||
}
|
||||
|
||||
private func reloadGroups(postbox: PostboxImpl) {
|
||||
@ -689,6 +696,8 @@ final class MutableChatListView {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.displaySavedMessagesAsTopicList = postbox.preferencesTable.get(key: self.displaySavedMessagesAsTopicListPreferencesKey)
|
||||
}
|
||||
|
||||
func refreshDueToExternalTransaction(postbox: PostboxImpl, currentTransaction: Transaction) -> Bool {
|
||||
@ -699,12 +708,16 @@ final class MutableChatListView {
|
||||
updated = true
|
||||
|
||||
let currentGroupEntries = self.groupEntries
|
||||
let currentDisplaySavedMessagesAsTopicList = self.displaySavedMessagesAsTopicList
|
||||
|
||||
self.reloadGroups(postbox: postbox)
|
||||
|
||||
if self.groupEntries != currentGroupEntries {
|
||||
updated = true
|
||||
}
|
||||
if self.displaySavedMessagesAsTopicList != currentDisplaySavedMessagesAsTopicList {
|
||||
updated = true
|
||||
}
|
||||
|
||||
return updated
|
||||
}
|
||||
@ -734,6 +747,20 @@ final class MutableChatListView {
|
||||
}
|
||||
}
|
||||
|
||||
if !transaction.currentPreferencesOperations.isEmpty {
|
||||
for operation in transaction.currentPreferencesOperations {
|
||||
switch operation {
|
||||
case let .update(key, value):
|
||||
if key == self.displaySavedMessagesAsTopicListPreferencesKey {
|
||||
if self.displaySavedMessagesAsTopicList != value {
|
||||
self.displaySavedMessagesAsTopicList = value
|
||||
hasChanges = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if case .root = self.groupId, self.filterPredicate == nil {
|
||||
var invalidatedGroups = false
|
||||
for (groupId, groupOperations) in operations {
|
||||
@ -938,6 +965,7 @@ public final class ChatListView {
|
||||
public let groupEntries: [ChatListGroupReferenceEntry]
|
||||
public let earlierIndex: ChatListIndex?
|
||||
public let laterIndex: ChatListIndex?
|
||||
public let displaySavedMessagesAsTopicList: PreferencesEntry?
|
||||
|
||||
init(_ mutableView: MutableChatListView) {
|
||||
self.groupId = mutableView.groupId
|
||||
@ -1006,5 +1034,6 @@ public final class ChatListView {
|
||||
}
|
||||
|
||||
self.additionalItemEntries = additionalItemEntries
|
||||
self.displaySavedMessagesAsTopicList = mutableView.displaySavedMessagesAsTopicList
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ public final class SeedConfiguration {
|
||||
public let isPeerUpgradeMessage: (Message) -> Bool
|
||||
public let automaticThreadIndexInfo: (PeerId, Int64) -> StoredMessageHistoryThreadInfo?
|
||||
public let customTagsFromAttributes: ([MessageAttribute]) -> [MemoryBuffer]
|
||||
public let displaySavedMessagesAsTopicListPreferencesKey: ValueBoxKey
|
||||
|
||||
public init(
|
||||
globalMessageIdsPeerIdNamespaces: Set<GlobalMessageIdsNamespace>,
|
||||
@ -109,7 +110,8 @@ public final class SeedConfiguration {
|
||||
decodeDisplayPeerAsRegularChat: @escaping (CachedPeerData) -> Bool,
|
||||
isPeerUpgradeMessage: @escaping (Message) -> Bool,
|
||||
automaticThreadIndexInfo: @escaping (PeerId, Int64) -> StoredMessageHistoryThreadInfo?,
|
||||
customTagsFromAttributes: @escaping ([MessageAttribute]) -> [MemoryBuffer]
|
||||
customTagsFromAttributes: @escaping ([MessageAttribute]) -> [MemoryBuffer],
|
||||
displaySavedMessagesAsTopicListPreferencesKey: ValueBoxKey
|
||||
) {
|
||||
self.globalMessageIdsPeerIdNamespaces = globalMessageIdsPeerIdNamespaces
|
||||
self.initializeChatListWithHole = initializeChatListWithHole
|
||||
@ -135,5 +137,6 @@ public final class SeedConfiguration {
|
||||
self.isPeerUpgradeMessage = isPeerUpgradeMessage
|
||||
self.automaticThreadIndexInfo = automaticThreadIndexInfo
|
||||
self.customTagsFromAttributes = customTagsFromAttributes
|
||||
self.displaySavedMessagesAsTopicListPreferencesKey = displaySavedMessagesAsTopicListPreferencesKey
|
||||
}
|
||||
}
|
||||
|
@ -295,7 +295,8 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
||||
topForumTopicItems: [],
|
||||
autoremoveTimeout: nil,
|
||||
storyState: nil,
|
||||
requiresPremiumForMessaging: false
|
||||
requiresPremiumForMessaging: false,
|
||||
displayAsTopicList: false
|
||||
)),
|
||||
editing: false,
|
||||
hasActiveRevealControls: false,
|
||||
|
@ -442,7 +442,8 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
topForumTopicItems: [],
|
||||
autoremoveTimeout: nil,
|
||||
storyState: nil,
|
||||
requiresPremiumForMessaging: false
|
||||
requiresPremiumForMessaging: false,
|
||||
displayAsTopicList: false
|
||||
)),
|
||||
editing: false,
|
||||
hasActiveRevealControls: false,
|
||||
|
@ -1458,7 +1458,8 @@ private func threadList(accountPeerId: EnginePeer.Id, postbox: Postbox, peerId:
|
||||
hasFailed: false,
|
||||
isContact: false,
|
||||
autoremoveTimeout: nil,
|
||||
storyStats: nil
|
||||
storyStats: nil,
|
||||
displayAsTopicList: false
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -1136,7 +1136,8 @@ public func _internal_searchForumTopics(account: Account, peerId: EnginePeer.Id,
|
||||
hasFailed: false,
|
||||
isContact: false,
|
||||
autoremoveTimeout: nil,
|
||||
storyStats: nil
|
||||
storyStats: nil,
|
||||
displayAsTopicList: false
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -278,6 +278,7 @@ private enum PreferencesKeyValues: Int32 {
|
||||
case storiesConfiguration = 32
|
||||
case audioTranscriptionTrialState = 33
|
||||
case didCacheSavedMessageTagsPrefix = 34
|
||||
case displaySavedChatsAsTopics = 35
|
||||
}
|
||||
|
||||
public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey {
|
||||
@ -455,6 +456,12 @@ public struct PreferencesKeys {
|
||||
key.setInt64(4, value: threadId ?? 0)
|
||||
return key
|
||||
}
|
||||
|
||||
public static func displaySavedChatsAsTopics() -> ValueBoxKey {
|
||||
let key = ValueBoxKey(length: 4)
|
||||
key.setInt32(0, value: PreferencesKeyValues.displaySavedChatsAsTopics.rawValue)
|
||||
return key
|
||||
}
|
||||
}
|
||||
|
||||
private enum SharedDataKeyValues: Int32 {
|
||||
|
@ -235,7 +235,8 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = {
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
},
|
||||
displaySavedMessagesAsTopicListPreferencesKey: PreferencesKeys.displaySavedChatsAsTopics()
|
||||
)
|
||||
}()
|
||||
|
||||
|
@ -18,6 +18,14 @@ public enum EnginePeerCachedInfoItem<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public struct EngineDisplaySavedChatsAsTopics: Codable, Equatable {
|
||||
public var value: Bool
|
||||
|
||||
public init(value: Bool) {
|
||||
self.value = value
|
||||
}
|
||||
}
|
||||
|
||||
extension EnginePeerCachedInfoItem: Equatable where T: Equatable {
|
||||
public static func ==(lhs: EnginePeerCachedInfoItem<T>, rhs: EnginePeerCachedInfoItem<T>) -> Bool {
|
||||
switch lhs {
|
||||
@ -1245,5 +1253,28 @@ public extension TelegramEngine.EngineData.Item {
|
||||
}
|
||||
}
|
||||
|
||||
public struct DisplaySavedChatsAsTopics: TelegramEngineDataItem, PostboxViewDataItem {
|
||||
public typealias Result = Bool
|
||||
|
||||
public init() {
|
||||
}
|
||||
|
||||
var key: PostboxViewKey {
|
||||
return .preferences(keys: Set([PreferencesKeys.displaySavedChatsAsTopics()]))
|
||||
}
|
||||
|
||||
func extract(view: PostboxView) -> Result {
|
||||
guard let view = view as? PreferencesView else {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
if let value = view.values[PreferencesKeys.displaySavedChatsAsTopics()]?.get(EngineDisplaySavedChatsAsTopics.self) {
|
||||
return value.value
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -129,6 +129,7 @@ public final class EngineChatList: Equatable {
|
||||
public let isContact: Bool
|
||||
public let autoremoveTimeout: Int32?
|
||||
public let storyStats: StoryStats?
|
||||
public let displayAsTopicList: Bool
|
||||
|
||||
public init(
|
||||
id: Id,
|
||||
@ -147,7 +148,8 @@ public final class EngineChatList: Equatable {
|
||||
hasFailed: Bool,
|
||||
isContact: Bool,
|
||||
autoremoveTimeout: Int32?,
|
||||
storyStats: StoryStats?
|
||||
storyStats: StoryStats?,
|
||||
displayAsTopicList: Bool
|
||||
) {
|
||||
self.id = id
|
||||
self.index = index
|
||||
@ -166,6 +168,7 @@ public final class EngineChatList: Equatable {
|
||||
self.isContact = isContact
|
||||
self.autoremoveTimeout = autoremoveTimeout
|
||||
self.storyStats = storyStats
|
||||
self.displayAsTopicList = displayAsTopicList
|
||||
}
|
||||
|
||||
public static func ==(lhs: Item, rhs: Item) -> Bool {
|
||||
@ -220,6 +223,9 @@ public final class EngineChatList: Equatable {
|
||||
if lhs.storyStats != rhs.storyStats {
|
||||
return false
|
||||
}
|
||||
if lhs.displayAsTopicList != rhs.displayAsTopicList {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -419,7 +425,7 @@ public extension EngineChatList.RelativePosition {
|
||||
}
|
||||
|
||||
extension EngineChatList.Item {
|
||||
convenience init?(_ entry: ChatListEntry) {
|
||||
convenience init?(_ entry: ChatListEntry, displayAsTopicList: Bool) {
|
||||
switch entry {
|
||||
case let .MessageEntry(entryData):
|
||||
let index = entryData.index
|
||||
@ -504,7 +510,8 @@ extension EngineChatList.Item {
|
||||
hasFailed: hasFailed,
|
||||
isContact: isContact,
|
||||
autoremoveTimeout: autoremoveTimeout,
|
||||
storyStats: entryData.storyStats
|
||||
storyStats: entryData.storyStats,
|
||||
displayAsTopicList: displayAsTopicList
|
||||
)
|
||||
case .HoleEntry:
|
||||
return nil
|
||||
@ -544,7 +551,7 @@ extension EngineChatList.AdditionalItem.PromoInfo {
|
||||
|
||||
extension EngineChatList.AdditionalItem {
|
||||
convenience init?(_ entry: ChatListAdditionalItemEntry) {
|
||||
guard let item = EngineChatList.Item(entry.entry) else {
|
||||
guard let item = EngineChatList.Item(entry.entry, displayAsTopicList: false) else {
|
||||
return nil
|
||||
}
|
||||
guard let promoInfo = (entry.info as? PromoChatListItem).flatMap(EngineChatList.AdditionalItem.PromoInfo.init) else {
|
||||
@ -555,14 +562,19 @@ extension EngineChatList.AdditionalItem {
|
||||
}
|
||||
|
||||
public extension EngineChatList {
|
||||
convenience init(_ view: ChatListView) {
|
||||
convenience init(_ view: ChatListView, accountPeerId: PeerId) {
|
||||
var isLoading = false
|
||||
|
||||
var displaySavedMessagesAsTopicList = false
|
||||
if let value = view.displaySavedMessagesAsTopicList?.get(EngineDisplaySavedChatsAsTopics.self) {
|
||||
displaySavedMessagesAsTopicList = value.value
|
||||
}
|
||||
|
||||
var items: [EngineChatList.Item] = []
|
||||
loop: for entry in view.entries {
|
||||
switch entry {
|
||||
case .MessageEntry:
|
||||
if let item = EngineChatList.Item(entry) {
|
||||
if let item = EngineChatList.Item(entry, displayAsTopicList: entry.index.messageIndex.id.peerId == accountPeerId ? displaySavedMessagesAsTopicList : false) {
|
||||
items.append(item)
|
||||
}
|
||||
case .HoleEntry:
|
||||
|
@ -328,9 +328,10 @@ public extension TelegramEngine {
|
||||
}
|
||||
|
||||
public func chatList(group: EngineChatList.Group, count: Int) -> Signal<EngineChatList, NoError> {
|
||||
let accountPeerId = self.account.peerId
|
||||
return self.account.postbox.tailChatListView(groupId: group._asGroup(), count: count, summaryComponents: ChatListEntrySummaryComponents())
|
||||
|> map { view -> EngineChatList in
|
||||
return EngineChatList(view.0)
|
||||
return EngineChatList(view.0, accountPeerId: accountPeerId)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1346,6 +1346,14 @@ public extension TelegramEngine {
|
||||
|> distinctUntilChanged
|
||||
}
|
||||
}
|
||||
|
||||
public func updateSavedMessagesViewAsTopics(value: Bool) {
|
||||
let _ = (self.account.postbox.transaction { transaction -> Void in
|
||||
transaction.updatePreferencesEntry(key: PreferencesKeys.displaySavedChatsAsTopics(), { _ in
|
||||
return PreferencesEntry(EngineDisplaySavedChatsAsTopics(value: value))
|
||||
})
|
||||
}).start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,10 +52,10 @@ public final class MoreHeaderButton: HighlightableButtonNode {
|
||||
strongSelf.contextAction?(strongSelf.containerNode, gesture)
|
||||
}
|
||||
|
||||
self.containerNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 26.0, height: 44.0))
|
||||
self.containerNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 30.0, height: 44.0))
|
||||
self.referenceNode.frame = self.containerNode.bounds
|
||||
|
||||
self.iconNode.image = MoreHeaderButton.optionsCircleImage(color: color)
|
||||
//self.iconNode.image = MoreHeaderButton.optionsCircleImage(color: color)
|
||||
if let image = self.iconNode.image {
|
||||
self.iconNode.frame = CGRect(origin: CGPoint(x: floor((self.containerNode.bounds.width - image.size.width) / 2.0), y: floor((self.containerNode.bounds.height - image.size.height) / 2.0)), size: image.size)
|
||||
}
|
||||
@ -72,11 +72,13 @@ public final class MoreHeaderButton: HighlightableButtonNode {
|
||||
private var content: Content?
|
||||
public func setContent(_ content: Content, animated: Bool = false) {
|
||||
if case .more = content {
|
||||
let animationSize = CGSize(width: 22.0, height: 22.0)
|
||||
let animationSize = CGSize(width: 30.0, height: 30.0)
|
||||
let _ = self.animationView.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(LottieComponent(
|
||||
content: LottieComponent.AppBundleContent(name: "anim_profilemore"),
|
||||
content: LottieComponent.AppBundleContent(
|
||||
name: "anim_moredots"
|
||||
),
|
||||
color: self.color
|
||||
)),
|
||||
environment: {},
|
||||
@ -119,13 +121,13 @@ public final class MoreHeaderButton: HighlightableButtonNode {
|
||||
if let animationComponentView = self.animationView.view {
|
||||
animationComponentView.isHidden = true
|
||||
}
|
||||
case let .more(image):
|
||||
if let image = image {
|
||||
case .more:
|
||||
/*if let image = image {
|
||||
self.iconNode.frame = CGRect(origin: CGPoint(x: floor((self.containerNode.bounds.width - image.size.width) / 2.0), y: floor((self.containerNode.bounds.height - image.size.height) / 2.0)), size: image.size)
|
||||
}
|
||||
|
||||
self.iconNode.image = image
|
||||
self.iconNode.isHidden = false
|
||||
self.iconNode.isHidden = false*/
|
||||
if let animationComponentView = self.animationView.view {
|
||||
animationComponentView.isHidden = false
|
||||
}
|
||||
@ -143,13 +145,13 @@ public final class MoreHeaderButton: HighlightableButtonNode {
|
||||
if let animationComponentView = self.animationView.view {
|
||||
animationComponentView.isHidden = true
|
||||
}
|
||||
case let .more(image):
|
||||
if let image = image {
|
||||
case .more:
|
||||
/*if let image = image {
|
||||
self.iconNode.frame = CGRect(origin: CGPoint(x: floor((self.containerNode.bounds.width - image.size.width) / 2.0), y: floor((self.containerNode.bounds.height - image.size.height) / 2.0)), size: image.size)
|
||||
}
|
||||
|
||||
self.iconNode.image = image
|
||||
self.iconNode.isHidden = false
|
||||
self.iconNode.isHidden = false*/
|
||||
if let animationComponentView = self.animationView.view {
|
||||
animationComponentView.isHidden = false
|
||||
}
|
||||
|
@ -79,6 +79,7 @@ public final class PeerInfoChatListPaneNode: ASDisplayNode, PeerInfoPaneNode, UI
|
||||
autoSetReady: false,
|
||||
isMainTab: nil
|
||||
)
|
||||
self.chatListNode.synchronousDrawingWhenNotAnimated = true
|
||||
|
||||
super.init()
|
||||
|
||||
|
@ -137,6 +137,7 @@ swift_library(
|
||||
"//submodules/MediaPickerUI",
|
||||
"//submodules/AttachmentUI",
|
||||
"//submodules/TelegramUI/Components/Settings/BoostLevelIconComponent",
|
||||
"//submodules/Components/MultilineTextComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -860,13 +860,23 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
|
||||
let hasSavedMessageTags: Signal<Bool, NoError>
|
||||
if let peerId = chatLocation.peerId {
|
||||
hasSavedMessageTags = context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Messages.SavedMessageTagStats(peerId: context.account.peerId, threadId: peerId.toInt64())
|
||||
)
|
||||
|> map { tags -> Bool in
|
||||
return !tags.isEmpty
|
||||
if case .peer = chatLocation {
|
||||
hasSavedMessageTags = context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Messages.SavedMessageTagStats(peerId: context.account.peerId, threadId: nil)
|
||||
)
|
||||
|> map { tags -> Bool in
|
||||
return !tags.isEmpty
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
} else {
|
||||
hasSavedMessageTags = context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Messages.SavedMessageTagStats(peerId: context.account.peerId, threadId: peerId.toInt64())
|
||||
)
|
||||
|> map { tags -> Bool in
|
||||
return !tags.isEmpty
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
} else {
|
||||
hasSavedMessageTags = .single(false)
|
||||
}
|
||||
|
@ -250,6 +250,10 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
||||
icon = nil
|
||||
isAnimation = true
|
||||
animationState = .search
|
||||
case .standaloneSearch:
|
||||
text = ""
|
||||
accessibilityText = presentationData.strings.Common_Search
|
||||
icon = PresentationResourcesRootController.navigationCompactSearchIcon(presentationData.theme)
|
||||
case .searchWithTags:
|
||||
text = ""
|
||||
accessibilityText = presentationData.strings.Common_Search
|
||||
|
@ -14,6 +14,7 @@ enum PeerInfoHeaderNavigationButtonKey {
|
||||
case selectionDone
|
||||
case search
|
||||
case searchWithTags
|
||||
case standaloneSearch
|
||||
case editPhoto
|
||||
case editVideo
|
||||
case more
|
||||
@ -52,11 +53,11 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
||||
}
|
||||
for (_, button) in self.rightButtonNodes {
|
||||
button.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, canBeExpanded: canBeExpanded, transition: transition)
|
||||
transition.updateSublayerTransformOffset(layer: button.layer, offset: CGPoint(x: canBeExpanded ? 8.0 : 0.0, y: 0.0))
|
||||
transition.updateSublayerTransformOffset(layer: button.layer, offset: CGPoint(x: canBeExpanded ? 16.0 : 0.0, y: 0.0))
|
||||
}
|
||||
}
|
||||
|
||||
func update(size: CGSize, presentationData: PresentationData, leftButtons: [PeerInfoHeaderNavigationButtonSpec], rightButtons: [PeerInfoHeaderNavigationButtonSpec], expandFraction: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
func update(size: CGSize, presentationData: PresentationData, leftButtons: [PeerInfoHeaderNavigationButtonSpec], rightButtons: [PeerInfoHeaderNavigationButtonSpec], expandFraction: CGFloat, shouldAnimateIn: Bool, transition: ContainedViewLayoutTransition) {
|
||||
let sideInset: CGFloat = 24.0
|
||||
|
||||
let maximumExpandOffset: CGFloat = 14.0
|
||||
@ -201,7 +202,7 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
||||
if case .postStory = spec.key {
|
||||
buttonFrame.origin.x -= 12.0
|
||||
}
|
||||
nextButtonOrigin -= buttonSize.width + 4.0
|
||||
nextButtonOrigin -= buttonSize.width + 15.0
|
||||
if spec.isForExpandedView {
|
||||
nextExpandedButtonOrigin = nextButtonOrigin
|
||||
} else {
|
||||
@ -211,15 +212,17 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
||||
if wasAdded {
|
||||
buttonNode.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, canBeExpanded: self.canBeExpanded, transition: .immediate)
|
||||
|
||||
if key == .moreToSearch || key == .searchWithTags {
|
||||
buttonNode.layer.animateScale(from: 0.001, to: 1.0, duration: 0.2)
|
||||
if shouldAnimateIn {
|
||||
if key == .moreToSearch || key == .searchWithTags || key == .standaloneSearch {
|
||||
buttonNode.layer.animateScale(from: 0.001, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
|
||||
buttonNode.frame = buttonFrame
|
||||
buttonNode.alpha = 0.0
|
||||
transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
||||
|
||||
transition.updateSublayerTransformOffset(layer: buttonNode.layer, offset: CGPoint(x: canBeExpanded ? 8.0 : 0.0, y: 0.0))
|
||||
transition.updateSublayerTransformOffset(layer: buttonNode.layer, offset: CGPoint(x: canBeExpanded ? 16.0 : 0.0, y: 0.0))
|
||||
} else {
|
||||
transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame)
|
||||
transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
||||
@ -237,7 +240,7 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
||||
}
|
||||
for key in removeKeys {
|
||||
if let buttonNode = self.rightButtonNodes.removeValue(forKey: key) {
|
||||
if key == .moreToSearch || key == .searchWithTags {
|
||||
if key == .moreToSearch || key == .searchWithTags || key == .standaloneSearch {
|
||||
buttonNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak buttonNode] _ in
|
||||
buttonNode?.removeFromSupernode()
|
||||
})
|
||||
@ -264,7 +267,7 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
||||
if case .postStory = spec.key {
|
||||
buttonFrame.origin.x -= 12.0
|
||||
}
|
||||
nextButtonOrigin -= buttonSize.width + 4.0
|
||||
nextButtonOrigin -= buttonSize.width + 15.0
|
||||
if spec.isForExpandedView {
|
||||
nextExpandedButtonOrigin = nextButtonOrigin
|
||||
} else {
|
||||
|
@ -37,6 +37,7 @@ import ChatAvatarNavigationNode
|
||||
import MultiScaleTextNode
|
||||
import PeerInfoCoverComponent
|
||||
import PeerInfoPaneNode
|
||||
import MultilineTextComponent
|
||||
|
||||
final class PeerInfoHeaderNavigationTransition {
|
||||
let sourceNavigationBar: NavigationBar
|
||||
@ -108,6 +109,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
let titleNodeContainer: ASDisplayNode
|
||||
let titleNodeRawContainer: ASDisplayNode
|
||||
let titleNode: MultiScaleTextNode
|
||||
var standardTitle: ComponentView<Empty>?
|
||||
|
||||
let titleCredibilityIconView: ComponentHostView<Empty>
|
||||
var credibilityIconSize: CGSize?
|
||||
@ -991,12 +993,15 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
|
||||
let titleShadowColor: UIColor? = nil
|
||||
|
||||
var displayStandardTitle = false
|
||||
|
||||
if let peer = peer {
|
||||
var title: String
|
||||
if peer.id == self.context.account.peerId && !self.isSettings {
|
||||
if case .replyThread = self.chatLocation {
|
||||
title = presentationData.strings.Conversation_MyNotes
|
||||
} else {
|
||||
displayStandardTitle = true
|
||||
title = presentationData.strings.Conversation_SavedMessages
|
||||
}
|
||||
} else if peer.id.isAnonymousSavedMessages {
|
||||
@ -1789,6 +1794,41 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
if displayStandardTitle {
|
||||
self.titleNode.isHidden = true
|
||||
|
||||
let standardTitle: ComponentView<Empty>
|
||||
if let current = self.standardTitle {
|
||||
standardTitle = current
|
||||
} else {
|
||||
standardTitle = ComponentView()
|
||||
self.standardTitle = standardTitle
|
||||
}
|
||||
|
||||
let titleSize = standardTitle.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: titleStringText, font: Font.semibold(17.0), textColor: navigationContentsPrimaryColor))
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: width, height: navigationHeight)
|
||||
)
|
||||
if let standardTitleView = standardTitle.view {
|
||||
if standardTitleView.superview == nil {
|
||||
self.regularContentNode.view.addSubview(standardTitleView)
|
||||
}
|
||||
let standardTitleFrame = titleSize.centered(in: self.titleNodeContainer.frame).offsetBy(dx: 2.0, dy: 0.0)
|
||||
standardTitleView.frame = standardTitleFrame
|
||||
}
|
||||
} else {
|
||||
if let standardTitle = self.standardTitle {
|
||||
self.standardTitle = nil
|
||||
standardTitle.view?.removeFromSuperview()
|
||||
|
||||
self.titleNode.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
let buttonsTransitionDistance: CGFloat = -min(0.0, apparentBackgroundHeight - backgroundHeight)
|
||||
let buttonsTransitionDistanceNorm: CGFloat = 40.0
|
||||
|
||||
|
@ -3758,11 +3758,17 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
strongSelf.chatInterfaceInteraction.selectionState = strongSelf.state.selectedMessageIds.flatMap { ChatInterfaceSelectionState(selectedIds: $0) }
|
||||
strongSelf.paneContainerNode.updateSelectedMessageIds(strongSelf.state.selectedMessageIds, animated: true)
|
||||
case .search, .searchWithTags:
|
||||
case .search, .searchWithTags, .standaloneSearch:
|
||||
strongSelf.activateSearch()
|
||||
case .more:
|
||||
if let source = source {
|
||||
strongSelf.displayMediaGalleryContextMenu(source: source, gesture: gesture)
|
||||
if let currentPaneKey = strongSelf.paneContainerNode.currentPaneKey, case .savedMessagesChats = currentPaneKey {
|
||||
if let controller = strongSelf.controller, let source {
|
||||
PeerInfoScreenImpl.openSavedMessagesMoreMenu(context: strongSelf.context, sourceController: controller, isViewingAsTopics: true, sourceView: source.view, gesture: gesture)
|
||||
}
|
||||
} else {
|
||||
if let source = source {
|
||||
strongSelf.displayMediaGalleryContextMenu(source: source, gesture: gesture)
|
||||
}
|
||||
}
|
||||
case .qrCode:
|
||||
strongSelf.openQrCode()
|
||||
@ -10177,7 +10183,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
|
||||
self.ignoreScrolling = false
|
||||
self.updateNavigation(transition: transition, additive: additive, animateHeader: true)
|
||||
self.updateNavigation(transition: transition, additive: additive, animateHeader: self.controller?.didAppear ?? false)
|
||||
|
||||
if !self.didSetReady && self.data != nil {
|
||||
self.didSetReady = true
|
||||
@ -10287,8 +10293,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
if self.state.selectedMessageIds == nil {
|
||||
if let currentPaneKey = self.paneContainerNode.currentPaneKey {
|
||||
switch currentPaneKey {
|
||||
case .files, .music, .links, .members, .savedMessagesChats:
|
||||
case .files, .music, .links, .members:
|
||||
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .search, isForExpandedView: true))
|
||||
case .savedMessagesChats:
|
||||
if let data = self.data, data.hasSavedMessageTags {
|
||||
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .searchWithTags, isForExpandedView: true))
|
||||
} else {
|
||||
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .standaloneSearch, isForExpandedView: true))
|
||||
}
|
||||
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .more, isForExpandedView: true))
|
||||
case .savedMessages:
|
||||
if let data = self.data, data.hasSavedMessageTags {
|
||||
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .searchWithTags, isForExpandedView: true))
|
||||
@ -10318,7 +10331,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
leftNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .back, isForExpandedView: false))
|
||||
}
|
||||
}
|
||||
self.headerNode.navigationButtonContainer.update(size: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: navigationBarHeight), presentationData: self.presentationData, leftButtons: leftNavigationButtons, rightButtons: rightNavigationButtons, expandFraction: effectiveAreaExpansionFraction, transition: transition)
|
||||
self.headerNode.navigationButtonContainer.update(size: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: navigationBarHeight), presentationData: self.presentationData, leftButtons: leftNavigationButtons, rightButtons: rightNavigationButtons, expandFraction: effectiveAreaExpansionFraction, shouldAnimateIn: animateHeader, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
@ -10622,6 +10635,8 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
}
|
||||
}
|
||||
|
||||
var didAppear: Bool = false
|
||||
|
||||
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool = false, hintGroupInCommon: PeerId? = nil, requestsContext: PeerInvitationImportersContext? = nil, forumTopicThread: ChatReplyThreadMessage? = nil, switchToRecommendedChannels: Bool = false) {
|
||||
@ -11145,6 +11160,10 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
override public func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.didAppear = true
|
||||
}
|
||||
|
||||
var chatNavigationStack: [ChatNavigationStackItem] = []
|
||||
if !self.isSettings, let summary = self.customNavigationDataSummary as? ChatControllerNavigationDataSummary {
|
||||
chatNavigationStack.removeAll()
|
||||
@ -11266,6 +11285,61 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
public static func openSavedMessagesMoreMenu(context: AccountContext, sourceController: ViewController, isViewingAsTopics: Bool, sourceView: UIView, gesture: ContextGesture?) {
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|> deliverOnMainQueue).startStandalone(next: { peer in
|
||||
guard let peer else {
|
||||
return
|
||||
}
|
||||
|
||||
let strings = context.sharedContext.currentPresentationData.with { $0 }.strings
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
//TODO:localize
|
||||
items.append(.action(ContextMenuActionItem(text: "View as Chats", icon: { theme in
|
||||
if !isViewingAsTopics {
|
||||
return nil
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { [weak sourceController] _, a in
|
||||
a(.default)
|
||||
|
||||
guard let sourceController = sourceController, let navigationController = sourceController.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
|
||||
if let infoController = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
|
||||
navigationController.replaceController(sourceController, with: infoController, animated: false)
|
||||
}
|
||||
|
||||
context.engine.peers.updateSavedMessagesViewAsTopics(value: true)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Chat_ContextViewAsMessages, icon: { theme in
|
||||
if isViewingAsTopics {
|
||||
return nil
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { [weak sourceController] _, a in
|
||||
a(.default)
|
||||
|
||||
guard let sourceController = sourceController, let navigationController = sourceController.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
|
||||
let chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(id: context.account.peerId), subject: nil, botStart: nil, mode: .standard(.default))
|
||||
|
||||
navigationController.replaceController(sourceController, with: chatController, animated: false)
|
||||
|
||||
context.engine.peers.updateSavedMessagesViewAsTopics(value: false)
|
||||
})))
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: sourceController, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
sourceController.presentInGlobalOverlay(contextController)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private final class SettingsTabBarContextExtractedContentSource: ContextExtractedContentSource {
|
||||
@ -12432,3 +12506,17 @@ private final class PeerInfoControllerContextReferenceContentSource: ContextRefe
|
||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds.inset(by: self.insets), insets: self.contentInsets)
|
||||
}
|
||||
}
|
||||
|
||||
private final class HeaderContextReferenceContentSource: ContextReferenceContentSource {
|
||||
private let controller: ViewController
|
||||
private let sourceView: UIView
|
||||
|
||||
init(controller: ViewController, sourceView: UIView) {
|
||||
self.controller = controller
|
||||
self.sourceView = sourceView
|
||||
}
|
||||
|
||||
func transitionInfo() -> ContextControllerReferenceViewInfo? {
|
||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
}
|
||||
|
@ -937,7 +937,8 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
topForumTopicItems: [],
|
||||
autoremoveTimeout: nil,
|
||||
storyState: nil,
|
||||
requiresPremiumForMessaging: false
|
||||
requiresPremiumForMessaging: false,
|
||||
displayAsTopicList: false
|
||||
)),
|
||||
editing: false,
|
||||
hasActiveRevealControls: false,
|
||||
|
@ -452,23 +452,58 @@ func updateChatPresentationInterfaceStateImpl(
|
||||
selfController.leftNavigationButton = nil
|
||||
}
|
||||
|
||||
var buttonsAnimated = transition.isAnimated
|
||||
if let button = rightNavigationButtonForChatInterfaceState(context: selfController.context, presentationInterfaceState: updatedChatPresentationInterfaceState, strings: updatedChatPresentationInterfaceState.strings, currentButton: selfController.rightNavigationButton, target: selfController, selector: #selector(selfController.rightNavigationButtonAction), chatInfoNavigationButton: selfController.chatInfoNavigationButton, moreInfoNavigationButton: selfController.moreInfoNavigationButton) {
|
||||
if selfController.rightNavigationButton != button {
|
||||
var animated = transition.isAnimated
|
||||
if let currentButton = selfController.rightNavigationButton?.action, currentButton == button.action {
|
||||
animated = false
|
||||
buttonsAnimated = false
|
||||
}
|
||||
if case .replyThread = selfController.chatLocation {
|
||||
animated = false
|
||||
buttonsAnimated = false
|
||||
}
|
||||
selfController.navigationItem.setRightBarButton(button.buttonItem, animated: animated)
|
||||
selfController.rightNavigationButton = button
|
||||
}
|
||||
} else if let _ = selfController.rightNavigationButton {
|
||||
selfController.navigationItem.setRightBarButton(nil, animated: transition.isAnimated)
|
||||
selfController.rightNavigationButton = nil
|
||||
}
|
||||
|
||||
if let button = secondaryRightNavigationButtonForChatInterfaceState(context: selfController.context, presentationInterfaceState: updatedChatPresentationInterfaceState, strings: updatedChatPresentationInterfaceState.strings, currentButton: selfController.secondaryRightNavigationButton, target: selfController, selector: #selector(selfController.secondaryRightNavigationButtonAction), chatInfoNavigationButton: selfController.chatInfoNavigationButton, moreInfoNavigationButton: selfController.moreInfoNavigationButton) {
|
||||
if selfController.secondaryRightNavigationButton != button {
|
||||
if let currentButton = selfController.secondaryRightNavigationButton?.action, currentButton == button.action {
|
||||
buttonsAnimated = false
|
||||
}
|
||||
if case .replyThread = selfController.chatLocation {
|
||||
buttonsAnimated = false
|
||||
}
|
||||
selfController.secondaryRightNavigationButton = button
|
||||
}
|
||||
} else if let _ = selfController.secondaryRightNavigationButton {
|
||||
selfController.secondaryRightNavigationButton = nil
|
||||
}
|
||||
|
||||
var rightBarButtons: [UIBarButtonItem] = []
|
||||
if let rightNavigationButton = selfController.rightNavigationButton {
|
||||
rightBarButtons.append(rightNavigationButton.buttonItem)
|
||||
}
|
||||
if let secondaryRightNavigationButton = selfController.secondaryRightNavigationButton {
|
||||
rightBarButtons.append(secondaryRightNavigationButton.buttonItem)
|
||||
}
|
||||
var rightBarButtonsUpdated = false
|
||||
let currentRightBarButtons = selfController.navigationItem.rightBarButtonItems ?? []
|
||||
if rightBarButtons.count != currentRightBarButtons.count {
|
||||
rightBarButtonsUpdated = true
|
||||
} else {
|
||||
for i in 0 ..< rightBarButtons.count {
|
||||
if rightBarButtons[i] !== currentRightBarButtons[i] {
|
||||
rightBarButtonsUpdated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if rightBarButtonsUpdated {
|
||||
selfController.navigationItem.setRightBarButtonItems(rightBarButtons, animated: buttonsAnimated)
|
||||
}
|
||||
|
||||
if let controllerInteraction = selfController.controllerInteraction {
|
||||
if updatedChatPresentationInterfaceState.interfaceState.selectionState != controllerInteraction.selectionState {
|
||||
controllerInteraction.selectionState = updatedChatPresentationInterfaceState.interfaceState.selectionState
|
||||
|
@ -122,6 +122,7 @@ import WallpaperGalleryScreen
|
||||
import WallpaperGridScreen
|
||||
import VideoMessageCameraScreen
|
||||
import TopMessageReactions
|
||||
import PeerInfoScreen
|
||||
|
||||
public enum ChatControllerPeekActions {
|
||||
case standard
|
||||
@ -267,6 +268,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
var chatTitleView: ChatTitleView?
|
||||
var leftNavigationButton: ChatNavigationButton?
|
||||
var rightNavigationButton: ChatNavigationButton?
|
||||
var secondaryRightNavigationButton: ChatNavigationButton?
|
||||
var chatInfoNavigationButton: ChatNavigationButton?
|
||||
|
||||
var moreBarButton: MoreHeaderButton
|
||||
@ -4725,13 +4727,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.moreBarButton.setContent(.more(MoreHeaderButton.optionsCircleImage(color: self.presentationData.theme.rootController.navigationBar.buttonColor)))
|
||||
self.moreInfoNavigationButton = ChatNavigationButton(action: .toggleInfoPanel, buttonItem: UIBarButtonItem(customDisplayNode: self.moreBarButton)!)
|
||||
self.moreBarButton.contextAction = { [weak self] sourceNode, gesture in
|
||||
guard let self = self else {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
guard case let .peer(peerId) = self.chatLocation else {
|
||||
return
|
||||
}
|
||||
ChatListControllerImpl.openMoreMenu(context: self.context, peerId: peerId, sourceController: self, isViewingAsTopics: false, sourceView: sourceNode.view, gesture: gesture)
|
||||
|
||||
if peerId == self.context.account.peerId {
|
||||
PeerInfoScreenImpl.openSavedMessagesMoreMenu(context: self.context, sourceController: self, isViewingAsTopics: false, sourceView: sourceNode.view, gesture: gesture)
|
||||
} else {
|
||||
ChatListControllerImpl.openMoreMenu(context: self.context, peerId: peerId, sourceController: self, isViewingAsTopics: false, sourceView: sourceNode.view, gesture: gesture)
|
||||
}
|
||||
}
|
||||
self.moreBarButton.addTarget(self, action: #selector(self.moreButtonPressed), forControlEvents: .touchUpInside)
|
||||
|
||||
@ -12087,6 +12094,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
|
||||
@objc func secondaryRightNavigationButtonAction() {
|
||||
if let button = self.secondaryRightNavigationButton {
|
||||
self.navigationButtonAction(button.action)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func moreButtonPressed() {
|
||||
self.moreBarButton.play()
|
||||
self.moreBarButton.contextAction?(self.moreBarButton.containerNode, nil)
|
||||
|
@ -182,3 +182,11 @@ func rightNavigationButtonForChatInterfaceState(context: AccountContext, present
|
||||
|
||||
return chatInfoNavigationButton
|
||||
}
|
||||
|
||||
func secondaryRightNavigationButtonForChatInterfaceState(context: AccountContext, presentationInterfaceState: ChatPresentationInterfaceState, strings: PresentationStrings, currentButton: ChatNavigationButton?, target: Any?, selector: Selector?, chatInfoNavigationButton: ChatNavigationButton?, moreInfoNavigationButton: ChatNavigationButton?) -> ChatNavigationButton? {
|
||||
if case .peer(context.account.peerId) = presentationInterfaceState.chatLocation {
|
||||
return moreInfoNavigationButton
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -104,7 +104,8 @@ private enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
topForumTopicItems: [],
|
||||
autoremoveTimeout: nil,
|
||||
storyState: nil,
|
||||
requiresPremiumForMessaging: false
|
||||
requiresPremiumForMessaging: false,
|
||||
displayAsTopicList: false
|
||||
)),
|
||||
editing: false,
|
||||
hasActiveRevealControls: false,
|
||||
|
@ -41,6 +41,13 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
|
||||
return false
|
||||
}
|
||||
}
|
||||
} else if case let .peer(peer) = params.chatLocation, peer.id == params.context.account.peerId {
|
||||
viewForumAsMessages = params.context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.DisplaySavedChatsAsTopics()
|
||||
)
|
||||
|> map { value in
|
||||
return !value
|
||||
}
|
||||
}
|
||||
|
||||
let _ = (viewForumAsMessages
|
||||
@ -93,6 +100,14 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
|
||||
return
|
||||
}
|
||||
|
||||
if !viewForumAsMessages, params.subject == nil, case let .peer(peer) = params.chatLocation, peer.id == params.context.account.peerId {
|
||||
if let controller = params.context.sharedContext.makePeerInfoController(context: params.context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
|
||||
params.navigationController.pushViewController(controller, animated: params.animated, completion: {
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var found = false
|
||||
var isFirst = true
|
||||
if params.useExisting {
|
||||
|
Loading…
x
Reference in New Issue
Block a user