diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index 8b3f20b0580d4387049bb0a858dc47101193f3ae..f4911b90b0ae8ebf363f26459dbd14e575a69db5 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -141,10 +141,12 @@ 47E7BE632232BD0A00C8EF94 /* SignedEncMailFromMac.eml in Resources */ = {isa = PBXBuildFile; fileRef = 47E7BE622232BD0A00C8EF94 /* SignedEncMailFromMac.eml */; }; 47EABF09241A9C8700774A93 /* AuthenticationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EABF06241A9C8700774A93 /* AuthenticationModel.swift */; }; 47EABF0A241A9C8700774A93 /* AuthenticationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EABF07241A9C8700774A93 /* AuthenticationViewModel.swift */; }; - 47EABF0B241A9C8700774A93 /* AuthenticationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EABF08241A9C8700774A93 /* AuthenticationScreen.swift */; }; 47EABF0D241A9CA800774A93 /* MailAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EABF0C241A9CA800774A93 /* MailAccount.swift */; }; 47EABF0E2420C63600774A93 /* GeneratedMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97C527A0241AA4090030BBC9 /* GeneratedMocks.swift */; }; 47EABF0F2420C63600774A93 /* AuthenticationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97C5279E241A9F7B0030BBC9 /* AuthenticationTests.swift */; }; + 47EABF272423BFDD00774A93 /* AuthenticationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EABF262423BFDD00774A93 /* AuthenticationScreen.swift */; }; + 47EABF292423C1FB00774A93 /* KeyboardChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EABF282423C1FB00774A93 /* KeyboardChecker.swift */; }; + 47EABF2B2423C20C00774A93 /* LoadingBlocker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EABF2A2423C20C00774A93 /* LoadingBlocker.swift */; }; 47F0376E22A7278A0005C9DE /* accounts.json in Resources */ = {isa = PBXBuildFile; fileRef = 47F0376D22A7278A0005C9DE /* accounts.json */; }; 47F79240203492E3005E7DB6 /* KeyRecord+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F7923E203492E3005E7DB6 /* KeyRecord+CoreDataClass.swift */; }; 47F79241203492E3005E7DB6 /* KeyRecord+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F7923F203492E3005E7DB6 /* KeyRecord+CoreDataProperties.swift */; }; @@ -171,9 +173,6 @@ 8428A8711F436A1E007649A5 /* GamificationStatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8428A86D1F436A1E007649A5 /* GamificationStatusViewController.swift */; }; 8428A8831F436AC9007649A5 /* GamificationDataUnitTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8428A8561F4369EA007649A5 /* GamificationDataUnitTest.swift */; }; 8428A8841F436ACC007649A5 /* GamificationElements.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8428A8541F4369CF007649A5 /* GamificationElements.xcassets */; }; - 976EEBED240D47C3006FE574 /* AuthenticationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 976EEBEC240D47C3006FE574 /* AuthenticationViewModel.swift */; }; - 9771AA8C241161190023A096 /* MailAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9771AA8B241161190023A096 /* MailAccount.swift */; }; - 97B2F4D6240D321B000DB34E /* depricated_AuthenticationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97B2F4D5240D321B000DB34E /* depricated_AuthenticationScreen.swift */; }; 988C9C5D240D507A006213F0 /* PhishingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 988C9C5C240D507A006213F0 /* PhishingTests.swift */; }; A102AA8A1EDDB4F40024B457 /* videoOnboarding2.m4v in Resources */ = {isa = PBXBuildFile; fileRef = A102AA891EDDB4E80024B457 /* videoOnboarding2.m4v */; }; A1083A541E8BFEA6003666B7 /* Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1083A531E8BFEA6003666B7 /* Onboarding.swift */; }; @@ -235,11 +234,7 @@ A1F992391DA7DD2E0073BF1B /* InboxTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A1F9923B1DA7DD2E0073BF1B /* InboxTableViewCell.xib */; }; A1FA44A721E10E1400DB02AC /* TravelHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1FA44A621E10E1400DB02AC /* TravelHandler.swift */; }; AC4001CA169DC07A7A1E3AD3 /* Pods_enzevalos_iphone.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 94EE54279AB591E0CAB8EFD8 /* Pods_enzevalos_iphone.framework */; }; - AD643504242243FD00F900B8 /* AuthenticationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD643503242243FD00F900B8 /* AuthenticationModel.swift */; }; - AD64350624224A5200F900B8 /* LoadingBlocker.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD64350524224A5200F900B8 /* LoadingBlocker.swift */; }; AD97DFBE241F97A300C35B95 /* OnboardingIntroInfoSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD97DFBD241F97A300C35B95 /* OnboardingIntroInfoSection.swift */; }; - AD97DFC22420FB3F00C35B95 /* AuthenticationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD97DFC12420FB3F00C35B95 /* AuthenticationView.swift */; }; - AD97DFC42421057400C35B95 /* KeyboardChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD97DFC32421057400C35B95 /* KeyboardChecker.swift */; }; F113C3851F30D06800E7F1D6 /* QRScannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F113C3841F30D06800E7F1D6 /* QRScannerView.swift */; }; F113C38B1F3344C200E7F1D6 /* ViewControllerPannable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F113C38A1F3344C200E7F1D6 /* ViewControllerPannable.swift */; }; F119D2901E364B59001D732A /* AnimatedSendIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F119D28F1E364B59001D732A /* AnimatedSendIcon.swift */; }; @@ -546,8 +541,10 @@ 47E7BE622232BD0A00C8EF94 /* SignedEncMailFromMac.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SignedEncMailFromMac.eml; sourceTree = "<group>"; }; 47EABF06241A9C8700774A93 /* AuthenticationModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationModel.swift; sourceTree = "<group>"; }; 47EABF07241A9C8700774A93 /* AuthenticationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationViewModel.swift; sourceTree = "<group>"; }; - 47EABF08241A9C8700774A93 /* AuthenticationScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationScreen.swift; sourceTree = "<group>"; }; 47EABF0C241A9CA800774A93 /* MailAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MailAccount.swift; sourceTree = "<group>"; }; + 47EABF262423BFDD00774A93 /* AuthenticationScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationScreen.swift; sourceTree = "<group>"; }; + 47EABF282423C1FB00774A93 /* KeyboardChecker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardChecker.swift; sourceTree = "<group>"; }; + 47EABF2A2423C20C00774A93 /* LoadingBlocker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingBlocker.swift; sourceTree = "<group>"; }; 47F0376D22A7278A0005C9DE /* accounts.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = accounts.json; sourceTree = "<group>"; }; 47F7923E203492E3005E7DB6 /* KeyRecord+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyRecord+CoreDataClass.swift"; sourceTree = "<group>"; }; 47F7923F203492E3005E7DB6 /* KeyRecord+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyRecord+CoreDataProperties.swift"; sourceTree = "<group>"; }; @@ -581,8 +578,8 @@ 91B6C9020C660BEA78FAEF28 /* Pods-enzevalos_iphone.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-enzevalos_iphone.debug.xcconfig"; path = "../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphone/Pods-enzevalos_iphone.debug.xcconfig"; sourceTree = "<group>"; }; 94EE54279AB591E0CAB8EFD8 /* Pods_enzevalos_iphone.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_enzevalos_iphone.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9771AA8B241161190023A096 /* MailAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailAccount.swift; sourceTree = "<group>"; }; - 97B2F4D5240D321B000DB34E /* depricated_AuthenticationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = depricated_AuthenticationScreen.swift; sourceTree = "<group>"; }; 97AACD2324178C230078A68E /* AuthenticationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationModel.swift; sourceTree = "<group>"; }; + 97B2F4D5240D321B000DB34E /* depricated_AuthenticationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = depricated_AuthenticationScreen.swift; sourceTree = "<group>"; }; 97C5279E241A9F7B0030BBC9 /* AuthenticationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationTests.swift; sourceTree = "<group>"; }; 97C527A0241AA4090030BBC9 /* GeneratedMocks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GeneratedMocks.swift; path = enzevalos_iphoneTests/GeneratedMocks.swift; sourceTree = SOURCE_ROOT; }; 988C9C5C240D507A006213F0 /* PhishingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhishingTests.swift; sourceTree = "<group>"; }; @@ -836,7 +833,6 @@ sourceTree = "<group>"; }; 472F39921E279792009260FB /* protocols */ = { - isa = PBXGroup; children = ( 472F398D1E251B8D009260FB /* MailAddress.swift */, @@ -865,7 +861,6 @@ path = lib; sourceTree = "<group>"; }; - 4764060D2416AA6F00C7D426 /* include */ = { isa = PBXGroup; children = ( @@ -1153,11 +1148,12 @@ 47EABF05241A9C7000774A93 /* Authentication */ = { isa = PBXGroup; children = ( - 74ABD44E240E635E00671734 /* OnboardingIntro.swift */, AD97DFBD241F97A300C35B95 /* OnboardingIntroInfoSection.swift */, + 47EABF282423C1FB00774A93 /* KeyboardChecker.swift */, 47EABF0C241A9CA800774A93 /* MailAccount.swift */, 47EABF06241A9C8700774A93 /* AuthenticationModel.swift */, - 47EABF08241A9C8700774A93 /* AuthenticationScreen.swift */, + 47EABF262423BFDD00774A93 /* AuthenticationScreen.swift */, + 47EABF2A2423C20C00774A93 /* LoadingBlocker.swift */, 47EABF07241A9C8700774A93 /* AuthenticationViewModel.swift */, ); name = Authentication; @@ -1242,9 +1238,7 @@ isa = PBXGroup; children = ( AD97DFC12420FB3F00C35B95 /* AuthenticationView.swift */, - 976EEBEC240D47C3006FE574 /* AuthenticationViewModel.swift */, 97B2F4D5240D321B000DB34E /* depricated_AuthenticationScreen.swift */, - 9771AA8B241161190023A096 /* MailAccount.swift */, AD97DFC32421057400C35B95 /* KeyboardChecker.swift */, AD643503242243FD00F900B8 /* AuthenticationModel.swift */, AD64350524224A5200F900B8 /* LoadingBlocker.swift */, @@ -1322,7 +1316,6 @@ A13526771D955BDF00D3BFE1 /* enzevalos_iphone */ = { isa = PBXGroup; children = ( - 97B2F4D4240D31E6000DB34E /* authentication */, 47EABF05241A9C7000774A93 /* Authentication */, 476406872416B54D00C7D426 /* SwiftUI */, 476403FA2413F95300C7D426 /* OpenSSL */, @@ -1987,17 +1980,16 @@ A1C3270E1DB907D900CE2ED5 /* TextFormatter.swift in Sources */, F12041FD1DA409A5002E4940 /* ListViewCell.swift in Sources */, A1EFF93321E6655C003BB240 /* IntroTableView.swift in Sources */, + 47EABF272423BFDD00774A93 /* AuthenticationScreen.swift in Sources */, 4764069A2416B54D00C7D426 /* MailView.swift in Sources */, A1E2324E1F0FA41A00DC9D40 /* FolderListCell.swift in Sources */, A1F8541021E8A60800614514 /* IntroSecretViewController.swift in Sources */, A1ACDD0921EB9C4C00A059D0 /* IntroInputViewController.swift in Sources */, 476406952416B54D00C7D426 /* KeyRecordRow.swift in Sources */, 476916A0216B86A100491527 /* PersistentMail +CoreDataClass.swift in Sources */, - AD97DFC42421057400C35B95 /* KeyboardChecker.swift in Sources */, 4751C7002344D37C006B2A4D /* SecretKey+CoreDataClass.swift in Sources */, A1AEBA5921E808CB00C84E59 /* IntroYesNoViewController.swift in Sources */, A1EB05941D956931008659C1 /* InboxCellDelegator.swift in Sources */, - AD97DFC22420FB3F00C35B95 /* AuthenticationView.swift in Sources */, 8428A85D1F436A05007649A5 /* Badges.swift in Sources */, 8428A8651F436A11007649A5 /* BadgeCaseCollectionViewCell.swift in Sources */, 472F39811E1E5347009260FB /* Mail_Address+CoreDataClass.swift in Sources */, @@ -2026,12 +2018,12 @@ F1ACF21C1E0C1C6800C1B843 /* ContactViewController.swift in Sources */, AD97DFBE241F97A300C35B95 /* OnboardingIntroInfoSection.swift in Sources */, 476406962416B54D00C7D426 /* Inbox.swift in Sources */, + 47EABF2B2423C20C00774A93 /* LoadingBlocker.swift in Sources */, 475B00351F7B9565006CDD41 /* CryptoObject.swift in Sources */, A1EB057E1D956848008659C1 /* VENDataDelegate.swift in Sources */, 4706D661225CD21D00B3F1D3 /* ExportKeyHelper.swift in Sources */, 8428A86F1F436A1E007649A5 /* InviteFriendViewController.swift in Sources */, A1735DFA205AB88500B336DB /* SendViewState.swift in Sources */, - AD64350624224A5200F900B8 /* LoadingBlocker.swift in Sources */, 475B00331F7B9565006CDD41 /* SwiftPGP.swift in Sources */, 477548E421F77BA0000B22A8 /* StudyParameterProtocol.swift in Sources */, 47A5D6E42294BFF50084F81D /* Logger.swift in Sources */, @@ -2040,7 +2032,6 @@ 4764069C2416B54D00C7D426 /* VCSwiftUIView.swift in Sources */, 478154A921FF3FF400A931EC /* Invitation.swift in Sources */, 47A2A56E2350A4EF0013883D /* MoreInformationViewController.swift in Sources */, - 97B2F4D6240D321B000DB34E /* depricated_AuthenticationScreen.swift in Sources */, F1AF938F1E2D04BA00755128 /* CustomCells.swift in Sources */, 8428A8711F436A1E007649A5 /* GamificationStatusViewController.swift in Sources */, F1866C86201F707200B72453 /* EmailHelper.m in Sources */, @@ -2054,12 +2045,12 @@ A1EB057A1D956829008659C1 /* ContactCell.swift in Sources */, A12FC23120221A1400196008 /* ExportInfoViewController.swift in Sources */, 4751C6EE233CA583006B2A4D /* DateExtension.swift in Sources */, - 74ABD44C240D4E0B00671734 /* NewOnboardingView.swift in Sources */, 477548DE21F5DABE000B22A8 /* MailServerConnectionError.swift in Sources */, 475DF47A1F0D54C9009D807F /* Folder+CoreDataProperties.swift in Sources */, 475B00431F7BB6D6006CDD41 /* PersistentKey+CoreDataProperties.swift in Sources */, 479C649A21F45DAF00A01071 /* HideShowPasswordTextField.swift in Sources */, 47CEAC98222541B40075B7DC /* MailSession.swift in Sources */, + 47EABF292423C1FB00774A93 /* KeyboardChecker.swift in Sources */, F119D2901E364B59001D732A /* AnimatedSendIcon.swift in Sources */, 4707096D1F8F9F4900657F41 /* ExportViewController.swift in Sources */, F12060801DA540FE00F6EF37 /* RefreshControlExtension.swift in Sources */, @@ -2107,7 +2098,6 @@ A182182E21E50D8D00918A29 /* IntroButtonViewController.swift in Sources */, 4764069D2416B54D00C7D426 /* Stroke.swift in Sources */, 478AF715222FD5C600AEF69E /* IncomingMail.swift in Sources */, - AD643504242243FD00F900B8 /* AuthenticationModel.swift in Sources */, 47EABF09241A9C8700774A93 /* AuthenticationModel.swift in Sources */, 47C036FF2347C0F5006295E8 /* ImportKeyOverviewController.swift in Sources */, A1EB05881D956879008659C1 /* AddressHandler.swift in Sources */, @@ -2129,7 +2119,6 @@ 47E7376E22845EC400972401 /* SecretKeyTableViewController.swift in Sources */, 478154A721FF3F0900A931EC /* Warning.swift in Sources */, 4764069F2416B5A600C7D426 /* NewOnboardingView.swift in Sources */, - 47EABF0B241A9C8700774A93 /* AuthenticationScreen.swift in Sources */, 8428A8681F436A11007649A5 /* SubBadgeTableViewCell.swift in Sources */, A1EB05861D956872008659C1 /* FrequentCell.swift in Sources */, F12041FB1DA3FBF7002E4940 /* ListViewController.swift in Sources */, diff --git a/enzevalos_iphone/AppDelegate.swift b/enzevalos_iphone/AppDelegate.swift index 6994fa85a09ad5034d04c5197c3bdb9f6daca305..9a3aab968d7c1bad40563cd3252061d9f953edc2 100644 --- a/enzevalos_iphone/AppDelegate.swift +++ b/enzevalos_iphone/AppDelegate.swift @@ -32,8 +32,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var newOnboarding=true - - + var inboxCoordinator: InboxCoordinator? = nil var window: UIWindow? var contactStore = CNContactStore() var mailHandler = MailHandler() diff --git a/enzevalos_iphone/AuthenticationScreen.swift b/enzevalos_iphone/AuthenticationScreen.swift new file mode 100644 index 0000000000000000000000000000000000000000..b4945a7fc601b663cdf933b9978836c3964e37f4 --- /dev/null +++ b/enzevalos_iphone/AuthenticationScreen.swift @@ -0,0 +1,148 @@ +// +// AuthenticationScreen.swift +// enzevalos_iphone +// +// Created by SWP Usable Security für Smartphones on 02.03.20. +// Copyright © 2020 fu-berlin. All rights reserved. +// + +import SwiftUI + +/** + View of the Authentication according to MVVP pattern. Observes the AuthenticationViewModel and adjusts the displayed data accordingly + */ +struct AuthenticationScreen: View { + @State private var login: String = "" + @State private var password: String = "" + @State private var username: String = "" + @State private var imapServer: String = "" + @State private var imapPort: String = "" + @State private var smtpServer: String = "" + @State private var smtpPort: String = "" + @State private var imapEncryption = 0 + @State private var smtpEncryption = 0 + + @ObservedObject private var viewModel = AuthenticationViewModel(authenticationModel: AuthenticationModel.instance) + + var body: some View { + ScrollView { + ZStack { + Color.white.edgesIgnoringSafeArea(.all) + + LoadingView(isShowing: self.$viewModel.showProgressSpinner) { + VStack { + Text("Please enter Your credentials").padding().foregroundColor(Color.yellow) + Text("Login") + TextField("Please enter your login", text: self.$login).textFieldStyle(RoundedBorderTextFieldStyle()) + Text("Password") + SecureField("Please enter your password", text: self.$password).textFieldStyle(RoundedBorderTextFieldStyle()) + + HStack { + Toggle(isOn: self.$viewModel.isDetailedAuthentication) { + Text("Advanced options") + } + Spacer() + Button(action: {self.viewModel.isDetailedAuthentication ? + self.viewModel.detailValidation(self.login, self.password, self.username, self.imapServer, self.imapPort, AuthenticationViewModel.encryptionOptions[self.imapEncryption].value, self.smtpServer, self.smtpPort, AuthenticationViewModel.encryptionOptions[self.smtpEncryption].value) : + self.viewModel.validate(self.login, self.password) + }) { + Text("Login") + } + } + + if self.viewModel.isDetailedAuthentication { + Text("Username") + TextField("Please enter your nickname", text: self.$username).textFieldStyle(RoundedBorderTextFieldStyle()) + + HStack { + Text("Imap server") + TextField("e.g. imap.web.de", text: self.$imapServer) + } + HStack { + Text("Imap port") + TextField("e.g. 993", text:self.$imapPort).keyboardType(.numberPad) + } + Picker(selection: self.$imapEncryption, label: Text("IMAP-Transportencryption")) { + ForEach(0..<AuthenticationViewModel.encryptionOptions.count) { + Text(AuthenticationViewModel.encryptionOptions[$0].name) + } + } + HStack { + Text("Smtp server") + TextField("e.g. smtp.web.de", text: self.$smtpServer) + } + HStack { + Text("Smtp port") + TextField("e.g. 587", text: self.$smtpPort).keyboardType(.numberPad) + } + + Picker(selection: self.$smtpEncryption, label: Text("SMTP-Transportencryption")) { + ForEach(0..<AuthenticationViewModel.encryptionOptions.count) { + Text(AuthenticationViewModel.encryptionOptions[$0].name) + } + } + } + + Button(action: { self.viewModel.startGoogleOauth() }) { + Text("Google login") + } + + }.padding() + } + + if shouldDisplayErrorMessage() { + VStack { + Text(self.viewModel.errorMessage!) + .foregroundColor(Color.white) + .background(Color.red) + Spacer() + } + } + } + } + } + + func shouldDisplayErrorMessage() -> Bool { + return (self.viewModel.errorMessage != nil) && (!self.viewModel.errorMessage!.isEmpty) + } +} + +struct ActivityIndicator: UIViewRepresentable { + + @Binding var isAnimating: Bool + let style: UIActivityIndicatorView.Style + + func makeUIView(context: UIViewRepresentableContext<ActivityIndicator>) -> UIActivityIndicatorView { + return UIActivityIndicatorView(style: style) + } + + func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<ActivityIndicator>) { + isAnimating ? uiView.startAnimating() : uiView.stopAnimating() + } +} + +struct LoadingView<Content>: View where Content: View { + + @Binding var isShowing: Bool + var content: () -> Content + + var body: some View { + ZStack(alignment: .center) { + + self.content() + .disabled(self.isShowing) + .blur(radius: self.isShowing ? 3 : 0) + + VStack { + Text("Loading...") + ActivityIndicator(isAnimating: .constant(true), style: .large) + } + .frame(width: UIScreen.main.bounds.size.width / 2, + height: UIScreen.main.bounds.size.height / 5) + .background(Color.secondary.colorInvert()) + .foregroundColor(Color.primary) + .cornerRadius(20) + .opacity(self.isShowing ? 1 : 0) + } + } +} diff --git a/enzevalos_iphone/DataHandler.swift b/enzevalos_iphone/DataHandler.swift index be2dc7370c4ef75907927ae13f8bfa49d5f36397..c0556cbda925d11c84f388d911eca264e2f30cc7 100644 --- a/enzevalos_iphone/DataHandler.swift +++ b/enzevalos_iphone/DataHandler.swift @@ -61,7 +61,7 @@ class DataHandler { private var mainMOC: NSManagedObjectContext private var backMOC: NSManagedObjectContext - private var managedObjectContext: NSManagedObjectContext { + var managedObjectContext: NSManagedObjectContext { get { if Thread.current.isMainThread { return mainMOC @@ -71,6 +71,31 @@ class DataHandler { } } } + /** + Make coredata available to SwiftUI + See: https://www.hackingwithswift.com/quick-start/swiftui/how-to-configure-core-data-to-work-with-swiftui + */ + lazy var persistentContainer: NSPersistentContainer = { + let container = NSPersistentContainer(name: "enzevalos_iphone") + container.loadPersistentStores { description, error in + if let error = error { + fatalError("Could not load data...") + } + } + return container + }() + + func saveContext () { + let context = persistentContainer.viewContext + if context.hasChanges { + do { + try context.save() + } catch { + // Show the error here + } + } + } + public let outgoingFolder = "OutgoingMails" diff --git a/enzevalos_iphone/KeyRecord+CoreDataClass.swift b/enzevalos_iphone/KeyRecord+CoreDataClass.swift index e95102f4f17d96163dc8fd9a18343d3c820e6e49..b1103a916545c5d80fd5e9e2be88cc1645f56b2f 100644 --- a/enzevalos_iphone/KeyRecord+CoreDataClass.swift +++ b/enzevalos_iphone/KeyRecord+CoreDataClass.swift @@ -22,6 +22,7 @@ import Foundation import CoreData import Contacts import UIKit +import SwiftUI /** Key records are mostly used in the inbox and for id (views). For each key we have a single key record. There are also key records for each mail address without keys, for instance when receiving unsigned mails. @@ -29,8 +30,7 @@ import UIKit One person can have multiple key records, e.g. one with key, one without a key or multiple keys. */ @objc(KeyRecord) -public class KeyRecord: NSManagedObject, Record { - +public class KeyRecord: NSManagedObject, Record, Identifiable { public var isUser: Bool { get{ /** @@ -134,7 +134,7 @@ public class KeyRecord: NSManagedObject, Record { } } } - return false + return false } public var cryptoscheme: CryptoScheme { @@ -335,3 +335,14 @@ public func < (lhs: KeyRecord, rhs: KeyRecord) -> Bool { return lhs.mails.first!.date > rhs.mails.first!.date } + +extension UIImage { + /** + Same as image but different type + */ + public var img: Image { + get { + return Image(uiImage: self) + } + } +} diff --git a/enzevalos_iphone/KeyRecord+CoreDataProperties.swift b/enzevalos_iphone/KeyRecord+CoreDataProperties.swift index 02a45fc35cd56ee2bcc456f54942a8620893defd..c967a9099fbf57e8ef4fc4e3b9428baee547fea0 100644 --- a/enzevalos_iphone/KeyRecord+CoreDataProperties.swift +++ b/enzevalos_iphone/KeyRecord+CoreDataProperties.swift @@ -68,3 +68,28 @@ extension KeyRecord { @NSManaged public func removeFromPersistentMails(_ values: NSSet) } + +extension KeyRecord { + static func allRecordsFetchRequest(in folder: Folder) -> NSFetchRequest<KeyRecord> { + let request: NSFetchRequest<KeyRecord> = KeyRecord.fetchRequest() + //request.predicate = NSPredicate(format: "folder == %@", folder) + request.sortDescriptors = [NSSortDescriptor(key: "newestDate", ascending: false)] + return request + } + + static func allRecordsFetchRequest(in folder: Folder, query: String) -> NSFetchRequest<KeyRecord> { + let request: NSFetchRequest<KeyRecord> = KeyRecord.fetchRequest() + let folderPredicate = NSPredicate(format: "folder == %@", folder) + if !query.isEmpty { + let name = NSPredicate(format: "name CONTAINS %@", query) + request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [folderPredicate, name]) + } else { + request.predicate = folderPredicate + } + request.sortDescriptors = [NSSortDescriptor(key: "newestDate", ascending: false)] + return request + } +} + + + diff --git a/enzevalos_iphone/NewOnboardingView.swift b/enzevalos_iphone/NewOnboardingView.swift index b982e2c5253a2cfa664816cab78a09a5afbcf512..392363820b89e5fd4d2e0dfa256abad178cc3d4a 100644 --- a/enzevalos_iphone/NewOnboardingView.swift +++ b/enzevalos_iphone/NewOnboardingView.swift @@ -13,7 +13,7 @@ struct NewOnboardingView: View { var body: some View { if press.loggedIn{ return AnyView( - VCSwiftUIView(storyboard: "Main", VC: "RootViewController") + VCSwiftUIView(storyboard: "Main", vcID: "RootViewController") //AuthenticationScreen() ) }else{ @@ -30,26 +30,6 @@ struct NewOnboardingView_Previews: PreviewProvider { } } - -//This loads the main storyboard after login() is called -struct VCSwiftUIView: UIViewControllerRepresentable { - let storyboard: String - let VC: String - - func makeUIViewController(context: UIViewControllerRepresentableContext<VCSwiftUIView>) -> UIViewController { - - //Load the storyboard - let loadedStoryboard = UIStoryboard(name: storyboard, bundle: nil) - - //Load the ViewController - return loadedStoryboard.instantiateViewController(withIdentifier: VC) - - } - - func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<VCSwiftUIView>) { - } -} - //this class checks whether we are logged in or nah class loginManager: ObservableObject { @Published var loggedIn=false diff --git a/enzevalos_iphone/OnboardingIntro.swift b/enzevalos_iphone/OnboardingIntro.swift index f31f335d17b564423a6f8cc208fce6b39b1d9317..7afac5456aa5ab34d11e395e6e9cd4ae55af71e0 100644 --- a/enzevalos_iphone/OnboardingIntro.swift +++ b/enzevalos_iphone/OnboardingIntro.swift @@ -54,7 +54,7 @@ struct OnboardingIntroStack:View{ struct OnboardingLoginButton: View{ @EnvironmentObject private var viewModel : AuthenticationViewModel - @State private var loggingIn:Bool = false + @State private var loggingIn: Bool = false var onClick: ()->Void var body: some View { diff --git a/enzevalos_iphone/SendViewController.swift b/enzevalos_iphone/SendViewController.swift index a867fd807ef4dd3ec5af49870043cf61032fbfca..8ecf39bd26554fafa80bd2a70cf62f83b98de228 100644 --- a/enzevalos_iphone/SendViewController.swift +++ b/enzevalos_iphone/SendViewController.swift @@ -121,6 +121,8 @@ class SendViewController: UIViewController { } var invitationSelection = InvitationSelection() + + var wasPushed = false override func viewDidLoad() { super.viewDidLoad() @@ -639,7 +641,7 @@ class SendViewController: UIViewController { } controller?.dismissAction = { [weak self] in - if self?.isFeedback ?? false{ + if self?.isFeedback ?? false || self?.wasPushed ?? false { self?.navigationController?.popViewController(animated: true) } else { self?.navigationController?.dismiss(animated: true, completion: nil) @@ -647,7 +649,7 @@ class SendViewController: UIViewController { } } else { - if isFeedback { + if isFeedback || wasPushed { self.navigationController?.popViewController(animated: true) } else { self.navigationController?.dismiss(animated: true, completion: nil) @@ -804,6 +806,9 @@ class SendViewController: UIViewController { } } if (textView.text.trimmed() == "" || textView.text.trimmed() == UserManager.loadUserSignature().trimmed()) && toText.mailTokens.count == 0 && ccText.mailTokens.count == 0 && subjectText.inputText()?.trimmed() == "" { + if wasPushed { + self.navigationController?.popViewController(animated: true) + } self.navigationController?.dismiss(animated: true, completion: nil) } else { let toEntrys = toText.mailTokens @@ -816,7 +821,7 @@ class SendViewController: UIViewController { if let delegate = self?.sendViewDelegate { delegate.compositionDiscarded() } - if self?.isFeedback ?? false { + if self?.isFeedback ?? false || self?.wasPushed ?? false { self?.navigationController?.popViewController(animated: true) } else { self?.navigationController?.dismiss(animated: true, completion: nil) @@ -830,7 +835,7 @@ class SendViewController: UIViewController { if let delegate = self?.sendViewDelegate { delegate.compositionSavedAsDraft() } - if self?.isFeedback ?? false { + if self?.isFeedback ?? false || self?.wasPushed ?? false { self?.navigationController?.popViewController(animated: true) } else { self?.navigationController?.dismiss(animated: true, completion: nil) @@ -857,7 +862,7 @@ class SendViewController: UIViewController { let (hmtlmessage, counterTextparts, plaintext) = self.htmlMessage() let message: String = (plaintext ?? self.textView.text) let inviteMail = invite || mailSecurityState == .extendedPostcard(.censored) || mailSecurityState == .extendedPostcard(.partiallyEncrypted) - let travelHandler = TravelHandler.instance() + let travelHandler = TravelHandler.instance() mailHandler.send(toEntrys as NSArray as! [String], ccEntrys: ccEntrys as NSArray as! [String], bccEntrys: [], subject: subject, message: message, sendEncryptedIfPossible: !enforcePostcard && travelHandler.mode != .borderCrossing, callback: nil, htmlContent: hmtlmessage, inviteMail: inviteMail, textparts: counterTextparts, uiState: mailSecurityState) diff --git a/enzevalos_iphone/SwiftUI/Inbox/InboxCoordinator.swift b/enzevalos_iphone/SwiftUI/Inbox/InboxCoordinator.swift new file mode 100644 index 0000000000000000000000000000000000000000..af075479c2b46e6c7926f5ad273bb616d076dd84 --- /dev/null +++ b/enzevalos_iphone/SwiftUI/Inbox/InboxCoordinator.swift @@ -0,0 +1,90 @@ +// +// InboxCoordinator.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 04.03.20. +// Copyright © 2020 fu-berlin. All rights reserved. +// + +import Foundation +import SwiftUI + +class InboxCoordinator { + let root: UINavigationController + + private let mainStoryboardName = "Main" + private let mainStoryboard: UIStoryboard + private var inbox: UIViewController? + + + init(root: UINavigationController) { + self.root = root + mainStoryboard = UIStoryboard(name: self.mainStoryboardName, bundle: nil) + } + + func pushInbox(){ + try? AppDelegate.getAppDelegate().mailHandler.startIMAPIdleIfSupported() + AppDelegate.getAppDelegate().mailHandler.updateFolder(folder: Folder.inbox, completionCallback: {_ in + }) + + root.isToolbarHidden = true + + if let vc = inbox { + if root.viewControllers.contains(vc) { + while root.topViewController != vc { + root.popViewController(animated: true) + } + } else { + root.pushViewController(vc, animated: true) + } + } + else { + let context = DataHandler.handler.managedObjectContext + let vc = UIHostingController(rootView: Inbox(coord: self).environment(\.managedObjectContext,context)) + inbox = vc + root.pushViewController(vc, animated: true) + } + } + + func pushFoldersView() { + let controller = mainStoryboard.instantiateViewController(withIdentifier: ViewID.FoldersView.rawValue) + root.isToolbarHidden = false + root.pushViewController(controller, animated: true) + } + + func pushReadView(mail: PersistentMail) { + let vc = mainStoryboard.instantiateViewController(withIdentifier: ViewID.ReadView.rawValue) + if let vc = vc as? ReadViewController { + vc.mail = mail + } + root.isToolbarHidden = false + root.pushViewController(vc, animated: true) + } + + func pushRecordView(record: KeyRecord){ + let vc = mainStoryboard.instantiateViewController(withIdentifier: ViewID.KeyRecordView.rawValue) + if let vc = vc as? ContactViewController { + vc.keyRecord = record + } + root.isToolbarHidden = false + root.pushViewController(vc, animated: true) + } + + func pushComposeView() { + let vc = mainStoryboard.instantiateViewController(identifier: ViewID.ComposeView.rawValue) + if let vc = vc as? SendViewController { + vc.wasPushed = true + } + root.isToolbarHidden = false + root.pushViewController(vc, animated: true) + } + + func pushMailListView(record: KeyRecord) { + let vc = mainStoryboard.instantiateViewController(identifier: ViewID.MailListView.rawValue) + if let vc = vc as? ListViewController { + vc.contact = record + } + root.isToolbarHidden = false + root.pushViewController(vc, animated: true) + } +} diff --git a/enzevalos_iphone/SwiftUI/Inbox/KeyRecordRow.swift b/enzevalos_iphone/SwiftUI/Inbox/KeyRecordRow.swift new file mode 100644 index 0000000000000000000000000000000000000000..e8bc192f461adb52329a9eb7ff5b17881abe97ae --- /dev/null +++ b/enzevalos_iphone/SwiftUI/Inbox/KeyRecordRow.swift @@ -0,0 +1,104 @@ +// +// KeyRecordRow.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 02.03.20. +// Copyright © 2020 fu-berlin. All rights reserved. +// + +import SwiftUI + +struct KeyRecordRow: View { + @ObservedObject var keyrecord: KeyRecord + let coord: InboxCoordinator + + var body: some View { + VStack { + HStack(alignment: .lastTextBaseline) { + icon + Spacer() + mailListView() + .offset(y: -10) + } + HStack { + name + Spacer() + moreMails + } + } + } + + /* + Displays the first (and second) mail + */ + private func mailListView() -> AnyView { + let spacing = CGFloat(10) + let offset = -(spacing / 2) + + if let first = self.keyrecord.firstMail { + if let second = self.keyrecord.secondMail { + return AnyView(VStack(alignment: .leading, spacing: spacing) { + MailView(mail: first, coord: coord) + MailView(mail: second, coord: coord) + .background(Stroke(offsetY: offset)) + }) + } else { + return AnyView(VStack(alignment: .leading,spacing: spacing) { + MailView(mail: first, coord: coord) + Text(NSLocalizedString("NoFurtherMessages", comment: "No more Mails")) + .background(Stroke(offsetY: offset)) + }) + } + } else { + return AnyView(Text("NO MAILS...")) + } + } + + private var icon: some View{ + self.keyrecord.image.img + .resizable() + .frame(width: 60, height: 60) + .shadow(radius: 5) + .onTapGesture { + self.coord.pushRecordView(record: self.keyrecord) + } + } + + private var name: some View { + Text(self.keyrecord.myNick) + .frame(maxWidth: 300, alignment: .leading) + .lineLimit(1) + .onTapGesture { + self.coord.pushRecordView(record: self.keyrecord) + } + } + + private var moreMails: some View { + Button(action: { + self.coord.pushMailListView(record: self.keyrecord) + }, label: { + Text(NSLocalizedString("MailView.MoreMails", comment: "More mails")) + .foregroundColor(.gray) + }) + } +} + + +extension KeyRecord { + public var firstMail: PersistentMail? { + get { + return mails.first + } + } + + public var secondMail: PersistentMail? { + get { + if mails.count > 1 { + return mails[1] + } + return nil + } + } +} + + diff --git a/enzevalos_iphone/SwiftUI/SupportingViews/CiricleImage.swift b/enzevalos_iphone/SwiftUI/SupportingViews/CiricleImage.swift new file mode 100644 index 0000000000000000000000000000000000000000..13e567f0a9ead8ea1c62e53333de2d25487d732b --- /dev/null +++ b/enzevalos_iphone/SwiftUI/SupportingViews/CiricleImage.swift @@ -0,0 +1,20 @@ +// +// CiricleImage.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 02.03.20. +// Copyright © 2020 fu-berlin. All rights reserved. +// + +import SwiftUI + +struct CircleImage: View { + var image: Image + + var body: some View { + image + .clipShape(Circle()) + .overlay(Circle().stroke(Color.white, lineWidth: 4)) + .shadow(radius: 10) + } +} diff --git a/enzevalos_iphone/SwiftUI/SupportingViews/Geometry/Stroke.swift b/enzevalos_iphone/SwiftUI/SupportingViews/Geometry/Stroke.swift new file mode 100644 index 0000000000000000000000000000000000000000..b71e6001ed49c08d98a4e5dd73ba7809469ef743 --- /dev/null +++ b/enzevalos_iphone/SwiftUI/SupportingViews/Geometry/Stroke.swift @@ -0,0 +1,36 @@ +// +// Stroke.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 03.03.20. +// Copyright © 2020 fu-berlin. All rights reserved. +// + +import SwiftUI + +/** + Creates a gray stroke + */ +struct Stroke: View{ + var color = Color.secondary + var lineWidth = CGFloat(0.2) + var offsetY = CGFloat(0) + + var body: some View { + GeometryReader { geometry in + Path { path in + path.move(to: .zero) + path.addLine(to: CGPoint(x: geometry.size.width, y: 0)) + } + .strokedPath(StrokeStyle(lineWidth: self.lineWidth)) + .foregroundColor(self.color) + .offset(y: self.offsetY) + } + } +} + +struct Stroke_Previews: PreviewProvider { + static var previews: some View { + Stroke() + } +} diff --git a/enzevalos_iphone/SwiftUI/SupportingViews/MailView.swift b/enzevalos_iphone/SwiftUI/SupportingViews/MailView.swift new file mode 100644 index 0000000000000000000000000000000000000000..2aa2587e4d9fed533c2374f1f4c3a2e5c0e9679e --- /dev/null +++ b/enzevalos_iphone/SwiftUI/SupportingViews/MailView.swift @@ -0,0 +1,49 @@ +// +// MailView.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 02.03.20. +// Copyright © 2020 fu-berlin. All rights reserved. +// + +import SwiftUI + + + +struct MailView: View { + var mail: PersistentMail + let coord: InboxCoordinator // We need this to move to the mail. + + init(mail: PersistentMail, coord: InboxCoordinator) { + self.mail = mail + self.coord = coord + + } + + var body: some View { + Group{ + HStack { + subject + .frame(minWidth: 10, maxWidth: 200, alignment: .leading) + .lineLimit(1) + Spacer() + Text(mail.timeString) + .font(.footnote) + } + } + .onTapGesture { + self.coord.pushReadView(mail: self.mail) + } + } + + var subject: some View { + var text = Text(mail.getSubjectWithFlagsString() ) + if !mail.isRead { + text = text.bold() + } + return text + } + +} + + diff --git a/enzevalos_iphone/SwiftUI/SupportingViews/SwiftUI to UIKit/VCSwiftUIView.swift b/enzevalos_iphone/SwiftUI/SupportingViews/SwiftUI to UIKit/VCSwiftUIView.swift new file mode 100644 index 0000000000000000000000000000000000000000..2b562cdfafc9accd9a404114e8782148c5dee4e3 --- /dev/null +++ b/enzevalos_iphone/SwiftUI/SupportingViews/SwiftUI to UIKit/VCSwiftUIView.swift @@ -0,0 +1,41 @@ +// +// VCSwiftUIView.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 03.03.20. +// Copyright © 2020 fu-berlin. All rights reserved. +// + +import SwiftUI + +enum ViewID: String{ + case KeyRecordView = "UITableViewController-8Di-x2-cWQ" + case ReadView = "UITableViewController-Ouw-WD-EV6" + case FoldersView = "folderViewController" + case ComposeView = "SendViewController" + case MailListView = "UITableViewController-ooe-0X-glz" +} + +/** + Generate a SwiftUIView for a UIViewController in the main story board + */ +struct VCSwiftUIView: UIViewControllerRepresentable { + var storyboard: String = "Main" + var vcID: String + + func makeUIViewController(context: UIViewControllerRepresentableContext<VCSwiftUIView>) -> UIViewController { + //Load the storyboard + let loadedStoryboard = UIStoryboard(name: storyboard, bundle: nil) + //Load the ViewController + let myVc = loadedStoryboard.instantiateViewController(withIdentifier: vcID) + return myVc + + } + + func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<VCSwiftUIView>) { + } +} + + + +