diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index ccc6e74a432a22d66efff2256a96aec3161b0441..ccca30b9e1c3af84e3b5b08f64489d9c565c9f1a 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -219,6 +219,8 @@ 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 */; }; @@ -520,6 +522,8 @@ A1F9923F1DA7DD370073BF1B /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InboxTableViewCell.strings; sourceTree = "<group>"; }; A1FA44A621E10E1400DB02AC /* TravelHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TravelHandler.swift; sourceTree = "<group>"; }; AA686D4FC9B86445A0C87F0F /* Pods-enzevalos_iphone.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-enzevalos_iphone.release.xcconfig"; path = "../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphone/Pods-enzevalos_iphone.release.xcconfig"; sourceTree = "<group>"; }; + AD643503242243FD00F900B8 /* AuthenticationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationModel.swift; sourceTree = "<group>"; }; + AD64350524224A5200F900B8 /* LoadingBlocker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingBlocker.swift; sourceTree = "<group>"; }; AD97DFBD241F97A300C35B95 /* OnboardingIntroInfoSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingIntroInfoSection.swift; sourceTree = "<group>"; }; AD97DFC12420FB3F00C35B95 /* AuthenticationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationView.swift; sourceTree = "<group>"; }; AD97DFC32421057400C35B95 /* KeyboardChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardChecker.swift; sourceTree = "<group>"; }; @@ -898,11 +902,13 @@ 97B2F4D4240D31E6000DB34E /* authentication */ = { isa = PBXGroup; children = ( - 97B2F4D5240D321B000DB34E /* depricated_AuthenticationScreen.swift */, + AD97DFC12420FB3F00C35B95 /* AuthenticationView.swift */, 976EEBEC240D47C3006FE574 /* AuthenticationViewModel.swift */, + 97B2F4D5240D321B000DB34E /* depricated_AuthenticationScreen.swift */, 9771AA8B241161190023A096 /* MailAccount.swift */, - AD97DFC12420FB3F00C35B95 /* AuthenticationView.swift */, AD97DFC32421057400C35B95 /* KeyboardChecker.swift */, + AD643503242243FD00F900B8 /* AuthenticationModel.swift */, + AD64350524224A5200F900B8 /* LoadingBlocker.swift */, ); name = authentication; sourceTree = "<group>"; @@ -1634,6 +1640,7 @@ 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 */, @@ -1706,6 +1713,7 @@ A1EB057C1D956838008659C1 /* MailHandler.swift in Sources */, A182182E21E50D8D00918A29 /* IntroButtonViewController.swift in Sources */, 478AF715222FD5C600AEF69E /* IncomingMail.swift in Sources */, + AD643504242243FD00F900B8 /* AuthenticationModel.swift in Sources */, 47C036FF2347C0F5006295E8 /* ImportKeyOverviewController.swift in Sources */, A1EB05881D956879008659C1 /* AddressHandler.swift in Sources */, 472F39701E14F75C009260FB /* DataHandler.swift in Sources */, diff --git a/enzevalos_iphone/AppDelegate.swift b/enzevalos_iphone/AppDelegate.swift index 9e1d55fd9b2fe491055f38e8831f66fe03339475..71ea146fe1a0c3f5f5155001d72e657ac5b0e525 100644 --- a/enzevalos_iphone/AppDelegate.swift +++ b/enzevalos_iphone/AppDelegate.swift @@ -63,8 +63,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { self.window = UIWindow(frame: UIScreen.main.bounds) if (newOnboarding) { - let avm=AuthenticationViewModel() - self.window?.rootViewController = UIHostingController(rootView: NewOnboardingView().environmentObject(avm))} + //let avm=AuthenticationViewModel() + self.window?.rootViewController = UIHostingController(rootView: NewOnboardingView()/*.environmentObject(avm)*/)} else {self.window?.rootViewController = Onboarding.onboarding()} self.window?.makeKeyAndVisible() diff --git a/enzevalos_iphone/AuthenticationModel.swift b/enzevalos_iphone/AuthenticationModel.swift new file mode 100644 index 0000000000000000000000000000000000000000..3f8231bb2cd3c863c99ed46d6cdb4da3a991b611 --- /dev/null +++ b/enzevalos_iphone/AuthenticationModel.swift @@ -0,0 +1,197 @@ +// +// AuthenticationModel.swift +// enzevalos_iphone +// +// Created by hanneh00 on 18.03.20. +// Copyright © 2020 fu-berlin. All rights reserved. +// + +import Foundation +import Combine + +/** + Model of the Authentication according to MVVP pattern. Performs all the necessary server calls according to the data provided by the ViewModel + */ +class AuthenticationModel: NSObject { + + enum AuthenticationResult {case Success, Timeout, Error(value: MailServerConnectionError)} + + static let instance: AuthenticationModel = AuthenticationModel() + + var extendedValidation: Bool = false + + private var currentIMAP: MailSession? + private var currentSMTP: MailSession? + var imapCallback: AuthenticationCallback? = nil + var smtpCallback: AuthenticationCallback? = nil + + var imapConfigurationSuccessful = false + var smtpConfigurationSuccessful = false + + var dispatchGroup = DispatchGroup() + + /** + Start asynchronous tasks for checking IMAP and SMTP configuration with a *timeoutDelay* after which the tasks are not getting consumed anymore. + + - Parameters: + - mailAccount: data class that holds the properties used for establishing the connection + - extendedValidation: indicates whether the imap/smtp configuration got specified by the user or should use default values + + - Returns: a Future that produces an AuthenticationResult once the server calls are done + */ + func checkConfig(mailAccount: MailAccount, extendedValidation: Bool) -> Future<AuthenticationResult, Never> { + self.extendedValidation = extendedValidation + var future: Future<AuthenticationResult, Never> + dispatchGroup = DispatchGroup() + imapCallback = AuthenticationCallback(callback: onImapCompleted) + let imapItem = DispatchWorkItem { self.checkIMAPConfig(mailAccount: mailAccount, self.imapCallback! ) } + dispatchGroup.enter() + DispatchQueue.global().async(execute: imapItem) + + smtpCallback = AuthenticationCallback(callback: onSmtpCompleted) + let smtpItem = DispatchWorkItem { self.checkSMTPConfig(mailAccount: mailAccount, self.smtpCallback!) } + dispatchGroup.enter() + DispatchQueue.global().async(execute: smtpItem) + + future = Future { promise in + DispatchQueue.global().async { + let timeoutDelay: DispatchTimeInterval = DispatchTimeInterval.seconds(10) + let result = self.dispatchGroup.wait(timeout: DispatchTime.now() + timeoutDelay) + DispatchQueue.main.async { + promise(.success(self.onTimeout(timeoutResult: result))) + } + } + } + return future + } + + func checkIMAPConfig(mailAccount: MailAccount, _ callback: AuthenticationCallback) { + imapConfigurationSuccessful = false + let mailSession: MailSession = setupIMAPSession(mailAccount: mailAccount, callback: callback) + currentIMAP = mailSession + if extendedValidation && mailSession.startTestingServerConfig(){ + imapConfigurationSuccessful = true + } else { + if !mailSession.hasJsonFile && mailSession.startLongSearchOfServerConfig(hostFromAdr: false){ + imapConfigurationSuccessful = true + } else { + if mailSession.startTestingServerConfigFromList() || mailSession.startLongSearchOfServerConfig(hostFromAdr: true){ + imapConfigurationSuccessful = true + } + } + } + } + + func checkSMTPConfig(mailAccount: MailAccount, _ callback: AuthenticationCallback) { + smtpConfigurationSuccessful = false + let mailSession: MailSession = setupSMTPSession(mailAccount: mailAccount, callback: callback) + currentSMTP = mailSession + if extendedValidation && mailSession.startTestingServerConfig() { + smtpConfigurationSuccessful = true + } else { + if !mailSession.hasJsonFile && mailSession.startLongSearchOfServerConfig(hostFromAdr: false) { + smtpConfigurationSuccessful = true + } else { + if mailSession.startTestingServerConfigFromList() || mailSession.startLongSearchOfServerConfig(hostFromAdr: true){ + smtpConfigurationSuccessful = true + } + } + } + } + + private func setupIMAPSession(mailAccount: MailAccount, callback: AuthenticationCallback) -> MailSession { + let mailSession = MailSession(configSession: SessionType.IMAP, mailAddress: mailAccount.emailAddress, password: mailAccount.password, username: mailAccount.username) + if extendedValidation { + let imapConnValue = mailAccount.imapEncryption + mailSession.setServer(hostname: mailAccount.imapServer, port: UInt32(mailAccount.imapPort), connType: imapConnValue, authType: mailAccount.authType) + } + let listenerIMAP = Listener(callback: callback, mailAccount: mailAccount) + mailSession.addListener(listener: listenerIMAP) + return mailSession + } + + private func setupSMTPSession(mailAccount: MailAccount, callback: AuthenticationCallback) -> MailSession { + let mailSession = MailSession(configSession: SessionType.SMTP, mailAddress: mailAccount.emailAddress, password: mailAccount.password, username: mailAccount.username) + if extendedValidation { + let smtpConnValue = mailAccount.smtpEncryption + mailSession.setServer(hostname: mailAccount.smtpServer, port: UInt32(mailAccount.smtpPort), connType: smtpConnValue, authType: mailAccount.authType) + } + let listenerSMTP = Listener(callback: callback, mailAccount: mailAccount) + mailSession.addListener(listener: listenerSMTP) + return mailSession + } + + func onTimeout(timeoutResult: DispatchTimeoutResult) -> AuthenticationResult { + imapCallback?.callback = nil + smtpCallback?.callback = nil + if timeoutResult == .success { + if imapConfigurationSuccessful && smtpConfigurationSuccessful { + return AuthenticationResult.Success + } else { + var error = MailServerConnectionError.AuthenticationError + if let smtp = currentIMAP, let e = MailServerConnectionError.findPrioError(errors: smtp.errors) { + error = e + } + if let imap = currentIMAP, let e = MailServerConnectionError.findPrioError(errors: imap.errors) { + error = e + } + + return AuthenticationResult.Error(value: error) + } + } else { + return AuthenticationResult.Timeout + } + } + + func onImapCompleted(imapWorks: Bool, _ login: String, _ password: String) { + if imapWorks { + _ = currentIMAP?.storeToUserDefaults() + imapConfigurationSuccessful = true + } else { + imapConfigurationSuccessful = false + } + dispatchGroup.leave() + } + + func onSmtpCompleted(smtpWorks: Bool, _ login: String, _ password: String) { + if smtpWorks { + _ = currentSMTP?.storeToUserDefaults() + smtpConfigurationSuccessful = true + } else { + smtpConfigurationSuccessful = false + } + dispatchGroup.leave() + } + + /** + A listner class that notifies the AuthenticationCallback's about the result once the server call is done + */ + class Listener: MailSessionListener { + let callback: AuthenticationCallback + let mailAccount: MailAccount + + init(callback: AuthenticationCallback, mailAccount: MailAccount) { + self.callback = callback + self.mailAccount = mailAccount + } + + func testFinish(result: Bool) { + callback.onResult(worked: result, login: mailAccount.emailAddress, password: mailAccount.password) + } + } +} + +class AuthenticationCallback { + var callback: ((Bool, String, String) -> Void)? + + init(callback: @escaping (Bool, String, String) -> Void) { + self.callback = callback + } + + func onResult(worked: Bool, login: String, password: String) { + if let callback = callback { + callback(worked, login, password) + } + } +} + diff --git a/enzevalos_iphone/AuthenticationView.swift b/enzevalos_iphone/AuthenticationView.swift index 8b4498f2ddb3ce0af8b74cf57ff27c971e438bdc..8c68f3bddb4d91b6c19d8faeb72a7f095edd6724 100644 --- a/enzevalos_iphone/AuthenticationView.swift +++ b/enzevalos_iphone/AuthenticationView.swift @@ -28,7 +28,9 @@ struct AuthenticationView: View{ var encryptionOptions = ["Plaintext", "StartTLS", "TLS/SSL"] - @EnvironmentObject var viewModel:AuthenticationViewModel + //@EnvironmentObject var viewModel:AuthenticationViewModel + @ObservedObject private var viewModel = AuthenticationViewModel(authenticationModel: AuthenticationModel.instance) + @ObservedObject private var keyboard = KeyboardResponder() //whether the next-button is enabled (correct email format and all necessary fields used) @@ -54,40 +56,42 @@ struct AuthenticationView: View{ .clipShape(RoundedRectangle(cornerRadius: 8)) .background(Color.red) } - VStack{ - LoginCredentialSection(email: $login, password: $password) - LoginAdvancedSection(username: $username, imapServer: $imapServer, imapPort: $imapPort, smtpServer: $smtpServer, smtpPort: $smtpPort, imapEncryption: $imapEncryption, smtpEncryption: $smtpEncryption, isDetailed: $viewModel.isDetailedAuthentication, encryptionOptions: encryptionOptions).padding([ .leading, .trailing],20) - HStack{ - Button(action: onBack){ - HStack(alignment: .center){ - Image(systemName: "arrow.down.circle") - .resizable() - .frame(width: imageSize, height: imageSize) - Text("Back") + LoadingView(isShowing: self.$viewModel.showProgressSpinner) { + VStack{ + LoginCredentialSection(email: self.$login, password: self.$password) + LoginAdvancedSection(username: self.$username, imapServer: self.$imapServer, imapPort: self.$imapPort, smtpServer: self.$smtpServer, smtpPort: self.$smtpPort, imapEncryption: self.$imapEncryption, smtpEncryption: self.$smtpEncryption, isDetailed: self.$viewModel.isDetailedAuthentication, encryptionOptions: self.encryptionOptions).padding([ .leading, .trailing],20) + HStack{ + Button(action: self.onBack){ + HStack(alignment: .center){ + Image(systemName: "arrow.down.circle") + .resizable() + .frame(width: self.imageSize, height: self.imageSize) + Text("Back") + } } - } - Spacer() - Button(action: {self.viewModel.isDetailedAuthentication ? - self.viewModel.detailValidation(self.login, self.password, self.username, self.imapServer, self.imapPort, self.imapEncryption, self.smtpServer, self.smtpPort, self.smtpEncryption) : - self.viewModel.validate(self.login, self.password) - }){ - HStack(alignment: .center){ - Text("Next") - Image(systemName: "arrow.right.circle") - .resizable() - .frame(width: imageSize, height: imageSize) + Spacer() + Button(action: {self.viewModel.isDetailedAuthentication ? + self.viewModel.detailValidation(self.login, self.password, self.username, self.imapServer, self.imapPort, self.imapEncryption, self.smtpServer, self.smtpPort, self.smtpEncryption) : + self.viewModel.validate(self.login, self.password) + }){ + HStack(alignment: .center){ + Text("Next") + Image(systemName: "arrow.right.circle") + .resizable() + .frame(width: self.imageSize, height: self.imageSize) + } } + .disabled(!self.buttonEnabled) + .opacity(self.buttonEnabled ? 1 : 0.5 ) } - .disabled(!buttonEnabled) - .opacity(buttonEnabled ? 1 : 0.5 ) - } - .padding(20) - .foregroundColor(.white) - - }.padding() - .padding(.bottom, keyboard.currentHeight) - .edgesIgnoringSafeArea(.bottom) - .animation(.easeOut(duration: 0.16)) + .padding(20) + .foregroundColor(.white) + + }.padding() + .padding(.bottom, self.keyboard.currentHeight) + .edgesIgnoringSafeArea(.bottom) + .animation(.easeOut(duration: 0.16)) + } } } } diff --git a/enzevalos_iphone/AuthenticationViewModel.swift b/enzevalos_iphone/AuthenticationViewModel.swift index 07f523c73454bc18260b8eab1e4ccba5b7a3f14e..e6fc4ea82c6d3933101d99b0966d98b139b74112 100644 --- a/enzevalos_iphone/AuthenticationViewModel.swift +++ b/enzevalos_iphone/AuthenticationViewModel.swift @@ -9,98 +9,55 @@ import Foundation class AuthenticationViewModel : ObservableObject { - + @Published var errorMessage: String? @Published var isDetailedAuthentication: Bool = false + @Published var showProgressSpinner: Bool = false - var isGoogleAuth = false - - var imapConfigurationSuccessful = false - var smtpConfigurationSuccessful = false - - private var currentIMAP: MailSession? - private var currentSMTP: MailSession? - var imapCallback: AuthenticationCallback? = nil - var smtpCallback: AuthenticationCallback? = nil + let model: AuthenticationModel + var cancellable: AnyCancellable? - var dispatchGroup = DispatchGroup() - - func validate(_ login: String, _ password: String) -> Void { - let mailAccount = MailAccount(emailAddress: login, password: password) + static let encryptionOptions: [(name: String, value: Int)] = [(name: "Plaintext", value: MCOConnectionType.clear.rawValue), (name: "StartTLS", value: MCOConnectionType.startTLS.rawValue), (name: "TLS/SSL", value: MCOConnectionType.TLS.rawValue)] - checkConfig(mailAccount: mailAccount) + init(authenticationModel: AuthenticationModel) { + self.model = authenticationModel } - - func detailValidation(_ login: String, _ password: String, _ username: String, _ imapServer: String, _ imapPort: String, _ imapEncryption: Int, _ smtpServer: String, _ smtpPort: String, _ smtpEncryption: Int) -> Void { - let mailAccount = MailAccount(emailAddress: login, password: password, username: username, imapServer: imapServer, imapPort: Int(imapPort)!, imapEncryption: 1 << imapEncryption, smtpServer: smtpServer, smtpPort: Int(smtpPort)!, smtpEncryption: 1 << smtpEncryption) - - checkConfig(mailAccount: mailAccount) - } - - /** - Start asynchronous tasks for checking IMAP and SMTP configuration with a *timeoutDelay* after which the tasks are not getting consumed anymore. - */ - fileprivate func checkConfig(mailAccount: MailAccount) { - dispatchGroup = DispatchGroup() - imapCallback = AuthenticationCallback(callback: onImapCompleted) - let imapItem = DispatchWorkItem { self.checkIMAPConfig(mailAccount: mailAccount, self.imapCallback! ) } - dispatchGroup.enter() - DispatchQueue.global().async(execute: imapItem) - - smtpCallback = AuthenticationCallback(callback: onSmtpCompleted) - let smtpItem = DispatchWorkItem { self.checkSMTPConfig(mailAccount: mailAccount, self.smtpCallback!) } - dispatchGroup.enter() - DispatchQueue.global().async(execute: smtpItem) + + func validate(_ login: String, _ password: String) -> Void { + let mailAccount = MailAccount(emailAddress: login, password: password) - DispatchQueue.global().async { - let timeoutDelay: DispatchTimeInterval = DispatchTimeInterval.seconds(10) - let result = self.dispatchGroup.wait(timeout: DispatchTime.now() + timeoutDelay) - DispatchQueue.main.async { - self.timeoutOccured(timeoutResult: result) - } - } - } - - func checkIMAPConfig(mailAccount: MailAccount, _ callback: AuthenticationCallback) { - imapConfigurationSuccessful = false - let mailSession: MailSession = setupIMAPSession(mailAccount: mailAccount, callback: callback) - currentIMAP = mailSession - if (isGoogleAuth || isDetailedAuthentication) && mailSession.startTestingServerConfig(){ - imapConfigurationSuccessful = true - } else { - if !mailSession.hasJsonFile && mailSession.startLongSearchOfServerConfig(hostFromAdr: true){ - imapConfigurationSuccessful = true - } else { - if mailSession.startTestingServerConfigFromList() || mailSession.startLongSearchOfServerConfig(hostFromAdr: true){ - imapConfigurationSuccessful = true - } + showProgressSpinner = true + cancellable = model.checkConfig(mailAccount: mailAccount, extendedValidation: false).sink { promise in + switch promise { + case AuthenticationModel.AuthenticationResult.Success : + self.authenticationSucceed() + case AuthenticationModel.AuthenticationResult.Error(let value) : + self.authenticationFailed(error: value) + case AuthenticationModel.AuthenticationResult.Timeout : + self.timeoutNotification() } + self.showProgressSpinner = false } } - func checkSMTPConfig(mailAccount: MailAccount, _ callback: AuthenticationCallback) { - smtpConfigurationSuccessful = false - let mailSession: MailSession = setupSMTPSession(mailAccount: mailAccount, callback: callback) - currentSMTP = mailSession - if (isGoogleAuth || isDetailedAuthentication) && mailSession.startTestingServerConfig() { - smtpConfigurationSuccessful = true - } else { - if !mailSession.hasJsonFile && mailSession.startLongSearchOfServerConfig(hostFromAdr: !isDetailedAuthentication) { - smtpConfigurationSuccessful = true - } else { - if mailSession.startTestingServerConfigFromList() || mailSession.startLongSearchOfServerConfig(hostFromAdr: true){ - smtpConfigurationSuccessful = true - } + func detailValidation(_ login: String, _ password: String, _ username: String, _ imapServer: String, _ imapPort: String, _ imapEncryption: Int, _ smtpServer: String, _ smtpPort: String, _ smtpEncryption: Int) -> Void { + let mailAccount = MailAccount(emailAddress: login, password: password, username: username, imapServer: imapServer, imapPort: Int(imapPort)!, imapEncryption: imapEncryption, smtpServer: smtpServer, smtpPort: Int(smtpPort)!, smtpEncryption: smtpEncryption) + + showProgressSpinner = true + cancellable = model.checkConfig(mailAccount: mailAccount, extendedValidation: true).sink { promise in + switch promise { + case AuthenticationModel.AuthenticationResult.Success : + self.authenticationSucceed() + case AuthenticationModel.AuthenticationResult.Error(let value) : + self.authenticationFailed(error: value) + case AuthenticationModel.AuthenticationResult.Timeout : + self.timeoutNotification() } + self.showProgressSpinner = false } } func startGoogleOauth() { - isGoogleAuth = true - googleLogin() - } - - func googleLogin() { guard let vc = AppDelegate.getAppDelegate().window?.rootViewController else { print("No view controller!") return @@ -110,116 +67,38 @@ class AuthenticationViewModel : ObservableObject { EmailHelper.singleton().doEmailLoginIfRequired(onVC: vc, completionBlock: { guard let userEmail = EmailHelper.singleton().authorization?.userEmail, EmailHelper.singleton().authorization?.canAuthorize() ?? false else { print("Google authetication failed") - self.isGoogleAuth = false return } - let mailAccount = MailAccount(emailAddress: userEmail.lowercased(), password: "", username: userEmail.lowercased(), imapServer: "imap.gmail.com", imapPort: 993, imapEncryption: 2, smtpServer: "smtp.gmail.com", smtpPort: 587, smtpEncryption: 1, authType: MCOAuthType.xoAuth2.rawValue) + let googleImapPort = 993 + let googleSmtpPort = 587 + + let mailAccount = MailAccount(emailAddress: userEmail.lowercased(), password: "", username: userEmail.lowercased(), imapServer: "imap.gmail.com", imapPort: googleImapPort, imapEncryption: AuthenticationViewModel.encryptionOptions[2].value, smtpServer: "smtp.gmail.com", smtpPort: googleSmtpPort, smtpEncryption: AuthenticationViewModel.encryptionOptions[1].value, authType: MCOAuthType.xoAuth2.rawValue) - self.checkConfig(mailAccount: mailAccount) + self.showProgressSpinner = true + self.cancellable = self.model.checkConfig(mailAccount: mailAccount, extendedValidation: true).sink { promise in + switch promise { + case AuthenticationModel.AuthenticationResult.Success : + self.authenticationSucceed() + case AuthenticationModel.AuthenticationResult.Error(let value) : + self.authenticationFailed(error: value) + case AuthenticationModel.AuthenticationResult.Timeout : + self.timeoutNotification() + } + self.showProgressSpinner = false + } }) } - private func setupIMAPSession(mailAccount: MailAccount, callback: AuthenticationCallback) -> MailSession { - let mailSession = MailSession(configSession: SessionType.IMAP, mailAddress: mailAccount.emailAddress, password: mailAccount.password, username: mailAccount.username) - if (isGoogleAuth || isDetailedAuthentication) { - let imapConnValue = mailAccount.imapEncryption - mailSession.setServer(hostname: mailAccount.imapServer, port: UInt32(mailAccount.imapPort), connType: imapConnValue, authType: mailAccount.authType) - } - - let listenerIMAP = Listener(callback: callback, mailAccount: mailAccount) - mailSession.addListener(listener: listenerIMAP) - return mailSession - } - - private func setupSMTPSession(mailAccount: MailAccount, callback: AuthenticationCallback) -> MailSession { - let mailSession = MailSession(configSession: SessionType.SMTP, mailAddress: mailAccount.emailAddress, password: mailAccount.password, username: mailAccount.username) - if (isGoogleAuth || isDetailedAuthentication) { - let smtpConnValue = mailAccount.smtpEncryption - mailSession.setServer(hostname: mailAccount.smtpServer, port: UInt32(mailAccount.smtpPort), connType: smtpConnValue, authType: mailAccount.authType) - } - - let listenerSMTP = Listener(callback: callback, mailAccount: mailAccount) - mailSession.addListener(listener: listenerSMTP) - return mailSession + func authenticationSucceed() { + AppDelegate.getAppDelegate().credentialsWork() } - func authenticationFailed() { - var error = MailServerConnectionError.AuthenticationError - if let smtp = currentIMAP, let e = MailServerConnectionError.findPrioError(errors: smtp.errors) { - error = e - } - if let imap = currentIMAP, let e = MailServerConnectionError.findPrioError(errors: imap.errors) { - error = e - } + func authenticationFailed(error: MailServerConnectionError) { errorMessage = NSLocalizedString(error.localizedUIBodyString, comment: "") } - + func timeoutNotification() { errorMessage = NSLocalizedString(MailServerConnectionError.TimeoutError.localizedUIBodyString, comment: "") } - - func timeoutOccured(timeoutResult: DispatchTimeoutResult) { - imapCallback?.callback = nil - smtpCallback?.callback = nil - if timeoutResult == .success { - if imapConfigurationSuccessful && smtpConfigurationSuccessful { - AppDelegate.getAppDelegate().credentialsWork() - } else { - authenticationFailed() - } - } else { - timeoutNotification() - } - } - - func onImapCompleted(imapWorks: Bool, _ login: String, _ password: String) { - if imapWorks { - _ = currentIMAP?.storeToUserDefaults() - imapConfigurationSuccessful = true - } else { - imapConfigurationSuccessful = false - authenticationFailed() - } - dispatchGroup.leave() - } - - func onSmtpCompleted(smtpWorks: Bool, _ login: String, _ password: String) { - if smtpWorks { - _ = currentSMTP?.storeToUserDefaults() - smtpConfigurationSuccessful = true - } else { - smtpConfigurationSuccessful = false - authenticationFailed() - } - dispatchGroup.leave() - return - } - - class Listener: MailSessionListener { - let callback: AuthenticationCallback - let mailAccount: MailAccount - - init(callback: AuthenticationCallback, mailAccount: MailAccount) { - self.callback = callback - self.mailAccount = mailAccount - } - - func testFinish(result: Bool) { - callback.onResult(worked: result, login: mailAccount.emailAddress, password: mailAccount.password) - } - } } -class AuthenticationCallback { - var callback: ((Bool, String, String) -> Void)? - - init(callback: @escaping (Bool, String, String) -> Void) { - self.callback = callback - } - - func onResult(worked: Bool, login: String, password: String) { - if let callback = callback { - callback(worked, login, password) - } - } -} diff --git a/enzevalos_iphone/LoadingBlocker.swift b/enzevalos_iphone/LoadingBlocker.swift new file mode 100644 index 0000000000000000000000000000000000000000..361a5e032b24c10c37605fafa734c8667960b43f --- /dev/null +++ b/enzevalos_iphone/LoadingBlocker.swift @@ -0,0 +1,50 @@ +// +// LoadingBlocker.swift +// enzevalos_iphone +// +// Created by hanneh00 on 18.03.20. +// Copyright © 2020 fu-berlin. All rights reserved. +// + +import SwiftUI + +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/depricated_AuthenticationScreen.swift b/enzevalos_iphone/depricated_AuthenticationScreen.swift index 470bf0cdcf195a5ca76860a5340c64f5e7727534..a04003b3e9fd39dc577336a1a64f372b0f712091 100644 --- a/enzevalos_iphone/depricated_AuthenticationScreen.swift +++ b/enzevalos_iphone/depricated_AuthenticationScreen.swift @@ -6,7 +6,7 @@ // Copyright © 2020 fu-berlin. All rights reserved. // -import SwiftUI +/*import SwiftUI struct AuthenticationScreen: View { @State private var login: String = "" @@ -114,6 +114,6 @@ struct LoginCredentials:View{ } } } - +*/