Skip to content

Commit

Permalink
refactor: Update autocompletion view
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinperignon committed Apr 3, 2023
1 parent 1748717 commit bfb502f
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 43 deletions.
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 */ }
}
}
78 changes: 42 additions & 36 deletions Mail/Views/New Message/ComposeMessageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ struct ComposeMessageView: View {
@StateObject private var attachmentsManager: AttachmentsManager
@State private var isShowingCancelAttachmentsError = false

@State private var unknownRecipientAutocompletion = ""

@State var scrollView: UIScrollView?

@StateObject private var alert = NewMessageAlert()
Expand All @@ -81,7 +83,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 +105,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 +126,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 +251,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 +304,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.

0 comments on commit bfb502f

Please sign in to comment.