From 5b5618eed1a855b8d906876c53ce1a9224e064c1 Mon Sep 17 00:00:00 2001 From: Oliver Wiese <oliver.wiese@fu-berlin.de> Date: Mon, 6 Apr 2020 16:59:26 +0200 Subject: [PATCH] improve ReadViewSender --- enzevalos_iphone.xcodeproj/project.pbxproj | 4 + .../KeyRecord+CoreDataProperties.swift | 14 +- .../PersistentMail +CoreDataProperties.swift | 19 +- .../SwiftUI/Read/ReadMainView.swift | 2 +- .../SwiftUI/Read/ReadViewCoordinator.swift | 9 + .../SwiftUI/Read/ReadViewModel.swift | 16 +- .../SwiftUI/Read/SenderViewMain.swift | 254 ++++++++---------- .../SmallContactListView.swift | 80 ++++++ enzevalos_iphone/de.lproj/Localizable.strings | 2 + enzevalos_iphone/en.lproj/Localizable.strings | 2 + 10 files changed, 242 insertions(+), 160 deletions(-) create mode 100644 enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewChildren/SmallContactListView.swift diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index adb25158..42161f51 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -141,6 +141,7 @@ 47A5D6E42294BFF50084F81D /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47A5D6E32294BFF50084F81D /* Logger.swift */; }; 47C036FF2347C0F5006295E8 /* ImportKeyOverviewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C036FE2347C0F4006295E8 /* ImportKeyOverviewController.swift */; }; 47C037032347D4D1006295E8 /* PasteKeyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C037022347D4D1006295E8 /* PasteKeyViewController.swift */; }; + 47C09C76243B3395007F74A2 /* SmallContactListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C09C75243B3395007F74A2 /* SmallContactListView.swift */; }; 47C22281218AFD6300BD2C2B /* AutocryptTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C22280218AFD6300BD2C2B /* AutocryptTest.swift */; }; 47C22283218B02C700BD2C2B /* autocryptSimpleExample1.eml in Resources */ = {isa = PBXBuildFile; fileRef = 47C22282218B02C700BD2C2B /* autocryptSimpleExample1.eml */; }; 47C8225324379EAE005BCE73 /* AttachmentsViewMain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C8224324379EAE005BCE73 /* AttachmentsViewMain.swift */; }; @@ -587,6 +588,7 @@ 47B2318A1F0D458100961B28 /* enzevalos_iphone 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "enzevalos_iphone 2.xcdatamodel"; sourceTree = "<group>"; }; 47C036FE2347C0F4006295E8 /* ImportKeyOverviewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportKeyOverviewController.swift; sourceTree = "<group>"; }; 47C037022347D4D1006295E8 /* PasteKeyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteKeyViewController.swift; sourceTree = "<group>"; }; + 47C09C75243B3395007F74A2 /* SmallContactListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmallContactListView.swift; sourceTree = "<group>"; }; 47C22280218AFD6300BD2C2B /* AutocryptTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocryptTest.swift; sourceTree = "<group>"; }; 47C22282218B02C700BD2C2B /* autocryptSimpleExample1.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = autocryptSimpleExample1.eml; sourceTree = "<group>"; }; 47C8224324379EAE005BCE73 /* AttachmentsViewMain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttachmentsViewMain.swift; sourceTree = "<group>"; }; @@ -1299,6 +1301,7 @@ children = ( 47C822672438A85C005BCE73 /* PhishingView.swift */, 47C822662438A85C005BCE73 /* SenderDetails.swift */, + 47C09C75243B3395007F74A2 /* SmallContactListView.swift */, ); path = SenderViewChildren; sourceTree = "<group>"; @@ -2222,6 +2225,7 @@ 472F39861E1FA34E009260FB /* Record.swift in Sources */, A1C3270E1DB907D900CE2ED5 /* TextFormatter.swift in Sources */, F12041FD1DA409A5002E4940 /* ListViewCell.swift in Sources */, + 47C09C76243B3395007F74A2 /* SmallContactListView.swift in Sources */, A1EFF93321E6655C003BB240 /* IntroTableView.swift in Sources */, 47EABF272423BFDD00774A93 /* AuthenticationScreen.swift in Sources */, 4764069A2416B54D00C7D426 /* MailView.swift in Sources */, diff --git a/enzevalos_iphone/KeyRecord+CoreDataProperties.swift b/enzevalos_iphone/KeyRecord+CoreDataProperties.swift index b4a2b9b6..a0471107 100644 --- a/enzevalos_iphone/KeyRecord+CoreDataProperties.swift +++ b/enzevalos_iphone/KeyRecord+CoreDataProperties.swift @@ -113,6 +113,18 @@ extension KeyRecord{ } extension KeyRecord: DisplayContact { + var previousMails: Int { + return self.persistentMails?.count ?? 0 + } + + var previousResponses: Int { + return -1 + } + + var keyRecord: KeyRecord? { + return self + } + var addr: String { return self.addresses.first?.mailAddress ?? "No address" } @@ -147,6 +159,4 @@ extension KeyRecord: DisplayContact { var similarContacts: [String] { return [] // TODO! } - - } diff --git a/enzevalos_iphone/PersistentMail +CoreDataProperties.swift b/enzevalos_iphone/PersistentMail +CoreDataProperties.swift index 6a41e619..ae53598b 100644 --- a/enzevalos_iphone/PersistentMail +CoreDataProperties.swift +++ b/enzevalos_iphone/PersistentMail +CoreDataProperties.swift @@ -420,17 +420,22 @@ extension PersistentMail { extension PersistentMail: DisplayMail { + typealias C = KeyRecord - var sender: DisplayContact { + var sender: C { return self.record! } - var ccs: [DisplayContact] { - return [] // TODO + var tos: [C] { + return [self.record!,self.record!,self.record!] } - var bccs: [DisplayContact] { - return [] // TODO + var ccs: [C] { + return [self.record!,self.record!,self.record!] // TODO + } + + var bccs: [C] { + return [self.record!,self.record!,self.record!] // TODO } var routingStops: [Landmark] { @@ -441,5 +446,9 @@ extension PersistentMail: DisplayMail { return self.sigState } + var persistentMail: PersistentMail? { + return self + } + } diff --git a/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift b/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift index cb1b7eef..2b9c3512 100644 --- a/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift +++ b/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift @@ -56,7 +56,7 @@ struct ReadMainView: View { Tab( image: Image(systemName: "person.fill"), description: "sender", - content: AnyView(SenderViewMain(mail: mail)) + content: AnyView(SenderViewMain<PersistentMail, KeyRecord>(mail: mail)) ), Tab( image: Image(systemName: "text.bubble.fill"), diff --git a/enzevalos_iphone/SwiftUI/Read/ReadViewCoordinator.swift b/enzevalos_iphone/SwiftUI/Read/ReadViewCoordinator.swift index 646a591c..a0fd4bb4 100644 --- a/enzevalos_iphone/SwiftUI/Read/ReadViewCoordinator.swift +++ b/enzevalos_iphone/SwiftUI/Read/ReadViewCoordinator.swift @@ -81,6 +81,15 @@ class ReadViewCoordinator { root.pushViewController(vc, animated: true) } + func pushContactView(contact: KeyRecord) { + let vc = mainStoryboard.instantiateViewController(withIdentifier: ViewID.KeyRecordView.rawValue) + if let vc = vc as? ContactViewController { + vc.keyRecord = contact + } + root.isToolbarHidden = false + root.pushViewController(vc, animated: true) + } + func shareData(_ data:NSData){ //let shareText = "Hello, world!" diff --git a/enzevalos_iphone/SwiftUI/Read/ReadViewModel.swift b/enzevalos_iphone/SwiftUI/Read/ReadViewModel.swift index ce942161..70855afa 100644 --- a/enzevalos_iphone/SwiftUI/Read/ReadViewModel.swift +++ b/enzevalos_iphone/SwiftUI/Read/ReadViewModel.swift @@ -21,23 +21,31 @@ protocol DisplayContact { var keys: [String] { get } // Phishing related - var hasPreviousMails: Bool { get } + var previousMails: Int { get } + var previousResponses: Int { get } var hasSimilarContacts: Bool { get } var similarContacts: [String] { get } + + var keyRecord: KeyRecord? { get } } protocol DisplayMail { + associatedtype C: DisplayContact + var subject: String? { get } var body: String? { get } - var sender: DisplayContact { get } - var ccs: [DisplayContact] { get } - var bccs: [DisplayContact] { get } + var sender: C { get } + var tos: [C] { get } + var ccs: [C] { get } + var bccs: [C] { get } var routingStops: [Landmark] { get } // Crypto var signedState: SignatureState { get } var encState: EncryptionState { get } + + var persistentMail: PersistentMail? { get } } class ReadViewModel: ObservableObject { diff --git a/enzevalos_iphone/SwiftUI/Read/SenderViewMain.swift b/enzevalos_iphone/SwiftUI/Read/SenderViewMain.swift index f7277e49..d90a48a0 100644 --- a/enzevalos_iphone/SwiftUI/Read/SenderViewMain.swift +++ b/enzevalos_iphone/SwiftUI/Read/SenderViewMain.swift @@ -22,122 +22,31 @@ import SwiftUI import CoreLocation -struct SenderViewMain: View { +struct SenderViewMain <M: DisplayMail, C: DisplayContact>: View { - let mail: DisplayMail + let mail: M @State var selectedLandmark: Landmark? = nil @State var showingLandmarkDetails = false var body: some View { - VStack { - ZStack { - ZStack { - MapView(landmarks: mail.routingStops, - selectedLandmark: $selectedLandmark, showingLandmarkDetails: $showingLandmarkDetails) - .frame(height: 300) - HStack { - Button(action: { - /// this button displays the previous selected landmark - self.selectPrevLandmark() - }) { - Text("prev") - .foregroundColor(.black) - .padding() - .background(Color.white) - .cornerRadius(6) - .shadow(radius: 3) - .padding(.top, 150) - } - - Spacer() - Button(action: { - /// this button displays the next selected landmark - self.selectNextLandmark() - }) { - Text("Next") - .foregroundColor(.black) - .padding() - .background(Color.white) - .cornerRadius(6) - .shadow(radius: 3) - .padding(.top, 150) - } - } - } .alert(isPresented: $showingLandmarkDetails) { - /// alert displays the landmark details and gets trigered when the user taps the information button of a landmark - Alert(title: Text("Domain for this location"), message: Text(selectedLandmark?.domain ?? "Missing place information"), dismissButton: .default(Text("OK")) ) - } - } + ScrollView { + map icon - //TODO: make toucarea clip to circle .clipShape(Circle() - ZStack { - - VStack(alignment: .leading) { - SenderDetails() - Divider() - VStack (alignment: .leading){ - - HStack{ - - Text("CC:") - //// the CC emails are displayed only when they exist - .font(.subheadline) - .padding(.bottom, 20) - - if mail.ccs.count == 0 { - Text("-") - }else{ - ScrollView(.vertical){ - - ForEach(0..<mail.ccs.count) { i in - Text(self.mail.ccs[i].name) - } - - }.frame(height: 30) - - .padding(.bottom, 10) - - } - - }.font(.system(size: 12)) - - } - - if mail.bccs.count > 0 { - /// the whole BCC section is displayed only when BCC emails exist - Divider() - VStack (alignment: .leading){ - HStack (spacing: 20){ - Text("BCC:") - .font(.subheadline) - .padding(.bottom, 8) - - ScrollView (.vertical){ - - ForEach(0..<mail.bccs.count) { i in - Text(self.mail.bccs[i].name) - } - - }.frame(height: 30) - .padding(.bottom, 10) - - }.font(.system(size: 12)) - - } - } - Divider() - DropDown() - Spacer() - - }.padding() - Spacer() - } - Spacer() + sender + .offset(y: (-110/2 + 5)) + Divider() + SmallContactListView(contacts: mail.tos, title: NSLocalizedString("To", comment: "To")) + Divider() + SmallContactListView(contacts: mail.ccs, title: NSLocalizedString("Cc", comment: "CC")) + Divider() + SmallContactListView(contacts: mail.bccs, title: NSLocalizedString("Bcc", comment: "BCC")) } } + + private func selectNextLandmark() { let landmarks = mail.routingStops /// This method identifies and moves to the next selected landmark @@ -168,48 +77,80 @@ struct SenderViewMain: View { .offset(y: -110/2) .padding(.bottom, -110/2) .onTapGesture { - //Goto contact view + self.goToContact(contact: self.mail.sender) } } -} - - - - -// important TODO: add phishing elements -struct DropDown: View { - /// Displays the phishing details in a drop down window - @State private var clicked = false - var body: some View { - VStack (alignment: .leading, spacing: 20) { - - HStack(alignment: .top) { - Text("Phishing:") - .font(.subheadline) - - Button (action: { - self.clicked.toggle() - }) { - - Image(systemName: clicked ? "chevron.up" : "chevron.down") + + private var sender: some View { + VStack (alignment: .leading, spacing: 10) { + Button(action: {self.goToContact(contact: self.mail.sender)}) { + VStack (alignment: .leading) { + Text(NSLocalizedString("Sender", comment: "Sender")) + .font(.headline) + Text(mail.sender.name) + .font(.subheadline) + Text(mail.sender.addr) + // .foregroundColor(.gray) + //TODO: Add last mail date } } - - if clicked { - - HStack { - - Spacer() - .frame(width: 70) - - PhishingView() - .font(.system(size: 12)) + HStack{ + Text(String(format: NSLocalizedString("ReadView.Sender.Previous", comment: "100 previous received mails"), mail.sender.previousMails)) + Spacer() + Text(String(format: NSLocalizedString("ReadView.Sender.Responses", comment: "5 previous sent mails"), mail.sender.previousResponses)) + } + } + .padding(10) + } + + private var map: some View { + ZStack { + ZStack { + MapView(landmarks: mail.routingStops, + selectedLandmark: $selectedLandmark, showingLandmarkDetails: $showingLandmarkDetails) + .frame(height: 300) + HStack { + Button(action: { + /// this button displays the previous selected landmark + self.selectPrevLandmark() + }) { + Text("prev") + .foregroundColor(.black) + .padding() + .background(Color.white) + .cornerRadius(6) + .shadow(radius: 3) + .padding(.top, 150) } - + Spacer() + Button(action: { + /// this button displays the next selected landmark + self.selectNextLandmark() + }) { + Text("Next") + .foregroundColor(.black) + .padding() + .background(Color.white) + .cornerRadius(6) + .shadow(radius: 3) + .padding(.top, 150) + } } - }.padding([.top, .bottom], 5) - } + } .alert(isPresented: $showingLandmarkDetails) { + /// alert displays the landmark details and gets trigered when the user taps the information button of a landmark + Alert(title: Text("Domain for this location"), message: Text(selectedLandmark?.domain ?? "Missing place information"), dismissButton: .default(Text("OK")) ) + } + } + } + + private func goToContact(contact: DisplayContact) { + guard let con = contact.keyRecord else { + print("No record...") + return + } + AppDelegate.getAppDelegate().readViewCoordinator?.pushContactView(contact: con) + } } struct SenderView_Previews: PreviewProvider { @@ -222,22 +163,30 @@ struct SenderView_Previews: PreviewProvider { // "iPad Pro (11-inch)" ] - let sender = PseudoContact(name: "Alice", addr: "alice@example.com", myImage: PseudoContact.makeImageFromName("Alice", color: .blue)) + let sender = PseudoContact(name: "Alice", addr: "alice@example.com", myImage: PseudoContact.makeImg("Alice", color: .blue)) + let bob = PseudoContact(name: "Bob", addr: "Bob.lord.of.kingsbridge.and.king.of.england@huge.subdomain.with. a.long.long.long.domain.example.com", myImage: PseudoContact.makeImg("Bob", color: .red)) + let charlie = PseudoContact(name: "Charlie", addr: "charlie@example.com", myImage: PseudoContact.makeImg("Charlie", color: .green)) let landmarks = [ Landmark(name: "Berlin", domain: "exampledomain.de", location: .init(latitude: 52.520008, longitude: 13.404954)), Landmark(name: "New York", domain: "secondexampledomain.de", location: .init(latitude: 40.730610, longitude: -73.935242)), Landmark(name: "Sydney", domain: "thirdexampledomain.de", location: .init(latitude: -33.865143, longitude: 151.209900)) ] - let mail = PseuoMail(sender: sender, ccs: [], bccs: [], routingStops: landmarks, signedState: .ValidSignature, encState: .ValidedEncryptedWithCurrentKey) + let mail = PseuoMail(sender: sender, tos: [bob,charlie], ccs: [bob, charlie,bob, charlie,bob], bccs: [], routingStops: landmarks, signedState: .ValidSignature, encState: .ValidedEncryptedWithCurrentKey) return ForEach(deviceNames, id: \.self) {deviceName in - SenderViewMain(mail: mail) + SenderViewMain<PseuoMail, PseudoContact>(mail: mail) .previewDisplayName(deviceName) + .previewDevice(.init(rawValue: deviceName)) + //.colorScheme(.dark) } } } struct PseudoContact: DisplayContact { + var previousMails: Int = 10 + + var previousResponses: Int = 2 + var name: String var addr: String @@ -256,7 +205,7 @@ struct PseudoContact: DisplayContact { var similarContacts: [String] = [] - public static func makeImageFromName(_ name: String, color: UIColor) -> Image { + public static func makeImg(_ name: String, color: UIColor) -> Image { var text: NSAttributedString var tag = String() if name.count > 0 { @@ -301,20 +250,26 @@ struct PseudoContact: DisplayContact { } - + var keyRecord: KeyRecord? { + return nil + } } struct PseuoMail: DisplayMail { + typealias U = PseudoContact + var subject: String? = "Hello World" var body: String? = "This is my message." - var sender: DisplayContact + var sender: U - var ccs: [DisplayContact] + var tos: [U] - var bccs: [DisplayContact] + var ccs: [U] + + var bccs: [U] var routingStops: [Landmark] @@ -322,5 +277,8 @@ struct PseuoMail: DisplayMail { var encState: EncryptionState + var persistentMail: PersistentMail? { + return nil + } } diff --git a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewChildren/SmallContactListView.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewChildren/SmallContactListView.swift new file mode 100644 index 00000000..945e505f --- /dev/null +++ b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewChildren/SmallContactListView.swift @@ -0,0 +1,80 @@ +// +// SmallContactListView.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 06.04.20. +// Copyright © 2020 fu-berlin. All rights reserved. +// + +import SwiftUI + +struct SmallContactListView <C: DisplayContact>: View { + let contacts: [C] + var title: String + @State var showList = true + + + var body: some View { + VStack (alignment: .leading, spacing: 10){ + HStack { + Text(title) + .font(.headline) + Button (action: { + self.showList.toggle() + }) { + + Image(systemName: showList ? "chevron.up" : "chevron.down") + .resizable() + .frame(width: 12.0, height: 7.0) + } + Spacer() + } + if showList { + ForEach(contacts, id: \.addr) {contact in + Group { + HStack { + CircleImage(image: contact.myImage, radius: 40) + VStack (alignment: .leading, spacing: 2){ + Text(contact.name) + .font(.subheadline) + Text(contact.addr) + .foregroundColor(.gray) + } + Spacer() + Button(action: {self.goToContact(contact: contact)}){ + Image(systemName: "chevron.right") + } + } + } + .onTapGesture { + self.goToContact(contact: contact) + } + } + + } + } + .padding(10) + } + + private func goToContact(contact: DisplayContact) { + guard let con = contact.keyRecord else { + return + } + AppDelegate.getAppDelegate().readViewCoordinator?.pushContactView(contact: con) + } +} + + +struct SmallContactListView_Previews: PreviewProvider { + static let alice = PseudoContact(name: "Alice", addr: "alice@example.com", myImage: PseudoContact.makeImg("Alice", color: .blue)) + static let bob = PseudoContact(name: "Bob", addr: "Bob.lord.of.kingsbridge.and.king.of.england@huge.subdomain.with. a.long.long.long.domain.example.com", myImage: PseudoContact.makeImg("Bob", color: .red)) + static let charlie = PseudoContact(name: "Charlie", addr: "charlie@example.com", myImage: PseudoContact.makeImg("Charlie", color: .green)) + + static var previews: some View { + VStack{ + SmallContactListView(contacts: [alice,bob,charlie], title: "To") + + SmallContactListView(contacts: [alice,bob,charlie], title: "To", showList: false) + } + } +} diff --git a/enzevalos_iphone/de.lproj/Localizable.strings b/enzevalos_iphone/de.lproj/Localizable.strings index 05c1df13..9089dee1 100644 --- a/enzevalos_iphone/de.lproj/Localizable.strings +++ b/enzevalos_iphone/de.lproj/Localizable.strings @@ -162,6 +162,8 @@ "ReadView.Attachments.No" = "Keine Anhänge vorhanden"; "ReadView.Attachments.Headline" = "Anhänge:"; "ReadView.Links.Future" = "a list of links contained in this mail will be visable here in a future update"; +"ReadView.Sender.Previous" = "%d empfangene Mails"; +"ReadView.Sender.Responses" = "%d gesendete Mails"; "Transportencryption" = "Transferverschlüsselung"; "Trash" = "Papierkorb"; "TwoDaysAgo" = "Vorgestern"; diff --git a/enzevalos_iphone/en.lproj/Localizable.strings b/enzevalos_iphone/en.lproj/Localizable.strings index 6719f20a..95fd261c 100644 --- a/enzevalos_iphone/en.lproj/Localizable.strings +++ b/enzevalos_iphone/en.lproj/Localizable.strings @@ -159,6 +159,8 @@ "ReadView.Attachments.No" = "This mail doesn't contain any attachments"; "ReadView.Attachments.Headline" = "Attachments:"; "ReadView.Links.Future" = "A list of links contained in this mail will be visable here in a future update"; +"ReadView.Sender.Previous" = "%d received emails"; +"ReadView.Sender.Responses" = "%d sent emails"; "Sender" = "Sender"; "To" = "To"; "to" = "to"; -- GitLab