Saved messages view as chats

This commit is contained in:
Isaac 2024-01-28 18:59:00 +01:00
parent ea9c9ae777
commit 4bd4884887
33 changed files with 421 additions and 106 deletions

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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
))
}

View File

@ -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]

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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,

View File

@ -442,7 +442,8 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
topForumTopicItems: [],
autoremoveTimeout: nil,
storyState: nil,
requiresPremiumForMessaging: false
requiresPremiumForMessaging: false,
displayAsTopicList: false
)),
editing: false,
hasActiveRevealControls: false,

View File

@ -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
))
}

View File

@ -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
))
}

View File

@ -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 {

View File

@ -235,7 +235,8 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = {
}
return result
}
},
displaySavedMessagesAsTopicListPreferencesKey: PreferencesKeys.displaySavedChatsAsTopics()
)
}()

View File

@ -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
}
}
}
}
}

View File

@ -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:

View File

@ -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)
}
}

View File

@ -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()
}
}
}

View File

@ -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
}

View File

@ -79,6 +79,7 @@ public final class PeerInfoChatListPaneNode: ASDisplayNode, PeerInfoPaneNode, UI
autoSetReady: false,
isMainTab: nil
)
self.chatListNode.synchronousDrawingWhenNotAnimated = true
super.init()

View File

@ -137,6 +137,7 @@ swift_library(
"//submodules/MediaPickerUI",
"//submodules/AttachmentUI",
"//submodules/TelegramUI/Components/Settings/BoostLevelIconComponent",
"//submodules/Components/MultilineTextComponent",
],
visibility = [
"//visibility:public",

View File

@ -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)
}

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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)
}
}

View File

@ -937,7 +937,8 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
topForumTopicItems: [],
autoremoveTimeout: nil,
storyState: nil,
requiresPremiumForMessaging: false
requiresPremiumForMessaging: false,
displayAsTopicList: false
)),
editing: false,
hasActiveRevealControls: false,

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -104,7 +104,8 @@ private enum ChatListSearchEntry: Comparable, Identifiable {
topForumTopicItems: [],
autoremoveTimeout: nil,
storyState: nil,
requiresPremiumForMessaging: false
requiresPremiumForMessaging: false,
displayAsTopicList: false
)),
editing: false,
hasActiveRevealControls: false,

View File

@ -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 {