diff --git a/Package.swift b/Package.swift index 8d4ef5559502d9c460fc78f7ef983fd72e941b4e..b3f848aaf253b239def7a62d44a4703b3fea0bcf 100644 --- a/Package.swift +++ b/Package.swift @@ -2,756 +2,684 @@ import PackageDescription let package = Package( - name: "client-ios", - defaultLocalization: "en", - platforms: [ - .iOS(.v14), - ], - products: [ - .library(name: "App", targets: ["App"]), - .library(name: "HUD", targets: ["HUD"]), - .library(name: "Theme", targets: ["Theme"]), - .library(name: "Shared", targets: ["Shared"]), - .library(name: "Models", targets: ["Models"]), - .library(name: "XXLogger", targets: ["XXLogger"]), - .library(name: "Defaults", targets: ["Defaults"]), - .library(name: "Keychain", targets: ["Keychain"]), - .library(name: "Voxophone", targets: ["Voxophone"]), - .library(name: "Countries", targets: ["Countries"]), - .library(name: "InputField", targets: ["InputField"]), - .library(name: "TestHelpers", targets: ["TestHelpers"]), - .library(name: "ScanFeature", targets: ["ScanFeature"]), - .library(name: "Permissions", targets: ["Permissions"]), - .library(name: "MenuFeature", targets: ["MenuFeature"]), - .library(name: "ChatFeature", targets: ["ChatFeature"]), - .library(name: "PushFeature", targets: ["PushFeature"]), - .library(name: "SFTPFeature", targets: ["SFTPFeature"]), - .library(name: "CrashService", targets: ["CrashService"]), - .library(name: "TermsFeature", targets: ["TermsFeature"]), - .library(name: "Presentation", targets: ["Presentation"]), - .library(name: "ToastFeature", targets: ["ToastFeature"]), - .library(name: "BackupFeature", targets: ["BackupFeature"]), - .library(name: "LaunchFeature", targets: ["LaunchFeature"]), - .library(name: "iCloudFeature", targets: ["iCloudFeature"]), - .library(name: "SearchFeature", targets: ["SearchFeature"]), - .library(name: "DrawerFeature", targets: ["DrawerFeature"]), - .library(name: "CollectionView", targets: ["CollectionView"]), - .library(name: "RestoreFeature", targets: ["RestoreFeature"]), - .library(name: "CrashReporting", targets: ["CrashReporting"]), - .library(name: "ProfileFeature", targets: ["ProfileFeature"]), - .library(name: "ContactFeature", targets: ["ContactFeature"]), - .library(name: "NetworkMonitor", targets: ["NetworkMonitor"]), - .library(name: "DropboxFeature", targets: ["DropboxFeature"]), - .library(name: "VersionChecking", targets: ["VersionChecking"]), - .library(name: "SettingsFeature", targets: ["SettingsFeature"]), - .library(name: "ChatListFeature", targets: ["ChatListFeature"]), - .library(name: "RequestsFeature", targets: ["RequestsFeature"]), - .library(name: "ChatInputFeature", targets: ["ChatInputFeature"]), - .library(name: "OnboardingFeature", targets: ["OnboardingFeature"]), - .library(name: "GoogleDriveFeature", targets: ["GoogleDriveFeature"]), - .library(name: "ContactListFeature", targets: ["ContactListFeature"]), - .library(name: "DependencyInjection", targets: ["DependencyInjection"]), - .library(name: "ReportingFeature", targets: ["ReportingFeature"]), - ], - dependencies: [ - .package( - url: "https://github.com/Quick/Quick", - .upToNextMajor(from: "3.0.0") - ), - .package( - url: "https://github.com/Quick/Nimble", - .upToNextMajor(from: "9.0.0") - ), - .package( - url: "https://github.com/SnapKit/SnapKit", - .upToNextMajor(from: "5.0.1") - ), - .package( - url: "https://github.com/icanzilb/Retry.git", - .upToNextMajor(from: "0.6.3") - ), - .package( - url: "https://github.com/ekazaev/ChatLayout", - .upToNextMajor(from: "1.1.14") - ), - .package( - url: "https://github.com/ra1028/DifferenceKit", - .upToNextMajor(from: "1.2.0") - ), - .package( - url: "https://github.com/apple/swift-protobuf", - .upToNextMajor(from: "1.14.0") - ), - .package( - url: "https://github.com/google/GoogleSignIn-iOS", - .upToNextMajor(from: "6.1.0") - ), - .package( - url: "https://github.com/dropbox/SwiftyDropbox.git", - .upToNextMajor(from: "8.2.1") - ), - .package( - url: "https://github.com/amosavian/FileProvider.git", - .upToNextMajor(from: "0.26.0") - ), - .package( - url: "https://github.com/SwiftyBeaver/SwiftyBeaver.git", - .upToNextMajor(from: "1.9.5") - ), - .package( - url: "https://github.com/darrarski/ScrollViewController", - .upToNextMajor(from: "1.2.0") - ), - .package( - url: "https://github.com/pointfreeco/combine-schedulers", - .upToNextMajor(from: "0.5.0") - ), - .package( - url: "https://github.com/kishikawakatsumi/KeychainAccess", - .upToNextMajor(from: "4.2.1") - ), - .package( - url: "https://github.com/google/google-api-objectivec-client-for-rest", - .upToNextMajor(from: "1.6.0") - ), - .package( - path: "../elixxir-dapps-sdk-swift" -// url: "https://git.xx.network/elixxir/elixxir-dapps-sdk-swift", -// branch: "development" - ), - .package( - url: "https://git.xx.network/elixxir/client-ios-db.git", - .upToNextMajor(from: "1.1.0") - ), - .package( - url: "https://github.com/firebase/firebase-ios-sdk.git", - .upToNextMajor(from: "8.10.0") - ), - .package( - url: "https://github.com/darrarski/Shout.git", - revision: "df5a662293f0ac15eeb4f2fd3ffd0c07b73d0de0" - ), - .package( - url: "https://github.com/pointfreeco/swift-composable-architecture.git", - .upToNextMajor(from: "0.32.0") - ), - .package( - url: "https://github.com/pointfreeco/swift-custom-dump.git", - .upToNextMajor(from: "0.5.0") - ), - .package( - url: "https://github.com/swiftcsv/SwiftCSV.git", - from: "0.8.0" - ), - .package( - url: "https://github.com/pointfreeco/xctest-dynamic-overlay.git", - .upToNextMajor(from: "0.3.3") - ), - ], - targets: [ - .target( - name: "App", - dependencies: [ - .target(name: "Keychain"), - .target(name: "Voxophone"), - .target(name: "Permissions"), - .target(name: "ScanFeature"), - .target(name: "ChatFeature"), - .target(name: "MenuFeature"), - .target(name: "PushFeature"), - .target(name: "SFTPFeature"), - .target(name: "TermsFeature"), - .target(name: "ToastFeature"), - .target(name: "CrashService"), - .target(name: "BackupFeature"), - .target(name: "SearchFeature"), - .target(name: "LaunchFeature"), - .target(name: "iCloudFeature"), - .target(name: "DropboxFeature"), - .target(name: "ContactFeature"), - .target(name: "RestoreFeature"), - .target(name: "ProfileFeature"), - .target(name: "CrashReporting"), - .target(name: "ChatListFeature"), - .target(name: "SettingsFeature"), - .target(name: "RequestsFeature"), - .target(name: "ReportingFeature"), - .target(name: "OnboardingFeature"), - .target(name: "GoogleDriveFeature"), - .target(name: "ContactListFeature"), - ] - ), - .testTarget( - name: "AppTests", - dependencies: [ - .target(name: "App"), - ] - ), - .target( - name: "CrashReporting" - ), - .target( - name: "NetworkMonitor", - dependencies: [ - .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), - ] - ), - .target( - name: "VersionChecking" - ), - .target( - name: "DependencyInjection" - ), - .testTarget( - name: "DependencyInjectionTests", - dependencies: [ - .target(name: "DependencyInjection"), - ] - ), - .target( - name: "InputField", - dependencies: [ - .target(name: "Shared"), - ] - ), - .target( - name: "Permissions", - dependencies: [ - .target(name: "Theme"), - .target(name: "Shared"), - .target(name: "DependencyInjection"), - ] - ), - .target( - name: "PushFeature", - dependencies: [ - .target(name: "Models"), - .target(name: "Defaults"), - .target(name: "ReportingFeature"), - .target(name: "DependencyInjection"), - .product(name: "XXDatabase", package: "client-ios-db"), - .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), - .product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"), - ] - ), - .target( - name: "TestHelpers", - dependencies: [ - .target(name: "Models"), - .target(name: "Presentation"), - ] - ), - .target( - name: "Keychain", - dependencies: [ - .product(name: "KeychainAccess", package: "KeychainAccess"), - ] - ), - .target( - name: "Voxophone", - dependencies: [ - .target(name: "Shared"), - ] - ), - .target( - name: "Models", - dependencies: [ - .product(name: "DifferenceKit", package: "DifferenceKit"), - .product(name: "SwiftProtobuf", package: "swift-protobuf"), - ] - ), - .target( - name: "Defaults", - dependencies: [ - .target(name: "DependencyInjection"), - ] - ), - .target( - name: "ToastFeature", - dependencies: [ - .target(name: "Shared"), - ] - ), - .target( - name: "CrashService", - dependencies: [ - .target(name: "CrashReporting"), - .product(name: "FirebaseCrashlytics", package: "firebase-ios-sdk"), - ] - ), - .target( - name: "SFTPFeature", - dependencies: [ - .target(name: "HUD"), - .target(name: "Models"), - .target(name: "Shared"), - .target(name: "Keychain"), - .target(name: "InputField"), - .target(name: "Presentation"), - .target(name: "DependencyInjection"), - .product(name: "Shout", package: "Shout"), - ] - ), - .target( - name: "GoogleDriveFeature", - dependencies: [ - .product(name: "GoogleSignIn", package: "GoogleSignIn-iOS"), - .product(name: "GoogleAPIClientForREST_Drive", package: "google-api-objectivec-client-for-rest"), - ], - resources: [ - .process("Resources"), - ] - ), - .target( - name: "iCloudFeature", - dependencies: [ - .product(name: "FilesProvider", package: "FileProvider"), - ] - ), - .target( - name: "DropboxFeature", - dependencies: [ - .product(name: "SwiftyDropbox", package: "SwiftyDropbox"), - ], - resources: [ - .process("Resources"), - ] - ), - .target( - name: "Countries", - dependencies: [ - .target(name: "Theme"), - .target(name: "Shared"), - .target(name: "DependencyInjection"), - ], - resources: [ - .process("Resources"), - ] - ), - .target( - name: "Theme", - dependencies: [ - .target(name: "Defaults"), - .target(name: "DependencyInjection"), - ] - ), - .testTarget( - name: "ThemeTests", - dependencies: [ - .target(name: "Theme"), - .product(name: "Quick", package: "Quick"), - .product(name: "Nimble", package: "Nimble"), - ] - ), - .target( - name: "DrawerFeature", - dependencies: [ - .target(name: "Shared"), - .target(name: "InputField"), - .product(name: "ScrollViewController", package: "ScrollViewController"), - ] - ), - .target( - name: "HUD", - dependencies: [ - .target(name: "Theme"), - .target(name: "Shared"), - .product(name: "SnapKit", package: "SnapKit"), - ] - ), - .target( - name: "XXLogger", - dependencies: [ - .product(name: "SwiftyBeaver", package: "SwiftyBeaver"), - ] - ), - .target( - name: "Shared", - dependencies: [ - .product(name: "SnapKit", package: "SnapKit"), - .product(name: "ChatLayout", package: "ChatLayout"), - .product(name: "DifferenceKit", package: "DifferenceKit"), - ], - exclude: [ - "swiftgen.yml", - ], - resources: [ - .process("Resources"), - ] - ), - .target( - name: "Presentation", - dependencies: [ - .target(name: "Theme"), - .target(name: "Shared"), - .product(name: "SnapKit", package: "SnapKit"), - ] - ), - .testTarget( - name: "PresentationTests", - dependencies: [ - .target(name: "Presentation"), - .product(name: "Quick", package: "Quick"), - .product(name: "Nimble", package: "Nimble"), - ] - ), - .target( - name: "ChatInputFeature", - dependencies: [ - .target(name: "Voxophone"), - .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), - ] - ), - .target( - name: "RestoreFeature", - dependencies: [ - .target(name: "HUD"), - .target(name: "Shared"), - .target(name: "SFTPFeature"), - .target(name: "Presentation"), - .target(name: "iCloudFeature"), - .target(name: "BackupFeature"), - .target(name: "DropboxFeature"), - .target(name: "GoogleDriveFeature"), - .target(name: "DependencyInjection"), - .product(name: "XXDatabase", package: "client-ios-db"), - .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), - ] - ), - .target( - name: "ContactFeature", - dependencies: [ - .target(name: "Shared"), - .target(name: "InputField"), - .target(name: "ChatFeature"), - .target(name: "Presentation"), - .product(name: "CombineSchedulers", package: "combine-schedulers"), - .product(name: "ScrollViewController", package: "ScrollViewController"), - ] - ), - .testTarget( - name: "ContactFeatureTests", - dependencies: [ - .target(name: "TestHelpers"), - .target(name: "ContactFeature"), - .product(name: "Quick", package: "Quick"), - .product(name: "Nimble", package: "Nimble"), - ] - ), - .target( - name: "ChatFeature", - dependencies: [ - .target(name: "HUD"), - .target(name: "Theme"), - .target(name: "Shared"), - .target(name: "Defaults"), - .target(name: "Keychain"), - .target(name: "Voxophone"), - .target(name: "Models"), - .target(name: "Permissions"), - .target(name: "Presentation"), - .target(name: "DrawerFeature"), - .target(name: "ChatInputFeature"), - .target(name: "ReportingFeature"), - .target(name: "DependencyInjection"), - .product(name: "ChatLayout", package: "ChatLayout"), - .product(name: "DifferenceKit", package: "DifferenceKit"), - .product(name: "ScrollViewController", package: "ScrollViewController"), - .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), - .product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"), - ] - ), - .testTarget( - name: "ChatFeatureTests", - dependencies: [ - .target(name: "ChatFeature"), - .target(name: "TestHelpers"), - .product(name: "Quick", package: "Quick"), - .product(name: "Nimble", package: "Nimble"), - ] - ), - .target( - name: "SearchFeature", - dependencies: [ - .target(name: "HUD"), - .target(name: "Shared"), - .target(name: "Countries"), - .target(name: "PushFeature"), - .target(name: "Presentation"), - .target(name: "ContactFeature"), - .target(name: "NetworkMonitor"), - .target(name: "DependencyInjection"), - .product(name: "Retry", package: "Retry"), - .product(name: "XXDatabase", package: "client-ios-db"), - ] - ), - .testTarget( - name: "SearchFeatureTests", - dependencies: [ - .target(name: "TestHelpers"), - .target(name: "SearchFeature"), - .product(name: "Quick", package: "Quick"), - .product(name: "Nimble", package: "Nimble"), - ] - ), - .target( - name: "LaunchFeature", - dependencies: [ - .target(name: "HUD"), - .target(name: "Theme"), - .target(name: "Shared"), - .target(name: "Defaults"), - .target(name: "PushFeature"), - .target(name: "Permissions"), - .target(name: "BackupFeature"), - .target(name: "DropboxFeature"), - .target(name: "VersionChecking"), - .target(name: "ReportingFeature"), - .target(name: "DependencyInjection"), - .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), - .product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"), - .product(name: "CombineSchedulers", package: "combine-schedulers"), - .product(name: "XXLegacyDatabaseMigrator", package: "client-ios-db"), - ] - ), - .target( - name: "TermsFeature", - dependencies: [ - .target(name: "Theme"), - .target(name: "Shared"), - .target(name: "Defaults"), - .target(name: "Presentation"), - ] - ), - .target( - name: "RequestsFeature", - dependencies: [ - .target(name: "Theme"), - .target(name: "Shared"), - .target(name: "ToastFeature"), - .target(name: "ContactFeature"), - .target(name: "DependencyInjection"), - .product(name: "DifferenceKit", package: "DifferenceKit"), - ] - ), - .testTarget( - name: "RequestsFeatureTests", - dependencies: [ - .target(name: "TestHelpers"), - .target(name: "RequestsFeature"), - .product(name: "Quick", package: "Quick"), - .product(name: "Nimble", package: "Nimble"), - ] - ), - .target( - name: "ProfileFeature", - dependencies: [ - .target(name: "HUD"), - .target(name: "Theme"), - .target(name: "Shared"), - .target(name: "Keychain"), - .target(name: "Defaults"), - .target(name: "Countries"), - .target(name: "InputField"), - .target(name: "MenuFeature"), - .target(name: "Permissions"), - .target(name: "Presentation"), - .target(name: "DrawerFeature"), - .target(name: "BackupFeature"), - .target(name: "DependencyInjection"), - .product(name: "CombineSchedulers", package: "combine-schedulers"), - .product(name: "ScrollViewController", package: "ScrollViewController"), - .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), - .product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"), - ] - ), - .testTarget( - name: "ProfileFeatureTests", - dependencies: [ - .target(name: "TestHelpers"), - .target(name: "ProfileFeature"), - .product(name: "Quick", package: "Quick"), - .product(name: "Nimble", package: "Nimble"), - ] - ), - .target( - name: "ChatListFeature", - dependencies: [ - .target(name: "Theme"), - .target(name: "Shared"), - .target(name: "Defaults"), - .target(name: "MenuFeature"), - .target(name: "ChatFeature"), - .target(name: "ProfileFeature"), - .target(name: "SettingsFeature"), - .target(name: "ContactListFeature"), - .target(name: "DependencyInjection"), - .product(name: "DifferenceKit", package: "DifferenceKit"), - ] - ), - .testTarget( - name: "ChatListFeatureTests", - dependencies: [ - .target(name: "TestHelpers"), - .target(name: "ChatListFeature"), - .product(name: "Quick", package: "Quick"), - .product(name: "Nimble", package: "Nimble"), - ] - ), - .target( - name: "OnboardingFeature", - dependencies: [ - .target(name: "HUD"), - .target(name: "Shared"), - .target(name: "Defaults"), - .target(name: "Keychain"), - .target(name: "Countries"), - .target(name: "InputField"), - .target(name: "Permissions"), - .target(name: "PushFeature"), - .target(name: "Presentation"), - .target(name: "DrawerFeature"), - .target(name: "VersionChecking"), - .target(name: "DependencyInjection"), - .product(name: "CombineSchedulers", package: "combine-schedulers"), - .product(name: "ScrollViewController", package: "ScrollViewController"), - ] - ), - .testTarget( - name: "OnboardingFeatureTests", - dependencies: [ - .target(name: "TestHelpers"), - .target(name: "OnboardingFeature"), - .product(name: "Quick", package: "Quick"), - .product(name: "Nimble", package: "Nimble"), - ] - ), - .target( - name: "MenuFeature", - dependencies: [ - .target(name: "Theme"), - .target(name: "Shared"), - .target(name: "Defaults"), - .target(name: "Presentation"), - .target(name: "DrawerFeature"), - .target(name: "ReportingFeature"), - .target(name: "DependencyInjection"), - .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), - ] - ), - .target( - name: "BackupFeature", - dependencies: [ - .target(name: "HUD"), - .target(name: "Shared"), - .target(name: "Models"), - .target(name: "InputField"), - .target(name: "SFTPFeature"), - .target(name: "Presentation"), - .target(name: "iCloudFeature"), - .target(name: "DrawerFeature"), - .target(name: "DropboxFeature"), - .target(name: "GoogleDriveFeature"), - .target(name: "DependencyInjection"), - ] - ), - .target( - name: "ScanFeature", - dependencies: [ - .target(name: "Theme"), - .target(name: "Shared"), - .target(name: "Countries"), - .target(name: "Permissions"), - .target(name: "Presentation"), - .target(name: "ContactFeature"), - .target(name: "NetworkMonitor"), - .target(name: "DependencyInjection"), - .product(name: "SnapKit", package: "SnapKit"), - ] - ), - .testTarget( - name: "ScanFeatureTests", - dependencies: [ - .target(name: "ScanFeature"), - .target(name: "TestHelpers"), - .product(name: "Quick", package: "Quick"), - .product(name: "Nimble", package: "Nimble"), - ] - ), - .target( - name: "ContactListFeature", - dependencies: [ - .target(name: "Theme"), - .target(name: "Shared"), - .target(name: "Presentation"), - .target(name: "ContactFeature"), - .target(name: "DependencyInjection"), - .product(name: "DifferenceKit", package: "DifferenceKit"), - ] - ), - .testTarget( - name: "ContactListFeatureTests", - dependencies: [ - .target(name: "TestHelpers"), - .target(name: "ContactListFeature"), - .product(name: "Quick", package: "Quick"), - .product(name: "Nimble", package: "Nimble"), - ] - ), - .target( - name: "SettingsFeature", - dependencies: [ - .target(name: "HUD"), - .target(name: "Theme"), - .target(name: "Shared"), - .target(name: "Defaults"), - .target(name: "Keychain"), - .target(name: "XXLogger"), - .target(name: "InputField"), - .target(name: "PushFeature"), - .target(name: "Permissions"), - .target(name: "MenuFeature"), - .target(name: "Presentation"), - .target(name: "DrawerFeature"), - .target(name: "DependencyInjection"), - .product(name: "CombineSchedulers", package: "combine-schedulers"), - .product(name: "ScrollViewController", package: "ScrollViewController"), - ] - ), - .testTarget( - name: "SettingsFeatureTests", - dependencies: [ - .target(name: "TestHelpers"), - .target(name: "SettingsFeature"), - .product(name: "Quick", package: "Quick"), - .product(name: "Nimble", package: "Nimble"), - ] - ), - .target( - name: "CollectionView", - dependencies: [ - .product(name: "ChatLayout", package: "ChatLayout"), - .product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"), - ] - ), - .testTarget( - name: "CollectionViewTests", - dependencies: [ - .target(name: "CollectionView"), - .product(name: "CustomDump", package: "swift-custom-dump"), - ] - ), - .target( - name: "ReportingFeature", - dependencies: [ - .target(name: "DrawerFeature"), - .target(name: "Shared"), - .product(name: "SwiftCSV", package: "SwiftCSV"), - .product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"), - ], - resources: [ - .process("Resources"), - ] - ), - ] + name: "client-ios", + defaultLocalization: "en", + platforms: [ + .iOS(.v14), + ], + products: [ + .library(name: "App", targets: ["App"]), + .library(name: "HUD", targets: ["HUD"]), + .library(name: "Theme", targets: ["Theme"]), + .library(name: "Shared", targets: ["Shared"]), + .library(name: "Models", targets: ["Models"]), + .library(name: "XXLogger", targets: ["XXLogger"]), + .library(name: "Defaults", targets: ["Defaults"]), + .library(name: "Keychain", targets: ["Keychain"]), + .library(name: "Voxophone", targets: ["Voxophone"]), + .library(name: "Countries", targets: ["Countries"]), + .library(name: "InputField", targets: ["InputField"]), + .library(name: "TestHelpers", targets: ["TestHelpers"]), + .library(name: "ScanFeature", targets: ["ScanFeature"]), + .library(name: "Permissions", targets: ["Permissions"]), + .library(name: "MenuFeature", targets: ["MenuFeature"]), + .library(name: "ChatFeature", targets: ["ChatFeature"]), + .library(name: "PushFeature", targets: ["PushFeature"]), + .library(name: "CrashService", targets: ["CrashService"]), + .library(name: "TermsFeature", targets: ["TermsFeature"]), + .library(name: "Presentation", targets: ["Presentation"]), + .library(name: "ToastFeature", targets: ["ToastFeature"]), + .library(name: "BackupFeature", targets: ["BackupFeature"]), + .library(name: "LaunchFeature", targets: ["LaunchFeature"]), + .library(name: "SearchFeature", targets: ["SearchFeature"]), + .library(name: "DrawerFeature", targets: ["DrawerFeature"]), + .library(name: "CollectionView", targets: ["CollectionView"]), + .library(name: "RestoreFeature", targets: ["RestoreFeature"]), + .library(name: "CrashReporting", targets: ["CrashReporting"]), + .library(name: "ProfileFeature", targets: ["ProfileFeature"]), + .library(name: "ContactFeature", targets: ["ContactFeature"]), + .library(name: "NetworkMonitor", targets: ["NetworkMonitor"]), + .library(name: "VersionChecking", targets: ["VersionChecking"]), + .library(name: "SettingsFeature", targets: ["SettingsFeature"]), + .library(name: "ChatListFeature", targets: ["ChatListFeature"]), + .library(name: "RequestsFeature", targets: ["RequestsFeature"]), + .library(name: "ChatInputFeature", targets: ["ChatInputFeature"]), + .library(name: "OnboardingFeature", targets: ["OnboardingFeature"]), + .library(name: "ContactListFeature", targets: ["ContactListFeature"]), + .library(name: "DependencyInjection", targets: ["DependencyInjection"]), + .library(name: "ReportingFeature", targets: ["ReportingFeature"]), + ], + dependencies: [ + .package( + url: "https://github.com/Quick/Quick", + .upToNextMajor(from: "3.0.0") + ), + .package( + url: "https://github.com/Quick/Nimble", + .upToNextMajor(from: "9.0.0") + ), + .package( + url: "https://github.com/SnapKit/SnapKit", + .upToNextMajor(from: "5.0.1") + ), + .package( + url: "https://github.com/icanzilb/Retry.git", + .upToNextMajor(from: "0.6.3") + ), + .package( + url: "https://github.com/ekazaev/ChatLayout", + .upToNextMajor(from: "1.1.14") + ), + .package( + url: "https://github.com/ra1028/DifferenceKit", + .upToNextMajor(from: "1.2.0") + ), + .package( + url: "https://github.com/apple/swift-protobuf", + .upToNextMajor(from: "1.14.0") + ), + .package( + url: "https://github.com/SwiftyBeaver/SwiftyBeaver.git", + .upToNextMajor(from: "1.9.5") + ), + .package( + url: "https://github.com/darrarski/ScrollViewController", + .upToNextMajor(from: "1.2.0") + ), + .package( + url: "https://github.com/pointfreeco/combine-schedulers", + .upToNextMajor(from: "0.5.0") + ), + .package( + url: "https://github.com/kishikawakatsumi/KeychainAccess", + .upToNextMajor(from: "4.2.1") + ), + .package( + path: "../elixxir-dapps-sdk-swift" + // url: "https://git.xx.network/elixxir/elixxir-dapps-sdk-swift", + // branch: "development" + ), + .package( + path: "../xxm-cloud-providers" + ), + .package( + url: "https://git.xx.network/elixxir/client-ios-db.git", + .upToNextMajor(from: "1.1.0") + ), + .package( + url: "https://github.com/firebase/firebase-ios-sdk.git", + .upToNextMajor(from: "8.10.0") + ), + .package( + url: "https://github.com/pointfreeco/swift-composable-architecture.git", + .upToNextMajor(from: "0.32.0") + ), + .package( + url: "https://github.com/pointfreeco/swift-custom-dump.git", + .upToNextMajor(from: "0.5.0") + ), + .package( + url: "https://github.com/swiftcsv/SwiftCSV.git", + from: "0.8.0" + ), + .package( + url: "https://github.com/pointfreeco/xctest-dynamic-overlay.git", + .upToNextMajor(from: "0.3.3") + ), + ], + targets: [ + .target( + name: "App", + dependencies: [ + .target(name: "Keychain"), + .target(name: "Voxophone"), + .target(name: "Permissions"), + .target(name: "ScanFeature"), + .target(name: "ChatFeature"), + .target(name: "MenuFeature"), + .target(name: "PushFeature"), + .target(name: "TermsFeature"), + .target(name: "ToastFeature"), + .target(name: "CrashService"), + .target(name: "BackupFeature"), + .target(name: "SearchFeature"), + .target(name: "LaunchFeature"), + .target(name: "ContactFeature"), + .target(name: "RestoreFeature"), + .target(name: "ProfileFeature"), + .target(name: "CrashReporting"), + .target(name: "ChatListFeature"), + .target(name: "SettingsFeature"), + .target(name: "RequestsFeature"), + .target(name: "ReportingFeature"), + .target(name: "OnboardingFeature"), + .target(name: "ContactListFeature"), + ] + ), + .testTarget( + name: "AppTests", + dependencies: [ + .target(name: "App"), + ] + ), + .target( + name: "CrashReporting" + ), + .target( + name: "NetworkMonitor", + dependencies: [ + .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), + ] + ), + .target( + name: "VersionChecking" + ), + .target( + name: "DependencyInjection" + ), + .testTarget( + name: "DependencyInjectionTests", + dependencies: [ + .target(name: "DependencyInjection"), + ] + ), + .target( + name: "InputField", + dependencies: [ + .target(name: "Shared"), + ] + ), + .target( + name: "Permissions", + dependencies: [ + .target(name: "Theme"), + .target(name: "Shared"), + .target(name: "DependencyInjection"), + ] + ), + .target( + name: "PushFeature", + dependencies: [ + .target(name: "Models"), + .target(name: "Defaults"), + .target(name: "ReportingFeature"), + .target(name: "DependencyInjection"), + .product(name: "XXDatabase", package: "client-ios-db"), + .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), + .product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"), + ] + ), + .target( + name: "TestHelpers", + dependencies: [ + .target(name: "Models"), + .target(name: "Presentation"), + ] + ), + .target( + name: "Keychain", + dependencies: [ + .product(name: "KeychainAccess", package: "KeychainAccess"), + ] + ), + .target( + name: "Voxophone", + dependencies: [ + .target(name: "Shared"), + ] + ), + .target( + name: "Models", + dependencies: [ + .product(name: "DifferenceKit", package: "DifferenceKit"), + .product(name: "SwiftProtobuf", package: "swift-protobuf"), + ] + ), + .target( + name: "Defaults", + dependencies: [ + .target(name: "DependencyInjection"), + ] + ), + .target( + name: "ToastFeature", + dependencies: [ + .target(name: "Shared"), + ] + ), + .target( + name: "CrashService", + dependencies: [ + .target(name: "CrashReporting"), + .product(name: "FirebaseCrashlytics", package: "firebase-ios-sdk"), + ] + ), + .target( + name: "Countries", + dependencies: [ + .target(name: "Theme"), + .target(name: "Shared"), + .target(name: "DependencyInjection"), + ], + resources: [ + .process("Resources"), + ] + ), + .target( + name: "Theme", + dependencies: [ + .target(name: "Defaults"), + .target(name: "DependencyInjection"), + ] + ), + .testTarget( + name: "ThemeTests", + dependencies: [ + .target(name: "Theme"), + .product(name: "Quick", package: "Quick"), + .product(name: "Nimble", package: "Nimble"), + ] + ), + .target( + name: "DrawerFeature", + dependencies: [ + .target(name: "Shared"), + .target(name: "InputField"), + .product(name: "ScrollViewController", package: "ScrollViewController"), + ] + ), + .target( + name: "HUD", + dependencies: [ + .target(name: "Theme"), + .target(name: "Shared"), + .product(name: "SnapKit", package: "SnapKit"), + ] + ), + .target( + name: "XXLogger", + dependencies: [ + .product(name: "SwiftyBeaver", package: "SwiftyBeaver"), + ] + ), + .target( + name: "Shared", + dependencies: [ + .product(name: "SnapKit", package: "SnapKit"), + .product(name: "ChatLayout", package: "ChatLayout"), + .product(name: "DifferenceKit", package: "DifferenceKit"), + ], + exclude: [ + "swiftgen.yml", + ], + resources: [ + .process("Resources"), + ] + ), + .target( + name: "Presentation", + dependencies: [ + .target(name: "Theme"), + .target(name: "Shared"), + .product(name: "SnapKit", package: "SnapKit"), + ] + ), + .testTarget( + name: "PresentationTests", + dependencies: [ + .target(name: "Presentation"), + .product(name: "Quick", package: "Quick"), + .product(name: "Nimble", package: "Nimble"), + ] + ), + .target( + name: "ChatInputFeature", + dependencies: [ + .target(name: "Voxophone"), + .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), + ] + ), + .target( + name: "RestoreFeature", + dependencies: [ + .target(name: "HUD"), + .target(name: "Shared"), + .target(name: "Presentation"), + .target(name: "BackupFeature"), + .target(name: "DependencyInjection"), + .product(name: "XXDatabase", package: "client-ios-db"), + .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), + ] + ), + .target( + name: "ContactFeature", + dependencies: [ + .target(name: "Shared"), + .target(name: "InputField"), + .target(name: "ChatFeature"), + .target(name: "Presentation"), + .product(name: "CombineSchedulers", package: "combine-schedulers"), + .product(name: "ScrollViewController", package: "ScrollViewController"), + ] + ), + .testTarget( + name: "ContactFeatureTests", + dependencies: [ + .target(name: "TestHelpers"), + .target(name: "ContactFeature"), + .product(name: "Quick", package: "Quick"), + .product(name: "Nimble", package: "Nimble"), + ] + ), + .target( + name: "ChatFeature", + dependencies: [ + .target(name: "HUD"), + .target(name: "Theme"), + .target(name: "Shared"), + .target(name: "Defaults"), + .target(name: "Keychain"), + .target(name: "Voxophone"), + .target(name: "Models"), + .target(name: "Permissions"), + .target(name: "Presentation"), + .target(name: "DrawerFeature"), + .target(name: "ChatInputFeature"), + .target(name: "ReportingFeature"), + .target(name: "DependencyInjection"), + .product(name: "ChatLayout", package: "ChatLayout"), + .product(name: "DifferenceKit", package: "DifferenceKit"), + .product(name: "ScrollViewController", package: "ScrollViewController"), + .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), + .product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"), + ] + ), + .testTarget( + name: "ChatFeatureTests", + dependencies: [ + .target(name: "ChatFeature"), + .target(name: "TestHelpers"), + .product(name: "Quick", package: "Quick"), + .product(name: "Nimble", package: "Nimble"), + ] + ), + .target( + name: "SearchFeature", + dependencies: [ + .target(name: "HUD"), + .target(name: "Shared"), + .target(name: "Countries"), + .target(name: "PushFeature"), + .target(name: "Presentation"), + .target(name: "ContactFeature"), + .target(name: "NetworkMonitor"), + .target(name: "DependencyInjection"), + .product(name: "Retry", package: "Retry"), + .product(name: "XXDatabase", package: "client-ios-db"), + ] + ), + .testTarget( + name: "SearchFeatureTests", + dependencies: [ + .target(name: "TestHelpers"), + .target(name: "SearchFeature"), + .product(name: "Quick", package: "Quick"), + .product(name: "Nimble", package: "Nimble"), + ] + ), + .target( + name: "LaunchFeature", + dependencies: [ + .target(name: "HUD"), + .target(name: "Theme"), + .target(name: "Shared"), + .target(name: "Defaults"), + .target(name: "PushFeature"), + .target(name: "Permissions"), + .target(name: "BackupFeature"), + .target(name: "VersionChecking"), + .target(name: "ReportingFeature"), + .target(name: "DependencyInjection"), + .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), + .product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"), + .product(name: "CombineSchedulers", package: "combine-schedulers"), + .product(name: "XXLegacyDatabaseMigrator", package: "client-ios-db"), + ] + ), + .target( + name: "TermsFeature", + dependencies: [ + .target(name: "Theme"), + .target(name: "Shared"), + .target(name: "Defaults"), + .target(name: "Presentation"), + ] + ), + .target( + name: "RequestsFeature", + dependencies: [ + .target(name: "Theme"), + .target(name: "Shared"), + .target(name: "ToastFeature"), + .target(name: "ContactFeature"), + .target(name: "DependencyInjection"), + .product(name: "DifferenceKit", package: "DifferenceKit"), + ] + ), + .testTarget( + name: "RequestsFeatureTests", + dependencies: [ + .target(name: "TestHelpers"), + .target(name: "RequestsFeature"), + .product(name: "Quick", package: "Quick"), + .product(name: "Nimble", package: "Nimble"), + ] + ), + .target( + name: "ProfileFeature", + dependencies: [ + .target(name: "HUD"), + .target(name: "Theme"), + .target(name: "Shared"), + .target(name: "Keychain"), + .target(name: "Defaults"), + .target(name: "Countries"), + .target(name: "InputField"), + .target(name: "MenuFeature"), + .target(name: "Permissions"), + .target(name: "Presentation"), + .target(name: "DrawerFeature"), + .target(name: "BackupFeature"), + .target(name: "DependencyInjection"), + .product(name: "CombineSchedulers", package: "combine-schedulers"), + .product(name: "ScrollViewController", package: "ScrollViewController"), + .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), + .product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"), + ] + ), + .testTarget( + name: "ProfileFeatureTests", + dependencies: [ + .target(name: "TestHelpers"), + .target(name: "ProfileFeature"), + .product(name: "Quick", package: "Quick"), + .product(name: "Nimble", package: "Nimble"), + ] + ), + .target( + name: "ChatListFeature", + dependencies: [ + .target(name: "Theme"), + .target(name: "Shared"), + .target(name: "Defaults"), + .target(name: "MenuFeature"), + .target(name: "ChatFeature"), + .target(name: "ProfileFeature"), + .target(name: "SettingsFeature"), + .target(name: "ContactListFeature"), + .target(name: "DependencyInjection"), + .product(name: "DifferenceKit", package: "DifferenceKit"), + ] + ), + .testTarget( + name: "ChatListFeatureTests", + dependencies: [ + .target(name: "TestHelpers"), + .target(name: "ChatListFeature"), + .product(name: "Quick", package: "Quick"), + .product(name: "Nimble", package: "Nimble"), + ] + ), + .target( + name: "OnboardingFeature", + dependencies: [ + .target(name: "HUD"), + .target(name: "Shared"), + .target(name: "Defaults"), + .target(name: "Keychain"), + .target(name: "Countries"), + .target(name: "InputField"), + .target(name: "Permissions"), + .target(name: "PushFeature"), + .target(name: "Presentation"), + .target(name: "DrawerFeature"), + .target(name: "VersionChecking"), + .target(name: "DependencyInjection"), + .product(name: "CombineSchedulers", package: "combine-schedulers"), + .product(name: "ScrollViewController", package: "ScrollViewController"), + ] + ), + .testTarget( + name: "OnboardingFeatureTests", + dependencies: [ + .target(name: "TestHelpers"), + .target(name: "OnboardingFeature"), + .product(name: "Quick", package: "Quick"), + .product(name: "Nimble", package: "Nimble"), + ] + ), + .target( + name: "MenuFeature", + dependencies: [ + .target(name: "Theme"), + .target(name: "Shared"), + .target(name: "Defaults"), + .target(name: "Presentation"), + .target(name: "DrawerFeature"), + .target(name: "ReportingFeature"), + .target(name: "DependencyInjection"), + .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), + ] + ), + .target( + name: "BackupFeature", + dependencies: [ + .target(name: "HUD"), + .target(name: "Shared"), + .target(name: "Models"), + .target(name: "InputField"), + .target(name: "Presentation"), + .target(name: "DrawerFeature"), + .target(name: "DependencyInjection"), + ] + ), + .target( + name: "ScanFeature", + dependencies: [ + .target(name: "Theme"), + .target(name: "Shared"), + .target(name: "Countries"), + .target(name: "Permissions"), + .target(name: "Presentation"), + .target(name: "ContactFeature"), + .target(name: "NetworkMonitor"), + .target(name: "DependencyInjection"), + .product(name: "SnapKit", package: "SnapKit"), + ] + ), + .testTarget( + name: "ScanFeatureTests", + dependencies: [ + .target(name: "ScanFeature"), + .target(name: "TestHelpers"), + .product(name: "Quick", package: "Quick"), + .product(name: "Nimble", package: "Nimble"), + ] + ), + .target( + name: "ContactListFeature", + dependencies: [ + .target(name: "Theme"), + .target(name: "Shared"), + .target(name: "Presentation"), + .target(name: "ContactFeature"), + .target(name: "DependencyInjection"), + .product(name: "DifferenceKit", package: "DifferenceKit"), + ] + ), + .testTarget( + name: "ContactListFeatureTests", + dependencies: [ + .target(name: "TestHelpers"), + .target(name: "ContactListFeature"), + .product(name: "Quick", package: "Quick"), + .product(name: "Nimble", package: "Nimble"), + ] + ), + .target( + name: "SettingsFeature", + dependencies: [ + .target(name: "HUD"), + .target(name: "Theme"), + .target(name: "Shared"), + .target(name: "Defaults"), + .target(name: "Keychain"), + .target(name: "XXLogger"), + .target(name: "InputField"), + .target(name: "PushFeature"), + .target(name: "Permissions"), + .target(name: "MenuFeature"), + .target(name: "Presentation"), + .target(name: "DrawerFeature"), + .target(name: "DependencyInjection"), + .product(name: "CombineSchedulers", package: "combine-schedulers"), + .product(name: "ScrollViewController", package: "ScrollViewController"), + ] + ), + .testTarget( + name: "SettingsFeatureTests", + dependencies: [ + .target(name: "TestHelpers"), + .target(name: "SettingsFeature"), + .product(name: "Quick", package: "Quick"), + .product(name: "Nimble", package: "Nimble"), + ] + ), + .target( + name: "CollectionView", + dependencies: [ + .product(name: "ChatLayout", package: "ChatLayout"), + .product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"), + ] + ), + .testTarget( + name: "CollectionViewTests", + dependencies: [ + .target(name: "CollectionView"), + .product(name: "CustomDump", package: "swift-custom-dump"), + ] + ), + .target( + name: "ReportingFeature", + dependencies: [ + .target(name: "DrawerFeature"), + .target(name: "Shared"), + .product(name: "SwiftCSV", package: "SwiftCSV"), + .product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"), + ], + resources: [ + .process("Resources"), + ] + ), + ] ) diff --git a/Sources/App/AppDelegate.swift b/Sources/App/AppDelegate.swift index 26b76e3ede2160f5bcce6ed1e2f1018adfa1d98f..b85cc758f100ce2c383b144772cd9f0c18921633 100644 --- a/Sources/App/AppDelegate.swift +++ b/Sources/App/AppDelegate.swift @@ -7,9 +7,7 @@ import XXLogger import Defaults import PushFeature import ToastFeature -import SwiftyDropbox import LaunchFeature -import DropboxFeature import CrashReporting import DependencyInjection diff --git a/Sources/App/DependencyRegistrator.swift b/Sources/App/DependencyRegistrator.swift index 4f2c9a0b5fdb0c0a588920024053a113b5001f3e..bbc8ef75a756e0ce2c10c5a41d142fd8a5c60993 100644 --- a/Sources/App/DependencyRegistrator.swift +++ b/Sources/App/DependencyRegistrator.swift @@ -17,16 +17,12 @@ import Countries import Voxophone import Permissions import PushFeature -import SFTPFeature import CrashService import ToastFeature -import iCloudFeature import CrashReporting import NetworkMonitor -import DropboxFeature import VersionChecking import ReportingFeature -import GoogleDriveFeature import DependencyInjection // MARK: UI Features diff --git a/Sources/BackupFeature/Service/BackupService.swift b/Sources/BackupFeature/Service/BackupService.swift index b71916f161e461ef6a48338070a9150b04bd017a..1ffc64356fa3307d5312ea76c1294f3f7d18848f 100644 --- a/Sources/BackupFeature/Service/BackupService.swift +++ b/Sources/BackupFeature/Service/BackupService.swift @@ -3,11 +3,7 @@ import Models import Combine import Defaults import Keychain -import SFTPFeature -import iCloudFeature -import DropboxFeature import NetworkMonitor -import GoogleDriveFeature import DependencyInjection import XXClient import XXMessengerClient diff --git a/Sources/BackupFeature/ViewModels/BackupSetupViewModel.swift b/Sources/BackupFeature/ViewModels/BackupSetupViewModel.swift index cc647d9aaecc7507eed9d517909dbf3229b6901f..fe94e5b00d0090c8bd39d443dd771ad3468fccfc 100644 --- a/Sources/BackupFeature/ViewModels/BackupSetupViewModel.swift +++ b/Sources/BackupFeature/ViewModels/BackupSetupViewModel.swift @@ -2,7 +2,6 @@ import UIKit import Models import Shared import Combine -import GoogleDriveFeature import DependencyInjection struct BackupSetupViewModel { diff --git a/Sources/DropboxFeature/DropboxInterface.swift b/Sources/DropboxFeature/DropboxInterface.swift deleted file mode 100644 index 1a5aa02a054ad29816530447c3ed5d725573160b..0000000000000000000000000000000000000000 --- a/Sources/DropboxFeature/DropboxInterface.swift +++ /dev/null @@ -1,18 +0,0 @@ -import UIKit -import Combine - -public protocol DropboxInterface { - func isAuthorized() -> Bool - - func unlink() - - func handleOpenUrl(_ url: URL) -> Bool - - func downloadBackup(_: String, _: @escaping (Result<Data, Error>) -> Void) - - func uploadBackup(_: URL, _: @escaping (Result<DropboxMetadata, Error>) -> Void) - - func downloadMetadata(_: @escaping (Result<DropboxMetadata?, Error>) -> Void) - - func authorize(presenting: UIViewController) -> AnyPublisher<Result<Bool, Error>, Never> -} diff --git a/Sources/DropboxFeature/DropboxMetadata.swift b/Sources/DropboxFeature/DropboxMetadata.swift deleted file mode 100644 index ceb4fe195242bf13ffb4e2a65a48d58aea282756..0000000000000000000000000000000000000000 --- a/Sources/DropboxFeature/DropboxMetadata.swift +++ /dev/null @@ -1,18 +0,0 @@ -import Foundation -import SwiftyDropbox - -public struct DropboxMetadata: Equatable { - public var size: Float - public var path: String - public var modifiedDate: Date - - public init( - size: Float, - path: String, - modifiedDate: Date - ) { - self.size = size - self.path = path - self.modifiedDate = modifiedDate - } -} diff --git a/Sources/DropboxFeature/DropboxService.swift b/Sources/DropboxFeature/DropboxService.swift deleted file mode 100644 index e90ef79721443c67ae452e1a0105ab0b86c2e6ca..0000000000000000000000000000000000000000 --- a/Sources/DropboxFeature/DropboxService.swift +++ /dev/null @@ -1,209 +0,0 @@ -import UIKit -import Combine -import SwiftyDropbox - -public struct DropboxService: DropboxInterface { - private let didAuthorizeSubject = PassthroughSubject<Result<Bool, Error>, Never>() - - public init() { - let path = Bundle.module.path(forResource: "Dropbox-Keys", ofType: "plist") - let url = URL(fileURLWithPath: path!) - let keys = try! NSDictionary(contentsOf: url, error: ()) - - DropboxClientsManager.setupWithAppKey(keys["DROPBOX_APP_KEY"] as! String) - } - - public func unlink() { - DropboxClientsManager.unlinkClients() - } - - public func isAuthorized() -> Bool { - DropboxClientsManager.authorizedClient != nil - } - - public func authorize(presenting controller: UIViewController) -> AnyPublisher<Result<Bool, Error>, Never> { - let scopes = ["files.metadata.read", "files.content.read", "files.content.write"] - - return didAuthorizeSubject.handleEvents(receiveSubscription: { _ in - let scopeRequest = ScopeRequest(scopeType: .user, scopes: scopes, includeGrantedScopes: false) - - DropboxClientsManager.authorizeFromControllerV2( - UIApplication.shared, - controller: controller, - loadingStatusDelegate: nil, - openURL: { (url: URL) -> Void in UIApplication.shared.open(url, options: [:], completionHandler: nil) }, - scopeRequest: scopeRequest - ) - }).first().eraseToAnyPublisher() - } - - public func handleOpenUrl(_ url: URL) -> Bool { - DropboxClientsManager.handleRedirectURL(url) { - switch $0 { - case .none: - didAuthorizeSubject.send(.success(false)) - case .error(let oAuthError, _): - didAuthorizeSubject.send(.failure(oAuthError)) - case .success: - didAuthorizeSubject.send(.success(true)) - case .cancel: - didAuthorizeSubject.send(.success(false)) - } - } - } - - public func downloadBackup(_ path: String, _ completion: @escaping (Result<Data, Error>) -> Void) { - Task { - do { - guard try await folderExists() else { fatalError() } - - let data = try await fetchBackup() - completion(.success(data)) - } catch { - completion(.failure(error)) - } - } - } - - public func uploadBackup(_ url: URL, _ completion: @escaping (Result<DropboxMetadata, Error>) -> Void) { - Task { - do { - if try await !folderExists() { - try await createFolder() - } - - let data = try Data(contentsOf: url) - let metadata = try await upload(data: data) - completion(.success(metadata)) - } catch { - completion(.failure(error)) - } - } - } - - public func downloadMetadata(_ completion: @escaping (Result<DropboxMetadata?, Error>) -> Void) { - Task { - do { - guard try await folderExists() else { - completion(.success(nil)) - return - } - - let metadata = try await fetchMetadata() - completion(.success(metadata)) - } catch { - completion(.failure(error)) - } - } - } -} - -extension DropboxService { - private func folderExists() async throws -> Bool { - guard let client = DropboxClientsManager.authorizedClient else { fatalError() } - - return try await withCheckedThrowingContinuation { continuation in - client.files.listFolder(path: "/backup") - .response { result, error in - if let error = error { - if case .routeError(_, _, _, _) = error as CallError { - continuation.resume(returning: false) - return - } - - let err = NSError(domain: error.description, code: 0) - continuation.resume(throwing: err) - return - } - - continuation.resume(returning: result != nil) - } - } - } - - private func createFolder() async throws { - guard let client = DropboxClientsManager.authorizedClient else { fatalError() } - - return try await withCheckedThrowingContinuation { continuation in - client.files.createFolderV2(path: "/backup") - .response { _, error in - if let error = error { - let err = NSError(domain: error.description, code: 0) - continuation.resume(throwing: err) - return - } - - continuation.resume(returning: ()) - } - } - } - - private func fetchMetadata() async throws -> DropboxMetadata? { - guard let client = DropboxClientsManager.authorizedClient else { fatalError() } - - return try await withCheckedThrowingContinuation { continuation in - client.files.getMetadata(path: "/backup/backup.xxm") - .response { response, error in - if let error = error { - let err = NSError(domain: error.description, code: 0) - continuation.resume(throwing: err) - return - } - - if let result = response as? Files.FileMetadata { - let size = Float(result.size) - let modifiedDate = result.serverModified - continuation.resume(returning: .init( - size: size, - path: "/backup/backup.xxm", - modifiedDate: modifiedDate - )) - } else { - continuation.resume(returning: nil) - } - } - } - } - - private func fetchBackup() async throws -> Data { - guard let client = DropboxClientsManager.authorizedClient else { fatalError() } - - return try await withCheckedThrowingContinuation { continuation in - client.files.download(path: "/backup/backup.xxm") - .response(completionHandler: { response, error in - if let error = error { - let err = NSError(domain: error.description, code: 0) - continuation.resume(throwing: err) - return - } - - if let response = response { - continuation.resume(returning: response.1) - } - }) - } - } - - private func upload(data: Data) async throws -> DropboxMetadata { - guard let client = DropboxClientsManager.authorizedClient else { fatalError() } - - return try await withCheckedThrowingContinuation { continuation in - client.files.upload(path: "/backup/backup.xxm", mode: .overwrite, input: data) - .response { response, error in - if let error = error { - let err = NSError(domain: error.description, code: 0) - continuation.resume(throwing: err) - return - } - - if let response = response { - continuation.resume(returning: .init( - size: Float(response.size), - path: response.pathLower!, - modifiedDate: response.serverModified - )) - } - } - } - } -} diff --git a/Sources/DropboxFeature/DropboxServiceMock.swift b/Sources/DropboxFeature/DropboxServiceMock.swift deleted file mode 100644 index ba9654b69f870fb28b49cd8414676375fcb866ba..0000000000000000000000000000000000000000 --- a/Sources/DropboxFeature/DropboxServiceMock.swift +++ /dev/null @@ -1,22 +0,0 @@ -import UIKit -import Combine - -public struct DropboxServiceMock: DropboxInterface { - public init() {} - - public func unlink() {} - - public func isAuthorized() -> Bool { true } - - public func handleOpenUrl(_ url: URL) -> Bool { true } - - public func didFinishAuthFlow(withError: String?) {} - - public func downloadBackup(_: String, _: @escaping (Result<Data, Error>) -> Void) {} - - public func uploadBackup(_: URL, _: @escaping (Result<DropboxMetadata, Error>) -> Void) {} - - public func downloadMetadata(_: @escaping (Result<DropboxMetadata?, Error>) -> Void) {} - - public func authorize(presenting: UIViewController) -> AnyPublisher<Result<Bool, Error>, Never> { fatalError() } -} diff --git a/Sources/DropboxFeature/Resources/Dropbox-Keys.plist b/Sources/DropboxFeature/Resources/Dropbox-Keys.plist deleted file mode 100644 index 5348e76e769e5604dfacdb05e1cd396bbb39a15b..0000000000000000000000000000000000000000 --- a/Sources/DropboxFeature/Resources/Dropbox-Keys.plist +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>DROPBOX_APP_KEY</key> - <string>ppx0de5f16p9aq2</string> -</dict> -</plist> diff --git a/Sources/GoogleDriveFeature/GoogleDriveInterface.swift b/Sources/GoogleDriveFeature/GoogleDriveInterface.swift deleted file mode 100644 index c6710b8610fc9081e211fe0363f10f40584ea0e6..0000000000000000000000000000000000000000 --- a/Sources/GoogleDriveFeature/GoogleDriveInterface.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit - -public protocol GoogleDriveInterface { - func isAuthorized(_: @escaping (Bool) -> Void) - - func downloadMetadata(_: @escaping (Result<GoogleDriveMetadata?, Error>) -> Void) - - func uploadBackup(_: URL, _: @escaping (Result<GoogleDriveMetadata, Error>) -> Void) - - func authorize(presenting: UIViewController, _: @escaping (Result<Void, Error>) -> Void) - - func downloadBackup(_: String, progressCallback: @escaping (Float) -> Void, _: @escaping (Result<Data, Error>) -> Void) -} diff --git a/Sources/GoogleDriveFeature/GoogleDriveMetadata.swift b/Sources/GoogleDriveFeature/GoogleDriveMetadata.swift deleted file mode 100644 index f4179db86b943af99a0eaacdcae32ea987bdd73f..0000000000000000000000000000000000000000 --- a/Sources/GoogleDriveFeature/GoogleDriveMetadata.swift +++ /dev/null @@ -1,27 +0,0 @@ -import GoogleAPIClientForREST_Drive - -public struct GoogleDriveMetadata: Equatable { - public var size: Float - public var identifier: String - public var modifiedDate: Date - - public init( - size: Float, - identifier: String, - modifiedDate: Date - ) { - self.size = size - self.identifier = identifier - self.modifiedDate = modifiedDate - } -} - -extension GoogleDriveMetadata { - init?(withDriveFile file: GTLRDrive_File) { - guard let size = file.size?.floatValue, - let identifier = file.identifier, - let modifiedDate = file.modifiedTime?.date else { return nil } - - self.init(size: size, identifier: identifier, modifiedDate: modifiedDate) - } -} diff --git a/Sources/GoogleDriveFeature/GoogleDriveService.swift b/Sources/GoogleDriveFeature/GoogleDriveService.swift deleted file mode 100644 index 4ae4ac7457058d11ab3777cd71a4e8843f33458c..0000000000000000000000000000000000000000 --- a/Sources/GoogleDriveFeature/GoogleDriveService.swift +++ /dev/null @@ -1,335 +0,0 @@ -import UIKit -import GoogleSignIn -import GTMSessionFetcherFull -import GTMSessionFetcherCore -import GoogleAPIClientForREST_Drive - -public final class GoogleDriveService: GoogleDriveInterface { - private static let scopeFile = "https://www.googleapis.com/auth/drive.file" - private static let scopeAppData = "https://www.googleapis.com/auth/drive.appdata" - - var user: GIDGoogleUser? - - let service: GTLRDriveService = { - let service = GTLRDriveService() - - let path = Bundle.module.path(forResource: "GoogleDrive-Keys", ofType: "plist") - let url = URL(fileURLWithPath: path!) - let keys = try! NSDictionary(contentsOf: url, error: ()) - - service.apiKey = keys["DRIVE_API_KEY"] as? String - return service - }() - - public init() {} - - public func isAuthorized(_ completion: @escaping (Bool) -> Void) { - guard GIDSignIn.sharedInstance.hasPreviousSignIn() else { - return completion(false) - } - - GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in - guard let user = user, let scopes = user.grantedScopes, error == nil else { - return completion(false) - } - - self.user = user - self.service.authorizer = user.authentication.fetcherAuthorizer() - completion(scopes.contains(GoogleDriveService.scopeFile) && scopes.contains(GoogleDriveService.scopeAppData)) - } - } - - public func authorize( - presenting controller: UIViewController, - _ completion: @escaping (Result<Void, Error>) -> Void - ) { - GIDSignIn.sharedInstance.restorePreviousSignIn { [weak self] user, error in - guard let self = self else { return } - - guard error == nil else { - self.signIn(presenting: controller) { - switch $0 { - case .success: - self.authorizeDrive(controller: controller, completion: completion) - case .failure(let error): - completion(.failure(error)) - } - } - - return - } - - guard let user = user else { fatalError() } - - self.user = user - self.service.authorizer = user.authentication.fetcherAuthorizer() - self.authorizeDrive(controller: controller, completion: completion) - } - } - - public func downloadMetadata(_ completion: @escaping (Result<GoogleDriveMetadata?, Error>) -> Void) { - Task { - do { - guard let folder = try await fetchFolder() else { - completion(.success(nil)) - return - } - - _ = try await listFiles(on: folder) - - let backup = try await fetchBackup(at: folder) - completion(.success(backup)) - } catch { - completion(.failure(error)) - } - } - } - - public func downloadBackup( - _ backup: String, - progressCallback: @escaping (Float) -> Void, - _ completion: @escaping (Result<Data, Error>) -> Void - ) { - let query = GTLRDriveQuery_FilesGet.queryForMedia(withFileId: backup) - service.executeQuery(query) { _, file, error in - guard error == nil else { - print("Error on line #\(#line): \(error!.localizedDescription)") - return completion(.failure(error!)) - } - - guard let data = (file as? GTLRDataObject)?.data else { - print("Error on line #\(#line)") - return completion(.failure(NSError())) - } - - completion(.success(data)) - } - } - - public func uploadBackup( - _ file: URL, - _ completion: @escaping (Result<GoogleDriveMetadata, Error>) -> Void - ) { - Task { - do { - var folder = try await fetchFolder() - if folder == nil { folder = try await createFolder() } - let metadata = try await uploadFile(file, to: folder!) - let listMetadata = try await listFiles(on: folder!) - try await cleanup(listMetadata) - completion(.success(metadata)) - } catch { - print("Error on line #\(#line): \(error.localizedDescription)") - completion(.failure(error)) - } - } - } -} - -extension GoogleDriveService { - private func authorizeDrive( - controller: UIViewController, - completion: @escaping (Result<Void, Error>) -> Void - ) { - if let user = user, - let scopes = user.grantedScopes, - scopes.contains(GoogleDriveService.scopeFile), - scopes.contains(GoogleDriveService.scopeAppData) { - return completion(.success(())) - } - - GIDSignIn.sharedInstance.addScopes( - [GoogleDriveService.scopeFile, GoogleDriveService.scopeAppData], - presenting: controller, callback: { user, error in - guard error == nil else { - print("Error on line #\(#line): \(error!.localizedDescription)") - return completion(.failure(error!)) - } - - guard let user = user else { fatalError() } - self.user = user - completion(.success(())) - } - ) - } - - private func signIn( - presenting controller: UIViewController, - completion: @escaping (Result<Void, Error>) -> Void - ) { - GIDSignIn.sharedInstance.signIn( - with: GIDConfiguration(clientID: "662236151640-30i07ubg6ukodg15u0bnpk322p030u3j.apps.googleusercontent.com"), - presenting: controller, - callback: { user, error in - guard error == nil else { - print("Error on line #\(#line): \(error!.localizedDescription)") - return completion(.failure(error!)) - } - - guard let user = user else { fatalError() } - - self.user = user - self.service.authorizer = user.authentication.fetcherAuthorizer() - completion(.success(())) - } - ) - } - - private func fetchFolder() async throws -> String? { - let query = GTLRDriveQuery_FilesList.query() - query.q = "mimeType = 'application/vnd.google-apps.folder' and name = 'backup'" - query.spaces = "appDataFolder" - query.fields = "nextPageToken, files(id, name)" - - return try await withCheckedThrowingContinuation { continuation in - service.executeQuery(query) { _, result, error in - if let error = error { - print("Error on line #\(#line): \(error.localizedDescription)") - continuation.resume(throwing: error) - return - } - - let item = (result as? GTLRDrive_FileList)?.files?.first - continuation.resume(returning: item?.identifier) - } - } - } - - private func fetchBackup(at folder: String) async throws -> GoogleDriveMetadata? { - let query = GTLRDriveQuery_FilesList.query() - query.q = "'\(folder)' in parents and name = 'backup.xxm'" - query.spaces = "appDataFolder" - query.fields = "nextPageToken, files(id, size, name, modifiedTime)" - - return try await withCheckedThrowingContinuation { continuation in - service.executeQuery(query) { _, result, error in - if let error = error { - print("Error on line #\(#line): \(error.localizedDescription)") - continuation.resume(throwing: error) - return - } - - var metadata: GoogleDriveMetadata? = nil - - if let file = (result as? GTLRDrive_FileList)?.files?.first, - let size = file.size, - let id = file.identifier, - let date = file.modifiedTime?.date { - metadata = GoogleDriveMetadata(size: size.floatValue, identifier: id, modifiedDate: date) - } - - continuation.resume(returning: metadata) - } - } - } - - private func createFolder() async throws -> String { - let file = GTLRDrive_File() - file.name = "backup" - file.parents = ["appDataFolder"] - file.mimeType = "application/vnd.google-apps.folder" - - let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: nil) - - return try await withCheckedThrowingContinuation { continuation in - service.executeQuery(query) { _, result, error in - if let error = error { - print("Error on line #\(#line): \(error.localizedDescription)") - continuation.resume(throwing: error) - return - } - - guard let identifier = (result as? GTLRDrive_File)?.identifier else { - let errorTitle = "Couldn't create backup folder but no error was passed (?)" - let error = NSError(domain: errorTitle, code: 0, userInfo: [NSLocalizedDescriptionKey: errorTitle]) - print("Error on line #\(#line): \(error.localizedDescription)") - continuation.resume(throwing: error) - return - } - - continuation.resume(returning: identifier) - } - } - } - - private func uploadFile( - _ fileURL: URL, - to folder: String - ) async throws -> GoogleDriveMetadata { - - let file = GTLRDrive_File() - file.name = "backup.xxm" - file.parents = [folder] - file.mimeType = "application/octet-stream" - - let params = GTLRUploadParameters(fileURL: fileURL, mimeType: file.mimeType!) - let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: params) - query.fields = "id, size, modifiedTime" - - return try await withCheckedThrowingContinuation { continuation in - service.executeQuery(query) { _, result, error in - if let error = error { - print("Error on line #\(#line): \(error.localizedDescription)") - continuation.resume(throwing: error) - return - } - - guard let driveFile = (result as? GTLRDrive_File), - let size = driveFile.size, - let id = driveFile.identifier, - let date = driveFile.modifiedTime?.date else { - let errorTitle = "Couldn't upload file but no error was passed (?)" - let error = NSError(domain: errorTitle, code: 0, userInfo: [NSLocalizedDescriptionKey: errorTitle]) - print("Error on line #\(#line): \(error.localizedDescription)") - continuation.resume(throwing: error) - return - } - - continuation.resume(returning: .init(size: size.floatValue, identifier: id, modifiedDate: date)) - } - } - } - - private func listFiles(on folder: String) async throws -> [GoogleDriveMetadata] { - let query = GTLRDriveQuery_FilesList.query() - query.q = "'\(folder)' in parents" - query.spaces = "appDataFolder" - query.fields = "nextPageToken, files(id, modifiedTime, size, name)" - - return try await withCheckedThrowingContinuation { continuation in - service.executeQuery(query) { _, result, error in - if let error = error { - print("Error on line #\(#line): \(error.localizedDescription)") - continuation.resume(throwing: error) - return - } - - guard let files = (result as? GTLRDrive_FileList)?.files else { - continuation.resume(returning: []) - return - } - - let metadataList = files.compactMap(GoogleDriveMetadata.init(withDriveFile:)) - continuation.resume(returning: metadataList) - } - } - } - - private func cleanup(_ files: [GoogleDriveMetadata]) async throws { - let latestBackup = files.max { $0.modifiedDate < $1.modifiedDate } - let identifiers = files.filter { $0 != latestBackup }.map(\.identifier) - let query = GTLRBatchQuery(queries: identifiers.map(GTLRDriveQuery_FilesDelete.query(withFileId:))) - - return try await withCheckedThrowingContinuation { continuation in - service.executeQuery(query) { _, _, error in - if let error = error { - print("Error on line #\(#line): \(error.localizedDescription)") - continuation.resume(throwing: error) - return - } - - continuation.resume(returning: ()) - } - } - } -} diff --git a/Sources/GoogleDriveFeature/GoogleDriveServiceMock.swift b/Sources/GoogleDriveFeature/GoogleDriveServiceMock.swift deleted file mode 100644 index cf7625355cbc778fca29eb245586079b1601db6f..0000000000000000000000000000000000000000 --- a/Sources/GoogleDriveFeature/GoogleDriveServiceMock.swift +++ /dev/null @@ -1,40 +0,0 @@ -import UIKit - -public final class GoogleDriveServiceMock: GoogleDriveInterface { - public init() {} - - public func isAuthorized(_ completion: @escaping (Bool) -> Void) { - completion(true) - } - - public func uploadBackup(_: URL, _ completion: @escaping (Result<GoogleDriveMetadata, Error>) -> Void) { - completion(.success(.init(size: 23.toBytes(), identifier: "", modifiedDate: Date()))) - } - - public func downloadMetadata(_ completion: @escaping (Result<GoogleDriveMetadata?, Error>) -> Void) { - completion(.success(.init(size: 23.toBytes(), identifier: "", modifiedDate: Date()))) - } - - public func authorize(presenting: UIViewController, _ completion: @escaping (Result<Void, Error>) -> Void) { - completion(.success(())) - } - - public func downloadBackup( - _: String, - progressCallback: @escaping (Float) -> Void, - _ completion: @escaping (Result<Data, Error>) -> Void - ) { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { progressCallback(3.toBytes()) } - DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { progressCallback(7.toBytes()) } - DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) { progressCallback(12.toBytes()) } - DispatchQueue.main.asyncAfter(deadline: .now() + 1.2) { progressCallback(15.toBytes()) } - DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { progressCallback(16.toBytes()) } - DispatchQueue.main.asyncAfter(deadline: .now() + 1.8) { progressCallback(19.toBytes()) } - DispatchQueue.main.asyncAfter(deadline: .now() + 2.1) { progressCallback(22.toBytes()) } - DispatchQueue.main.asyncAfter(deadline: .now() + 2.4) { completion(.success(Data())) } - } -} - -private extension Int { - func toBytes() -> Float { Float(self) * 1000000.0 } -} diff --git a/Sources/GoogleDriveFeature/Resources/GoogleDrive-Keys.plist b/Sources/GoogleDriveFeature/Resources/GoogleDrive-Keys.plist deleted file mode 100644 index d25a7ec0e57eaa6ec8785dd599263d2ef82ae613..0000000000000000000000000000000000000000 --- a/Sources/GoogleDriveFeature/Resources/GoogleDrive-Keys.plist +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>DRIVE_API_KEY</key> - <string>AIzaSyCbI2yQ7pbuVSRvraqanjGcS9CDrjD7lNU</string> -</dict> -</plist> diff --git a/Sources/LaunchFeature/LaunchViewModel.swift b/Sources/LaunchFeature/LaunchViewModel.swift index 79fafead16257f18d3310e00891ad76b14cb59d9..4ac8d1bfa793b4b4fa9854de283f62dec0770ccc 100644 --- a/Sources/LaunchFeature/LaunchViewModel.swift +++ b/Sources/LaunchFeature/LaunchViewModel.swift @@ -10,7 +10,6 @@ import Foundation import Permissions import ToastFeature import BackupFeature -import DropboxFeature import VersionChecking import ReportingFeature import CombineSchedulers diff --git a/Sources/RestoreFeature/ViewModels/RestoreListViewModel.swift b/Sources/RestoreFeature/ViewModels/RestoreListViewModel.swift index e02adb2dbabc0d2e112446f02654a6820025011b..a8bc39c3a3f3fa106d9500044b8091813e1baeff 100644 --- a/Sources/RestoreFeature/ViewModels/RestoreListViewModel.swift +++ b/Sources/RestoreFeature/ViewModels/RestoreListViewModel.swift @@ -6,11 +6,6 @@ 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 diff --git a/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift b/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift index bbf4daa2d9b4c714c763ffa7f8ab981139110125..d28bb3e6574f0fda353fe24fccc23cf3d1e65d91 100644 --- a/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift +++ b/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift @@ -7,11 +7,6 @@ import Foundation import BackupFeature import DependencyInjection -import SFTPFeature -import iCloudFeature -import DropboxFeature -import GoogleDriveFeature - import XXModels import XXDatabase diff --git a/Sources/SFTPFeature/ActionHandlers/SFTPAuthenticator.swift b/Sources/SFTPFeature/ActionHandlers/SFTPAuthenticator.swift deleted file mode 100644 index 6693ac08eedb5f9ce86212614a8a2a0eb4eccfa0..0000000000000000000000000000000000000000 --- a/Sources/SFTPFeature/ActionHandlers/SFTPAuthenticator.swift +++ /dev/null @@ -1,54 +0,0 @@ -import Shout -import Socket -import Keychain -import Foundation -import DependencyInjection - -public struct SFTPAuthenticator { - public var authenticate: (String, String, String) throws -> Void - - public func callAsFunction(host: String, username: String, password: String) throws { - try authenticate(host, username, password) - } -} - -extension SFTPAuthenticator { - static let mock = SFTPAuthenticator { host, username, password in - print("^^^ Requested authentication on sftp service.") - print("^^^ Host: \(host)") - print("^^^ Username: \(username)") - print("^^^ Password: \(password)") - } - - static let live = SFTPAuthenticator { host, username, password in - do { - try SSH.connect( - host: host, - port: 22, - username: username, - authMethod: SSHPassword(password)) { ssh in - _ = try ssh.openSftp() - - let keychain = try DependencyInjection.Container.shared.resolve() as KeychainHandling - try keychain.store(key: .host, value: host) - try keychain.store(key: .pwd, value: password) - try keychain.store(key: .username, value: username) - } - } catch { - if let error = error as? SSHError { - print(error.kind) - print(error.message) - print(error.description) - } else if let error = error as? Socket.Error { - print(error.errorCode) - print(error.description) - print(error.errorReason ?? "No error reason available") - print(error.localizedDescription) - } else { - print(error.localizedDescription) - } - - throw error - } - } -} diff --git a/Sources/SFTPFeature/ActionHandlers/SFTPDownloader.swift b/Sources/SFTPFeature/ActionHandlers/SFTPDownloader.swift deleted file mode 100644 index 6a435df0051a2755f2fb73522f7be92a24c4dd77..0000000000000000000000000000000000000000 --- a/Sources/SFTPFeature/ActionHandlers/SFTPDownloader.swift +++ /dev/null @@ -1,56 +0,0 @@ -import Shout -import Socket -import Keychain -import Foundation -import DependencyInjection - -public typealias SFTPDownloadResult = (Result<Data, Error>) -> Void - -public struct SFTPDownloader { - public var download: (String, @escaping SFTPDownloadResult) -> Void - - public func callAsFunction(path: String, completion: @escaping SFTPDownloadResult) { - download(path, completion) - } -} - -extension SFTPDownloader { - static let mock = SFTPDownloader { path, _ in - print("^^^ Requested backup download on sftp service.") - print("^^^ Path: \(path)") - } - - static let live = SFTPDownloader { path, completion in - DispatchQueue.global().async { - do { - let keychain = try DependencyInjection.Container.shared.resolve() as KeychainHandling - let host = try keychain.get(key: .host) - let password = try keychain.get(key: .pwd) - let username = try keychain.get(key: .username) - - let ssh = try SSH(host: host!, port: 22) - try ssh.authenticate(username: username!, password: password!) - let sftp = try ssh.openSftp() - - let localURL = FileManager.default - .containerURL(forSecurityApplicationGroupIdentifier: "group.elixxir.messenger")! - .appendingPathComponent("sftp") - - try sftp.download(remotePath: path, localURL: localURL) - - let data = try Data(contentsOf: localURL) - completion(.success(data)) - } catch { - completion(.failure(error)) - - if var error = error as? SSHError { - print(error.kind) - print(error.message) - print(error.description) - } else { - print(error.localizedDescription) - } - } - } - } -} diff --git a/Sources/SFTPFeature/ActionHandlers/SFTPFetcher.swift b/Sources/SFTPFeature/ActionHandlers/SFTPFetcher.swift deleted file mode 100644 index 0c30331bae777cd08cb255af0e8d3fc1f21f940a..0000000000000000000000000000000000000000 --- a/Sources/SFTPFeature/ActionHandlers/SFTPFetcher.swift +++ /dev/null @@ -1,68 +0,0 @@ -import Shout -import Socket -import Models -import Keychain -import Foundation -import DependencyInjection - -public typealias SFTPFetchResult = (Result<RestoreSettings?, Error>) -> Void - -public struct SFTPFetcher { - public var fetch: (@escaping SFTPFetchResult) -> Void - - public func callAsFunction(completion: @escaping SFTPFetchResult) { - fetch(completion) - } -} - -extension SFTPFetcher { - static let mock = SFTPFetcher { _ in - print("^^^ Requested backup metadata on sftp service.") - } - - static let live = SFTPFetcher { completion in - DispatchQueue.global().async { - do { - let keychain = try DependencyInjection.Container.shared.resolve() as KeychainHandling - let host = try keychain.get(key: .host) - let password = try keychain.get(key: .pwd) - let username = try keychain.get(key: .username) - - let ssh = try SSH(host: host!, port: 22) - try ssh.authenticate(username: username!, password: password!) - let sftp = try ssh.openSftp() - - if let files = try? sftp.listFiles(in: "backup"), - let backup = files.filter({ file in file.0 == "backup.xxm" }).first { - completion(.success(.init( - backup: .init( - id: "backup/backup.xxm", - date: backup.value.lastModified, - size: Float(backup.value.size) - ), - cloudService: .sftp - ))) - - return - } - - completion(.success(nil)) - } catch { - if let error = error as? SSHError { - print(error.kind) - print(error.message) - print(error.description) - } else if let error = error as? Socket.Error { - print(error.errorCode) - print(error.description) - print(error.errorReason ?? "No error reason available") - print(error.localizedDescription) - } else { - print(error.localizedDescription) - } - - completion(.failure(error)) - } - } - } -} diff --git a/Sources/SFTPFeature/ActionHandlers/SFTPUploader.swift b/Sources/SFTPFeature/ActionHandlers/SFTPUploader.swift deleted file mode 100644 index 4217d83793f239e03460e466e4f0f0981c38580f..0000000000000000000000000000000000000000 --- a/Sources/SFTPFeature/ActionHandlers/SFTPUploader.swift +++ /dev/null @@ -1,69 +0,0 @@ -import Shout -import Socket -import Models -import Keychain -import Foundation -import DependencyInjection - -public typealias SFTPUploadResult = (Result<BackupModel, Error>) -> Void - -public struct SFTPUploader { - public var upload: (URL, @escaping SFTPUploadResult) -> Void - - public func callAsFunction(url: URL, completion: @escaping SFTPUploadResult) { - upload(url, completion) - } -} - -extension SFTPUploader { - static let mock = SFTPUploader( - upload: { url, _ in - print("^^^ Requested upload on sftp service") - print("^^^ URL path: \(url.path)") - } - ) - - static let live = SFTPUploader { url, completion in - DispatchQueue.global().async { - do { - let keychain = try DependencyInjection.Container.shared.resolve() as KeychainHandling - let host = try keychain.get(key: .host) - let password = try keychain.get(key: .pwd) - let username = try keychain.get(key: .username) - - let ssh = try SSH(host: host!, port: 22) - try ssh.authenticate(username: username!, password: password!) - let sftp = try ssh.openSftp() - - let data = try Data(contentsOf: url) - - if (try? sftp.listFiles(in: "backup")) == nil { - try sftp.createDirectory("backup") - } - - try sftp.upload(data: data, remotePath: "backup/backup.xxm") - - completion(.success(.init( - id: "backup/backup.xxm", - date: Date(), - size: Float(data.count) - ))) - } catch { - if let error = error as? SSHError { - print(error.kind) - print(error.message) - print(error.description) - } else if let error = error as? Socket.Error { - print(error.errorCode) - print(error.description) - print(error.errorReason ?? "No error reason available") - print(error.localizedDescription) - } else { - print(error.localizedDescription) - } - - completion(.failure(error)) - } - } - } -} diff --git a/Sources/SFTPFeature/SFTPController.swift b/Sources/SFTPFeature/SFTPController.swift deleted file mode 100644 index 21bf8ca1f224ad3b5439d619fbd27025a2a96295..0000000000000000000000000000000000000000 --- a/Sources/SFTPFeature/SFTPController.swift +++ /dev/null @@ -1,86 +0,0 @@ -import HUD -import UIKit -import Combine -import DependencyInjection -import ScrollViewController - -public final class SFTPController: UIViewController { - @Dependency private var hud: HUD - - lazy private var screenView = SFTPView() - lazy private var scrollViewController = ScrollViewController() - - private let completion: () -> Void - private let viewModel = SFTPViewModel() - private var cancellables = Set<AnyCancellable>() - - public init(_ completion: @escaping () -> Void) { - self.completion = completion - super.init(nibName: nil, bundle: nil) - } - - required init?(coder: NSCoder) { nil } - - public override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - navigationItem.backButtonTitle = "" - navigationController?.navigationBar.customize(translucent: true) - } - - public override func viewDidLoad() { - super.viewDidLoad() - setupScrollView() - setupBindings() - } - - private func setupScrollView() { - scrollViewController.scrollView.backgroundColor = .white - - addChild(scrollViewController) - view.addSubview(scrollViewController.view) - scrollViewController.view.snp.makeConstraints { $0.edges.equalToSuperview() } - scrollViewController.didMove(toParent: self) - scrollViewController.contentView = screenView - } - - private func setupBindings() { - viewModel.hudPublisher - .receive(on: DispatchQueue.main) - .sink { [hud] in hud.update(with: $0) } - .store(in: &cancellables) - - viewModel.authPublisher - .receive(on: DispatchQueue.main) - .sink { [unowned self] in completion() } - .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) - } -} diff --git a/Sources/SFTPFeature/SFTPService.swift b/Sources/SFTPFeature/SFTPService.swift deleted file mode 100644 index f1a908564df810ed2aeaa1b4af358b367253f84b..0000000000000000000000000000000000000000 --- a/Sources/SFTPFeature/SFTPService.swift +++ /dev/null @@ -1,47 +0,0 @@ -import UIKit -import Keychain -import Presentation -import DependencyInjection - -public typealias SFTPAuthorizationParams = (UIViewController, () -> Void) - -public struct SFTPService { - public var isAuthorized: () -> Bool - public var fetchMetadata: SFTPFetcher - public var uploadBackup: SFTPUploader - public var authorizeFlow: (SFTPAuthorizationParams) -> Void - public var authenticate: SFTPAuthenticator - public var downloadBackup: SFTPDownloader -} - -public extension SFTPService { - static var mock = SFTPService( - isAuthorized: { true }, - fetchMetadata: .mock, - uploadBackup: .mock, - authorizeFlow: { (_, completion) in completion() }, - authenticate: .mock, - downloadBackup: .mock - ) - - static var live = SFTPService( - isAuthorized: { - if let keychain = try? DependencyInjection.Container.shared.resolve() as KeychainHandling, - let pwd = try? keychain.get(key: .pwd), - let host = try? keychain.get(key: .host), - let username = try? keychain.get(key: .username) { - return true - } - - return false - }, - fetchMetadata: .live, - uploadBackup: .live , - authorizeFlow: { controller, completion in - var pushPresenter: Presenting = PushPresenter() - pushPresenter.present(SFTPController(completion), from: controller) - }, - authenticate: .live, - downloadBackup: .live - ) -} diff --git a/Sources/SFTPFeature/SFTPView.swift b/Sources/SFTPFeature/SFTPView.swift deleted file mode 100644 index 5653d85bacd6c112d737217dfdb9c8312c631de4..0000000000000000000000000000000000000000 --- a/Sources/SFTPFeature/SFTPView.swift +++ /dev/null @@ -1,83 +0,0 @@ -import UIKit -import Shared -import InputField - -final class SFTPView: 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 = NSMutableAttributedString( - string: Localized.AccountRestore.Sftp.subtitle, - attributes: [ - .foregroundColor: Asset.neutralBody.color, - .font: Fonts.Mulish.regular.font(size: 16.0) as Any, - .paragraphStyle: paragraph - ]) - - attString.setAttributes( - attributes: [ - .foregroundColor: Asset.neutralDark.color, - .font: Fonts.Mulish.bold.font(size: 12.0) as Any, - .paragraphStyle: paragraph - ], betweenCharacters: "*") - - 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/SFTPViewModel.swift b/Sources/SFTPFeature/SFTPViewModel.swift deleted file mode 100644 index e64536bfd96277642d25ddb13f5c81570836a22b..0000000000000000000000000000000000000000 --- a/Sources/SFTPFeature/SFTPViewModel.swift +++ /dev/null @@ -1,77 +0,0 @@ -import HUD -import Combine -import Foundation -import DependencyInjection - -struct SFTPViewState { - var host: String = "" - var username: String = "" - var password: String = "" - var isButtonEnabled: Bool = false -} - -final class SFTPViewModel { - @Dependency private var service: SFTPService - - var hudPublisher: AnyPublisher<HUDStatus, Never> { - hudSubject.eraseToAnyPublisher() - } - - var statePublisher: AnyPublisher<SFTPViewState, Never> { - stateSubject.eraseToAnyPublisher() - } - - var authPublisher: AnyPublisher<Void, Never> { - authSubject.eraseToAnyPublisher() - } - - private let authSubject = PassthroughSubject<Void, Never>() - private let hudSubject = CurrentValueSubject<HUDStatus, Never>(.none) - 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() { - hudSubject.send(.on) - - let host = stateSubject.value.host - let username = stateSubject.value.username - let password = stateSubject.value.password - - DispatchQueue.global().async { [weak self] in - guard let self = self else { return } - do { - try self.service.authenticate( - host: host, - username: username, - password: password - ) - - self.hudSubject.send(.none) - self.authSubject.send(()) - } catch { - self.hudSubject.send(.error(.init(with: error))) - } - } - } - - private func validate() { - stateSubject.value.isButtonEnabled = - !stateSubject.value.host.isEmpty && - !stateSubject.value.username.isEmpty && - !stateSubject.value.password.isEmpty - } -} diff --git a/Sources/iCloudFeature/iCloudInterface.swift b/Sources/iCloudFeature/iCloudInterface.swift deleted file mode 100644 index 41b3153667013967f53fab9eb01d95a99293297c..0000000000000000000000000000000000000000 --- a/Sources/iCloudFeature/iCloudInterface.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Foundation - -public protocol iCloudInterface { - func openSettings() - - func isAuthorized() -> Bool - - func downloadMetadata(_: @escaping (Result<iCloudMetadata?, Error>) -> Void) - - func uploadBackup(_: URL, _: @escaping (Result<iCloudMetadata, Error>) -> Void) - - func downloadBackup(_: String, _: @escaping (Result<Data, Error>) -> Void) -} diff --git a/Sources/iCloudFeature/iCloudMetadata.swift b/Sources/iCloudFeature/iCloudMetadata.swift deleted file mode 100644 index 9aa70514badbef94033ec24bc965f49b23567e21..0000000000000000000000000000000000000000 --- a/Sources/iCloudFeature/iCloudMetadata.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -public struct iCloudMetadata: Equatable { - public var size: Float - public var path: String - public var modifiedDate: Date - - public init( - path: String, - size: Float, - modifiedDate: Date - ) { - self.path = path - self.size = size - self.modifiedDate = modifiedDate - } -} diff --git a/Sources/iCloudFeature/iCloudService.swift b/Sources/iCloudFeature/iCloudService.swift deleted file mode 100644 index 9c804211e759b7901af2f2917e8d071d9de2ffa2..0000000000000000000000000000000000000000 --- a/Sources/iCloudFeature/iCloudService.swift +++ /dev/null @@ -1,89 +0,0 @@ -import UIKit -import FilesProvider - -public struct iCloudService: iCloudInterface { - private let documentsProvider = CloudFileProvider(containerId: "iCloud.xxm-cloud", scope: .data) - - public init() {} - - public func isAuthorized() -> Bool { - FileManager.default.ubiquityIdentityToken != nil - } - - public func openSettings() { - if let url = URL(string: "App-Prefs:root=CASTLE"), UIApplication.shared.canOpenURL(url) { - UIApplication.shared.open(url, options: [:], completionHandler: nil) - } - } - - public func downloadMetadata(_ completion: @escaping (Result<iCloudMetadata?, Error>) -> Void) { - guard let documentsProvider = documentsProvider else { - fatalError("ICloud wasn't set properly, force crashed due to lack of fallback") - } - - documentsProvider.contentsOfDirectory(path: "/", completionHandler: { contents, error in - guard error == nil else { - print(">>> [iCloud] downloadMetadata got error: \(error!.localizedDescription)") - completion(.failure(error!)) - return - } - - print(contents) - - if let file = contents.first(where: { $0.name == "backup.xxm" }) { - completion(.success(.init( - path: file.path, - size: Float(file.size), - modifiedDate: file.modifiedDate! - ))) - } else { - completion(.success(nil)) - } - }) - } - - public func uploadBackup(_ url: URL, _ completion: @escaping (Result<iCloudMetadata, Error>) -> Void) { - guard let documentsProvider = documentsProvider else { fatalError() } - - do { - let data = try Data(contentsOf: url) - - documentsProvider.writeContents(path: "backup.xxm", contents: data, overwrite: true) { error in - guard error == nil else { - print(">>> [iCloud] uploadBackup got error: \(error!.localizedDescription)") - completion(.failure(error!)) - return - } - - completion(.success(.init( - path: "backup.xxm", - size: Float(data.count), - modifiedDate: Date() - ))) - } - } catch { - completion(.failure(error)) - } - } - - public func downloadBackup( - _ path: String, - _ completion: @escaping (Result<Data, Error>) -> Void - ) { - guard let documentsProvider = documentsProvider else { fatalError() } - - documentsProvider.contents(path: path, completionHandler: { contents, error in - guard error == nil else { - print(">>> [iCloud] downloadBackup got error: \(error!.localizedDescription)") - completion(.failure(error!)) - return - } - - if let contents = contents { - completion(.success(contents)) - } else { - completion(.failure(NSError(domain: "Backup file is invalid", code: 0))) - } - }) - } -} diff --git a/Sources/iCloudFeature/iCloudServiceMock.swift b/Sources/iCloudFeature/iCloudServiceMock.swift deleted file mode 100644 index f0bcfca66108e297f5d04de4fb3e5dc0705ae097..0000000000000000000000000000000000000000 --- a/Sources/iCloudFeature/iCloudServiceMock.swift +++ /dev/null @@ -1,39 +0,0 @@ -import Foundation - -public struct iCloudServiceMock: iCloudInterface { - public init() { - // TODO - } - - public func openSettings() { - // TODO - } - - public func isAuthorized() -> Bool { - true - } - - public func downloadBackup( - _: String, - _: @escaping (Result<Data, Error>) -> Void - ) { - // TODO - } - - public func uploadBackup( - _: URL, - _: @escaping (Result<iCloudMetadata, Error>) -> Void - ) { - // TODO - } - - public func downloadMetadata( - _ completion: @escaping (Result<iCloudMetadata?, Error>) -> Void - ) { - completion(.success(.init( - path: "/", - size: 1230000000.0, - modifiedDate: Date() - ))) - } -} diff --git a/client-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved b/client-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved index b1639bc2fd1a68e6e0ac6a9ed6ba62404e56b029..3bca0daa0ddbe040fcc9e4f097dbcc15e01def8b 100644 --- a/client-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/client-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -122,8 +122,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/google-api-objectivec-client-for-rest", "state" : { - "revision" : "3228334d0584cb9174796fecbe628a723be70452", - "version" : "1.7.0" + "revision" : "0078161fcc2900ca06213a192bdfa5ece8ee58f1", + "version" : "2.0.1" } }, { @@ -341,6 +341,15 @@ "version" : "0.4.1" } }, + { + "identity" : "swift-log", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-log.git", + "state" : { + "revision" : "6fe203dc33195667ce1759bf0182975e4653ba1c", + "version" : "1.4.4" + } + }, { "identity" : "swift-protobuf", "kind" : "remoteSourceControl", @@ -373,8 +382,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/dropbox/SwiftyDropbox.git", "state" : { - "revision" : "9df3d4997127f1f17ed295e5f373ab676419df08", - "version" : "8.3.0" + "revision" : "ff2da46242267837818b40ea1062a045840bc944", + "version" : "9.1.0" } }, {