From 1a3f8c1faf293d3109b54acda40b92e4ea1e274d Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 6 Sep 2023 22:53:37 +0400 Subject: [PATCH] Cherry-pick session review changes --- .../Sources/Node/ChatListNode.swift | 22 +++++---- .../Node/ChatListStorageInfoItem.swift | 2 +- submodules/Display/Source/ListView.swift | 3 +- .../Account/AccountIntermediateState.swift | 7 ++- .../State/AccountStateManagementUtils.swift | 19 +++++++- .../SyncCore/SyncCore_NewSessionReview.swift | 47 ++++++++++++++++++- .../Privacy/TelegramEnginePrivacy.swift | 16 +++++++ .../Sources/StorageUsageScreen.swift | 4 ++ 8 files changed, 105 insertions(+), 15 deletions(-) diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index dc45ee810b..f281846a61 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -23,8 +23,6 @@ import ChatListHeaderComponent import UndoUI import NewSessionInfoScreen -private var debugDidAddNewSessionReview = false - public enum ChatListNodeMode { case chatList(appendContacts: Bool) case peers(filter: ChatListNodePeersFilter, isSelecting: Bool, additionalCategories: [ChatListNodeAdditionalCategory], chatListFilters: [ChatListFilter]?, displayAutoremoveTimeout: Bool, displayPresence: Bool) @@ -1637,11 +1635,11 @@ public final class ChatListNode: ListView { return true })) - let _ = removeNewSessionReviews(postbox: self.context.account.postbox, ids: [newSessionReview.id]).start() + let _ = self.context.engine.privacy.confirmNewSessionReview(id: newSessionReview.id) } else { self.push?(NewSessionInfoScreen(context: self.context, newSessionReview: newSessionReview)) - let _ = removeNewSessionReviews(postbox: self.context.account.postbox, ids: [newSessionReview.id]).start() + let _ = self.context.engine.privacy.terminateAnotherSession(id: newSessionReview.id).start() } }, openChatFolderUpdates: { [weak self] in guard let self else { @@ -1743,12 +1741,7 @@ public final class ChatListNode: ListView { let suggestedChatListNotice: Signal if case .chatList(groupId: .root) = location, chatListFilter == nil { - #if DEBUG - if !debugDidAddNewSessionReview { - debugDidAddNewSessionReview = true - let _ = addNewSessionReview(postbox: context.account.postbox, item: NewSessionReview(id: 1, device: "iPhone 14 Pro", location: "Dubai, UAE")).start() - } - #endif + let _ = context.engine.privacy.cleanupSessionReviews().start() suggestedChatListNotice = .single(nil) |> then ( @@ -2952,6 +2945,15 @@ public final class ChatListNode: ListView { } } + self.dynamicVisualInsets = { [weak self] in + guard let self else { + return UIEdgeInsets() + } + + let _ = self + return UIEdgeInsets() + } + self.pollFilterUpdates() self.resetFilter() diff --git a/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift b/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift index 2c3d428b03..50790bea38 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift @@ -112,12 +112,12 @@ class ChatListStorageInfoItemNode: ItemListRevealOptionsItemNode { self.contentContainer.clipsToBounds = true self.clipsToBounds = true - self.addSubnode(self.separatorNode) self.contentContainer.addSubnode(self.titleNode) self.contentContainer.addSubnode(self.textNode) self.contentContainer.addSubnode(self.arrowNode) self.addSubnode(self.contentContainer) + self.addSubnode(self.separatorNode) self.zPosition = 1.0 } diff --git a/submodules/Display/Source/ListView.swift b/submodules/Display/Source/ListView.swift index 6672f43915..c0b1854353 100644 --- a/submodules/Display/Source/ListView.swift +++ b/submodules/Display/Source/ListView.swift @@ -189,6 +189,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture public private(set) final var visibleSize: CGSize = CGSize() public private(set) final var insets = UIEdgeInsets() public final var visualInsets: UIEdgeInsets? + public final var dynamicVisualInsets: (() -> UIEdgeInsets)? public private(set) final var headerInsets = UIEdgeInsets() public private(set) final var scrollIndicatorInsets = UIEdgeInsets() private final var ensureTopInsetForOverlayHighlightedItems: CGFloat? @@ -4388,7 +4389,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture if abs(apparentHeightDelta) > CGFloat.ulpOfOne { itemNode.updateFrame(itemNode.frame, within: self.visibleSize) - let visualInsets = self.visualInsets ?? self.insets + let visualInsets = self.dynamicVisualInsets?() ?? self.visualInsets ?? self.insets if itemNode.apparentFrame.maxY <= visualInsets.top { offsetRanges.offset(IndexRange(first: 0, last: index), offset: -apparentHeightDelta) diff --git a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift index 79b4f16fca..15a99e5cd8 100644 --- a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift +++ b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift @@ -124,6 +124,7 @@ enum AccountStateMutationOperation { case UpdateReadStories(peerId: PeerId, maxId: Int32) case UpdateStoryStealthMode(data: Api.StoriesStealthMode) case UpdateStorySentReaction(peerId: PeerId, id: Int32, reaction: Api.Reaction) + case UpdateNewAuthorization(isUnconfirmed: Bool, hash: Int64, date: Int32, device: String, location: String) } struct HoleFromPreviousState { @@ -653,9 +654,13 @@ struct AccountMutableState { self.addOperation(.UpdateStorySentReaction(peerId: peerId, id: id, reaction: reaction)) } + mutating func updateNewAuthorization(isUnconfirmed: Bool, hash: Int64, date: Int32, device: String, location: String) { + self.addOperation(.UpdateNewAuthorization(isUnconfirmed: isUnconfirmed, hash: hash, date: date, device: device, location: location)) + } + mutating func addOperation(_ operation: AccountStateMutationOperation) { switch operation { - case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization: break case let .AddMessages(messages, location): for message in messages { diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index da1f555d16..fe1b5b5352 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -1681,6 +1681,9 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: updatedState.updateStoryStealthMode(stealthMode) case let .updateSentStoryReaction(userId, storyId, reaction): updatedState.updateStorySentReaction(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), id: storyId, reaction: reaction) + case let .updateNewAuthorization(flags, hash, date, device, location): + let isUnconfirmed = (flags & (1 << 0)) != 0 + updatedState.updateNewAuthorization(isUnconfirmed: isUnconfirmed, hash: hash, date: date ?? 0, device: device ?? "", location: location ?? "") default: break } @@ -3169,7 +3172,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation]) var currentAddScheduledMessages: OptimizeAddMessagesState? for operation in operations { switch operation { - case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization: if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty { result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) } @@ -4618,6 +4621,20 @@ func replayFinalState( transaction.setStory(id: StoryId(peerId: peerId, id: id), value: entry) } } + case let .UpdateNewAuthorization(isUnconfirmed, hash, date, device, location): + let id = NewSessionReview.Id(id: hash) + if isUnconfirmed { + if let entry = CodableEntry(NewSessionReview( + id: hash, + device: device, + location: location, + timestamp: date + )) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.NewSessionReviews, item: OrderedItemListEntry(id: id.rawValue, contents: entry), removeTailIfCountExceeds: 200) + } + } else { + transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.NewSessionReviews, itemId: id.rawValue) + } } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_NewSessionReview.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_NewSessionReview.swift index e999641dfc..71e3094910 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_NewSessionReview.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_NewSessionReview.swift @@ -1,6 +1,7 @@ import Foundation import Postbox import SwiftSignalKit +import TelegramApi public final class NewSessionReview: Codable, Equatable { struct Id { @@ -19,11 +20,13 @@ public final class NewSessionReview: Codable, Equatable { public let id: Int64 public let device: String public let location: String + public let timestamp: Int32 - public init(id: Int64, device: String, location: String) { + public init(id: Int64, device: String, location: String, timestamp: Int32) { self.id = id self.device = device self.location = location + self.timestamp = timestamp } public init(from decoder: Decoder) throws { @@ -32,6 +35,7 @@ public final class NewSessionReview: Codable, Equatable { self.id = try container.decode(Int64.self, forKey: "id") self.device = try container.decode(String.self, forKey: "device") self.location = try container.decode(String.self, forKey: "location") + self.timestamp = try container.decode(Int32.self, forKey: "timestamp") } public func encode(to encoder: Encoder) throws { @@ -40,6 +44,7 @@ public final class NewSessionReview: Codable, Equatable { try container.encode(self.id, forKey: "id") try container.encode(self.device, forKey: "device") try container.encode(self.location, forKey: "location") + try container.encode(self.timestamp, forKey: "timestamp") } public static func ==(lhs: NewSessionReview, rhs: NewSessionReview) -> Bool { @@ -52,10 +57,42 @@ public final class NewSessionReview: Codable, Equatable { if lhs.location != rhs.location { return false } + if lhs.timestamp != rhs.timestamp { + return false + } return true } } +func _internal_cleanupSessionReviews(account: Account) -> Signal { + return account.postbox.transaction { transaction -> Void in + var autoconfirmTimeout: Int32 = 7 * 24 * 60 * 60 + let appConfig = currentAppConfiguration(transaction: transaction) + if let data = appConfig.data { + if let value = data["authorization_autoconfirm_period"] as? Double { + autoconfirmTimeout = Int32(round(value)) + } + } + + let timestamp = Int32(Date().timeIntervalSince1970) + var removeIds: [MemoryBuffer] = [] + for entry in transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.NewSessionReviews) { + guard let item = entry.contents.get(NewSessionReview.self) else { + removeIds.append(entry.id) + continue + } + if item.timestamp <= timestamp - autoconfirmTimeout { + removeIds.append(entry.id) + } + } + + for removeId in removeIds { + transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.NewSessionReviews, itemId: removeId) + } + } + |> ignoreValues +} + public func newSessionReviews(postbox: Postbox) -> Signal<[NewSessionReview], NoError> { let viewKey: PostboxViewKey = .orderedItemList(id: Namespaces.OrderedItemList.NewSessionReviews) return postbox.combinedView(keys: [viewKey]) @@ -102,3 +139,11 @@ public func removeNewSessionReviews(postbox: Postbox, ids: [Int64]) -> Signal ignoreValues } + +func _internal_confirmNewSessionReview(account: Account, id: Int64) -> Signal { + return account.network.request(Api.functions.account.changeAuthorizationSettings(flags: 1 << 3, hash: id, encryptedRequestsDisabled: nil, callRequestsDisabled: nil)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> ignoreValues +} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/TelegramEnginePrivacy.swift b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/TelegramEnginePrivacy.swift index 1b8fc0a08b..28dccb7329 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/TelegramEnginePrivacy.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/TelegramEnginePrivacy.swift @@ -68,5 +68,21 @@ public extension TelegramEngine { public func updateCloseFriends(peerIds: [EnginePeer.Id]) -> Signal { return _internal_updateCloseFriends(account: self.account, peerIds: peerIds) } + + public func cleanupSessionReviews() -> Signal { + return _internal_cleanupSessionReviews(account: self.account) + } + + public func confirmNewSessionReview(id: Int64) -> Signal { + let _ = removeNewSessionReviews(postbox: self.account.postbox, ids: [id]).start() + return _internal_confirmNewSessionReview(account: self.account, id: id) + } + + public func terminateAnotherSession(id: Int64) -> Signal { + let _ = removeNewSessionReviews(postbox: self.account.postbox, ids: [id]).start() + + return terminateAccountSession(account: self.account, hash: id) + |> ignoreValues + } } } diff --git a/submodules/TelegramUI/Components/StorageUsageScreen/Sources/StorageUsageScreen.swift b/submodules/TelegramUI/Components/StorageUsageScreen/Sources/StorageUsageScreen.swift index b697b39f71..a2f19cae51 100644 --- a/submodules/TelegramUI/Components/StorageUsageScreen/Sources/StorageUsageScreen.swift +++ b/submodules/TelegramUI/Components/StorageUsageScreen/Sources/StorageUsageScreen.swift @@ -3244,6 +3244,10 @@ final class StorageUsageScreenComponent: Component { } } + if case .separator = subItems.last { + subItems.removeLast() + } + if let sourceLabelView = sourceView.labelView { let items: Signal = .single(ContextController.Items(content: .list(subItems))) let source: ContextContentSource = .reference(StorageUsageContextReferenceContentSource(sourceView: sourceLabelView))