From 507f6257eb085278181aae6275dfca06227e624c Mon Sep 17 00:00:00 2001 From: Ivan Date: Fri, 5 Nov 2021 13:29:10 +0300 Subject: [PATCH 1/2] PR review feedback for threads --- .../Controllers/Inbox/InboxRenderable.swift | 9 ++++---- .../Inbox/InboxViewController.swift | 1 - .../Inbox/InboxViewDecorator.swift | 5 ++++ .../Threads/ThreadDetailsViewController.swift | 23 ++++++++++++------- .../Message Provider/MessageService.swift | 14 ++++++++--- FlowCryptUI/Cell Nodes/InboxCellNode.swift | 23 ++++++++++++++++--- 6 files changed, 55 insertions(+), 20 deletions(-) diff --git a/FlowCrypt/Controllers/Inbox/InboxRenderable.swift b/FlowCrypt/Controllers/Inbox/InboxRenderable.swift index 158f4b2bf..058f7351c 100644 --- a/FlowCrypt/Controllers/Inbox/InboxRenderable.swift +++ b/FlowCrypt/Controllers/Inbox/InboxRenderable.swift @@ -16,6 +16,7 @@ struct InboxRenderable { } let title: String + let messageCount: Int let subtitle: String let dateString: String var isRead: Bool @@ -43,6 +44,7 @@ extension InboxRenderable { extension InboxRenderable { init(message: Message) { self.title = message.sender ?? "message_unknown_sender".localized + self.messageCount = 1 self.subtitle = message.subject ?? "message_missed_subject".localized self.dateString = DateFormatter().formatDate(message.date) self.isRead = message.isMessageRead @@ -55,12 +57,9 @@ extension InboxRenderable { .compactMap { $0.components(separatedBy: "@").first ?? "" } .unique() .joined(separator: ",") - let messagesCount = thread.messages.count - let amount = messagesCount == 1 - ? "" - : " (\(messagesCount))" - self.title = sender + amount + self.title = sender + self.messageCount = thread.messages.count self.subtitle = thread.subject ?? "message_missed_subject".localized if let date = thread.messages.first?.date { diff --git a/FlowCrypt/Controllers/Inbox/InboxViewController.swift b/FlowCrypt/Controllers/Inbox/InboxViewController.swift index 1518747e0..b021441b2 100644 --- a/FlowCrypt/Controllers/Inbox/InboxViewController.swift +++ b/FlowCrypt/Controllers/Inbox/InboxViewController.swift @@ -5,7 +5,6 @@ import AsyncDisplayKit import FlowCryptCommon import FlowCryptUI -import Promises import Foundation final class InboxViewController: ASDKViewController { diff --git a/FlowCrypt/Controllers/Inbox/InboxViewDecorator.swift b/FlowCrypt/Controllers/Inbox/InboxViewDecorator.swift index 098b7c3ff..0a60763c8 100644 --- a/FlowCrypt/Controllers/Inbox/InboxViewDecorator.swift +++ b/FlowCrypt/Controllers/Inbox/InboxViewDecorator.swift @@ -30,6 +30,11 @@ extension InboxCellNode.Input { self.init( emailText: NSAttributedString.text(from: email, style: style, color: textColor), + countText: { + guard element.messageCount > 0 else { return nil } + let count = element.messageCount > 99 ? "99+" : String(element.messageCount) + return NSAttributedString.text(from: "(\(count))", style: style, color: textColor) + }(), dateText: NSAttributedString.text(from: date, style: style, color: dateColor), messageText: NSAttributedString.text(from: msg, style: style, color: textColor) ) diff --git a/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift b/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift index 56d8ed3ac..293da7762 100644 --- a/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift +++ b/FlowCrypt/Controllers/Threads/ThreadDetailsViewController.swift @@ -135,13 +135,14 @@ extension ThreadDetailsViewController { let message = input[indexPath.section].rawMessage logger.logInfo("Start loading message") - showSpinner("loading_title".localized, isUserInteractionEnabled: true) + handleFetchProgress(state: .fetch) Task { do { let processedMessage = try await messageService.getAndProcessMessage( with: message, - folder: thread.path + folder: thread.path, + progressHandler: { [weak self] in self?.handleFetchProgress(state: $0) } ) handleReceived(message: processedMessage, at: indexPath) } catch { @@ -214,18 +215,13 @@ extension ThreadDetailsViewController { } private func handlePassPhraseEntry(rawMimeData: Data, with passPhrase: String, at indexPath: IndexPath) { - let message = input[indexPath.section].rawMessage - showSpinner("loading_title".localized, isUserInteractionEnabled: true) Task { do { let matched = try await messageService.checkAndPotentiallySaveEnteredPassPhrase(passPhrase) if matched { - let processedMessage = try await messageService.getAndProcessMessage( - with: message, - folder: thread.path - ) + let processedMessage = try await messageService.decryptAndProcessMessage(mime: rawMimeData) handleReceived(message: processedMessage, at: indexPath) } else { handleWrongPathPhrase(for: rawMimeData, with: passPhrase, at: indexPath) @@ -248,6 +244,17 @@ extension ThreadDetailsViewController { } } } + + private func handleFetchProgress(state: MessageFetchState) { + switch state { + case .fetch: + showSpinner("loading_title".localized, isUserInteractionEnabled: true) + case .download(let progress): + updateSpinner(label: "downloading_title".localized, progress: progress) + case .decrypt: + updateSpinner(label: "decrypting_title".localized) + } + } } extension ThreadDetailsViewController: MessageActionsHandler { diff --git a/FlowCrypt/Functionality/Mail Provider/Message Provider/MessageService.swift b/FlowCrypt/Functionality/Mail Provider/Message Provider/MessageService.swift index ea54e16b4..5456eb67c 100644 --- a/FlowCrypt/Functionality/Mail Provider/Message Provider/MessageService.swift +++ b/FlowCrypt/Functionality/Mail Provider/Message Provider/MessageService.swift @@ -96,7 +96,7 @@ final class MessageService { passPhraseService.savePassPhrasesInMemory(passPhrase, for: matchingKeys) return matchingKeys.isNotEmpty } - + func validateMessage(rawMimeData: Data, with passPhrase: String) async throws -> ProcessedMessage { let keys = try await keyService.getPrvKeyInfo() guard keys.isNotEmpty else { @@ -121,8 +121,16 @@ final class MessageService { return try await processMessage(rawMimeData: rawMimeData, with: decrypted, keys: keys) } - func getAndProcessMessage(with input: Message, folder: String) async throws -> ProcessedMessage { - let rawMimeData = try await messageProvider.fetchMsg(message: input, folder: folder, progressHandler: nil) + func getAndProcessMessage( + with input: Message, + folder: String, + progressHandler: ((MessageFetchState) -> Void)? + ) async throws -> ProcessedMessage { + let rawMimeData = try await messageProvider.fetchMsg( + message: input, + folder: folder, + progressHandler: progressHandler + ) return try await decryptAndProcessMessage(mime: rawMimeData) } diff --git a/FlowCryptUI/Cell Nodes/InboxCellNode.swift b/FlowCryptUI/Cell Nodes/InboxCellNode.swift index 846dcc316..569d82ee0 100644 --- a/FlowCryptUI/Cell Nodes/InboxCellNode.swift +++ b/FlowCryptUI/Cell Nodes/InboxCellNode.swift @@ -11,26 +11,35 @@ import AsyncDisplayKit public final class InboxCellNode: CellNode { public struct Input { public let emailText: NSAttributedString + public let countText: NSAttributedString? public let dateText: NSAttributedString public let messageText: NSAttributedString? public init( emailText: NSAttributedString, + countText: NSAttributedString?, dateText: NSAttributedString, messageText: NSAttributedString? ) { self.emailText = emailText + self.countText = countText self.dateText = dateText self.messageText = messageText } } private let emailNode = ASTextNode2() + private let countNode: ASTextNode2? private let dateNode = ASTextNode2() private lazy var messageNode: ASTextNode2? = ASTextNode2() private let separatorNode = ASDisplayNode() public init(input: Input) { + countNode = input.countText.map({ + let node = ASTextNode2() + node.attributedText = $0 + return node + }) super.init() emailNode.attributedText = input.emailText dateNode.attributedText = input.dateText @@ -48,6 +57,15 @@ public final class InboxCellNode: CellNode { } public override func layoutSpecThatFits(_: ASSizeRange) -> ASLayoutSpec { + let emailElement: ASLayoutElement = { + guard let countNode = countNode else { return emailNode } + emailNode.style.flexShrink = 1.0 + let spec = ASStackLayoutSpec.horizontal() + spec.children = [emailNode, countNode] + spec.spacing = 5 + return spec + }() + let nameLocationStack = ASStackLayoutSpec.vertical() nameLocationStack.spacing = 6 nameLocationStack.style.flexShrink = 1.0 @@ -55,11 +73,10 @@ public final class InboxCellNode: CellNode { separatorNode.style.flexGrow = 1.0 separatorNode.style.preferredSize.height = 1.0 - if let messageNode = messageNode { - nameLocationStack.children = [emailNode, messageNode] + nameLocationStack.children = [emailElement, messageNode] } else { - nameLocationStack.children = [emailNode] + nameLocationStack.children = [emailElement] } let headerStackSpec = ASStackLayoutSpec( From 651cbe5159a59e89114a21497d34750d660a82c7 Mon Sep 17 00:00:00 2001 From: Ivan Date: Fri, 5 Nov 2021 13:51:29 +0300 Subject: [PATCH 2/2] Review fixes --- FlowCrypt/Controllers/Inbox/InboxViewDecorator.swift | 2 +- FlowCryptUI/Cell Nodes/InboxCellNode.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/FlowCrypt/Controllers/Inbox/InboxViewDecorator.swift b/FlowCrypt/Controllers/Inbox/InboxViewDecorator.swift index 0a60763c8..0d46c4075 100644 --- a/FlowCrypt/Controllers/Inbox/InboxViewDecorator.swift +++ b/FlowCrypt/Controllers/Inbox/InboxViewDecorator.swift @@ -31,7 +31,7 @@ extension InboxCellNode.Input { self.init( emailText: NSAttributedString.text(from: email, style: style, color: textColor), countText: { - guard element.messageCount > 0 else { return nil } + guard element.messageCount > 1 else { return nil } let count = element.messageCount > 99 ? "99+" : String(element.messageCount) return NSAttributedString.text(from: "(\(count))", style: style, color: textColor) }(), diff --git a/FlowCryptUI/Cell Nodes/InboxCellNode.swift b/FlowCryptUI/Cell Nodes/InboxCellNode.swift index 569d82ee0..d0cf8b1fa 100644 --- a/FlowCryptUI/Cell Nodes/InboxCellNode.swift +++ b/FlowCryptUI/Cell Nodes/InboxCellNode.swift @@ -83,7 +83,7 @@ public final class InboxCellNode: CellNode { direction: .horizontal, spacing: 8, justifyContent: .start, - alignItems: .baselineFirst, + alignItems: .start, children: [nameLocationStack, dateNode] )