diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index 42161f51db636aea736ccb46e13e52f3888690d2..ebcc98c3682be949cf98a3ad2bbc1db657e449f6 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -145,7 +145,7 @@ 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 */; }; - 47C8225724379EAE005BCE73 /* Warning_MessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C8224924379EAE005BCE73 /* Warning_MessageView.swift */; }; + 47C8225724379EAE005BCE73 /* DialogView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C8224924379EAE005BCE73 /* DialogView.swift */; }; 47C8225824379EAE005BCE73 /* FloatingActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C8224A24379EAE005BCE73 /* FloatingActionButton.swift */; }; 47C8225924379EAE005BCE73 /* AttPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C8224C24379EAE005BCE73 /* AttPreview.swift */; }; 47C8225A24379EAE005BCE73 /* CardWithTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C8224D24379EAE005BCE73 /* CardWithTitle.swift */; }; @@ -592,7 +592,7 @@ 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>"; }; - 47C8224924379EAE005BCE73 /* Warning_MessageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Warning_MessageView.swift; sourceTree = "<group>"; }; + 47C8224924379EAE005BCE73 /* DialogView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DialogView.swift; sourceTree = "<group>"; }; 47C8224A24379EAE005BCE73 /* FloatingActionButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloatingActionButton.swift; sourceTree = "<group>"; }; 47C8224C24379EAE005BCE73 /* AttPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttPreview.swift; sourceTree = "<group>"; }; 47C8224D24379EAE005BCE73 /* CardWithTitle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardWithTitle.swift; sourceTree = "<group>"; }; @@ -1259,8 +1259,6 @@ children = ( 47C8224224379EAE005BCE73 /* Tabbed Views */, 47C8225124379EAE005BCE73 /* ReadViewCoordinator.swift */, - 47C8226A2438A86A005BCE73 /* SenderViewMain.swift */, - 47C8224324379EAE005BCE73 /* AttachmentsViewMain.swift */, 47C8225224379EAE005BCE73 /* ReadMainView.swift */, 47C8226C2438C2CF005BCE73 /* ReadViewModel.swift */, ); @@ -1270,10 +1268,12 @@ 47C8224224379EAE005BCE73 /* Tabbed Views */ = { isa = PBXGroup; children = ( + 47C8224E24379EAE005BCE73 /* MessageViewMain.swift */, + 47C8226A2438A86A005BCE73 /* SenderViewMain.swift */, + 47C8224324379EAE005BCE73 /* AttachmentsViewMain.swift */, 47C822632438A84C005BCE73 /* SenderViewChildren */, 47C8224824379EAE005BCE73 /* MessageViewChildren */, 47C8224B24379EAE005BCE73 /* AttachmentChildren */, - 47C8224E24379EAE005BCE73 /* MessageViewMain.swift */, ); path = "Tabbed Views"; sourceTree = "<group>"; @@ -1281,7 +1281,7 @@ 47C8224824379EAE005BCE73 /* MessageViewChildren */ = { isa = PBXGroup; children = ( - 47C8224924379EAE005BCE73 /* Warning_MessageView.swift */, + 47C8224924379EAE005BCE73 /* DialogView.swift */, 47C8224A24379EAE005BCE73 /* FloatingActionButton.swift */, ); path = MessageViewChildren; @@ -2387,7 +2387,7 @@ F1984D741E1E92B300804E1E /* LabelStyleKit.swift in Sources */, A1FA44A721E10E1400DB02AC /* TravelHandler.swift in Sources */, 47E7376E22845EC400972401 /* SecretKeyTableViewController.swift in Sources */, - 47C8225724379EAE005BCE73 /* Warning_MessageView.swift in Sources */, + 47C8225724379EAE005BCE73 /* DialogView.swift in Sources */, 478154A721FF3F0900A931EC /* Warning.swift in Sources */, 4764069F2416B5A600C7D426 /* NewOnboardingView.swift in Sources */, 0EF73F4324237E6500932FA0 /* SMIMEHelpers.swift in Sources */, diff --git a/enzevalos_iphone/Dialog/DialogOption.swift b/enzevalos_iphone/Dialog/DialogOption.swift index fd14977ce38f4a13b1269515c293223585b843b0..9adff83503d2b5db084c1168a4783ea5d1dbe983 100644 --- a/enzevalos_iphone/Dialog/DialogOption.swift +++ b/enzevalos_iphone/Dialog/DialogOption.swift @@ -19,6 +19,75 @@ // import UIKit +import SwiftUI + +/* TODO: MORE DIALOGS + if mail.trouble{ + Text(NSLocalizedString("corruptedHeadline", comment: "corrupted mail")) + .font(.system(size: 25)) + .frame(maxWidth: .infinity) + .background(Color.yellow) + HStack{ + Text("!") + .foregroundColor(Color.red) + .font(.system(size: 60)) + .padding([.leading, .top, .bottom]) + Text(NSLocalizedString("corruptedText", comment: "corrupted mail")) + .padding() + } + } + else if mail.isEncrypted && mail.unableToDecrypt{ + if TravelHandler.instance().mode != .atHome{ + Text(NSLocalizedString("couldNotDecryptTravelHeadline", comment: "couldn't decrypt message")) + .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("couldNotDecryptTravelText", comment: "couldn't decrypt message")) + .padding() + } + } + else { + Text(NSLocalizedString("couldNotDecryptHeadline", comment: "couldn't decrypt message")) + .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("couldNotDecryptText", comment: "couldn't decrypt message")) + .padding() + } + } + } + //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() + } + } + //else if mail.deleteWhileTravel{} + // message not readable while traveling +}.background(Color(UIColor.systemGray5)).padding() +} + +*/ enum DialogOption { @@ -28,17 +97,63 @@ enum DialogOption { case invitationStep case invitationHelp case travelInfo + case corrupted + case couldNotDecrypt + case couldNotDecryptTravel + case encryptedBefore + var color: UIColor { switch self { - case .postcard : return .yellow + case .postcard : return ThemeManager.unencryptedMessageColor() case .invitationCode : return UIColor.Invitation.orange case .invitationWelcome : return UIColor.Invitation.orange case .invitationStep : return UIColor.Invitation.orange case .invitationHelp : return UIColor.Invitation.orange case .travelInfo : return UIColor.Invitation.orange + case .corrupted : return ThemeManager.troubleMessageColor() + case .couldNotDecrypt : return ThemeManager.unencryptedMessageColor() + case .couldNotDecryptTravel : return ThemeManager.unencryptedMessageColor() + case .encryptedBefore : return ThemeManager.unencryptedMessageColor() } } + + var messageImage: Image? { + switch self { + case .postcard : return nil + case .invitationCode : return nil + case .invitationWelcome, .invitationHelp : + switch StudySettings.invitationsmode { + case .Censorship: + var images = [UIImage]() + if let sender = UIImage(named: "bg_inviation_censor_sender"), let receiver = UIImage(named: "bg_inviation_censor_receiver") { + images.append(sender) + images.append(receiver) + if let img = UIImage.animatedImage(with: images, duration: 4) { + return Image(uiImage: img) + } + } + return nil + case .PasswordEnc: + if let img = UIImage(named: "bg_inviation"){ + return Image(uiImage: img) + } + return nil + case .FreeText, + .InviteMail: + if let img = UIImage(named: "postcard") { + return Image(uiImage: img) + } + return nil + } + case .invitationStep : return nil + case .travelInfo : return nil + case .corrupted : return Image(systemName: "exclamationmark.triangle.fill") + case .couldNotDecrypt : return nil + case .couldNotDecryptTravel : return nil + case .encryptedBefore : return nil + } + } var titleImage: UIImage? { switch self { @@ -62,6 +177,14 @@ enum DialogOption { } case .invitationStep : return nil case .travelInfo : return nil + case .corrupted : + let icon = UIImage(systemName: "exclamationmark.triangle.fill")? + .tint(color: self.color) + return icon + case .couldNotDecrypt : return nil + case .couldNotDecryptTravel : return nil + case .encryptedBefore : return nil + } } @@ -73,23 +196,33 @@ enum DialogOption { .invitationHelp : return nil case .invitationStep : return UIImage(named: "ic_secure_card") case .travelInfo : return TravelHandler.planeIcon + case .corrupted : return nil + case .couldNotDecrypt : return nil + case .couldNotDecryptTravel : return nil + case .encryptedBefore : return nil } } + + - var title: String? { + var title: String { switch self { - case .postcard : return "Welcome" + case .postcard : return NSLocalizedString("Postcard", comment: "") case .invitationCode : return NSLocalizedString("Invitation.Code.Title", comment: "") case .invitationWelcome, .invitationHelp : return NSLocalizedString("Invitation.Welcome.Title", comment: "") case .invitationStep : return NSLocalizedString("Invitation.Step.Title", comment: "") case .travelInfo : return NSLocalizedString("TravelInfo.Title", comment: "") + case .corrupted : return NSLocalizedString("corruptedHeadline", comment: "corrupted mail") + case .couldNotDecrypt : return NSLocalizedString("couldNotDecryptHeadline", comment: "couldn't decrypt message") + case .couldNotDecryptTravel : return NSLocalizedString("couldNotDecryptTravelHeadline", comment: "couldn't decrypt message") + case .encryptedBefore : return NSLocalizedString("encryptedBeforeHeadline", comment: "encrypted by sender before") } } - var message: String? { + var message: String { switch self { - case .postcard : return "Message\nMultiline and long texts are allowed, btw second button is hidden" + case .postcard : return NSLocalizedString("ReceiveInsecureInfo", comment: "") case .invitationWelcome, .invitationHelp : switch StudySettings.invitationsmode { @@ -109,6 +242,10 @@ enum DialogOption { } return String(format: NSLocalizedString("Invitation.Code.Message", comment: ""), code) case .travelInfo : return NSLocalizedString("TravelInfo.Message", comment: "") + case .corrupted : return NSLocalizedString("corruptedText", comment: "corrupted mail") + case .couldNotDecrypt : return NSLocalizedString("couldNotDecryptText", comment: "couldn't decrypt message") + case .couldNotDecryptTravel : return NSLocalizedString("couldNotDecryptTravelText", comment: "couldn't decrypt message") + case .encryptedBefore : return NSLocalizedString("encryptedBeforeText", comment: "encrypted by sender before") } } @@ -126,6 +263,10 @@ enum DialogOption { case .invitationStep : return NSLocalizedString("Invitation.Step.CTA", comment: "") case .invitationHelp : return NSLocalizedString("Done", comment: "") case .travelInfo : return NSLocalizedString("TravelInfo.Remember", comment: "") + case .corrupted : return nil + case .couldNotDecrypt : return nil + case .couldNotDecryptTravel : return nil + case .encryptedBefore : return nil } } @@ -137,6 +278,10 @@ enum DialogOption { case .invitationStep : return nil case .invitationHelp : return nil case .travelInfo : return NSLocalizedString("MoreInformation", comment: "") + case .corrupted : return nil + case .couldNotDecrypt : return nil + case .couldNotDecryptTravel : return nil + case .encryptedBefore : return nil } } @@ -148,6 +293,11 @@ enum DialogOption { case .invitationStep : return NSLocalizedString("Invitation.Step.Undo", comment: "") case .invitationHelp : return nil case .travelInfo : return NSLocalizedString("OK", comment: "") + case .corrupted : return nil + case .couldNotDecrypt : return nil + case .couldNotDecryptTravel : return nil + case .encryptedBefore : return nil } } + } diff --git a/enzevalos_iphone/Dialog/DialogViewController.swift b/enzevalos_iphone/Dialog/DialogViewController.swift index cee6f42e03194bc69ec5cda32c43464d67337cbc..7ff808b9809e88921eccf885dbe34ccf3395334e 100644 --- a/enzevalos_iphone/Dialog/DialogViewController.swift +++ b/enzevalos_iphone/Dialog/DialogViewController.swift @@ -86,9 +86,7 @@ extension DialogViewController { } func layout(for option: DialogOption) { - self.titleLabel?.isHidden = (option.title == nil) self.titleLabel?.text = option.title - self.messageLabel?.isHidden = (option.message == nil) self.messageLabel?.text = option.message self.ctaButton?.isHidden = (option.ctaButtonTitle == nil) self.ctaButton?.setTitle(option.ctaButtonTitle, for: .normal) diff --git a/enzevalos_iphone/PersistentMail +CoreDataProperties.swift b/enzevalos_iphone/PersistentMail +CoreDataProperties.swift index ae53598b880c12d2595c7927a68c79925ee4468e..59346e60d0ddb108a1a66eda0540a1cc9f8a89fe 100644 --- a/enzevalos_iphone/PersistentMail +CoreDataProperties.swift +++ b/enzevalos_iphone/PersistentMail +CoreDataProperties.swift @@ -450,5 +450,24 @@ extension PersistentMail: DisplayMail { return self } + var folderType: FolderType { + return .Other // TODO FIX + } + + var warnings: [DialogOption] { + var result = [DialogOption]() + if self.unableToDecrypt { + result.append(.couldNotDecrypt) + } + else if self.trouble { + result.append(.corrupted) + } + + return result + } + func markAsRead(isRead: Bool) { + self.isRead = isRead + } + } diff --git a/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift b/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift index 2b9c3512ae5594387bbb286e10d6235d2f712969..b9731961e8d07e88151332f2674a0d7b29ab814f 100644 --- a/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift +++ b/enzevalos_iphone/SwiftUI/Read/ReadMainView.swift @@ -61,7 +61,7 @@ struct ReadMainView: View { Tab( image: Image(systemName: "text.bubble.fill"), description: "message", - content: AnyView(MessageViewMain(coord: coord, mail: mail)) + content: AnyView(MessageViewMain<PersistentMail>(mail: mail)) ), Tab( image: Image(systemName: "rectangle.and.paperclip"), diff --git a/enzevalos_iphone/SwiftUI/Read/ReadViewCoordinator.swift b/enzevalos_iphone/SwiftUI/Read/ReadViewCoordinator.swift index a0fd4bb43f00ea6a813368c39dd01a0fb6f855e8..d7518caaa5db0daaeb834e30098d2ae140c1ec41 100644 --- a/enzevalos_iphone/SwiftUI/Read/ReadViewCoordinator.swift +++ b/enzevalos_iphone/SwiftUI/Read/ReadViewCoordinator.swift @@ -62,10 +62,15 @@ class ReadViewCoordinator { AppDelegate.getAppDelegate().mailHandler.move(mails: [mail], from: mail.folder.path, to: UserManager.backendArchiveFolderPath) } - func pushComposeView() { + func pushComposeView(to: [EnzevalosContact], cc: [EnzevalosContact], bcc: [EnzevalosContact], subject: String?, body: String?, responseType: ResponseType?) { let vc = mainStoryboard.instantiateViewController(identifier: ViewID.ComposeView.rawValue) + var prefilledMail: EphemeralMail? + if let subject = subject, let body = body, let responseType = responseType { + prefilledMail = EphemeralMail(to: NSSet(object: to), cc: NSSet(object: cc), bcc: NSSet(object: bcc), date: Date(), subject: responseType.addPrefix(subject: subject), body: body, uid: 0, predecessor: nil) + } if let vc = vc as? SendViewController { vc.wasPushed = true + vc.prefilledMail = prefilledMail } root.isToolbarHidden = false root.pushViewController(vc, animated: true) diff --git a/enzevalos_iphone/SwiftUI/Read/ReadViewModel.swift b/enzevalos_iphone/SwiftUI/Read/ReadViewModel.swift index eaa35486b11b00f69bb2308fef7e4d28ab2d6028..7bb22e7b65a4b01c9d53308e38fd911e6c5c3688 100644 --- a/enzevalos_iphone/SwiftUI/Read/ReadViewModel.swift +++ b/enzevalos_iphone/SwiftUI/Read/ReadViewModel.swift @@ -9,15 +9,36 @@ import Foundation import SwiftUI +enum FolderType { + case Archive, Trash, Inbox, Sent, Draft, Other +} + +enum ResponseType { + case Reply, Forward, Draft + + func addPrefix(subject: String) -> String { + switch self { + case .Reply: + return "Re: " + subject + case .Forward: + return "Fwd: " + subject + case .Draft: + return subject + } + } +} + let alice = 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 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: 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: .ValidSignature, encState: .ValidedEncryptedWithCurrentKey) + + protocol DisplayContact { // General @@ -39,7 +60,6 @@ protocol DisplayContact { var keyRecord: KeyRecord? { get } } - protocol DisplayMail { associatedtype C: DisplayContact @@ -51,11 +71,20 @@ protocol DisplayMail { var bccs: [C] { get } var routingStops: [Landmark] { get } + var isRead: Bool {get set} + var folderType: FolderType { get } + // Crypto var signedState: SignatureState { get } var encState: EncryptionState { get } + var warnings: [DialogOption] { get } + var persistentMail: PersistentMail? { get } + + func markAsRead(isRead: Bool) + + } class ReadViewModel: ObservableObject { @@ -155,6 +184,17 @@ struct PseudoContact: DisplayContact { } struct PseuoMail: DisplayMail { + func markAsRead(isRead: Bool) { + print("Mail is marked as read: \(isRead)") + } + + var folderType: FolderType + + var isRead: Bool = false + + + var warnings: [DialogOption] = [DialogOption.corrupted, DialogOption.postcard] + typealias U = PseudoContact var subject: String? = "Hello World" diff --git a/enzevalos_iphone/SwiftUI/Read/AttachmentsViewMain.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/AttachmentsViewMain.swift similarity index 100% rename from enzevalos_iphone/SwiftUI/Read/AttachmentsViewMain.swift rename to enzevalos_iphone/SwiftUI/Read/Tabbed Views/AttachmentsViewMain.swift diff --git a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewChildren/DialogView.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewChildren/DialogView.swift new file mode 100644 index 0000000000000000000000000000000000000000..b4dafc54acee1fd5c30676d33adae31fed3f1a5c --- /dev/null +++ b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewChildren/DialogView.swift @@ -0,0 +1,115 @@ +// +// WarningMessageView.swift +// enzevalos_iphone +// +// Created by melicoa97 on 11.03.20. +// Copyright © 2020 fu-berlin. All rights reserved. +// + +import SwiftUI + +struct DialogView: View { + + let option: DialogOption + var ctaAction: (() -> Void)? + var additionalAction: (() -> Void)? + var dismissAction: (() -> Void)? + + private let color = Color(UIColor.systemGray6) + + + 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) + .frame(maxWidth: .infinity) + .padding(.bottom, 20) + .addBorder(Color(option.color), 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) + .fontWeight(.light) + } + .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)) + .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) + } + } + if option.dismissButtonTitle != nil && dismissAction != nil { + Button(action: dismissAction!) { + Text(option.dismissButtonTitle!) + .foregroundColor(.red) + .frame(maxWidth: .infinity,maxHeight: 50) + .background(RoundedCorners(color: color, radius: 30)) + .padding(.vertical, 10) + .padding(.horizontal, 20) + } + } + } + .background(RoundedCorners(color: color, radius: 30)) + .padding(10) + } + +} + +struct WarningMessageView_Previews: PreviewProvider { + static var previews: some View { + VStack{ + DialogView(option: .postcard, ctaAction: action, additionalAction: action, dismissAction: action) + DialogView(option: .corrupted, ctaAction: action) + + } .padding(20) + } + + static func action() { + print("Button click!") + } +} + +extension View { + public func addBorder<S>(_ content: S, width: CGFloat = 1, cornerRadius: CGFloat) -> some View where S : ShapeStyle { + return overlay(RoundedRectangle(cornerRadius: cornerRadius).strokeBorder(content, lineWidth: width)) + } +} diff --git a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewMain.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewMain.swift index f2e218362866c7e8d80b202f038191c88e31cc89..a4bfe08ed54f29700ddc950e8fedc8873e76ee7d 100644 --- a/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewMain.swift +++ b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/MessageViewMain.swift @@ -8,158 +8,93 @@ import SwiftUI -struct MessageViewMain: View { +struct MessageViewMain <M: DisplayMail>: View { + + var mail: M - let coord:ReadViewCoordinator + @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode> - let mail:PersistentMail + let innerPadding:CGFloat = 20 // button radius + let outerPadding:CGFloat = 5 + let extraButtonFactor: CGFloat = 0.8 + + @State var showExtraButtons:Bool = false - @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode> + func action() { + print("Click!") + } var body: some View { ZStack{ ScrollView{ VStack{ Subjectbar - VStack{Stroke(offsetY:-15)}.frame(height: 3)//workaround - if mail.isEncrypted || mail.trouble || mail.containsSecretKey || mail.deleteWhileTravel || mail.isNewPubKey { - WarnMsg + Divider() + if mail.warnings.count > 0 { + ForEach(0..<mail.warnings.count) { index in + DialogView(option: self.mail.warnings[index], ctaAction: self.action, additionalAction: self.action, dismissAction: self.action) + } + Divider() + MessageBody.padding(.horizontal) } - else{ + else{ MessageBody.padding(.horizontal) } } } .onTapGesture { - self.showExtraButtons=false + self.showExtraButtons = false } FloatingReplyButtons - }.onAppear(perform: {self.mail.isRead = true}) - } - + }.onAppear(perform: {self.mail.markAsRead(isRead: true)}) + } var Subjectbar: some View{ - return - VStack(alignment: .leading){ - Text(mail.subject ?? "--no-subject--").font(.system(size: 23)).fontWeight(.light) - }.padding() + VStack(alignment: .leading){ + Text(mail.subject ?? "--no-subject--").font(.largeTitle).fontWeight(.light) + } + .padding() } func actionButton(image:Image , description:String, action:@escaping ()->Void)->some View{ return Button(action: action){ VStack{ image - Text(description).font(.system(size: 10)).fontWeight(.none) + Text(description).font(.callout).fontWeight(.none) } } } - - var WarnMsg: some View{ - return VStack{ - if mail.trouble{ - Text(NSLocalizedString("corruptedHeadline", comment: "corrupted mail")) - .font(.system(size: 25)) - .frame(maxWidth: .infinity) - .background(Color.yellow) - HStack{ - Text("!") - .foregroundColor(Color.red) - .font(.system(size: 60)) - .padding([.leading, .top, .bottom]) - Text(NSLocalizedString("corruptedText", comment: "corrupted mail")) - .padding() - } - } - else if mail.isEncrypted && mail.unableToDecrypt{ - if TravelHandler.instance().mode != .atHome{ - Text(NSLocalizedString("couldNotDecryptTravelHeadline", comment: "couldn't decrypt message")) - .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("couldNotDecryptTravelText", comment: "couldn't decrypt message")) - .padding() - } - } - else { - Text(NSLocalizedString("couldNotDecryptHeadline", comment: "couldn't decrypt message")) - .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("couldNotDecryptText", comment: "couldn't decrypt message")) - .padding() - } - } - } - //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() - } - } - //else if mail.deleteWhileTravel{} - // message not readable while traveling - }.background(Color(UIColor.systemGray5)).padding() - } - - var MessageBody : some View { - return Text(self.mail.body!).padding(.bottom, 2*innerPadding+outerPadding) + return Text(self.mail.body!).padding(.bottom, 2 * innerPadding + outerPadding) } - - let innerPadding:CGFloat = 15 //buttonRadius - let outerPadding:CGFloat = 5 - let extraButtonFactor: CGFloat = 0.8 - - @State var showExtraButtons:Bool = false - var FloatingReplyButtons: some View{ return VStack{ Spacer() HStack{ Spacer() ZStack{ - - if mail.folder.path.hasPrefix(UserManager.backendArchiveFolderPath){ + + if mail.folderType == FolderType.Archive { forwardButton.offset(y: showExtraButtons ? -innerPadding*9 : 0) replyAllButton.offset(y: showExtraButtons ? -innerPadding*4.5 : 0) replyButton unreadButton.offset(x: showExtraButtons ? -innerPadding*4.5 : 0) deleteButton.offset(x: showExtraButtons ? -innerPadding*9 : 0) } - else if mail.folder.path.hasPrefix(UserManager.backendTrashFolderPath){ + else if mail.folderType == FolderType.Trash{ forwardButton.offset(y: showExtraButtons ? -innerPadding*9 : 0) replyAllButton.offset(y: showExtraButtons ? -innerPadding*4.5 : 0) replyButton unreadButton.offset(x: showExtraButtons ? -innerPadding*4.5 : 0) archiveButton.offset(x: showExtraButtons ? -innerPadding*9 : 0) } - else if mail.folder.path.hasPrefix(UserManager.backendSentFolderPath){ + else if mail.folderType == FolderType.Sent { forwardButton.offset(y: showExtraButtons ? -innerPadding*4.5 : 0) deleteButton.offset(x: showExtraButtons ? -innerPadding*4.5 : 0) } - else if mail.folder.path.hasPrefix(UserManager.backendDraftFolderPath){ + else if mail.folderType == FolderType.Draft { deleteButton.offset(x: showExtraButtons ? -innerPadding*4.5 :0) } else{ @@ -189,7 +124,9 @@ struct MessageViewMain: View { var forwardButton: some View { FloatingActionButton( radius: innerPadding*extraButtonFactor, - onShortPress: self.coord.pushComposeView/*TODO: fill in stuff*/ + onShortPress: { + self.newMail(type: .Forward, toAll: false) + } ){ VStack{ Image(systemName: "arrowshape.turn.up.right.fill") @@ -202,7 +139,9 @@ struct MessageViewMain: View { var replyAllButton: some View{ FloatingActionButton( radius: innerPadding*extraButtonFactor, - onShortPress: self.coord.pushComposeView/*TODO: fill in stuff*/ + onShortPress: { + self.newMail(type: .Reply, toAll: true) + } ){ VStack{ Image(systemName: "arrowshape.turn.up.left.2.fill") @@ -215,9 +154,9 @@ struct MessageViewMain: View { FloatingActionButton( radius: innerPadding*extraButtonFactor, onShortPress: { - self.mail.isRead = false + self.mail.markAsRead(isRead: false) self.presentationMode.wrappedValue.dismiss() - }/*TODO: fill in stuff*/ + } ){ VStack{ Image(systemName: "envelope.badge") @@ -230,7 +169,7 @@ struct MessageViewMain: View { FloatingActionButton( radius: innerPadding*extraButtonFactor, onShortPress: { - self.coord.delete(mail: self.mail); + self.moveMail(target: .Trash) self.presentationMode.wrappedValue.dismiss()}/*TODO: fill in stuff*/ ){ VStack{ @@ -245,6 +184,7 @@ struct MessageViewMain: View { FloatingActionButton( radius: innerPadding*extraButtonFactor, onShortPress: { + self.moveMail(target: .Archive) self.presentationMode.wrappedValue.dismiss() } ){ @@ -257,8 +197,9 @@ struct MessageViewMain: View { var replyButton: some View{ FloatingActionButton( - //radius: innerPadding, - onShortPress: self.coord.pushComposeView/*TODO: fill in stuff*/ + onShortPress: { + self.newMail(type: .Reply, toAll: false) + } ){ VStack{ Image(systemName: "arrowshape.turn.up.left.fill") @@ -266,13 +207,54 @@ struct MessageViewMain: View { } } } + + private func moveMail(target: FolderType, foldername: String? = nil) { + guard let coord = AppDelegate.getAppDelegate().readViewCoordinator, let m = mail.persistentMail else { + return + } + switch target { + case .Archive : coord.archive(mail: m) + case .Trash : coord.delete(mail: m) + default : break //TODO Move mail + } + } + + private func newMail(type: ResponseType, toAll: Bool) { + if let coord = AppDelegate.getAppDelegate().readViewCoordinator { + var to = [EnzevalosContact] () + var cc = [EnzevalosContact]() + var bcc = [EnzevalosContact] () + if let sender = mail.sender.keyRecord?.ezContact, type != .Forward { + to.append(sender) + } + if toAll { + to.append(contentsOf: makeEnzContactArray(contacts: mail.tos)) + cc.append(contentsOf: makeEnzContactArray(contacts: mail.ccs)) + bcc.append(contentsOf: makeEnzContactArray(contacts: mail.bccs)) + } + coord.pushComposeView(to: to, cc: cc, bcc: bcc, subject: mail.subject, body: mail.body, responseType: type) + } + } + + private func makeEnzContactArray(contacts: [DisplayContact]) -> [EnzevalosContact] { + let enzContacts = contacts.map({$0.keyRecord?.ezContact}) + return enzContacts.compactMap({$0}) + } } -/*struct MessageViewMain_Previews: PreviewProvider { +struct MessageViewMain_Previews: PreviewProvider { static var previews: some View { - MessageViewMain() - } -}*/ - + let deviceNames: [String] = [ + "iPhone SE", + "iPhone 11 Pro Max" + ] + return ForEach(deviceNames, id: \.self) {deviceName in + MessageViewMain(mail: mail) + .previewDisplayName(deviceName) + .previewDevice(.init(rawValue: deviceName)) + } + + } +} diff --git a/enzevalos_iphone/SwiftUI/Read/SenderViewMain.swift b/enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift similarity index 100% rename from enzevalos_iphone/SwiftUI/Read/SenderViewMain.swift rename to enzevalos_iphone/SwiftUI/Read/Tabbed Views/SenderViewMain.swift diff --git a/enzevalos_iphone/SwiftUI/SupportingViews/Geometry/CornerRounder.swift b/enzevalos_iphone/SwiftUI/SupportingViews/Geometry/CornerRounder.swift index 677a2fa4bcf7fe44e7d4a7d3a298a970fa051571..4d38c52661dbdf3cc611d9e4fe6b400bf72c256c 100644 --- a/enzevalos_iphone/SwiftUI/SupportingViews/Geometry/CornerRounder.swift +++ b/enzevalos_iphone/SwiftUI/SupportingViews/Geometry/CornerRounder.swift @@ -14,6 +14,22 @@ struct RoundedCorners: View { var tr: CGFloat = 0.0 var bl: CGFloat = 0.0 var br: CGFloat = 0.0 + + init(color: Color, radius: CGFloat) { + tl = radius + tr = radius + bl = radius + br = radius + self.color = color + } + + init(color: Color, tl: CGFloat, tr: CGFloat, bl: CGFloat, br: CGFloat) { + self.tl = tl + self.tr = tr + self.bl = bl + self.br = br + self.color = color + } var body: some View { GeometryReader { geometry in @@ -42,3 +58,9 @@ struct RoundedCorners: View { } } } + +struct CornerRounder_Previews: PreviewProvider { + static var previews: some View { + RoundedCorners(color: .gray, tl: 10, tr: 10, bl: 10, br: 10) + } +}