diff --git a/Sources/App/DependencyRegistrator.swift b/Sources/App/DependencyRegistrator.swift index 4ad75419d54accc4c3e9b8bc15eb7f4b249d0e33..471e100836f6211d97d8897802d0a71f9a3e06cb 100644 --- a/Sources/App/DependencyRegistrator.swift +++ b/Sources/App/DependencyRegistrator.swift @@ -64,6 +64,7 @@ struct DependencyRegistrator { /// Restore / Backup + container.register(SFTPService.mock) container.register(iCloudServiceMock() as iCloudInterface) container.register(DropboxServiceMock() as DropboxInterface) container.register(GoogleDriveServiceMock() as GoogleDriveInterface) @@ -121,6 +122,7 @@ struct DependencyRegistrator { container.register( BackupCoordinator( + sftpFactory: BackupSFTPController.init, passphraseFactory: BackupPassphraseController.init(_:_:) ) as BackupCoordinating) @@ -161,9 +163,9 @@ struct DependencyRegistrator { container.register( RestoreCoordinator( - sftpFactory: SFTPController.init, successFactory: RestoreSuccessController.init, chatListFactory: ChatListController.init, + sftpFactory: RestoreSFTPController.init(_:), restoreFactory: RestoreController.init(_:_:), passphraseFactory: RestorePassphraseController.init(_:) ) as RestoreCoordinating) diff --git a/Sources/BackupFeature/Controllers/BackupConfigController.swift b/Sources/BackupFeature/Controllers/BackupConfigController.swift index a901e6b9668fc89df2cd1ae1184ca655fa8bdb1b..4a2b5974435f6f5417cc53e8d3998920f1510611 100644 --- a/Sources/BackupFeature/Controllers/BackupConfigController.swift +++ b/Sources/BackupFeature/Controllers/BackupConfigController.swift @@ -122,7 +122,7 @@ final class BackupConfigController: UIViewController { screenView.sftpButton .publisher(for: .touchUpInside) - .sink { [unowned self] in viewModel.didTapService(.sftp, self) } + .sink { [unowned self] in coordinator.toSFTP(from: self) } .store(in: &cancellables) screenView.iCloudButton diff --git a/Sources/SFTPFeature/SFTPController.swift b/Sources/BackupFeature/Controllers/BackupSFTPController.swift similarity index 74% rename from Sources/SFTPFeature/SFTPController.swift rename to Sources/BackupFeature/Controllers/BackupSFTPController.swift index 47b8c5423ef6819859ab699320a5593b880fbc13..f0f851863ed28da1159dddd3b5a5d548ff1c3f61 100644 --- a/Sources/SFTPFeature/SFTPController.swift +++ b/Sources/BackupFeature/Controllers/BackupSFTPController.swift @@ -1,10 +1,14 @@ +import HUD import UIKit import Combine +import DependencyInjection -public final class SFTPController: UIViewController { - lazy private var screenView = SFTPView() +public final class BackupSFTPController: UIViewController { + @Dependency private var hud: HUDType - private let viewModel = SFTPViewModel() + lazy private var screenView = BackupSFTPView() + + private let viewModel = BackupSFTPViewModel() private var cancellables = Set<AnyCancellable>() public override func loadView() { @@ -29,6 +33,17 @@ public final class SFTPController: UIViewController { } private func setupBindings() { + viewModel.hudPublisher + .receive(on: DispatchQueue.main) + .sink { [hud] in hud.update(with: $0) } + .store(in: &cancellables) + + viewModel.popPublisher + .receive(on: DispatchQueue.main) + .sink { [unowned self] in + navigationController?.popViewController(animated: true) + }.store(in: &cancellables) + screenView.hostField .textPublisher .receive(on: DispatchQueue.main) diff --git a/Sources/BackupFeature/Coordinator/BackupCoordinator.swift b/Sources/BackupFeature/Coordinator/BackupCoordinator.swift index 9dbd110e659f066dd25d5bda897ebccc14047748..c79cdcdb18d2d04197d92d6207affebb567b2f4f 100644 --- a/Sources/BackupFeature/Coordinator/BackupCoordinator.swift +++ b/Sources/BackupFeature/Coordinator/BackupCoordinator.swift @@ -8,6 +8,8 @@ public protocol BackupCoordinating { from: UIViewController ) + func toSFTP(from: UIViewController) + func toPassphrase( from: UIViewController, cancelClosure: @escaping EmptyClosure, @@ -16,24 +18,27 @@ public protocol BackupCoordinating { } public struct BackupCoordinator: BackupCoordinating { + var pushPresenter: Presenting = PushPresenter() var bottomPresenter: Presenting = BottomPresenter() - var passphraseFactory: ( - @escaping EmptyClosure, - @escaping StringClosure - ) -> UIViewController + var sftpFactory: () -> UIViewController + var passphraseFactory: (@escaping EmptyClosure, @escaping StringClosure) -> UIViewController public init( - passphraseFactory: @escaping ( - @escaping EmptyClosure, - @escaping StringClosure - ) -> UIViewController + sftpFactory: @escaping () -> UIViewController, + passphraseFactory: @escaping (@escaping EmptyClosure, @escaping StringClosure) -> UIViewController ) { + self.sftpFactory = sftpFactory self.passphraseFactory = passphraseFactory } } public extension BackupCoordinator { + func toSFTP(from parent: UIViewController) { + let screen = sftpFactory() + pushPresenter.present(screen, from: parent) + } + func toDrawer( _ screen: UIViewController, from parent: UIViewController diff --git a/Sources/BackupFeature/Service/BackupService.swift b/Sources/BackupFeature/Service/BackupService.swift index 0c163e4d92d470a7e3bcaf86cac1c9be0bf26176..b914322433260bbb798de1d18ad4712043f6415b 100644 --- a/Sources/BackupFeature/Service/BackupService.swift +++ b/Sources/BackupFeature/Service/BackupService.swift @@ -152,9 +152,7 @@ extension BackupService { }.store(in: &cancellables) } case .sftp: - if !sftpService.isAuthorized() { - // TODO - } + break } } } @@ -209,7 +207,25 @@ extension BackupService { } if sftpService.isAuthorized() { - // TODO + let host = "" + let username = "" + let password = "" + + let completion: SFTPFetchResult = { result in + switch result { + case .success(let settings): + if let settings = settings { + print("") + } else { + print("") + } + case .failure(let error): + print(error.localizedDescription) + } + } + + let authParams = SFTPAuthParams(host, username, password) + sftpService.fetch((authParams, completion)) } if dropboxService.isAuthorized() { diff --git a/Sources/BackupFeature/ViewModels/BackupSFTPViewModel.swift b/Sources/BackupFeature/ViewModels/BackupSFTPViewModel.swift new file mode 100644 index 0000000000000000000000000000000000000000..8368713e723419159be8c112d8ffa729dae5d79a --- /dev/null +++ b/Sources/BackupFeature/ViewModels/BackupSFTPViewModel.swift @@ -0,0 +1,68 @@ +import HUD +import Models +import Combine +import Foundation +import SFTPFeature +import DependencyInjection + +struct BackupSFTPViewState { + var host: String = "" + var username: String = "" + var password: String = "" + var isButtonEnabled: Bool = false +} + +final class BackupSFTPViewModel { + @Dependency private var service: SFTPService + + var hudPublisher: AnyPublisher<HUDStatus, Never> { + hudSubject.eraseToAnyPublisher() + } + + var popPublisher: AnyPublisher<Void, Never> { + popSubject.eraseToAnyPublisher() + } + + var statePublisher: AnyPublisher<BackupSFTPViewState, Never> { + stateSubject.eraseToAnyPublisher() + } + + private let popSubject = PassthroughSubject<Void, Never>() + private let hudSubject = CurrentValueSubject<HUDStatus, Never>(.none) + private let stateSubject = CurrentValueSubject<BackupSFTPViewState, Never>(.init()) + + func didEnterHost(_ string: String) { + stateSubject.value.host = string + validate() + } + + func didEnterUsername(_ string: String) { + stateSubject.value.username = string + validate() + } + + func didEnterPassword(_ string: String) { + stateSubject.value.password = string + validate() + } + + func didTapLogin() { + hudSubject.send(.on(nil)) + + let host = stateSubject.value.host + let username = stateSubject.value.username + let password = stateSubject.value.password + + let authParams = SFTPAuthParams(host, username, password) + service.justAuthenticate(authParams) + hudSubject.send(.none) + popSubject.send(()) + } + + private func validate() { + stateSubject.value.isButtonEnabled = + !stateSubject.value.host.isEmpty && + !stateSubject.value.username.isEmpty && + !stateSubject.value.password.isEmpty + } +} diff --git a/Sources/SFTPFeature/SFTPView.swift b/Sources/BackupFeature/Views/BackupSFTPView.swift similarity index 98% rename from Sources/SFTPFeature/SFTPView.swift rename to Sources/BackupFeature/Views/BackupSFTPView.swift index 3e62e4caeb0eca188fd1dad4db740545f0b3f045..3a88917aafaa46786efd5c5ffce3fb3285cd1a63 100644 --- a/Sources/SFTPFeature/SFTPView.swift +++ b/Sources/BackupFeature/Views/BackupSFTPView.swift @@ -2,7 +2,7 @@ import UIKit import Shared import InputField -final class SFTPView: UIView { +final class BackupSFTPView: UIView { let titleLabel = UILabel() let subtitleLabel = UILabel() let hostField = OutlinedInputField() diff --git a/Sources/RestoreFeature/Controllers/RestoreListController.swift b/Sources/RestoreFeature/Controllers/RestoreListController.swift index 4a5f22f2bdca94a16f23f126d8b41f88c1dcdbe2..803e46e79d1f6dd9e543a8ee34c18fbb5c3bd105 100644 --- a/Sources/RestoreFeature/Controllers/RestoreListController.swift +++ b/Sources/RestoreFeature/Controllers/RestoreListController.swift @@ -1,8 +1,8 @@ import HUD -import DrawerFeature import Shared import UIKit import Combine +import DrawerFeature import DependencyInjection public final class RestoreListController: UIViewController { @@ -88,7 +88,7 @@ public final class RestoreListController: UIViewController { screenView.sftpButton .publisher(for: .touchUpInside) .sink { [unowned self] in - coordinator.toSFTP(from: self) + coordinator.toSFTP(using: ndf, from: self) }.store(in: &cancellables) } diff --git a/Sources/RestoreFeature/Controllers/RestoreSFTPController.swift b/Sources/RestoreFeature/Controllers/RestoreSFTPController.swift new file mode 100644 index 0000000000000000000000000000000000000000..024b2df411105415aa94825d46a19c59112dda84 --- /dev/null +++ b/Sources/RestoreFeature/Controllers/RestoreSFTPController.swift @@ -0,0 +1,89 @@ +import HUD +import UIKit +import Combine +import DependencyInjection + +public final class RestoreSFTPController: UIViewController { + @Dependency private var hud: HUDType + @Dependency private var coordinator: RestoreCoordinating + + lazy private var screenView = RestoreSFTPView() + + private let ndf: String + private let viewModel = RestoreSFTPViewModel() + private var cancellables = Set<AnyCancellable>() + + public override func loadView() { + view = screenView + } + + public init(_ ndf: String) { + self.ndf = ndf + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { nil } + + public override func viewDidLoad() { + super.viewDidLoad() + setupNavigationBar() + setupBindings() + } + + private func setupNavigationBar() { + navigationItem.backButtonTitle = "" + + let back = UIButton.back() + back.addTarget(self, action: #selector(didTapBack), for: .touchUpInside) + + navigationItem.leftBarButtonItem = UIBarButtonItem( + customView: UIStackView(arrangedSubviews: [back]) + ) + } + + private func setupBindings() { + viewModel.hudPublisher + .receive(on: DispatchQueue.main) + .sink { [hud] in hud.update(with: $0) } + .store(in: &cancellables) + + viewModel.backupPublisher + .receive(on: DispatchQueue.main) + .sink { [unowned self] in + coordinator.toRestoreReplacing(using: ndf, with: $0, from: self) + }.store(in: &cancellables) + + screenView.hostField + .textPublisher + .receive(on: DispatchQueue.main) + .sink { [unowned self] in viewModel.didEnterHost($0) } + .store(in: &cancellables) + + screenView.usernameField + .textPublisher + .receive(on: DispatchQueue.main) + .sink { [unowned self] in viewModel.didEnterUsername($0) } + .store(in: &cancellables) + + screenView.passwordField + .textPublisher + .receive(on: DispatchQueue.main) + .sink { [unowned self] in viewModel.didEnterPassword($0) } + .store(in: &cancellables) + + viewModel.statePublisher + .receive(on: DispatchQueue.main) + .map(\.isButtonEnabled) + .sink { [unowned self] in screenView.loginButton.isEnabled = $0 } + .store(in: &cancellables) + + screenView.loginButton + .publisher(for: .touchUpInside) + .sink { [unowned self] in viewModel.didTapLogin() } + .store(in: &cancellables) + } + + @objc private func didTapBack() { + navigationController?.popViewController(animated: true) + } +} diff --git a/Sources/RestoreFeature/Coordinator/RestoreCoordinator.swift b/Sources/RestoreFeature/Coordinator/RestoreCoordinator.swift index 3a63883c13726d9c398f270534760ffcc0c98d21..a76b5c744ca8e00c5c192a9f9b729d60c5403f79 100644 --- a/Sources/RestoreFeature/Coordinator/RestoreCoordinator.swift +++ b/Sources/RestoreFeature/Coordinator/RestoreCoordinator.swift @@ -4,29 +4,31 @@ import Shared import Presentation public protocol RestoreCoordinating { - func toSFTP(from: UIViewController) func toChats(from: UIViewController) func toSuccess(from: UIViewController) + func toSFTP(using: String, from: UIViewController) func toDrawer(_: UIViewController, from: UIViewController) func toPassphrase(from: UIViewController, _: @escaping StringClosure) func toRestore(using: String, with: RestoreSettings, from: UIViewController) + func toRestoreReplacing(using: String, with: RestoreSettings, from: UIViewController) } public struct RestoreCoordinator: RestoreCoordinating { var pushPresenter: Presenting = PushPresenter() var bottomPresenter: Presenting = BottomPresenter() var replacePresenter: Presenting = ReplacePresenter() + var replaceLastPresenter: Presenting = ReplacePresenter(mode: .replaceLast) - var sftpFactory: () -> UIViewController var successFactory: () -> UIViewController var chatListFactory: () -> UIViewController + var sftpFactory: (String) -> UIViewController var restoreFactory: (String, RestoreSettings) -> UIViewController var passphraseFactory: (@escaping StringClosure) -> UIViewController public init( - sftpFactory: @escaping () -> UIViewController, successFactory: @escaping () -> UIViewController, chatListFactory: @escaping () -> UIViewController, + sftpFactory: @escaping (String) -> UIViewController, restoreFactory: @escaping (String, RestoreSettings) -> UIViewController, passphraseFactory: @escaping (@escaping StringClosure) -> UIViewController ) { @@ -48,6 +50,15 @@ public extension RestoreCoordinator { pushPresenter.present(screen, from: parent) } + func toRestoreReplacing( + using ndf: String, + with settings: RestoreSettings, + from parent: UIViewController + ) { + let screen = restoreFactory(ndf, settings) + replaceLastPresenter.present(screen, from: parent) + } + func toChats(from parent: UIViewController) { let screen = chatListFactory() replacePresenter.present(screen, from: parent) @@ -70,8 +81,8 @@ public extension RestoreCoordinator { bottomPresenter.present(screen, from: parent) } - func toSFTP(from parent: UIViewController) { - let screen = sftpFactory() + func toSFTP(using ndf: String, from parent: UIViewController) { + let screen = sftpFactory(ndf) pushPresenter.present(screen, from: parent) } } diff --git a/Sources/RestoreFeature/ViewModels/RestoreListViewModel.swift b/Sources/RestoreFeature/ViewModels/RestoreListViewModel.swift index 301ad92afe128971bb38b7099aafce4081c85625..d0119b84211abd97bbbfff022455fb84a1db9b7c 100644 --- a/Sources/RestoreFeature/ViewModels/RestoreListViewModel.swift +++ b/Sources/RestoreFeature/ViewModels/RestoreListViewModel.swift @@ -6,22 +6,24 @@ import Combine import BackupFeature import DependencyInjection -import SFTPFeature import iCloudFeature import DropboxFeature import GoogleDriveFeature final class RestoreListViewModel { - @Dependency private var sftpService: SFTPService @Dependency private var icloudService: iCloudInterface @Dependency private var dropboxService: DropboxInterface @Dependency private var googleDriveService: GoogleDriveInterface - var hud: AnyPublisher<HUDStatus, Never> { hudSubject.eraseToAnyPublisher() } - var didFetchBackup: AnyPublisher<RestoreSettings, Never> { backupSubject.eraseToAnyPublisher() } + var hud: AnyPublisher<HUDStatus, Never> { + hudSubject.eraseToAnyPublisher() + } - private var dropboxAuthCancellable: AnyCancellable? + var didFetchBackup: AnyPublisher<RestoreSettings, Never> { + backupSubject.eraseToAnyPublisher() + } + private var dropboxAuthCancellable: AnyCancellable? private let hudSubject = PassthroughSubject<HUDStatus, Never>() private let backupSubject = PassthroughSubject<RestoreSettings, Never>() diff --git a/Sources/RestoreFeature/ViewModels/RestoreSFTPViewModel.swift b/Sources/RestoreFeature/ViewModels/RestoreSFTPViewModel.swift new file mode 100644 index 0000000000000000000000000000000000000000..7bf34b4c75f1ec8691aba8a11de89e3438db847b --- /dev/null +++ b/Sources/RestoreFeature/ViewModels/RestoreSFTPViewModel.swift @@ -0,0 +1,81 @@ +import HUD +import Models +import Combine +import Foundation +import SFTPFeature +import DependencyInjection + +struct RestoreSFTPViewState { + var host: String = "" + var username: String = "" + var password: String = "" + var isButtonEnabled: Bool = false +} + +final class RestoreSFTPViewModel { + @Dependency private var service: SFTPService + + var hudPublisher: AnyPublisher<HUDStatus, Never> { + hudSubject.eraseToAnyPublisher() + } + + var backupPublisher: AnyPublisher<RestoreSettings, Never> { + backupSubject.eraseToAnyPublisher() + } + + var statePublisher: AnyPublisher<RestoreSFTPViewState, Never> { + stateSubject.eraseToAnyPublisher() + } + + private let hudSubject = CurrentValueSubject<HUDStatus, Never>(.none) + private let backupSubject = PassthroughSubject<RestoreSettings, Never>() + private let stateSubject = CurrentValueSubject<RestoreSFTPViewState, Never>(.init()) + + func didEnterHost(_ string: String) { + stateSubject.value.host = string + validate() + } + + func didEnterUsername(_ string: String) { + stateSubject.value.username = string + validate() + } + + func didEnterPassword(_ string: String) { + stateSubject.value.password = string + validate() + } + + func didTapLogin() { + hudSubject.send(.on(nil)) + + let host = stateSubject.value.host + let username = stateSubject.value.username + let password = stateSubject.value.password + + let completion: SFTPFetchResult = { result in + switch result { + case .success(let backup): + self.hudSubject.send(.none) + + if let backup = backup { + self.backupSubject.send(backup) + } else { + self.backupSubject.send(.init(cloudService: .sftp)) + } + case .failure(let error): + self.hudSubject.send(.error(.init(with: error))) + } + } + + let authParams = SFTPAuthParams(host, username, password) + service.fetch((authParams, completion)) + } + + private func validate() { + stateSubject.value.isButtonEnabled = + !stateSubject.value.host.isEmpty && + !stateSubject.value.username.isEmpty && + !stateSubject.value.password.isEmpty + } +} diff --git a/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift b/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift index 663d3529b44012f24408c11ff1ad223cb5a58a7d..0a7d988ef270cbcfabbe6d1e929809ba3c24e9c9 100644 --- a/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift +++ b/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift @@ -8,7 +8,6 @@ import Integration import BackupFeature import DependencyInjection -import SFTPFeature import iCloudFeature import DropboxFeature import GoogleDriveFeature @@ -39,7 +38,6 @@ extension RestorationStep: Equatable { } final class RestoreViewModel { - @Dependency private var sftpService: SFTPService @Dependency private var iCloudService: iCloudInterface @Dependency private var dropboxService: DropboxInterface @Dependency private var googleService: GoogleDriveInterface diff --git a/Sources/RestoreFeature/Views/RestoreSFTPView.swift b/Sources/RestoreFeature/Views/RestoreSFTPView.swift new file mode 100644 index 0000000000000000000000000000000000000000..de41e3719f0cac00cb59ccc303c9d062fae1f22d --- /dev/null +++ b/Sources/RestoreFeature/Views/RestoreSFTPView.swift @@ -0,0 +1,76 @@ +import UIKit +import Shared +import InputField + +final class RestoreSFTPView: UIView { + let titleLabel = UILabel() + let subtitleLabel = UILabel() + let hostField = OutlinedInputField() + let usernameField = OutlinedInputField() + let passwordField = OutlinedInputField() + let loginButton = CapsuleButton() + let stackView = UIStackView() + + init() { + super.init(frame: .zero) + backgroundColor = Asset.neutralWhite.color + + titleLabel.textColor = Asset.neutralDark.color + titleLabel.text = Localized.AccountRestore.Sftp.title + titleLabel.font = Fonts.Mulish.bold.font(size: 24.0) + + let paragraph = NSMutableParagraphStyle() + paragraph.alignment = .left + paragraph.lineHeightMultiple = 1.15 + + let attString = NSAttributedString( + string: Localized.AccountRestore.Sftp.subtitle, + attributes: [ + .foregroundColor: Asset.neutralBody.color, + .font: Fonts.Mulish.regular.font(size: 16.0) as Any, + .paragraphStyle: paragraph + ]) + + subtitleLabel.numberOfLines = 0 + subtitleLabel.attributedText = attString + + hostField.setup(title: Localized.AccountRestore.Sftp.host) + usernameField.setup(title: Localized.AccountRestore.Sftp.username) + passwordField.setup(title: Localized.AccountRestore.Sftp.password, sensitive: true) + + loginButton.set(style: .brandColored, title: Localized.AccountRestore.Sftp.login) + + stackView.spacing = 30 + stackView.axis = .vertical + stackView.distribution = .fillEqually + stackView.addArrangedSubview(hostField) + stackView.addArrangedSubview(usernameField) + stackView.addArrangedSubview(passwordField) + stackView.addArrangedSubview(loginButton) + + addSubview(titleLabel) + addSubview(subtitleLabel) + addSubview(stackView) + + titleLabel.snp.makeConstraints { + $0.top.equalTo(safeAreaLayoutGuide).offset(15) + $0.left.equalToSuperview().offset(38) + $0.right.equalToSuperview().offset(-41) + } + + subtitleLabel.snp.makeConstraints { + $0.top.equalTo(titleLabel.snp.bottom).offset(8) + $0.left.equalToSuperview().offset(38) + $0.right.equalToSuperview().offset(-41) + } + + stackView.snp.makeConstraints { + $0.top.equalTo(subtitleLabel.snp.bottom).offset(28) + $0.left.equalToSuperview().offset(38) + $0.right.equalToSuperview().offset(-38) + $0.bottom.lessThanOrEqualToSuperview() + } + } + + required init?(coder: NSCoder) { nil } +} diff --git a/Sources/SFTPFeature/SFTPService.swift b/Sources/SFTPFeature/SFTPService.swift index 7181c915a13c1e8fb9f6f849763cdf315ce9b369..30b92573a75e1cc4fc956e3f68f8433aa59f9e13 100644 --- a/Sources/SFTPFeature/SFTPService.swift +++ b/Sources/SFTPFeature/SFTPService.swift @@ -1,15 +1,49 @@ +import Models +import Foundation + +public typealias SFTPAuthParams = (String, String, String) +public typealias SFTPFetchResult = (Result<RestoreSettings?, Error>) -> Void +public typealias SFTPFetchParams = (SFTPAuthParams, SFTPFetchResult) + public struct SFTPService { public var isAuthorized: () -> Bool - public var downloadMetadata: (@escaping (String) -> Void) -> Void + public var fetch: (SFTPFetchParams) -> Void + public var justAuthenticate: (SFTPAuthParams) -> Void } public extension SFTPService { + static var mock = SFTPService( + isAuthorized: { + false + }, + fetch: { (authParams, completion) in + print("^^^ RestoreSFTP Host: \(authParams.0)") + print("^^^ RestoreSFTP Username: \(authParams.1)") + print("^^^ RestoreSFTP Password: \(authParams.2)") + + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + completion(.success(.init( + backup: .init(id: "ASDF", date: Date.distantPast, size: 100_000_000), + cloudService: .sftp + ))) + } + }, + justAuthenticate: { host, username, password in + // TODO: Store these params on the keychain + }) + static var live = SFTPService( isAuthorized: { + /// If it has host/username/password on keychain + /// means its authorized, not that is working + /// true }, - downloadMetadata: { completion in - completion("MOCK") + fetch: { (authParams, completion) in + // TODO: Store host/username/password on keychain + }, + justAuthenticate: { host, username, password in + // TODO: Store host/username/password on keychain } ) } diff --git a/Sources/SFTPFeature/SFTPViewModel.swift b/Sources/SFTPFeature/SFTPViewModel.swift deleted file mode 100644 index f429f25140050c8cee4aec38ad66247ef99eb40d..0000000000000000000000000000000000000000 --- a/Sources/SFTPFeature/SFTPViewModel.swift +++ /dev/null @@ -1,56 +0,0 @@ -import Combine -import Foundation - -struct SFTPViewState { - var host: String = "" - var username: String = "" - var password: String = "" - var isButtonEnabled: Bool = false -} - -final class SFTPViewModel { - var statePublisher: AnyPublisher<SFTPViewState, Never> { - stateSubject.eraseToAnyPublisher() - } - - private let stateSubject = CurrentValueSubject<SFTPViewState, Never>(.init()) - - func didEnterHost(_ string: String) { - stateSubject.value.host = string - validate() - } - - func didEnterUsername(_ string: String) { - stateSubject.value.username = string - validate() - } - - func didEnterPassword(_ string: String) { - stateSubject.value.password = string - validate() - } - - func didTapLogin() { - - -// do { -// let session = try SSH(host: stateSubject.value.host) -// try session.authenticate( -// username: stateSubject.value.username, -// password: stateSubject.value.password -// ) -// -// let sftp = try session.openSftp() -// try sftp.download(remotePath: "", localURL: URL(string: "")!) -// } catch { -// print(error.localizedDescription) -// } - } - - private func validate() { - stateSubject.value.isButtonEnabled = - !stateSubject.value.host.isEmpty && - !stateSubject.value.username.isEmpty && - !stateSubject.value.password.isEmpty - } -}