From 2a2c74ca784c5a9795a5efeee519997be4649ac0 Mon Sep 17 00:00:00 2001 From: Oliver Wiese <oliver.wiese@fu-berlin.de> Date: Wed, 8 Apr 2020 17:29:30 +0200 Subject: [PATCH] working on user actions after receiving a mail --- enzevalos_iphone/Base.lproj/Main.storyboard | 10 +-- enzevalos_iphone/CryptoObject.swift | 44 +++++++++- enzevalos_iphone/Dialog/DialogOption.swift | 21 ----- .../SwiftUI/Read/ReadMainView.swift | 85 +++++------------- .../SwiftUI/Read/ReadViewCoordinator.swift | 5 +- .../SwiftUI/Read/ReadViewModel.swift | 17 ++-- .../Read/Tabbed Views/SenderViewMain.swift | 2 +- .../SwiftUI/SupportingViews/DialogView.swift | 87 ++++++++----------- 8 files changed, 126 insertions(+), 145 deletions(-) diff --git a/enzevalos_iphone/Base.lproj/Main.storyboard b/enzevalos_iphone/Base.lproj/Main.storyboard index f5182e68..3770628f 100644 --- a/enzevalos_iphone/Base.lproj/Main.storyboard +++ b/enzevalos_iphone/Base.lproj/Main.storyboard @@ -1792,7 +1792,7 @@ Um deine sicheren E-Mails auch auf einem anderen Gerät lesen zu können, muss d <rect key="frame" x="0.0" y="0.0" width="414" height="32"/> <subviews> <button opaque="NO" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="w9U-eC-Koh"> - <rect key="frame" x="8" y="-8.3333333333333357" width="30" height="38.333333333333336"/> + <rect key="frame" x="8" y="-8.3333333333333339" width="30" height="38.333333333333336"/> <fontDescription key="fontDescription" type="system" weight="heavy" pointSize="21"/> <state key="normal" title="✕"> <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/> @@ -1802,7 +1802,7 @@ Um deine sicheren E-Mails auch auf einem anderen Gerät lesen zu können, muss d </connections> </button> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" insetsLayoutMarginsFromSafeArea="NO" text="Kontakt verifizieren" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="25l-XT-PFo"> - <rect key="frame" x="116.33333333333333" y="-2.3333333333333357" width="181.66666666666669" height="26.333333333333336"/> + <rect key="frame" x="116.33333333333333" y="-2.3333333333333339" width="181.66666666666669" height="26.333333333333336"/> <fontDescription key="fontDescription" style="UICTFontTextStyleTitle2"/> <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <nil key="highlightedColor"/> @@ -2221,9 +2221,9 @@ Um deine sicheren E-Mails auch auf einem anderen Gerät lesen zu können, muss d </scene> </scenes> <inferredMetricsTieBreakers> - <segue reference="3Wb-uL-BB5"/> - <segue reference="td8-VW-Wrt"/> - <segue reference="DcR-GX-scc"/> + <segue reference="rhW-cI-4c4"/> + <segue reference="hSn-Um-hji"/> + <segue reference="btx-4o-o0r"/> <segue reference="TgN-rB-esa"/> <segue reference="Fv4-FT-5gV"/> <segue reference="ecN-Wn-7S0"/> diff --git a/enzevalos_iphone/CryptoObject.swift b/enzevalos_iphone/CryptoObject.swift index 6a3d2964..9a2a0cad 100644 --- a/enzevalos_iphone/CryptoObject.swift +++ b/enzevalos_iphone/CryptoObject.swift @@ -15,7 +15,12 @@ struct SecurityState <M: DisplayMail> { let mail: M - // TODO: Handling new key attack + /* TODO: MORE DIALOGS + //else if (mail.isNewPubKey) && !(mail.deleteWhileTravel){} + // message contained new public key + } + + */ var title: String { get { @@ -47,6 +52,19 @@ struct SecurityState <M: DisplayMail> { } } + var titleIcon: UIImage { + get { + switch evaluateSecurity() { + case (_, .EncValidSign): + return StudySettings.securityIndicator.imageOfSecureIndicator() + case (_, .UnableToDecrypt), (_, .InvalidSignature): + return StudySettings.securityIndicator.imageOfCorruptedIndicator() + case (_, .NoCrypto), (_, .PlainMissingPublicKeyToVerify), (_, .PlainButValidSignature), (_, .EncNoSignature), (_, .EncButMissingPublicKeyToVerify): + return StudySettings.securityIndicator.imageOfInsecureIndicator() + } + } + } + var dialog: DialogStruct { get { // TODO: Do we add new public key stuff? @@ -154,7 +172,29 @@ struct SecurityState <M: DisplayMail> { var warnings: [DialogStruct] { get { - return [] + var result = [DialogStruct] () + switch evaluateSecurity() { + case (_, .EncValidSign), (_, .NoCrypto), (_, .PlainButValidSignature), (_, .EncNoSignature): + break // No warning required + case (_, .UnableToDecrypt), (_, .InvalidSignature) , (_, .PlainMissingPublicKeyToVerify), (_, .EncButMissingPublicKeyToVerify): + result.append(dialog) // warning required + } + if mail.sender.keys.count > 0 && mail.signedState == .NoSignature { + let icon = Image(systemName: "exclamationmark.triangl.fill") + let missingSignature = DialogStruct(dialogColor: Color(ThemeManager.unencryptedMessageColor()), + title: NSLocalizedString("encryptedBeforeHeadline", + comment: "encrypted by sender before"), + body: NSLocalizedString("encryptedBeforeText", comment: "encrypted by sender before"), + img: icon, messageImage: icon, + ctaButtonTitle: NSLocalizedString("Security.Dialog.Button.Title.Confirmation", comment: ""), + ctaButtonAction: .AskSenderToConfirm, + infoButtonTitle: NSLocalizedString("Security.Dialog.Button.Title.MoreInfo", comment: ""), + moreButtons: [], + dismissButtonTitle: NSLocalizedString("Security.Dialog.Button.Title.OK", comment: ""), + dismissButtonAction: .IgnoreWarning) + result.append(missingSignature) + } + return result } } diff --git a/enzevalos_iphone/Dialog/DialogOption.swift b/enzevalos_iphone/Dialog/DialogOption.swift index 0ff9b70d..e6b13a20 100644 --- a/enzevalos_iphone/Dialog/DialogOption.swift +++ b/enzevalos_iphone/Dialog/DialogOption.swift @@ -21,27 +21,6 @@ import UIKit import SwiftUI -/* TODO: MORE DIALOGS - - //else if (mail.isNewPubKey) && !(mail.deleteWhileTravel){} - // message contained new public key - else if mail.from.hasKey && !mail.isSecure{ - Text(NSLocalizedString("encryptedBeforeHeadline", comment: "encrypted by sender before")) - .font(.system(size: 25)) - .frame(maxWidth: .infinity) - .background(Color.yellow) - HStack{ - Text("?") - .foregroundColor(Color.orange) - .font(.system(size: 60)) - .padding([.leading, .top, .bottom]) - Text(NSLocalizedString("encryptedBeforeText", comment: "encrypted by sender before")) - .padding() - } - } - -*/ - protocol Dialog { var dialogColor: Color { get } var title: String { get } diff --git a/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift b/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift index b8be6ac8..a3b03991 100644 --- a/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift +++ b/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift @@ -21,30 +21,19 @@ struct ReadMainView <M: DisplayMail>: View { public var mail: M - @State private var currentScreen: Int = 1 //doesnt work - - @State private var isSecIndExpanded:Bool = false + @State private var isSecIndExpanded = false var body: some View { - //TODO: put into zstack instead - VStack(spacing:0){ - //SecIndicator //TODO: Why the hell does expanding it reset the whole tabview - TabView{ - ForEach(Tabs, id: \.id ){ tab in - tab.content - .tabItem { - tab.image - Text(tab.description) - } + TabView{ + ForEach(Tabs, id: \.id ){ tab in + tab.content + .tabItem { + tab.image + Text(tab.description) } } - .animation(.easeInOut(duration: 0.4)) } - // .navigationBarTitle(Text((mail.trouble ? "❌" :( mail.isSecure ? "🔒" : "👀" )) + " " + (mail.subject ?? "")) - // , displayMode: .inline) //TODO: make smooth or find better solution .navigationBarItems(trailing: moreInfoButton) - //.onAppear(perform: self.coord.setup) - //.onDisappear(perform: self.coord.reset) } //TODO: not use AnyView-workaround @@ -71,53 +60,27 @@ struct ReadMainView <M: DisplayMail>: View { } var moreInfoButton: some View{ - return Button(action: {self.isSecIndExpanded.toggle()}){ + /* NavigationLink(destination: DialogView(option: SecurityState(mail: mail).dialog, ctaAction: nil, additionalAction: nil, dismissAction: nil), label: { Image(systemName: isSecIndExpanded ? "arrow.up.circle" : "info.circle") - } - } - /* - //securityIndicator - var SecIndicator:some View{ - get{ - - if mail.trouble{ - - return AnyView(SecInd(secNum:1,isExpanded: $isSecIndExpanded, color:Color(ThemeManager.troubleMessageColor()))) - - }else if mail.isSecure{ - - return AnyView(VStack{ - SecInd(secNum:2,isExpanded: $isSecIndExpanded,color:Color(ThemeManager.encryptedMessageColor())) - //TODO: Design and test - Button(action: { - self.coord.pushExportKeyView() - //let duration = Date().timeIntervalSince(opening) - //Logger.log(close: icon, mail: m, action: .exportKey, duration: duration) - //self.performSegue(withIdentifier: "exportKeyFromReadView", sender: nil) - }){ - Text(NSLocalizedString("ReadMailOnOtherDevice", comment: "email is not readable on other devices")) - } - }) - } - - //special subcases of unsecure mail - else if mail.isCorrectlySigned { - return AnyView(SecInd(secNum:4,isExpanded: $isSecIndExpanded,color:Color(ThemeManager.unencryptedMessageColor()))) - } else if mail.isEncrypted && !mail.unableToDecrypt { - return AnyView(SecInd(secNum:5,isExpanded: $isSecIndExpanded,color:Color(ThemeManager.unencryptedMessageColor()))) - } else if mail.isEncrypted && mail.unableToDecrypt { - return AnyView(SecInd(secNum:6,isExpanded: $isSecIndExpanded,color:Color(ThemeManager.unencryptedMessageColor()))) - } - + }) + .isDetailLink(false)*/ + Button(action: { + self.isSecIndExpanded.toggle() - else{ - - return AnyView(SecInd(secNum:3,isExpanded: $isSecIndExpanded,color:Color(ThemeManager.unencryptedMessageColor()))) - - } + }){ + Image(systemName: isSecIndExpanded ? "arrow.up.circle" : "info.circle") } } - */ + var naviTitle: String { + return mail.subject ?? "" + } + + var detailInfo: some View { + let dialog = SecurityState(mail: mail).dialog + return DialogView(option: dialog, ctaAction: { + self.isSecIndExpanded = false + }, additionalAction: nil, dismissAction: nil) + } } diff --git a/enzevalos_iphone/SwiftUI/Read/ReadViewCoordinator.swift b/enzevalos_iphone/SwiftUI/Read/ReadViewCoordinator.swift index 487bb441..4a350010 100644 --- a/enzevalos_iphone/SwiftUI/Read/ReadViewCoordinator.swift +++ b/enzevalos_iphone/SwiftUI/Read/ReadViewCoordinator.swift @@ -43,9 +43,12 @@ class ReadViewCoordinator { try? AppDelegate.getAppDelegate().mailHandler.startIMAPIdleIfSupported() AppDelegate.getAppDelegate().mailHandler.updateFolder(folder: Folder.inbox, completionCallback: {_ in }) - + let secState = SecurityState.init(mail: mail) + let icon = secState.titleIcon + let view = UIImageView(image: icon) let vc = UIHostingController(rootView: ReadMainView(mail: mail)) readView = vc + vc.navigationItem.titleView = view root.pushViewController(vc, animated: true) } diff --git a/enzevalos_iphone/SwiftUI/Read/ReadViewModel.swift b/enzevalos_iphone/SwiftUI/Read/ReadViewModel.swift index d0ad4135..6053b8ab 100644 --- a/enzevalos_iphone/SwiftUI/Read/ReadViewModel.swift +++ b/enzevalos_iphone/SwiftUI/Read/ReadViewModel.swift @@ -36,7 +36,7 @@ let bob = PseudoContact(name: "Bob", addr: "Bob.lord.of.kingsbridge.and.king.of. 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(folderType: .Inbox, sender: alice, tos: [bob,charlie], ccs: [bob, charlie,bob, charlie,bob], bccs: [], routingStops: landmarks, signedState: .ValidSignature, encState: .ValidedEncryptedWithCurrentKey) +let mail = PseuoMail(folderType: .Inbox, sender: alice, tos: [bob,charlie], ccs: [bob, charlie,bob, charlie,bob], bccs: [], routingStops: landmarks, signedState: SignatureState.NoSignature, encState: .ValidedEncryptedWithCurrentKey) protocol DisplayAttachment { var myName: String { get } @@ -65,6 +65,7 @@ protocol DisplayContact { protocol DisplayMail { associatedtype C: DisplayContact + associatedtype D: Dialog var subject: String? { get } var sender: C { get } @@ -83,7 +84,7 @@ protocol DisplayMail { var signedState: SignatureState { get } var encState: EncryptionState { get } - var warnings: [DialogOption] { get } + var warnings: [D] { get } var persistentMail: PersistentMail? { get } @@ -129,7 +130,7 @@ struct PseudoContact: DisplayContact { var otherAddresses: [String] = [] - var keys: [String] = [] + var keys: [String] = ["ABC"] var hasPreviousMails: Bool = false @@ -189,6 +190,9 @@ struct PseudoContact: DisplayContact { } struct PseuoMail: DisplayMail { + typealias U = PseudoContact + typealias D = DialogStruct + var displayAttachments: [DisplayAttachment] = [] func markAsRead(isRead: Bool) { @@ -200,9 +204,12 @@ struct PseuoMail: DisplayMail { var isRead: Bool = false - var warnings: [DialogOption] = [DialogOption.corrupted, DialogOption.postcard] + var warnings: [D] { + get { + return SecurityState.init(mail: self).warnings + } + } - typealias U = PseudoContact var subject: String? = "Hello World" diff --git a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift index 72d9d5e6..f711db6b 100644 --- a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift +++ b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift @@ -78,7 +78,7 @@ struct SenderViewMain <M: DisplayMail>: View { .padding(.bottom, -110/2) .onTapGesture { self.goToContact(contact: self.mail.sender) - } + } } private var sender: some View { diff --git a/enzevalos_iphone/SwiftUI/SupportingViews/DialogView.swift b/enzevalos_iphone/SwiftUI/SupportingViews/DialogView.swift index 2c93e4ed..9149d513 100644 --- a/enzevalos_iphone/SwiftUI/SupportingViews/DialogView.swift +++ b/enzevalos_iphone/SwiftUI/SupportingViews/DialogView.swift @@ -8,9 +8,9 @@ import SwiftUI -struct DialogView : View { +struct DialogView <D: Dialog> : View { - let option: DialogOption + let option: D var ctaAction: (() -> Void)? var additionalAction: (() -> Void)? var dismissAction: (() -> Void)? @@ -21,67 +21,55 @@ struct DialogView : View { var body: some View { simpleUI } - - var alternativeUI: some View { - VStack { - Text(option.title) - .font(.largeTitle) - .frame(maxWidth: .infinity, maxHeight: 100) - .cornerRadius(20) - .background(color) - .border(Color.red, width: 2) - if option.messageImage != nil { - CircleImage(image: option.messageImage!, radius: 60) - .foregroundColor(Color(option.color)) - .background(Color(.white)) - .padding(10) - } - } - .padding(10) - } - + var simpleUI: some View { VStack { Text(option.title) - .font(.largeTitle) + .font(.headline) + .lineLimit(3) .frame(maxWidth: .infinity) - .padding(.bottom, 20) - .addBorder(Color(option.color), width: 2, cornerRadius: 30) + .padding(.vertical, 20) + .addBorder(option.dialogColor, width: 2, cornerRadius: 30) HStack{ - if option.messageImage != nil { - option.messageImage! - .resizable() - .frame(width: 60, height: 60) - .foregroundColor(Color(option.color)) - .padding(.trailing, 20) - } - Text(option.message) + option.img + .resizable() + .frame(width: 60, height: 60) + .foregroundColor(option.dialogColor) + .padding(.trailing, 20) + Text(option.body) .fontWeight(.light) + .font(.body) + .lineLimit(10) + .fixedSize(horizontal: false, vertical: true) } .padding(20) if option.ctaButtonTitle != nil && ctaAction != nil { Button(action: ctaAction!) { Text(option.ctaButtonTitle!) - .frame(maxWidth: .infinity,maxHeight: 50) - .background(RoundedCorners(color: Color(option.color), radius: 30)) + .frame(maxWidth: .infinity, minHeight: 50, maxHeight: 50) + .background(RoundedCorners(color: .white, radius: 30)) .padding(.vertical, 10) .padding(.horizontal, 20) } } - if option.additionActionButtonTitle != nil && additionalAction != nil { - Button(action: additionalAction!) { - Text(option.additionActionButtonTitle!) - .frame(maxWidth: .infinity,maxHeight: 50) - .background(RoundedCorners(color: color, radius: 30)) - .padding(.vertical, 10) - .padding(.horizontal, 20) - } + ForEach(0..<option.moreButtons.count) { index in + Button(action: { + if let action = self.additionalAction { + action() + } + }) { + Text(self.option.moreButtons[index].title) + .frame(maxWidth: .infinity, minHeight: 50, maxHeight: 50) + .background(RoundedCorners(color: self.color, radius: 30)) + .padding(.vertical, 10) + .padding(.horizontal, 20) + } } if option.dismissButtonTitle != nil && dismissAction != nil { Button(action: dismissAction!) { Text(option.dismissButtonTitle!) .foregroundColor(.red) - .frame(maxWidth: .infinity,maxHeight: 50) + .frame(maxWidth: .infinity, minHeight: 50, maxHeight: 50) .background(RoundedCorners(color: color, radius: 30)) .padding(.vertical, 10) .padding(.horizontal, 20) @@ -93,21 +81,22 @@ struct DialogView : View { } } -/* + struct DialogView_Previews: PreviewProvider { + static let options = SecurityState.init(mail: mail) static var previews: some View { VStack{ - DialogView(option: .postcard, ctaAction: action, additionalAction: action, dismissAction: action) - DialogView(option: .corrupted, ctaAction: action) - - } .padding(20) + DialogView(option: options.dialog, ctaAction: action, additionalAction: action, dismissAction: action) + //DialogView(option: DialogOption.corrupted, ctaAction: action, additionalAction: action, dismissAction: action) + // DialogView(option: DialogOption.couldNotDecrypt, ctaAction: action, additionalAction: action, dismissAction: action) + } } static func action() { print("Button click!") } } - */ + extension View { public func addBorder<S>(_ content: S, width: CGFloat = 1, cornerRadius: CGFloat) -> some View where S : ShapeStyle { -- GitLab