Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
da0083d
#1337 add RecipientBase protocol
sosnovsky Feb 17, 2022
6a37325
#1337 add names to recipients
sosnovsky Feb 18, 2022
49dd73f
Merge branch 'master' into feature/issue-1337-fes-names
sosnovsky Feb 21, 2022
f1b19fd
Merge branch 'master' into feature/issue-1337-fes-names
sosnovsky Feb 21, 2022
bd2e381
Show recipient name when available
sosnovsky Feb 21, 2022
b14e857
Merge branch 'master' into feature/issue-1337-fes-names
sosnovsky Feb 22, 2022
7d10b97
Update recipients search logic
sosnovsky Feb 22, 2022
2982212
merge MessageRecipient and Recipient
sosnovsky Feb 22, 2022
9f18dc8
fix unit tests
sosnovsky Feb 23, 2022
04e5b71
update public key detail screen
sosnovsky Feb 23, 2022
b3bd61f
code cleanup
sosnovsky Feb 23, 2022
ac0b0b9
fixes for ui tests
sosnovsky Feb 23, 2022
fddf24b
fix ui tests
sosnovsky Feb 28, 2022
6720e48
#1337 fix conflicts
ioanmo226 Mar 21, 2022
f69be50
#1337 fix local contact provider mock
ioanmo226 Mar 21, 2022
b05cdc4
#1337 remove unused files
ioanmo226 Mar 21, 2022
cd7f37b
#1337 fix lint issue
ioanmo226 Mar 21, 2022
a255537
#1337 fix check reply and forward test
ioanmo226 Mar 21, 2022
1a7ea59
#1337 fix check thread test
ioanmo226 Mar 21, 2022
b1fd927
#1337 fix attachment test
ioanmo226 Mar 21, 2022
e09f928
#1337 fix draft recipients evaulate issue
ioanmo226 Mar 22, 2022
67dfc23
#1337 use MCOAddress to parse mailbox address
ioanmo226 Mar 22, 2022
384acab
#1337 fix do not use email for name in recipient
ioanmo226 Mar 22, 2022
500715b
#1337 fix evaluate recipient issue
ioanmo226 Mar 23, 2022
0d35bfc
fix: reply all crash issue
ioanmo226 Mar 23, 2022
c2342e3
#1337 fix invalid type in compose view
ioanmo226 Mar 23, 2022
635aba2
fix: conflits
ioanmo226 Mar 23, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions FlowCrypt.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
50531BE42629B9A80039BAE9 /* AttachmentNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50531BE32629B9A80039BAE9 /* AttachmentNode.swift */; };
51074E6427BD0C5800FBB124 /* RecipientToggleButtonNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51074E6327BD0C5800FBB124 /* RecipientToggleButtonNode.swift */; };
5109A77C272153B400D2CEB9 /* LeftAlignedCollectionViewFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5109A77B272153B400D2CEB9 /* LeftAlignedCollectionViewFlowLayout.swift */; };
510BB63527BE92CC00B1011F /* RecipientBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510BB63427BE92CC00B1011F /* RecipientBase.swift */; };
511D07E12769FBBA0050417B /* MessagePasswordCellNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511D07E02769FBBA0050417B /* MessagePasswordCellNode.swift */; };
511D07E3276A2DF80050417B /* ButtonWithPaddingNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511D07E2276A2DF80050417B /* ButtonWithPaddingNode.swift */; };
512C1414271077F8002DE13F /* GoogleAPIClientForREST_PeopleService in Frameworks */ = {isa = PBXBuildFile; productRef = 512C1413271077F8002DE13F /* GoogleAPIClientForREST_PeopleService */; };
Expand Down Expand Up @@ -506,6 +507,7 @@
50531BE32629B9A80039BAE9 /* AttachmentNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentNode.swift; sourceTree = "<group>"; };
51074E6327BD0C5800FBB124 /* RecipientToggleButtonNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipientToggleButtonNode.swift; sourceTree = "<group>"; };
5109A77B272153B400D2CEB9 /* LeftAlignedCollectionViewFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeftAlignedCollectionViewFlowLayout.swift; sourceTree = "<group>"; };
510BB63427BE92CC00B1011F /* RecipientBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipientBase.swift; sourceTree = "<group>"; };
511D07E02769FBBA0050417B /* MessagePasswordCellNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePasswordCellNode.swift; sourceTree = "<group>"; };
511D07E2276A2DF80050417B /* ButtonWithPaddingNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonWithPaddingNode.swift; sourceTree = "<group>"; };
5133B66F2716320F00C95463 /* ContactKeyDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactKeyDetailViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -990,6 +992,7 @@
2C141B2E274578C20038A3F8 /* Keypair.swift */,
5180CB9227357B67001FC7EF /* RawClientConfiguration.swift */,
2C141B2B274572D50038A3F8 /* Recipient.swift */,
510BB63427BE92CC00B1011F /* RecipientBase.swift */,
2CC50FAE27440B2C0051629A /* Session.swift */,
9F0C3C132316E69300299985 /* User.swift */,
);
Expand Down Expand Up @@ -2712,6 +2715,7 @@
9F31AB8E23298BCF00CF87EA /* Imap+folders.swift in Sources */,
D2891AC224C59EFA008918E3 /* KeyService.swift in Sources */,
D269E02724103A20000495C3 /* ComposeViewControllerInput.swift in Sources */,
510BB63527BE92CC00B1011F /* RecipientBase.swift in Sources */,
9FAFD75D2714A06400321FA4 /* InboxProviders.swift in Sources */,
2C141B2C274572D50038A3F8 /* Recipient.swift in Sources */,
9F0C3C142316E69300299985 /* User.swift in Sources */,
Expand Down
101 changes: 65 additions & 36 deletions FlowCrypt/Controllers/Compose/ComposeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import PhotosUI
final class ComposeViewController: TableNodeViewController {

private enum Constants {
static let endTypingCharacters = [",", " ", "\n", ";"]
static let endTypingCharacters = [",", "\n", ";"]
static let minRecipientsPartHeight: CGFloat = 32
}

Expand All @@ -29,7 +29,7 @@ final class ComposeViewController: TableNodeViewController {
}

private enum State {
case main, searchEmails([String])
case main, searchEmails([Recipient])
}

enum Section: Hashable {
Expand All @@ -49,7 +49,6 @@ final class ComposeViewController: TableNodeViewController {
}

private var userFinishedSearching = false
private var isRecipientLoading = false
private var userTappedOutSideRecipientsArea = false
private var shouldShowEmailRecipientsLabel = false
private let appContext: AppContextWithUser
Expand Down Expand Up @@ -199,13 +198,26 @@ final class ComposeViewController: TableNodeViewController {
func update(with message: Message) {
self.contextToSend.subject = message.subject
self.contextToSend.message = message.raw
self.contextToSend.recipients = [
ComposeMessageRecipient(
email: "tom@flowcrypt.com",
type: .to,
state: decorator.recipientIdleState
)
]
message.to.forEach { recipient in
evaluateMessage(recipient: recipient, type: .to)
}
message.cc.forEach { recipient in
evaluateMessage(recipient: recipient, type: .cc)
}
message.bcc.forEach { recipient in
evaluateMessage(recipient: recipient, type: .bcc)
}
}

func evaluateMessage(recipient: Recipient, type: RecipientType) {
let recipient = ComposeMessageRecipient(
email: recipient.email,
name: recipient.name,
type: type,
state: decorator.recipientIdleState
)
contextToSend.add(recipient: recipient)
evaluate(recipient: recipient)
}

private func observeComposeUpdates() {
Expand Down Expand Up @@ -326,16 +338,12 @@ extension ComposeViewController {
private func setupQuote() {
guard input.isQuote else { return }

input.quoteRecipients.forEach { email in
let recipient = ComposeMessageRecipient(email: email, type: .to, state: decorator.recipientIdleState)
contextToSend.add(recipient: recipient)
evaluate(recipient: recipient)
input.quoteRecipients.forEach { recipient in
evaluateMessage(recipient: recipient, type: .to)
}

input.quoteCCRecipients.forEach { email in
let recipient = ComposeMessageRecipient(email: email, type: .cc, state: decorator.recipientIdleState)
contextToSend.add(recipient: recipient)
evaluate(recipient: recipient)
input.quoteCCRecipients.forEach { recipient in
evaluateMessage(recipient: recipient, type: .cc)
}

if input.quoteCCRecipients.isNotEmpty {
Expand Down Expand Up @@ -633,10 +641,21 @@ extension ComposeViewController: ASTableDelegate, ASTableDataSource {
return ASCellNode()
}
return self.attachmentNode(for: indexPath.row)
case let (.searchEmails(emails), .searchResults):
case let (.searchEmails(recipients), .searchResults):
guard indexPath.row > 0 else { return DividerCellNode() }
guard emails.isNotEmpty else { return self.noSearchResultsNode() }
return InfoCellNode(input: self.decorator.styledRecipientInfo(with: emails[indexPath.row-1]))
guard recipients.isNotEmpty else { return self.noSearchResultsNode() }
guard let recipient = recipients[safe: indexPath.row-1] else { return ASCellNode() }

if let name = recipient.name {
let input = self.decorator.styledRecipientInfo(
with: recipient.email,
name: name
)
return LabelCellNode(input: input)
} else {
let input = self.decorator.styledRecipientInfo(with: recipient.email)
return InfoCellNode(input: input)
}
case (.searchEmails, .contacts):
return indexPath.row == 0 ? DividerCellNode() : self.enableGoogleContactsNode()
default:
Expand All @@ -646,13 +665,13 @@ extension ComposeViewController: ASTableDelegate, ASTableDataSource {
}

func tableNode(_ tableNode: ASTableNode, didSelectRowAt indexPath: IndexPath) {
if case let .searchEmails(emails) = state, let recipientType = selectedRecipientType {
if case let .searchEmails(recipients) = state, let recipientType = selectedRecipientType {
guard let section = sectionsList[safe: indexPath.section] else { return }

switch section {
case .searchResults:
let selectedEmail = emails[safe: indexPath.row-1]
handleEndEditingAction(with: selectedEmail, for: recipientType)
let recipient = recipients[safe: indexPath.row-1]
handleEndEditingAction(with: recipient?.email, name: recipient?.name, for: recipientType)
case .contacts:
askForContactsPermission()
default:
Expand Down Expand Up @@ -692,7 +711,8 @@ extension ComposeViewController {
}

private func showRecipientLabelIfNecessary() {
guard !self.isRecipientLoading,
let isRecipientLoading = self.contextToSend.recipients.filter { $0.state == decorator.recipientIdleState }.isNotEmpty
guard !isRecipientLoading,
self.contextToSend.recipients.isNotEmpty,
self.userTappedOutSideRecipientsArea else {
return
Expand Down Expand Up @@ -963,9 +983,9 @@ extension ComposeViewController {
}
}

private func handleEndEditingAction(with text: String?, for recipientType: RecipientType) {
private func handleEndEditingAction(with email: String?, name: String? = nil, for recipientType: RecipientType) {
guard shouldEvaluateRecipientInput,
let text = text, text.isNotEmpty
let email = email, email.isNotEmpty
else { return }

let recipients = contextToSend.recipients(type: recipientType)
Expand All @@ -984,7 +1004,13 @@ extension ComposeViewController {

contextToSend.set(recipients: idleRecipients, for: recipientType)

let newRecipient = ComposeMessageRecipient(email: text, type: recipientType, state: decorator.recipientIdleState)
let newRecipient = ComposeMessageRecipient(
email: email,
name: name,
type: recipientType,
state: decorator.recipientIdleState
)

let indexOfRecipient: Int

let indexPath = recipientsIndexPath(type: recipientType, part: .list)
Expand Down Expand Up @@ -1090,10 +1116,14 @@ extension ComposeViewController {
private func searchEmail(with query: String) {
Task {
do {
let localEmails = try localContactsProvider.searchEmails(query: query)
let cloudEmails = try? await cloudContactProvider.searchContacts(query: query)
let emails = Set([localEmails, cloudEmails].compactMap { $0 }.flatMap { $0 })
updateState(with: .searchEmails(Array(emails)))
let cloudRecipients = try await cloudContactProvider.searchContacts(query: query)
let localRecipients = try localContactsProvider.searchRecipients(query: query)

let recipients = (cloudRecipients + localRecipients)
.unique()
.sorted()

updateState(with: .searchEmails(recipients))
} catch {
showAlert(message: error.localizedDescription)
}
Expand All @@ -1110,21 +1140,20 @@ extension ComposeViewController {
}

Task {
isRecipientLoading = true
var localContact: RecipientWithSortedPubKeys?
do {
if let contact = try await localContactsProvider.searchRecipient(with: recipient.email) {
localContact = contact
handleEvaluation(for: contact)
}

let contactWithFetchedKeys = try await pubLookup.fetchRemoteUpdateLocal(with: recipient.email)
let contact = Recipient(recipient: recipient)
let contactWithFetchedKeys = try await pubLookup.fetchRemoteUpdateLocal(with: contact)

handleEvaluation(for: contactWithFetchedKeys)
isRecipientLoading = false
showRecipientLabelIfNecessary()
} catch {
handleEvaluation(error: error, with: recipient.email, contact: localContact)
isRecipientLoading = false
showRecipientLabelIfNecessary()
}
}
Expand Down
10 changes: 5 additions & 5 deletions FlowCrypt/Controllers/Compose/ComposeViewControllerInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ struct ComposeMessageInput: Equatable {
static let empty = ComposeMessageInput(type: .idle)

struct MessageQuoteInfo: Equatable {
let recipients: [String]
let ccRecipients: [String]
let sender: String?
let recipients: [Recipient]
let ccRecipients: [Recipient]
let sender: Recipient?
let subject: String?
let mime: Data?
let sentDate: Date
Expand All @@ -31,14 +31,14 @@ struct ComposeMessageInput: Equatable {

let type: InputType

var quoteRecipients: [String] {
var quoteRecipients: [Recipient] {
guard case .reply(let info) = type else {
return []
}
return info.recipients
}

var quoteCCRecipients: [String] {
var quoteCCRecipients: [Recipient] {
guard case .reply(let info) = type else {
return []
}
Expand Down
27 changes: 22 additions & 5 deletions FlowCrypt/Controllers/Compose/ComposeViewDecorator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,23 @@ struct ComposeViewDecorator {
)
}

func styledRecipientInfo(with email: String, name: String) -> LabelCellNode.Input {
LabelCellNode.Input(
title: name.attributed(
.medium(17),
color: .mainTextColor.withAlphaComponent(0.8),
alignment: .left
),
text: email.attributed(
.regular(15),
color: .mainTextColor.withAlphaComponent(0.5),
alignment: .left
),
insets: .deviceSpecificTextInsets(top: 8, bottom: 8),
spacing: 0
)
}

func styledMessage(with text: String) -> NSAttributedString {
text.attributed(.regular(17))
}
Expand All @@ -95,7 +112,7 @@ struct ComposeViewDecorator {
dateFormatter.timeStyle = .short
let time = dateFormatter.string(from: info.sentDate)

let from = info.sender ?? "unknown sender"
let from = info.sender?.email ?? "unknown sender"

let text: String = "\n\n"
+ "compose_quote_from".localizeWithArguments(date, time, from)
Expand Down Expand Up @@ -162,9 +179,9 @@ struct ComposeViewDecorator {
color: UIColor,
imageName: String
) -> MessagePasswordCellNode.Input {
.init(
text: text.attributed(.regular(14), color: color),
color: color,
.init(
text: text.attributed(.regular(14), color: color),
color: color,
image: UIImage(systemName: imageName)?.tinted(color)
)
}
Expand Down Expand Up @@ -311,7 +328,7 @@ extension ComposeViewDecorator {
extension RecipientEmailsCellNode.Input {
init(_ recipient: ComposeMessageRecipient) {
self.init(
email: recipient.email.lowercased().attributed(
email: recipient.displayName.attributed(
.regular(17),
color: recipient.state.textColor,
alignment: .left
Expand Down
7 changes: 3 additions & 4 deletions FlowCrypt/Controllers/Inbox/InboxRenderable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ extension InboxRenderable {
extension InboxRenderable {

init(message: Message) {
self.title = message.sender ?? "message_unknown_sender".localized
self.title = message.sender?.shortName ?? "message_unknown_sender".localized
self.messageCount = 1
self.subtitle = message.subject ?? "message_missing_subject".localized
self.dateString = DateFormatter().formatDate(message.date)
Expand Down Expand Up @@ -71,15 +71,14 @@ extension InboxRenderable {
if folderPath == MessageLabelType.sent.value {
let recipients = thread.messages
.flatMap(\.allRecipients)
.map(\.displayName)
.map(\.shortName)
.unique()
.joined(separator: ", ")
return "To: \(recipients)"

} else {
return thread.messages
.compactMap(\.sender)
.compactMap { $0.components(separatedBy: "@").first }
.compactMap(\.sender?.shortName)
.unique()
.joined(separator: ",")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct ContactDetailDecorator {

func userNodeInput(with contact: RecipientWithSortedPubKeys) -> ContactUserCellNode.Input {
ContactUserCellNode.Input(
user: (contact.name ?? contact.email).attributed(.regular(16))
user: contact.formatted.attributed(.regular(16))
)
}

Expand Down
6 changes: 3 additions & 3 deletions FlowCrypt/Controllers/Threads/ThreadDetailsDecorator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import UIKit

extension ThreadMessageInfoCellNode.Input {
init(threadMessage: ThreadDetailsViewController.Input, index: Int) {
let sender = threadMessage.rawMessage.sender ?? "message_unknown_sender".localized
let sender = threadMessage.rawMessage.sender?.displayName ?? "message_unknown_sender".localized
let recipientPrefix = "to".localized
let recipientsList = threadMessage.rawMessage
.allRecipients
.map(\.displayName)
.map(\.shortName)
.joined(separator: ", ")
let recipientLabel = [recipientPrefix, recipientsList].joined(separator: " ")
let date = DateFormatter().formatDate(threadMessage.rawMessage.date)
Expand All @@ -34,7 +34,7 @@ extension ThreadMessageInfoCellNode.Input {
signatureBadge: makeSignatureBadge(threadMessage),
sender: .text(from: sender, style: style, color: .label),
recipientLabel: .text(from: recipientLabel, style: style, color: .secondaryLabel),
recipients: threadMessage.rawMessage.recipients.map(\.rawString),
recipients: threadMessage.rawMessage.to.map(\.rawString),
ccRecipients: threadMessage.rawMessage.cc.map(\.rawString),
bccRecipients: threadMessage.rawMessage.bcc.map(\.rawString),
date: .text(from: date, style: style, color: dateColor),
Expand Down
Loading