diff --git a/Thunderbird/Thunderbird/EmailDisplay/EmailCellView.swift b/Thunderbird/Thunderbird/EmailDisplay/EmailCellView.swift index 9acbc3d9..b66eb875 100644 --- a/Thunderbird/Thunderbird/EmailDisplay/EmailCellView.swift +++ b/Thunderbird/Thunderbird/EmailDisplay/EmailCellView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import EmailAddress struct EmailCellView: View { @Environment(FeatureFlags.self) private var flags: FeatureFlags @@ -22,7 +23,7 @@ struct EmailCellView: View { let isThread: Bool init(email: TempEmail) { - self.senderText = email.senderText + self.senderText = email.from[0].label ?? email.from[0].value self.headerText = email.headerText self.bodyText = email.bodyText self.dateSent = email.dateSent @@ -45,9 +46,10 @@ struct EmailCellView: View { .font(.headline) .fontWeight(unread ? .semibold : .regular) Spacer() - Text(SmartDateFormatter() - .dateFormatter(date: dateSent, isSmartDate: !flags.flagForKey(key: Flag.fullDate.rawValue)) -) + Text( + SmartDateFormatter() + .dateFormatter(date: dateSent, isSmartDate: !flags.flagForKey(key: Flag.fullDate.rawValue)) + ) }.padding(.leading, pinned ? 0 : 20) HStack { if newEmail { @@ -95,16 +97,260 @@ struct EmailCellView: View { } #Preview("Email Cell") { - let tempEmail = TempEmail( - sender: "Sender5", - recipients: ["Rhea"], - headerText: "Email four with a longer set of text", - bodyText: "This is some nice long text", + var tempEmail = TempEmail( + from: [EmailAddress("sender1@test.com", label: "Sender1")], + sender: [EmailAddress("sender1@test.com", label: "Sender1")], + reply: [EmailAddress("sender1@test.com", label: "Sender1")], + to: [EmailAddress("rheaThun@thundermail.com", label: "Rhea Thunderbird")], + cc: [], + bcc: [], + headerText: "This is the subject line of the email", + bodyText: """ + + + + + + + + +
+ +
+
+

Appr= + oval requested

+

+ Laurel has requested an approval from you for a group of screen= + s. +

+ +
+
+
+

+ i= + OS Alpha screens +

+
+ + Pending + review +
+
+

+ 16 screens =E2=80=A2 7 PM UTC, Dec 3, 2025 +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ manual set up combined
+ manual set up complete
+ manual set up protocol
+ lrg/WelcomeiOS_v01
+ manual set up complete (dark mode)
+ lrg/WelcomeiOS_v01 (dark mode)
+ manual set up combined (dark mode)
+ manual set up protocol (dark mode)
+ message-view-threaded v01
+ message-view v01
+ message-list-v01
+ account-drawer-v01
+ manual set up: email & password (with 2 + variants)
+ manual set up: email & password (with 2 + variants)
+
+ + Start review + +
+
+
+ 3D"divider" +
+

+ Let us know if you have any questions: + support@zeplin.io +

+

+ Zeplin Crew +

+

+
+ +
+
+ + + +
+ +
+ 3D"" + + + + """, dateSent: Date(), - unread: true, + unread: false, newEmail: false, - attachments: nil, - isThread: true, + attachments: [Data(), Data()], + isThread: false, pinned: true ) EmailCellView(email: tempEmail) diff --git a/Thunderbird/Thunderbird/EmailDisplay/ReadEmailView.swift b/Thunderbird/Thunderbird/EmailDisplay/ReadEmailView.swift index e0601177..24250ef1 100644 --- a/Thunderbird/Thunderbird/EmailDisplay/ReadEmailView.swift +++ b/Thunderbird/Thunderbird/EmailDisplay/ReadEmailView.swift @@ -7,45 +7,32 @@ import SwiftUI import WebKit +import EmailAddress struct ReadEmailView: View { init(_ email: TempEmail) { - self.email = email - - self.emailBody = email.bodyText - self.sender = email.senderText - self.subject = email.headerText - self.sentDate = email.dateSent - self.recipients = email.recipients - self.attachments = email.attachments } private var email: TempEmail - private var emailBody: String - private var sender: String - private var recipients: [String] - private var subject: String - private var sentDate: Date - private var attachments: [Data]! var body: some View { NavigationView { VStack(alignment: .leading, spacing: 20) { HStack { - Text(subject) + Text(email.headerText) .font(.title3) Spacer() - if attachments != nil { + if email.attachments != nil { Image(systemName: "paperclip").font(.caption) } } ScrollView { VStack(alignment: .leading) { - SenderView(sender, sentDate, recipients) - WebView(htmlString: emailBody).scaledToFill() - if attachments != nil { - AttachmentBlockView(attachments) + SenderView(email: email) + WebView(htmlString: email.bodyText).scaledToFill() + if email.attachments != nil { + AttachmentBlockView(email.attachments) } } } @@ -168,31 +155,41 @@ struct WebView: UIViewRepresentable { } struct SenderView: View { - init(_ sender: String, _ sentDate: Date, _ recipients: [String]) { - self.sender = sender - self.date = sentDate - self.recipients = recipients + init(email: TempEmail) { + from = email.from + sender = email.sender + recipients = email.cc + toText = email.to + date = email.dateSent + replyTo = email.reply } - private var sender: String - private var recipients: [String] + private var from: [EmailAddress] + private var sender: [EmailAddress] + private var replyTo: [EmailAddress] + private var recipients: [EmailAddress] + private var toText: [EmailAddress] private var date: Date @State private var showingAlert = false @State private var unimplementedFeatureName: String = "" + @State private var showSenderRecipientInfo = false var body: some View { HStack { VStack(alignment: .leading) { HStack { - Text(sender).font(.title3) + Text(from[0].value).font(.title3) } HStack { - Text("To: \(recipients[0])") - if recipients.count > 1 { - Text("+\(recipients.count-1)") + Text("To: \(toText[0].label ?? toText[0].value)") + if recipients.count > 0 { + Text("+\(recipients.count)") } } .font(.subheadline) .foregroundStyle(.accent) + .onTapGesture { + showSenderRecipientInfo = true + } } Spacer() @@ -211,13 +208,79 @@ struct SenderView: View { } } + .sheet(isPresented: $showSenderRecipientInfo) { + VStack { + Text(date.formatted(.dateTime.hour().minute().second().month(.abbreviated).day().year())) + .font(.caption2) + .frame(maxWidth: .infinity, alignment: .trailing) + .padding([.top, .trailing]) + + List { + Section(header: Text("from_header")) { + ForEach(from) { person in + ContactCellView(contact: person) + } + }.listRowSeparator(.hidden) + + if !sender.isEmpty { + Section(header: Text("sender_header")) { + ForEach(sender) { person in + ContactCellView(contact: person) + } + }.listRowSeparator(.hidden) + } + if !replyTo.isEmpty { + Section(header: Text("reply_to_header")) { + ForEach(replyTo) { person in + ContactCellView(contact: person) + } + }.listRowSeparator(.hidden) + } + Section(header: Text("to_header")) { + ForEach(toText) { person in + ContactCellView(contact: person) + } + if !recipients.isEmpty { + ForEach(recipients) { person in + ContactCellView(contact: person) + } + } + }.listRowSeparator(.hidden) + + } + .listSectionSpacing(.compact) + } + .presentationDetents([.medium]) + + } + } +} + +struct ContactCellView: View { + let contact: EmailAddress + init(contact: EmailAddress) { + self.contact = contact + } + var body: some View { + HStack { + //TODO: Avatar with initials/icon + VStack(alignment: .leading) { + if contact.label != nil { Text(contact.label!) } + Text(contact.value) + }.font(.caption) + //TODO: button for interaction + } } } #Preview { var tempEmail = TempEmail( - sender: "Sender@sender.com", - recipients: ["Rhea Thunderbird", "Roc"], + from: [EmailAddress("sender1@test.com", label: "Sender1")], + sender: [EmailAddress("sender1@test.com", label: "Sender1")], + reply: [EmailAddress("sender1@test.com", label: "Sender1")], + to: [EmailAddress("rheaThun@thundermail.com", label: "Rhea Thunderbird")], + cc: [], + bcc: [], headerText: "This is the subject line of the email", bodyText: """ diff --git a/Thunderbird/Thunderbird/Localization/en.lproj/Localizable.strings b/Thunderbird/Thunderbird/Localization/en.lproj/Localizable.strings index 9fadb14f..608e2ef0 100644 --- a/Thunderbird/Thunderbird/Localization/en.lproj/Localizable.strings +++ b/Thunderbird/Thunderbird/Localization/en.lproj/Localizable.strings @@ -47,6 +47,17 @@ "feature_not_implemented" = "This feature has not been implemented yet"; "demo_button" = "Demo"; +//Headers +"to_header" = "To"; +"from_header" = "From"; +"reply_to_header" = "Reply To"; +"sender_header" = "Sender"; +"cc_header" = "CC"; +"bcc_header" = "BCC"; +"copy_header" = "Copy"; +"blind_copy_header" = "Blind Copy"; + + // Other "next_button" = "Next"; "donation_support" = "Donate"; diff --git a/Thunderbird/Thunderbird/Util/TempEmailModel.swift b/Thunderbird/Thunderbird/Util/TempEmailModel.swift index eafcf755..7d09d206 100644 --- a/Thunderbird/Thunderbird/Util/TempEmailModel.swift +++ b/Thunderbird/Thunderbird/Util/TempEmailModel.swift @@ -8,15 +8,20 @@ import Foundation import SwiftData +import EmailAddress @Model class TempEmail { - - var senderText: String var headerText: String var bodyText: String var dateSent: Date var uuid: UUID - var recipients: [String] + + var from: [EmailAddress] + var sender: [EmailAddress] + var reply: [EmailAddress] + var to: [EmailAddress] + var cc: [EmailAddress] + var bcc: [EmailAddress] var attachments: [Data]! // For alignment, bool check likely not final @@ -26,8 +31,12 @@ class TempEmail { var pinned: Bool init( - sender: String, - recipients: [String], + from: [EmailAddress], + sender: [EmailAddress], + reply: [EmailAddress], + to: [EmailAddress], + cc: [EmailAddress], + bcc: [EmailAddress], headerText: String, bodyText: String, dateSent: Date, @@ -37,7 +46,12 @@ class TempEmail { isThread: Bool, pinned: Bool ) { - self.senderText = sender + self.from = from + self.sender = sender + self.reply = reply + self.to = to + self.cc = cc + self.bcc = bcc self.headerText = headerText self.bodyText = bodyText self.dateSent = dateSent @@ -46,14 +60,17 @@ class TempEmail { self.attachments = attachments self.isThread = isThread self.uuid = UUID() - self.recipients = recipients self.pinned = pinned } @MainActor static let sampleData = [ TempEmail( - sender: "Sender1", - recipients: ["Rhea Thunderbird"], + from: [EmailAddress("sender1@test.com", label: "Sender1")], + sender: [EmailAddress("sender1@test.com", label: "Sender1")], + reply: [EmailAddress("sender1@test.com", label: "Sender1")], + to: [EmailAddress("rheaThun@thundermail.com", label: "Rhea Thunderbird")], + cc: [], + bcc: [], headerText: "Email one", bodyText: "This is some nice long text", dateSent: Date(), @@ -64,8 +81,12 @@ class TempEmail { pinned: false ), TempEmail( - sender: "Sender1", - recipients: ["Rhea Thunderbird"], + from: [EmailAddress("sender1@test.com", label: "Sender1")], + sender: [EmailAddress("sender1@test.com", label: "Sender1")], + reply: [EmailAddress("sender1@test.com", label: "Sender1")], + to: [EmailAddress("rheaThun@thundermail.com", label: "Rhea Thunderbird")], + cc: [], + bcc: [], headerText: "Email two", bodyText: "This is some nice long text", dateSent: Date(timeIntervalSinceNow: -6000), @@ -76,8 +97,12 @@ class TempEmail { pinned: true ), TempEmail( - sender: "Sender2", - recipients: ["Rhea Thunderbird"], + from: [EmailAddress("sendera@test.com", label: "Sendera")], + sender: [], + reply: [EmailAddress("sender2replyto@test.com", label: "Sender2")], + to: [EmailAddress("rheaThun@thundermail.com", label: "Rhea Thunderbird")], + cc: [], + bcc: [], headerText: "Email three with a longer set of text", bodyText: "This is some nice long text", dateSent: Date(timeIntervalSinceNow: -6200), @@ -88,8 +113,12 @@ class TempEmail { pinned: false ), TempEmail( - sender: "Sender5", - recipients: ["Rhea Thunderbird", "Roc Thunderbird Jr", "Roc Thunderbird", "Roc Thunderbird Sr"], + from: [EmailAddress("sender3@test.com", label: "Sender3")], + sender: [EmailAddress("sender3@test.com", label: "Sender3")], + reply: [EmailAddress("sender2@test.com", label: "Sender2")], + to: [EmailAddress("rheaThun@thundermail.com", label: "Rhea Thunderbird")], + cc: [EmailAddress("rocThun@thundermail.com", label: "Roc Thunderbird"), EmailAddress("rocjrThun@thundermail.com"), EmailAddress("rocsrThun@thundermail.com", label: "Dad")], + bcc: [], headerText: "Email four with a longer set of text", bodyText: "This is some nice long text", dateSent: Date(timeIntervalSinceNow: -100000), @@ -100,8 +129,12 @@ class TempEmail { pinned: false ), TempEmail( - sender: "Sender5", - recipients: ["Rhea Thunderbird", "Roc Thunderbird"], + from: [EmailAddress("sender2@test.com", label: "Sender2")], + sender: [EmailAddress("sender2@test.com", label: "Sender2")], + reply: [EmailAddress("sender2@test.com", label: "Sender2")], + to: [EmailAddress("rheaThun@thundermail.com", label: "Rhea Thunderbird")], + cc: [], + bcc: [], headerText: "Email four with a longer set of text", bodyText: "This is some nice long text", dateSent: Date(timeIntervalSinceNow: -257000), @@ -110,18 +143,6 @@ class TempEmail { attachments: [Data()], isThread: false, pinned: false - ), - TempEmail( - sender: "Sender6", - recipients: ["Rhea Thunderbird", "Roc Thunderbird"], - headerText: "Email four with a longer set of text", - bodyText: "This is some nice long text", - dateSent: Date(timeIntervalSinceReferenceDate: 51_556_900), - unread: false, - newEmail: false, - attachments: [Data()], - isThread: false, - pinned: false ) ]