Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Update autocompletion unknown recipient view #673

Merged
merged 1 commit into from
Apr 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 13 additions & 6 deletions Mail/Components/RecipientField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct RecipientChip: View {
struct RecipientField: View {
@Binding var recipients: RealmSwift.List<Recipient>
@Binding var autocompletion: [Recipient]
@Binding var unknownRecipientAutocompletion: String
@Binding var addRecipientHandler: ((Recipient) -> Void)?
@FocusState var focusedField: ComposeViewFieldType?
let type: ComposeViewFieldType
Expand Down Expand Up @@ -95,16 +96,21 @@ struct RecipientField: View {
}

private func updateAutocompletion() {
let trimmedCurrentText = currentText.trimmingCharacters(in: .whitespacesAndNewlines)

let contactManager = AccountManager.instance.currentContactManager
let autocompleteContacts = contactManager?.contacts(matching: currentText) ?? []
let autocompleteContacts = contactManager?.contacts(matching: trimmedCurrentText) ?? []
var autocompleteRecipients = autocompleteContacts.map { Recipient(email: $0.email, name: $0.name) }
// Append typed email
if !currentText.isEmpty && !autocompletion
.contains(where: { $0.email.caseInsensitiveCompare(currentText) == .orderedSame }) {
autocompleteRecipients.append(Recipient(email: currentText, name: ""))
}

withAnimation {
autocompletion = autocompleteRecipients.filter { !recipients.map(\.email).contains($0.email) }

if !trimmedCurrentText.isEmpty && !autocompletion
.contains(where: { $0.email.caseInsensitiveCompare(trimmedCurrentText) == .orderedSame }) {
unknownRecipientAutocompletion = trimmedCurrentText
} else {
unknownRecipientAutocompletion = ""
}
}
}

Expand Down Expand Up @@ -135,6 +141,7 @@ struct RecipientField_Previews: PreviewProvider {
PreviewHelper.sampleRecipient1, PreviewHelper.sampleRecipient2, PreviewHelper.sampleRecipient3
].toRealmList()),
autocompletion: .constant([]),
unknownRecipientAutocompletion: .constant(""),
addRecipientHandler: .constant { _ in /* Preview */ },
focusedField: .init(),
type: .to)
Expand Down
57 changes: 57 additions & 0 deletions Mail/Views/New Message/AddRecipientCell.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
Infomaniak Mail - iOS App
Copyright (C) 2022 Infomaniak Network SA

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import MailCore
import SwiftUI
import MailResources

struct AddRecipientCell: View {
@AppStorage(UserDefaults.shared.key(.accentColor)) private var accentColor = DefaultPreferences.accentColor

let recipientEmail: String

var body: some View {
HStack(spacing: 8) {
Circle()
.fill(accentColor.primary.swiftUIColor)
.frame(width: 40, height: 40)
.overlay {
MailResourcesAsset.userBold.swiftUIImage
.resizable()
.foregroundColor(accentColor.onAccent.swiftUIColor)
.frame(width: 24, height: 24)
}

VStack(alignment: .leading, spacing: 0) {
Text(MailResourcesStrings.Localizable.addUnknownRecipientTitle)
.textStyle(.bodyMedium)
Text(recipientEmail)
.textStyle(.bodySecondary)
}

Spacer()
}
.lineLimit(1)
}
}

struct AddRecipientCell_Previews: PreviewProvider {
static var previews: some View {
AddRecipientCell(recipientEmail: "")
}
}
14 changes: 13 additions & 1 deletion Mail/Views/New Message/AutocompletionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import SwiftUI

struct AutocompletionView: View {
@Binding var autocompletion: [Recipient]
@Binding var unknownRecipientAutocompletion: String

let onSelect: (Recipient) -> Void

var body: some View {
Expand All @@ -37,17 +39,27 @@ struct AutocompletionView: View {

IKDivider()
}
}

if !unknownRecipientAutocompletion.isEmpty {
Button {
onSelect(Recipient(email: unknownRecipientAutocompletion, name: ""))
} label: {
AddRecipientCell(recipientEmail: unknownRecipientAutocompletion)
}
.padding(.horizontal, 8)
}
}
.padding(.top, 8)
.padding(.horizontal, 8)
}
}

struct AutocompletionView_Previews: PreviewProvider {
static var previews: some View {
AutocompletionView(autocompletion: .constant([
PreviewHelper.sampleRecipient1, PreviewHelper.sampleRecipient2, PreviewHelper.sampleRecipient3
])) { _ in /* Preview */ }
]),
unknownRecipientAutocompletion: .constant("")) { _ in /* Preview */ }
}
}
80 changes: 44 additions & 36 deletions Mail/Views/New Message/ComposeMessageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,16 @@ struct ComposeMessageView: View {
@LazyInjectService private var matomo: MatomoUtils

@State private var mailboxManager: MailboxManager

@StateRealmObject var draft: Draft
@State private var editor = RichTextEditorModel()
@State private var showCc = false
@FocusState private var focusedField: ComposeViewFieldType?

@State private var addRecipientHandler: ((Recipient) -> Void)?
@State private var autocompletion: [Recipient] = []
@State private var unknownRecipientAutocompletion = ""

@State private var isShowingCamera = false
@State private var isShowingFileSelection = false
@State private var isShowingPhotoLibrary = false
Expand All @@ -81,7 +85,7 @@ struct ComposeMessageView: View {
}

private var shouldDisplayAutocompletion: Bool {
return !autocompletion.isEmpty && focusedField != nil
return (!autocompletion.isEmpty || !unknownRecipientAutocompletion.isEmpty) && focusedField != nil
}

private init(mailboxManager: MailboxManager, draft: Draft) {
Expand All @@ -103,39 +107,6 @@ struct ComposeMessageView: View {
_attachmentsManager = StateObject(wrappedValue: AttachmentsManager(draft: draft, mailboxManager: mailboxManager))
}

static func newMessage(mailboxManager: MailboxManager) -> ComposeMessageView {
return ComposeMessageView(mailboxManager: mailboxManager, draft: Draft(localUUID: UUID().uuidString))
}

static func replyOrForwardMessage(messageReply: MessageReply, mailboxManager: MailboxManager) -> ComposeMessageView {
let message = messageReply.message
// If message doesn't exist anymore try to show the frozen one
let freshMessage = message.thaw() ?? message
return ComposeMessageView(
mailboxManager: mailboxManager,
draft: .replying(to: freshMessage, mode: messageReply.replyMode, localDraftUUID: messageReply.localDraftUUID)
)
}

static func editDraft(draft: Draft, mailboxManager: MailboxManager) -> ComposeMessageView {
@InjectService var matomo: MatomoUtils
matomo.track(eventWithCategory: .newMessage, name: "openFromDraft")
return ComposeMessageView(mailboxManager: mailboxManager, draft: draft)
}

static func writingTo(recipient: Recipient, mailboxManager: MailboxManager) -> ComposeMessageView {
return ComposeMessageView(mailboxManager: mailboxManager, draft: .writing(to: recipient))
}

static func mailTo(urlComponents: URLComponents, mailboxManager: MailboxManager) -> ComposeMessageView {
let draft = Draft.mailTo(subject: urlComponents.getQueryItem(named: "subject"),
body: urlComponents.getQueryItem(named: "body"),
to: [Recipient(email: urlComponents.path, name: "")],
cc: Recipient.createListUsing(from: urlComponents, name: "cc"),
bcc: Recipient.createListUsing(from: urlComponents, name: "bcc"))
return ComposeMessageView(mailboxManager: mailboxManager, draft: draft)
}

var body: some View {
NavigationView {
ScrollView(.vertical, showsIndicators: true) {
Expand All @@ -157,7 +128,8 @@ struct ComposeMessageView: View {

// Show the rest of the view, or the autocompletion list
if shouldDisplayAutocompletion {
AutocompletionView(autocompletion: $autocompletion) { recipient in
AutocompletionView(autocompletion: $autocompletion,
unknownRecipientAutocompletion: $unknownRecipientAutocompletion) { recipient in
matomo.track(eventWithCategory: .newMessage, name: "addNewRecipient")
addRecipientHandler?(recipient)
}
Expand Down Expand Up @@ -281,6 +253,7 @@ struct ComposeMessageView: View {
showCc: type == .to ? $showCc : nil) {
RecipientField(recipients: binding(for: type),
autocompletion: $autocompletion,
unknownRecipientAutocompletion: $unknownRecipientAutocompletion,
addRecipientHandler: $addRecipientHandler,
focusedField: _focusedField,
type: type)
Expand Down Expand Up @@ -333,7 +306,42 @@ struct ComposeMessageView: View {
}
}

struct NewMessageView_Previews: PreviewProvider {
extension ComposeMessageView {
static func newMessage(mailboxManager: MailboxManager) -> ComposeMessageView {
return ComposeMessageView(mailboxManager: mailboxManager, draft: Draft(localUUID: UUID().uuidString))
}

static func replyOrForwardMessage(messageReply: MessageReply, mailboxManager: MailboxManager) -> ComposeMessageView {
let message = messageReply.message
// If message doesn't exist anymore try to show the frozen one
let freshMessage = message.thaw() ?? message
return ComposeMessageView(
mailboxManager: mailboxManager,
draft: .replying(to: freshMessage, mode: messageReply.replyMode, localDraftUUID: messageReply.localDraftUUID)
)
}

static func editDraft(draft: Draft, mailboxManager: MailboxManager) -> ComposeMessageView {
@InjectService var matomo: MatomoUtils
matomo.track(eventWithCategory: .newMessage, name: "openFromDraft")
return ComposeMessageView(mailboxManager: mailboxManager, draft: draft)
}

static func writingTo(recipient: Recipient, mailboxManager: MailboxManager) -> ComposeMessageView {
return ComposeMessageView(mailboxManager: mailboxManager, draft: .writing(to: recipient))
}

static func mailTo(urlComponents: URLComponents, mailboxManager: MailboxManager) -> ComposeMessageView {
let draft = Draft.mailTo(subject: urlComponents.getQueryItem(named: "subject"),
body: urlComponents.getQueryItem(named: "body"),
to: [Recipient(email: urlComponents.path, name: "")],
cc: Recipient.createListUsing(from: urlComponents, name: "cc"),
bcc: Recipient.createListUsing(from: urlComponents, name: "bcc"))
return ComposeMessageView(mailboxManager: mailboxManager, draft: draft)
}
}

struct ComposeMessageView_Previews: PreviewProvider {
static var previews: some View {
ComposeMessageView.newMessage(mailboxManager: PreviewHelper.sampleMailboxManager)
}
Expand Down
1 change: 1 addition & 0 deletions Mail/Views/New Message/NewMessageCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ struct RecipientCellView_Previews: PreviewProvider {
showCc: .constant(false)) {
RecipientField(recipients: .constant([PreviewHelper.sampleRecipient1].toRealmList()),
autocompletion: .constant([]),
unknownRecipientAutocompletion: .constant(""),
addRecipientHandler: .constant { _ in /* Preview */ },
focusedField: .init(),
type: .to)
Expand Down
16 changes: 16 additions & 0 deletions MailResources/Assets.xcassets/user-bold.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"images" : [
{
"filename" : "user-bold.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.