Skip to content
Snippets Groups Projects
Commit af0c08a4 authored by cruxfilm's avatar cruxfilm
Browse files

Fixed showing of Bcc field.

parent 19b98ea3
Branches
No related tags found
1 merge request!76Resolve "InboxView & MailListView improvements"
...@@ -10,56 +10,41 @@ import SwiftUI ...@@ -10,56 +10,41 @@ import SwiftUI
/// A view used to compose and send an email. /// A view used to compose and send an email.
struct ComposeView: View { struct ComposeView: View {
@State private var cc = "" @State private var cc = ""
@State private var isEditingCcOrBcc = false @ObservedObject var model: ComposeModel
@ObservedObject var composer: ComposeModel
/// - Parameter preData: Data of email to reply to or forward. /// - Parameter preData: Data of email to reply to or forward.
init(preData: PreMailData? = nil) { init(preData: PreMailData? = nil) {
composer = ComposeModel(preData: preData) model = ComposeModel(preData: preData)
} }
var body: some View { var body: some View {
VStack { VStack {
// Top bar with Cancel and Send button // Top bar with Cancel and Send button
ComposeViewHeader() ComposeViewHeader()
.environmentObject(composer) .environmentObject(model)
Divider() Divider()
// "To" recipient // "To" recipients
RecipientField(recipientFieldModel: composer.recipientsModel.toModel) RecipientField(model: model.recipientsModel.toModel)
Divider() Divider()
// "Cc/Bcc" recipient // "Cc/Bcc" recipients
if isEditingCcOrBcc || !cc.isEmpty { CcAndBccFields(model: model.recipientsModel)
RecipientField(recipientFieldModel: composer.recipientsModel.ccModel)
Divider()
RecipientField(recipientFieldModel: composer.recipientsModel.bccModel)
} else {
// TODO: Solve "Cc/Bcc" <--> "Cc", "Bcc" switch more elegantly.
// "Cc/Bcc" field never actually gets used, it gets replaced by
// separate "Cc" and "Bcc" RecipientFields above, once selected.
TextField("Cc" + "/" + "Bcc", text: $cc) { ccSelected in
self.isEditingCcOrBcc = ccSelected
}
}
Divider()
// Subject // Subject
HStack { HStack {
Text("Subject") Text("Subject")
.foregroundColor(Color(UIColor.tertiaryLabel)) .foregroundColor(Color(UIColor.tertiaryLabel))
TextField("", text: $composer.subject) TextField("", text: $model.subject)
.autocapitalization(.none) .autocapitalization(.none)
.frame(minWidth: 0, maxWidth: .infinity) .frame(minWidth: 0, maxWidth: .infinity)
} }
Divider() Divider()
// Email body // Email body
TextEditor(text: $composer.body) TextEditor(text: $model.body)
} }
.padding() .padding()
.animation(.default) .animation(.default)
...@@ -67,23 +52,41 @@ struct ComposeView: View { ...@@ -67,23 +52,41 @@ struct ComposeView: View {
} }
} }
struct CcAndBccFields: View {
@ObservedObject var model: RecipientsModel
var body: some View {
VStack {
RecipientField(model: model.ccModel)
Divider()
if model.showBccField {
RecipientField(model: model.bccModel)
Divider()
}
}
}
}
/// A view in which recipients get added or removed. /// A view in which recipients get added or removed.
struct RecipientField: View { struct RecipientField: View {
@ObservedObject var recipientFieldModel: RecipientFieldModel @ObservedObject var model: RecipientFieldModel
@State var showList = false @State var showList = false
var body: some View { var body: some View {
VStack { VStack {
HStack { HStack {
// Recipient text field // Recipient text field
Text(recipientFieldModel.type.asString) Text(model.type.asString)
.foregroundColor(Color(UIColor.tertiaryLabel)) .foregroundColor(Color(UIColor.tertiaryLabel))
// Shows selected recipients as blue capsules // Shows selected recipients as blue capsules
// followed by TextField for new recipients // followed by TextField for new recipients
ScrollView(.horizontal) { ScrollView(.horizontal) {
HStack(spacing: 4) { HStack(spacing: 4) {
ForEach(recipientFieldModel.selectedContacts) { (recipient: AddressRecord) in ForEach(model.selectedContacts) { (recipient: AddressRecord) in
Text(recipient.displayname ?? recipient.email) Text(recipient.displayname ?? recipient.email)
.foregroundColor(.white) .foregroundColor(.white)
.padding(.horizontal, 12) .padding(.horizontal, 12)
...@@ -91,9 +94,18 @@ struct RecipientField: View { ...@@ -91,9 +94,18 @@ struct RecipientField: View {
.background(Color.accentColor) .background(Color.accentColor)
.clipShape(Capsule()) .clipShape(Capsule())
} }
TextField("", text: $recipientFieldModel.text, onCommit: { TextField("", text: $model.text) { isEditing in
recipientFieldModel.commitText() model.parent?.isEditingCcOrBcc = isEditing
}) } onCommit: {
model.commitText()
// TODO: Fix bug on first Cc or Bcc recipient commit
// For some reason, model.selectedContacts.count stays 0
// after the first committed recipient, leading to the Cc
// and Bcc fields getting collapsed again despite the
// first recipient clearly getting rendered as a blue
// capsule in the ForEach loop above. 🤔🤔🤔
print(model.selectedContacts.count)
}
.frame(minWidth: 200) .frame(minWidth: 200)
.autocapitalization(.none) .autocapitalization(.none)
.keyboardType(.emailAddress) .keyboardType(.emailAddress)
...@@ -101,27 +113,29 @@ struct RecipientField: View { ...@@ -101,27 +113,29 @@ struct RecipientField: View {
} }
// Toggles contact list // Toggles contact list
if model.type != .ccBcc {
Button(action: { showList.toggle() }) { Button(action: { showList.toggle() }) {
Image(systemName: !showList ? "plus.circle" : "chevron.up.circle") Image(systemName: !showList ? "plus.circle" : "chevron.up.circle")
} }
} }
}
.frame(height: 20) .frame(height: 20)
// Contact list // Contact list
if showList { if showList {
Divider() Divider()
RecipientListView() RecipientListView()
.frame(height: 464) .frame(height: 460)
} }
} }
.environmentObject(recipientFieldModel) .environmentObject(model)
} }
} }
/// A view containing the Cancel and Send buttons for an email. /// A view containing the Cancel and Send buttons for an email.
struct ComposeViewHeader: View { struct ComposeViewHeader: View {
@Environment(\.presentationMode) var presentationMode @Environment(\.presentationMode) var presentationMode
@EnvironmentObject var composer: ComposeModel @EnvironmentObject var model: ComposeModel
var body: some View { var body: some View {
VStack { VStack {
...@@ -130,7 +144,6 @@ struct ComposeViewHeader: View { ...@@ -130,7 +144,6 @@ struct ComposeViewHeader: View {
.fill(Color(.lightGray)) .fill(Color(.lightGray))
.frame(width: 70, height: 5) .frame(width: 70, height: 5)
HStack { HStack {
// Cancel button // Cancel button
Button("Cancel") { Button("Cancel") {
...@@ -140,17 +153,17 @@ struct ComposeViewHeader: View { ...@@ -140,17 +153,17 @@ struct ComposeViewHeader: View {
Spacer() Spacer()
// Send button // Send button
Button(action: { Button {
composer.sendMail() model.sendMail()
presentationMode.wrappedValue.dismiss() presentationMode.wrappedValue.dismiss()
}) { } label: {
if composer.encryptionOff { if model.encryptionOff {
UnencryptedSendButton(grayedOut: composer.recipientsModel.hasNoRecipients) UnencryptedSendButton(grayedOut: model.recipientsModel.hasNoRecipients)
} else { } else {
EncryptedSendButton(grayedOut: composer.recipientsModel.hasNoRecipients) EncryptedSendButton(grayedOut: model.recipientsModel.hasNoRecipients)
} }
} }
.disabled(composer.recipientsModel.hasNoRecipients) .disabled(model.recipientsModel.hasNoRecipients)
} }
} }
} }
......
...@@ -11,12 +11,13 @@ import SwiftUI ...@@ -11,12 +11,13 @@ import SwiftUI
/// A model for a single recipient field. /// A model for a single recipient field.
class RecipientFieldModel: ObservableObject { class RecipientFieldModel: ObservableObject {
@Published var suggestions: [AddressRecord] = [] @Published var suggestions = [AddressRecord]()
@Published var selectedContacts = [AddressRecord]() // TODO: As AddressProperty??? @Published var selectedContacts = [AddressRecord]()
@Published var type: RecipientType
private var dataprovider: PersistentDataProvider private var dataprovider: PersistentDataProvider
let type: RecipientType var parent: RecipientsModel?
init(type: RecipientType, parent: RecipientsModel?, dataprovider: PersistentDataProvider) { init(type: RecipientType, dataprovider: PersistentDataProvider) {
self.type = type self.type = type
self.dataprovider = dataprovider self.dataprovider = dataprovider
} }
...@@ -68,16 +69,18 @@ class RecipientFieldModel: ObservableObject { ...@@ -68,16 +69,18 @@ class RecipientFieldModel: ObservableObject {
addNewAddress(text) addNewAddress(text)
text = "" text = ""
} }
print(selectedContacts.count)
} }
func addNewAddress(_ address: String) { func addNewAddress(_ address: String) {
guard address.count > 0 else { guard address.count > 0 && address.contains("@") else {
// TODO: Add email validiation + warning? // TODO: Add email validation + warning?
return return
} }
dataprovider.importNewData(from: [AddressProperties(email: address)]) { error in dataprovider.importNewData(from: [AddressProperties(email: address)]) { error in
let frc = self.dataprovider.createFetchResultController(fetchRequest: AddressRecord.lookForExisting(email: address)) let frc = self.dataprovider.createFetchResultController(fetchRequest: AddressRecord.lookForExisting(email: address))
if let addresses = frc.fetchedObjects, let addr = addresses.first { if let addresses = frc.fetchedObjects, let addr = addresses.first {
self.selectedContacts.append(addr) self.selectedContacts.append(addr)
} }
......
...@@ -15,6 +15,7 @@ enum RecipientType { ...@@ -15,6 +15,7 @@ enum RecipientType {
case to case to
case cc case cc
case bcc case bcc
case ccBcc
var asString: LocalizedStringKey { var asString: LocalizedStringKey {
switch self { switch self {
...@@ -24,6 +25,8 @@ enum RecipientType { ...@@ -24,6 +25,8 @@ enum RecipientType {
return "Cc" return "Cc"
case .bcc: case .bcc:
return "Bcc" return "Bcc"
case .ccBcc:
return "CcBcc"
} }
} }
} }
...@@ -33,13 +36,25 @@ class RecipientsModel: ObservableObject { ...@@ -33,13 +36,25 @@ class RecipientsModel: ObservableObject {
let toModel: RecipientFieldModel let toModel: RecipientFieldModel
let ccModel: RecipientFieldModel let ccModel: RecipientFieldModel
let bccModel: RecipientFieldModel let bccModel: RecipientFieldModel
@Published var showBccField = false
/// Initializes models for "To", "Cc", and "Bcc" fields. /// Initializes models for "To", "Cc", and "Bcc" fields.
init() { init() {
let dataprovider = LetterboxModel.instance.dataProvider let dataprovider = LetterboxModel.instance.dataProvider
toModel = RecipientFieldModel(type: .to, parent: nil, dataprovider: dataprovider) toModel = RecipientFieldModel(type: .to, dataprovider: dataprovider)
ccModel = RecipientFieldModel(type: .cc, parent: nil, dataprovider: dataprovider) ccModel = RecipientFieldModel(type: .ccBcc, dataprovider: dataprovider)
bccModel = RecipientFieldModel(type: .bcc, parent: nil, dataprovider: dataprovider) bccModel = RecipientFieldModel(type: .bcc, dataprovider: dataprovider)
ccModel.parent = self
bccModel.parent = self
}
/// Used to show or hide Bcc field
var isEditingCcOrBcc: Bool = false {
didSet {
print("isEditingCcOrBcc: \(isEditingCcOrBcc)")
updateShowBccField()
print("showBccField: \(showBccField)")
}
} }
/// Used to deactivate Send button if email has no recipients. /// Used to deactivate Send button if email has no recipients.
...@@ -69,4 +84,11 @@ class RecipientsModel: ObservableObject { ...@@ -69,4 +84,11 @@ class RecipientsModel: ObservableObject {
bccModel.selectedContacts.map({ $0.email }) bccModel.selectedContacts.map({ $0.email })
} }
} }
func updateShowBccField() {
showBccField = isEditingCcOrBcc
|| !ccModel.selectedContacts.isEmpty
|| !bccModel.selectedContacts.isEmpty
ccModel.type = showBccField ? .cc : .ccBcc
}
} }
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
"Bcc" = "Bcc"; "Bcc" = "Bcc";
"Cancel" = "Abbrechen"; "Cancel" = "Abbrechen";
"Cc" = "Cc"; "Cc" = "Cc";
"CcBcc" = "Cc/Bcc";
"Name" = "Name"; "Name" = "Name";
"SortBy" = "Sortiere nach"; "SortBy" = "Sortiere nach";
"LastContacted" = "zuletzt kontaktiert"; "LastContacted" = "zuletzt kontaktiert";
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
"Bcc" = "Bcc"; "Bcc" = "Bcc";
"Cancel" = "Cancel"; "Cancel" = "Cancel";
"Cc" = "Cc"; "Cc" = "Cc";
"CcBcc" = "Cc/Bcc";
"SortBy" = "Sort by"; "SortBy" = "Sort by";
"Name" = "Name"; "Name" = "Name";
"LastContacted" = "Last Contacted"; "LastContacted" = "Last Contacted";
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment