From 10b0bdd301ca70ed2051528dba69ee0a4dc9d2c7 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 23 Oct 2020 18:14:26 +0400 Subject: [PATCH] Pinned message improvements --- .../AnimatedNavigationStripeNode.swift | 18 +++++++++ .../Postbox/Sources/AccountManager.swift | 14 ++++++- .../Sources/AccountManagerAtomicState.swift | 12 +++++- .../Sources/AccountManagerMetadataTable.swift | 30 ++++++++++++++- .../TelegramUI/Sources/ChatController.swift | 38 +++++++++++++++++-- .../ChatPinnedMessageTitlePanelNode.swift | 8 +++- 6 files changed, 113 insertions(+), 7 deletions(-) diff --git a/submodules/AnimatedNavigationStripeNode/Sources/AnimatedNavigationStripeNode.swift b/submodules/AnimatedNavigationStripeNode/Sources/AnimatedNavigationStripeNode.swift index f802576d83..c95452e7e4 100644 --- a/submodules/AnimatedNavigationStripeNode/Sources/AnimatedNavigationStripeNode.swift +++ b/submodules/AnimatedNavigationStripeNode/Sources/AnimatedNavigationStripeNode.swift @@ -149,6 +149,11 @@ public final class AnimatedNavigationStripeNode: ASDisplayNode { } if self.currentConfiguration != configuration { + var isCycledJump = false + if let currentConfiguration = self.currentConfiguration, currentConfiguration.count == configuration.count, currentConfiguration.index == 0, currentConfiguration.count > 4, configuration.index == configuration.count - 1 { + isCycledJump = true + } + self.currentConfiguration = configuration let defaultVerticalInset: CGFloat = 7.0 @@ -276,6 +281,19 @@ public final class AnimatedNavigationStripeNode: ASDisplayNode { } transition.updateFrame(node: self.foregroundLineNode, frame: CGRect(origin: CGPoint(x: 0.0, y: itemScreenOffset), size: CGSize(width: 2.0, height: segmentHeight)), beginWithCurrentState: true) + + if transition.isAnimated && isCycledJump { + let duration: Double = 0.18 + let maxOffset: CGFloat = -8.0 + let offsetAnimation0 = self.layer.makeAnimation(from: 0.0 as NSNumber, to: maxOffset as NSNumber, keyPath: "bounds.origin.y", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: duration / 2.0, removeOnCompletion: false, additive: true, completion: { [weak self] _ in + guard let strongSelf = self else { + return + } + let offsetAnimation1 = strongSelf.layer.makeAnimation(from: maxOffset as NSNumber, to: 0.0 as NSNumber, keyPath: "bounds.origin.y", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: duration / 2.0, additive: true) + strongSelf.layer.add(offsetAnimation1, forKey: "cycleShake") + }) + self.layer.add(offsetAnimation0, forKey: "cycleShake") + } } } } diff --git a/submodules/Postbox/Sources/AccountManager.swift b/submodules/Postbox/Sources/AccountManager.swift index 7ec6028f6d..9ba356de94 100644 --- a/submodules/Postbox/Sources/AccountManager.swift +++ b/submodules/Postbox/Sources/AccountManager.swift @@ -86,7 +86,17 @@ final class AccountManagerImpl { for record in self.legacyRecordTable.getRecords() { legacyRecordDict[record.id] = record } - self.currentAtomicState = AccountManagerAtomicState(records: legacyRecordDict, currentRecordId: self.legacyMetadataTable.getCurrentAccountId(), currentAuthRecord: self.legacyMetadataTable.getCurrentAuthAccount()) + self.currentAtomicState = AccountManagerAtomicState(records: legacyRecordDict, currentRecordId: self.legacyMetadataTable.getCurrentAccountId(), currentAuthRecord: self.legacyMetadataTable.getCurrentAuthAccount(), accessChallengeData: self.legacyMetadataTable.getAccessChallengeData()) + self.syncAtomicStateToFile() + } + + let tableAccessChallengeData = self.legacyMetadataTable.getAccessChallengeData() + if self.currentAtomicState.accessChallengeData != .none { + if tableAccessChallengeData == .none { + self.legacyMetadataTable.setAccessChallengeData(self.currentAtomicState.accessChallengeData) + } + } else if tableAccessChallengeData != .none { + self.currentAtomicState.accessChallengeData = tableAccessChallengeData self.syncAtomicStateToFile() } @@ -165,7 +175,9 @@ final class AccountManagerImpl { return self.legacyMetadataTable.getAccessChallengeData() }, setAccessChallengeData: { data in self.currentUpdatedAccessChallengeData = data + self.currentAtomicStateUpdated = true self.legacyMetadataTable.setAccessChallengeData(data) + self.currentAtomicState.accessChallengeData = data }, getVersion: { return self.legacyMetadataTable.getVersion() }, setVersion: { version in diff --git a/submodules/Postbox/Sources/AccountManagerAtomicState.swift b/submodules/Postbox/Sources/AccountManagerAtomicState.swift index 19c9c3aa58..d74557c755 100644 --- a/submodules/Postbox/Sources/AccountManagerAtomicState.swift +++ b/submodules/Postbox/Sources/AccountManagerAtomicState.swift @@ -5,16 +5,19 @@ final class AccountManagerAtomicState: Codable { case records case currentRecordId case currentAuthRecord + case accessChallengeData } var records: [AccountRecordId: AccountRecord] var currentRecordId: AccountRecordId? var currentAuthRecord: AuthAccountRecord? + var accessChallengeData: PostboxAccessChallengeData - init(records: [AccountRecordId: AccountRecord] = [:], currentRecordId: AccountRecordId? = nil, currentAuthRecord: AuthAccountRecord? = nil) { + init(records: [AccountRecordId: AccountRecord] = [:], currentRecordId: AccountRecordId? = nil, currentAuthRecord: AuthAccountRecord? = nil, accessChallengeData: PostboxAccessChallengeData = .none) { self.records = records self.currentRecordId = currentRecordId self.currentAuthRecord = currentAuthRecord + self.accessChallengeData = accessChallengeData } init(from decoder: Decoder) throws { @@ -34,6 +37,12 @@ final class AccountManagerAtomicState: Codable { self.currentRecordId = try container.decodeIfPresent(AccountRecordId.self, forKey: .currentRecordId) } self.currentAuthRecord = try container.decodeIfPresent(AuthAccountRecord.self, forKey: .currentAuthRecord) + + if let accessChallengeData = try? container.decodeIfPresent(PostboxAccessChallengeData.self, forKey: .accessChallengeData) { + self.accessChallengeData = accessChallengeData + } else { + self.accessChallengeData = .none + } } public func encode(to encoder: Encoder) throws { @@ -43,5 +52,6 @@ final class AccountManagerAtomicState: Codable { let currentRecordIdString: String? = self.currentRecordId.flatMap({ "\($0.rawValue)" }) try container.encodeIfPresent(currentRecordIdString, forKey: .currentRecordId) try container.encodeIfPresent(self.currentAuthRecord, forKey: .currentAuthRecord) + try container.encode(self.accessChallengeData, forKey: .accessChallengeData) } } diff --git a/submodules/Postbox/Sources/AccountManagerMetadataTable.swift b/submodules/Postbox/Sources/AccountManagerMetadataTable.swift index 2863d8baf3..9f5eb28ba1 100644 --- a/submodules/Postbox/Sources/AccountManagerMetadataTable.swift +++ b/submodules/Postbox/Sources/AccountManagerMetadataTable.swift @@ -12,7 +12,12 @@ public struct AccessChallengeAttempts: Equatable { } } -public enum PostboxAccessChallengeData: PostboxCoding, Equatable { +public enum PostboxAccessChallengeData: PostboxCoding, Equatable, Codable { + enum CodingKeys: String, CodingKey { + case numericalPassword + case plaintextPassword + } + case none case numericalPassword(value: String) case plaintextPassword(value: String) @@ -44,6 +49,29 @@ public enum PostboxAccessChallengeData: PostboxCoding, Equatable { } } + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + if let value = try? container.decode(String.self, forKey: .numericalPassword) { + self = .numericalPassword(value: value) + } else if let value = try? container.decode(String.self, forKey: .plaintextPassword) { + self = .plaintextPassword(value: value) + } else { + self = .none + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + switch self { + case .none: + break + case let .numericalPassword(value): + try container.encode(value, forKey: .numericalPassword) + case let .plaintextPassword(value): + try container.encode(value, forKey: .plaintextPassword) + } + } + public var isLockable: Bool { if case .none = self { return false diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 6ede82d2b3..9cb5f6fbbc 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3387,13 +3387,32 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G |> restartIfError } + struct TopMessage { + var message: Message + var index: Int + } + let topMessage = pinnedHistorySignal(anchorMessageId: nil, count: 3) - |> map { update -> Message? in + |> map { update -> TopMessage? in switch update { case .Loading: return nil case let .HistoryView(viewValue, _, _, _, _, _, _): - return viewValue.entries.last?.message + if let entry = viewValue.entries.last { + let index: Int + if let location = entry.location { + index = location.index + } else { + index = viewValue.entries.count - 1 + } + + return TopMessage( + message: entry.message, + index: index + ) + } else { + return nil + } } } @@ -3529,7 +3548,20 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if pinnedMessages.messages.isEmpty { return nil } - topMessageId = topMessage?.id ?? pinnedMessages.messages[pinnedMessages.messages.count - 1].message.id + topMessageId = topMessage?.message.id ?? pinnedMessages.messages[pinnedMessages.messages.count - 1].message.id + + if let referenceMessage = referenceMessage, referenceMessage.isScrolled, !pinnedMessages.messages.isEmpty, referenceMessage.id == pinnedMessages.messages[0].message.id, let topMessage = topMessage { + var index = topMessage.index + for message in pinnedMessages.messages { + if message.message.id == topMessage.message.id { + index = message.index + break + } + } + + return ChatPinnedMessage(message: topMessage.message, index: index, totalCount: pinnedMessages.totalCount, topMessageId: topMessageId) + } + //print("reference: \(String(describing: referenceMessage?.id.id)) entries: \(view.entries.map(\.index.id.id))") for i in 0 ..< pinnedMessages.messages.count { let entry = pinnedMessages.messages[i] diff --git a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift index 9675f3ee49..468065476c 100644 --- a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift @@ -311,7 +311,13 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { var imageDimensions: CGSize? var titleStrings: [AnimatedCountLabelNode.Segment] = [] - if pinnedMessage.totalCount > 1 { + if pinnedMessage.totalCount == 2 { + if pinnedMessage.index == 0 { + titleStrings.append(.text(0, NSAttributedString(string: "\(strings.Conversation_PinnedPreviousMessage) ", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor))) + } else { + titleStrings.append(.text(0, NSAttributedString(string: "\(strings.Conversation_PinnedMessage) ", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor))) + } + } else if pinnedMessage.totalCount > 1 { titleStrings.append(.text(0, NSAttributedString(string: "\(strings.Conversation_PinnedMessage)", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor))) titleStrings.append(.text(1, NSAttributedString(string: " #", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor))) titleStrings.append(.number(pinnedMessage.index + 1, NSAttributedString(string: "\(pinnedMessage.index + 1)", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor)))