From 2aee3365897ef12b758384c5d75d2214913df861 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 9 May 2024 13:06:45 -0300 Subject: [PATCH 001/167] implementing google sdk --- Podfile | 1 + Tella.xcodeproj/project.pbxproj | 36 +++++++++++++++++-- Tella/Application/TellaApp.swift | 8 +++++ .../Views/Servers/ServerSelectionView.swift | 28 ++++++++++++++- Tella/Supporting Files/Info.plist | 15 ++++++++ 5 files changed, 85 insertions(+), 3 deletions(-) diff --git a/Podfile b/Podfile index 2aebf0363..21a8ce69f 100644 --- a/Podfile +++ b/Podfile @@ -9,6 +9,7 @@ target 'Tella' do pod 'SQLCipher', ">= 4.5.2" pod 'ZIPFoundation' pod 'Mantis', '~> 2.21.0' + pod 'GoogleSignIn' target 'TellaTests' do inherit! :search_paths diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 349f2ac53..5ed05a1e3 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -2989,6 +2989,40 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 11819532921BA895BF7C12D0 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 1ADB16E63DE3CFDCE1776489 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 36C5FA1BF18AC473E32B7C1A /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -3884,7 +3918,6 @@ CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = 6ZG9T42688; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 6ZG9T42688; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = "Tella/Supporting Files/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -3896,7 +3929,6 @@ PRODUCT_BUNDLE_IDENTIFIER = org.wearehorizontal.tella; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Tella (AppStore)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; }; diff --git a/Tella/Application/TellaApp.swift b/Tella/Application/TellaApp.swift index eed499db7..e8bea91ff 100644 --- a/Tella/Application/TellaApp.swift +++ b/Tella/Application/TellaApp.swift @@ -7,6 +7,7 @@ // import SwiftUI +import GoogleSignIn @main struct TellaApp: App { @@ -26,6 +27,13 @@ struct TellaApp: App { if value { self.saveData(lockApptype: .finishBackgroundTasks) } + }.onAppear { + GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in + dump(user) + } + }.onOpenURL { url in + dump(url) + GIDSignIn.sharedInstance.handle(url) } }.onChange(of: scenePhase) { phase in diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 14d3d7a83..3b350fbac 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -8,6 +8,8 @@ import SwiftUI +import GoogleSignIn + struct ServerSelectionView: View { @EnvironmentObject var serversViewModel : ServersViewModel @StateObject var serverViewModel : ServerViewModel @@ -33,7 +35,24 @@ struct ServerSelectionView: View { } } } - fileprivate func buttonViews() -> Group> { + + func handleSignInButton() { + guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { + print("There is no root view controller!") + return + } + + GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { signInResult, error in + if let error = error { + print("Error during Google Sign-In: \(error.localizedDescription)") + return + } + dump(signInResult) + } + } + + + fileprivate func buttonViews() -> Group> { return Group { TellaButtonView(title: LocalizableSettings.settServerTellaWeb.localized, nextButtonAction: .action, @@ -48,6 +67,13 @@ struct ServerSelectionView: View { isValid: .constant(true), action: { selectedServerType = .uwazi }).padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) + TellaButtonView(title: "GOOGLE DRIVE", + nextButtonAction: .action, +// isOverlay: selectedServerType == .uwazi, + isValid: .constant(true), action: { + handleSignInButton() + }).padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) +// GoogleSignInButton(action: handleSignInButton) } } diff --git a/Tella/Supporting Files/Info.plist b/Tella/Supporting Files/Info.plist index adeaa04e3..d4d55ea53 100644 --- a/Tella/Supporting Files/Info.plist +++ b/Tella/Supporting Files/Info.plist @@ -24,8 +24,23 @@ $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString $(MARKETING_VERSION) + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + googleDrive + CFBundleURLSchemes + + com.googleusercontent.apps.428441678272-3qafj3vp7njl6r3ohgi65m87lqe6mcc3 + + + CFBundleVersion $(CURRENT_PROJECT_VERSION) + GIDClientID + 428441678272-3qafj3vp7njl6r3ohgi65m87lqe6mcc3.apps.googleusercontent.com ITSAppUsesNonExemptEncryption LSApplicationCategoryType From 4db1ebe1aec22e533489a197467692734af6f6c1 Mon Sep 17 00:00:00 2001 From: Dhekra Rouatbi Date: Fri, 10 May 2024 10:44:12 +0100 Subject: [PATCH 002/167] Move dissmiss views to resetApp function --- Tella/Application/TellaApp.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tella/Application/TellaApp.swift b/Tella/Application/TellaApp.swift index e8bea91ff..ff2943f15 100644 --- a/Tella/Application/TellaApp.swift +++ b/Tella/Application/TellaApp.swift @@ -42,7 +42,6 @@ struct TellaApp: App { UIApplication.getTopViewController()?.dismiss(animated: false) self.saveData(lockApptype: .enterInBackground) case .active: - UIApplication.getTopViewController()?.dismiss(animated: false) self.resetApp() case .inactive: appViewState.homeViewModel.shouldShowSecurityScreen = true @@ -80,7 +79,8 @@ struct TellaApp: App { let shouldResetApp = appViewState.homeViewModel.shouldResetApp() if shouldResetApp && appEnterInBackground && !hasFileOnBackground { - + UIApplication.getTopViewController()?.dismiss(animated: false) + DispatchQueue.main.async { appViewState.shouldHidePresentedView = true appViewState.resetApp() From 1853d08d4361b8e12283fe9e380453077dc1de30 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 20 May 2024 16:47:51 -0300 Subject: [PATCH 003/167] add selected type of drive connection view --- Tella.xcodeproj/project.pbxproj | 12 +++ Tella/Domain/Entity/Report/ServerType.swift | 1 + .../gdrive.icon.imageset/Contents.json | 21 +++++ .../gdrive.icon.imageset/gdrive-icon.svg | 9 ++ .../GDrive/SelectDriveConnection.swift | 91 +++++++++++++++++++ .../Views/Servers/ServerSelectionView.swift | 20 ++-- 6 files changed, 145 insertions(+), 9 deletions(-) create mode 100644 Tella/NewAssets.xcassets/gdrive.icon.imageset/Contents.json create mode 100644 Tella/NewAssets.xcassets/gdrive.icon.imageset/gdrive-icon.svg create mode 100644 Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 5ed05a1e3..992c72638 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -368,6 +368,7 @@ 15BD9CB12BC744BC00C3932B /* NavigationHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CB02BC744BC00C3932B /* NavigationHeaderView.swift */; }; 15BD9CB32BC7472A00C3932B /* UwaziRelationshipDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CB22BC7472A00C3932B /* UwaziRelationshipDTO.swift */; }; 15CD89102BF297BE00F724F5 /* SelectedEntityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */; }; + 15994A0C2BFBC6F40017F153 /* SelectDriveConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */; }; 15EE30FE2B5073E20033BBBB /* Pages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15EE30FD2B5073E20033BBBB /* Pages.swift */; }; 15F64C9D2B6D7904008A57AA /* DownloadedResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */; }; 15F64CA02B6D794B008A57AA /* SectionTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */; }; @@ -910,6 +911,7 @@ 15BD9CB02BC744BC00C3932B /* NavigationHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationHeaderView.swift; sourceTree = ""; }; 15BD9CB22BC7472A00C3932B /* UwaziRelationshipDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziRelationshipDTO.swift; sourceTree = ""; }; 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedEntityView.swift; sourceTree = ""; }; + 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectDriveConnection.swift; sourceTree = ""; }; 15EE30FD2B5073E20033BBBB /* Pages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pages.swift; sourceTree = ""; }; 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResources.swift; sourceTree = ""; }; 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionTitle.swift; sourceTree = ""; }; @@ -1754,6 +1756,7 @@ 127B053F289C0A58008C047D /* Servers */ = { isa = PBXGroup; children = ( + 15994A0A2BFBC6B10017F153 /* GDrive */, 12ADF98A28BD130C00FA96EB /* ServersListView.swift */, 120451F928C7525200D572A7 /* EditSettingsServerView.swift */, E1EEE29529E6796E009FE227 /* ServerSelectionView.swift */, @@ -2277,6 +2280,14 @@ path = ViewModel; sourceTree = ""; }; + 15994A0A2BFBC6B10017F153 /* GDrive */ = { + isa = PBXGroup; + children = ( + 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */, + ); + path = GDrive; + sourceTree = ""; + }; 15F64C9B2B6D78D8008A57AA /* Views */ = { isa = PBXGroup; children = ( @@ -3514,6 +3525,7 @@ 12964D922BAB44C8003E1E0A /* UwaziEntityInstanceFile.swift in Sources */, 0DC267A6267AED7C00E55AFA /* VaultFile.swift in Sources */, 12751EAA2A13A22100FAD7C6 /* SettingsModel.swift in Sources */, + 15994A0C2BFBC6F40017F153 /* SelectDriveConnection.swift in Sources */, 1203CDDE298D7C1300D09073 /* FileToUpload.swift in Sources */, 1227FC912922BE24002FD6FB /* CameraPreview.swift in Sources */, 125A895B2A965BED009347C3 /* FilterType.swift in Sources */, diff --git a/Tella/Domain/Entity/Report/ServerType.swift b/Tella/Domain/Entity/Report/ServerType.swift index d20d1f36c..805bd856e 100644 --- a/Tella/Domain/Entity/Report/ServerType.swift +++ b/Tella/Domain/Entity/Report/ServerType.swift @@ -8,6 +8,7 @@ enum ServerConnectionType: Int, Codable { case tella = 0 case uwazi = 1 case odkCollect = 3 + case gDrive = 4 case unknown } diff --git a/Tella/NewAssets.xcassets/gdrive.icon.imageset/Contents.json b/Tella/NewAssets.xcassets/gdrive.icon.imageset/Contents.json new file mode 100644 index 000000000..ea90be336 --- /dev/null +++ b/Tella/NewAssets.xcassets/gdrive.icon.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "gdrive-icon.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Tella/NewAssets.xcassets/gdrive.icon.imageset/gdrive-icon.svg b/Tella/NewAssets.xcassets/gdrive.icon.imageset/gdrive-icon.svg new file mode 100644 index 000000000..92aea8581 --- /dev/null +++ b/Tella/NewAssets.xcassets/gdrive.icon.imageset/gdrive-icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift new file mode 100644 index 000000000..7240c161c --- /dev/null +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -0,0 +1,91 @@ +// +// SelectDriveConnection.swift +// Tella +// +// Created by gus valbuena on 5/20/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import SwiftUI +enum DriveConnectionType { + case shared + case personal + case none +} +struct SelectDriveConnection: View { + @State var selectedDriveConnectionType: DriveConnectionType = .none + var body: some View { + ContainerView { + VStack(spacing: 20) { + Spacer() + headerView + connectionsButtons + Spacer() + bottomView + }.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) + .toolbar { + LeadingTitleToolbar(title: "Select Google drive") + } + } + } + + var headerView: some View { + VStack(spacing: 20) { + Image("gdrive.icon") + Text("Select a Drive to connect to") + .font(.custom(Styles.Fonts.semiBoldFontName, size: 18)) + .foregroundColor(.white) + .multilineTextAlignment(.center) + Text("You can either connect to an organizational Shared Drive or create a new folder in your personal Drive.") + .font(.custom(Styles.Fonts.regularFontName, size: 14)) + .foregroundColor(.white) + .multilineTextAlignment(.center) + } + } + + var connectionsButtons: some View { + VStack { + TellaButtonView( + title: "USE SHARED DRIVE", + nextButtonAction: .action, + isOverlay: selectedDriveConnectionType == .shared, + isValid: .constant(true), + action: { selectedDriveConnectionType = .shared } + ).padding(.vertical, 5) + TellaButtonView( + title: "USE PERSONAL DRIVE", + nextButtonAction: .action, + isOverlay: selectedDriveConnectionType == .personal, + isValid: .constant(true), + action: {selectedDriveConnectionType = .personal} + ).padding(.vertical, 5) + Text("Learn more about the types of drives") + .font(.custom(Styles.Fonts.regularFontName, size: 14)) + .foregroundColor(Styles.Colors.yellow) + .multilineTextAlignment(.center) + .padding(.vertical, 5) + } + } + + var bottomView: some View { + BottomLockView(isValid: .constant(true), + nextButtonAction: .action, + shouldHideNext: selectedDriveConnectionType == .none, + shouldHideBack: false, + nextAction: { + switch selectedDriveConnectionType { + case .shared: + dump("shared") + case .personal: + dump("personal") + default: + break + } + }) + + } +} + +#Preview { + SelectDriveConnection(selectedDriveConnectionType: .personal) +} diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 3b350fbac..9f763379b 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -42,13 +42,16 @@ struct ServerSelectionView: View { return } - GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { signInResult, error in - if let error = error { - print("Error during Google Sign-In: \(error.localizedDescription)") - return - } - dump(signInResult) - } +// GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { signInResult, error in +// if let error = error { +// print("Error during Google Sign-In: \(error.localizedDescription)") +// return +// } else { +// dump(signInResult) +// navigateTo(destination: SelectDriveConnection(), title: "Select Google drive") +// } +// } + navigateTo(destination: SelectDriveConnection(), title: "Select Google drive") } @@ -69,11 +72,10 @@ struct ServerSelectionView: View { }).padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) TellaButtonView(title: "GOOGLE DRIVE", nextButtonAction: .action, -// isOverlay: selectedServerType == .uwazi, + isOverlay: selectedServerType == .gDrive, isValid: .constant(true), action: { handleSignInButton() }).padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) -// GoogleSignInButton(action: handleSignInButton) } } From 851aa054102c06c492e68519cc021f1f5687cc4e Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 21 May 2024 12:44:11 -0300 Subject: [PATCH 004/167] add SelectSharedDrive view --- Tella.xcodeproj/project.pbxproj | 17 ++++++++++ Tella/Domain/Entity/GDrive/SharedDrive.swift | 21 ++++++++++++ .../GDrive/SelectDriveConnection.swift | 2 +- .../Servers/GDrive/SelectSharedDrive.swift | 34 +++++++++++++++++++ .../Views/Servers/ServerSelectionView.swift | 2 +- 5 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 Tella/Domain/Entity/GDrive/SharedDrive.swift create mode 100644 Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 992c72638..0a1908cdd 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -369,6 +369,8 @@ 15BD9CB32BC7472A00C3932B /* UwaziRelationshipDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CB22BC7472A00C3932B /* UwaziRelationshipDTO.swift */; }; 15CD89102BF297BE00F724F5 /* SelectedEntityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */; }; 15994A0C2BFBC6F40017F153 /* SelectDriveConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */; }; + 15994A0E2BFBE15F0017F153 /* SelectSharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */; }; + 15994A112BFBF0E50017F153 /* SharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A102BFBF0E50017F153 /* SharedDrive.swift */; }; 15EE30FE2B5073E20033BBBB /* Pages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15EE30FD2B5073E20033BBBB /* Pages.swift */; }; 15F64C9D2B6D7904008A57AA /* DownloadedResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */; }; 15F64CA02B6D794B008A57AA /* SectionTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */; }; @@ -912,6 +914,8 @@ 15BD9CB22BC7472A00C3932B /* UwaziRelationshipDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziRelationshipDTO.swift; sourceTree = ""; }; 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedEntityView.swift; sourceTree = ""; }; 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectDriveConnection.swift; sourceTree = ""; }; + 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectSharedDrive.swift; sourceTree = ""; }; + 15994A102BFBF0E50017F153 /* SharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedDrive.swift; sourceTree = ""; }; 15EE30FD2B5073E20033BBBB /* Pages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pages.swift; sourceTree = ""; }; 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResources.swift; sourceTree = ""; }; 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionTitle.swift; sourceTree = ""; }; @@ -1424,6 +1428,7 @@ 1231A45B294C76990057DA85 /* Entity */ = { isa = PBXGroup; children = ( + 15994A0F2BFBF0C70017F153 /* GDrive */, 1519BED42B9A5A2B006FD290 /* Resource */, E18BD4312AA0C2EB00EE62E2 /* Uwazi */, E1975EE52AB032350060228F /* UwaziEntity */, @@ -2284,6 +2289,15 @@ isa = PBXGroup; children = ( 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */, + 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */, + ); + path = GDrive; + sourceTree = ""; + }; + 15994A0F2BFBF0C70017F153 /* GDrive */ = { + isa = PBXGroup; + children = ( + 15994A102BFBF0E50017F153 /* SharedDrive.swift */, ); path = GDrive; sourceTree = ""; @@ -3200,6 +3214,7 @@ CC0D56EF2AC4B59B00AA5D81 /* AddTemplateVM.swift in Sources */, CCF8D5C22AE994BF000D27C5 /* SupportingFileWidget.swift in Sources */, 12E6772F27A9719F00DC1E1C /* UIImageExtension.swift in Sources */, + 15994A0E2BFBE15F0017F153 /* SelectSharedDrive.swift in Sources */, D5B823EB262774E00008E04B /* MainView.swift in Sources */, 151308172BF3DBD9000C51D7 /* UwaziRelationshipList.swift in Sources */, 1220A72E292EB11B000BC24C /* ReportFileGridView.swift in Sources */, @@ -3598,6 +3613,8 @@ 122E6A5529A396C400BDACAD /* ServerFileSize.swift in Sources */, 125EFACD274A447100D93DF6 /* FileSortMenu.swift in Sources */, 15FABA362B73F96800B2EFEE /* ResourceRepository.swift in Sources */, + CCD586C72A7ABDE800014F87 /* TemplateCardView.swift in Sources */, + 15994A112BFBF0E50017F153 /* SharedDrive.swift in Sources */, 12607D58279042CE00E2B8CC /* VideoPlayer.swift in Sources */, 121AD8222943A2F00056AC2A /* ReportRepository.swift in Sources */, E1E7C5792AAB515100DDB07E /* UwaziTemplateRow.swift in Sources */, diff --git a/Tella/Domain/Entity/GDrive/SharedDrive.swift b/Tella/Domain/Entity/GDrive/SharedDrive.swift new file mode 100644 index 000000000..6e1fce089 --- /dev/null +++ b/Tella/Domain/Entity/GDrive/SharedDrive.swift @@ -0,0 +1,21 @@ +// +// SharedDrive.swift +// Tella +// +// Created by gus valbuena on 5/20/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +class SharedDrive: DomainModel { + var id: String + var name: String + var kind: String + + init(id: String, name: String, kind: String) { + self.id = id + self.name = name + self.kind = kind + } +} diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index 7240c161c..72b5b52c6 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -75,7 +75,7 @@ struct SelectDriveConnection: View { nextAction: { switch selectedDriveConnectionType { case .shared: - dump("shared") + navigateTo(destination: SelectSharedDrive()) case .personal: dump("personal") default: diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift new file mode 100644 index 000000000..694a999cd --- /dev/null +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -0,0 +1,34 @@ +// +// SelectSharedDrive.swift +// Tella +// +// Created by gus valbuena on 5/20/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import SwiftUI + +struct SelectSharedDrive: View { + var body: some View { + ContainerView { + VStack(alignment: .leading){ + HStack { + Text("one of the drive") + .font(.custom(Styles.Fonts.regularFontName, size: 15)) + .foregroundColor(.white) + Spacer() + Image("settings.done") + }.padding(18) + + Spacer() + }.background(Color.white.opacity(0.05)) + .toolbar { + LeadingTitleToolbar(title: "Select shared drive") + } + } + } +} + +#Preview { + SelectSharedDrive() +} diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 9f763379b..d5e1c55a1 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -51,7 +51,7 @@ struct ServerSelectionView: View { // navigateTo(destination: SelectDriveConnection(), title: "Select Google drive") // } // } - navigateTo(destination: SelectDriveConnection(), title: "Select Google drive") + navigateTo(destination: SelectDriveConnection()) } From ed6658e30d38d7b629a2133b390e6232acfdb117 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 21 May 2024 16:27:30 -0300 Subject: [PATCH 005/167] mock shared drives --- Tella/Domain/Entity/GDrive/SharedDrive.swift | 8 ++++ .../Servers/GDrive/SelectSharedDrive.swift | 37 +++++++++++++++---- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/Tella/Domain/Entity/GDrive/SharedDrive.swift b/Tella/Domain/Entity/GDrive/SharedDrive.swift index 6e1fce089..684fb3f7d 100644 --- a/Tella/Domain/Entity/GDrive/SharedDrive.swift +++ b/Tella/Domain/Entity/GDrive/SharedDrive.swift @@ -19,3 +19,11 @@ class SharedDrive: DomainModel { self.kind = kind } } + +var SharedDrivesList: [SharedDrive] = [ + SharedDrive(id: "1", name: "Admin", kind: "drive#drive"), + SharedDrive(id: "2", name: "Backup", kind: "drive#drive"), + SharedDrive(id: "3", name: "Community", kind: "drive#drive"), + SharedDrive(id: "4", name: "Contact database", kind: "drive#drive"), + SharedDrive(id: "5", name: "Incident reports", kind: "drive#drive") +] diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index 694a999cd..37426b0fb 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -9,19 +9,18 @@ import SwiftUI struct SelectSharedDrive: View { + @State var selectedDrive: String = "" var body: some View { ContainerView { VStack(alignment: .leading){ - HStack { - Text("one of the drive") - .font(.custom(Styles.Fonts.regularFontName, size: 15)) - .foregroundColor(.white) - Spacer() - Image("settings.done") - }.padding(18) + ForEach(SharedDrivesList, id: \.id) { drive in + DriveCardView(sharedDrive: drive, selectedDrive: $selectedDrive) + } Spacer() - }.background(Color.white.opacity(0.05)) + } + .padding(.vertical, 8) + .background(Color.white.opacity(0.03)) .toolbar { LeadingTitleToolbar(title: "Select shared drive") } @@ -29,6 +28,28 @@ struct SelectSharedDrive: View { } } +struct DriveCardView: View { + var sharedDrive: SharedDrive + @Binding var selectedDrive: String + var body: some View { + Button(action: { + self.selectedDrive = sharedDrive.name + }) { + HStack { + Text(sharedDrive.name) + .font(.custom(Styles.Fonts.regularFontName, size: 16)) + .foregroundColor(.white) + Spacer() + if selectedDrive == sharedDrive.name { + Image("settings.done") + } + } + .padding(18) + .background(selectedDrive == sharedDrive.name ? Color.white.opacity(0.1) : Color.clear) + } + } +} + #Preview { SelectSharedDrive() } From d1c54181814384e22c6f2e749fedc9815f270802 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 22 May 2024 11:10:20 -0300 Subject: [PATCH 006/167] create drive folder view --- Tella.xcodeproj/project.pbxproj | 4 ++ .../Servers/GDrive/CreateDriveFolder.swift | 53 +++++++++++++++++++ .../GDrive/SelectDriveConnection.swift | 4 +- 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 0a1908cdd..28ea0eac6 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -354,6 +354,7 @@ 1535A5F12BAA06490009EA42 /* DownloadedResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1535A5F02BAA06490009EA42 /* DownloadedResource.swift */; }; 153AACF72BE40BEA0075D5B2 /* UwaziEntityFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 153AACF62BE40BEA0075D5B2 /* UwaziEntityFetcher.swift */; }; 153AACFB2BE41C010075D5B2 /* UwaziEntityRelationshipItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 153AACFA2BE41C010075D5B2 /* UwaziEntityRelationshipItem.swift */; }; + 153F96492BFD306F00FE5464 /* CreateDriveFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 153F96482BFD306F00FE5464 /* CreateDriveFolder.swift */; }; 155369232B7E9CC100129F2F /* ResourceDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155369222B7E9CC100129F2F /* ResourceDatabase.swift */; }; 15622F4A2B72B1FF00289816 /* DeleteConfirmation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15622F492B72B1FF00289816 /* DeleteConfirmation.swift */; }; 156986252B88FCB600534720 /* ResourcePDFView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 156986242B88FCB600534720 /* ResourcePDFView.swift */; }; @@ -897,6 +898,7 @@ 1535A5F02BAA06490009EA42 /* DownloadedResource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResource.swift; sourceTree = ""; }; 153AACF62BE40BEA0075D5B2 /* UwaziEntityFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziEntityFetcher.swift; sourceTree = ""; }; 153AACFA2BE41C010075D5B2 /* UwaziEntityRelationshipItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziEntityRelationshipItem.swift; sourceTree = ""; }; + 153F96482BFD306F00FE5464 /* CreateDriveFolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateDriveFolder.swift; sourceTree = ""; }; 155369222B7E9CC100129F2F /* ResourceDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceDatabase.swift; sourceTree = ""; }; 15622F492B72B1FF00289816 /* DeleteConfirmation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteConfirmation.swift; sourceTree = ""; }; 156986242B88FCB600534720 /* ResourcePDFView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourcePDFView.swift; sourceTree = ""; }; @@ -2290,6 +2292,7 @@ children = ( 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */, 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */, + 153F96482BFD306F00FE5464 /* CreateDriveFolder.swift */, ); path = GDrive; sourceTree = ""; @@ -3217,6 +3220,7 @@ 15994A0E2BFBE15F0017F153 /* SelectSharedDrive.swift in Sources */, D5B823EB262774E00008E04B /* MainView.swift in Sources */, 151308172BF3DBD9000C51D7 /* UwaziRelationshipList.swift in Sources */, + 153F96492BFD306F00FE5464 /* CreateDriveFolder.swift in Sources */, 1220A72E292EB11B000BC24C /* ReportFileGridView.swift in Sources */, 125FA6D6278DE49A004B9D06 /* URLExtension.swift in Sources */, 127369E327B3C4DA00CF7BE5 /* UIDeviceExtension.swift in Sources */, diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift new file mode 100644 index 000000000..a0648f565 --- /dev/null +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift @@ -0,0 +1,53 @@ +// +// CreateDriveFolder.swift +// Tella +// +// Created by gus valbuena on 5/21/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import SwiftUI + +struct CreateDriveFolder: View { + @State var fieldContent : String = "" + var body: some View { + ContainerView { + VStack(spacing: 20) { + Spacer() + headerView + TextfieldView(fieldContent: $fieldContent, isValid: .constant(true), shouldShowError: .constant(false), fieldType: .text, placeholder: "Folder name") + .padding(.vertical, 12) + Spacer() + bottomView + }.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) + .navigationBarHidden(true) + } + } + + var headerView: some View { + VStack(spacing: 20) { + Image("gdrive.icon") + Text("Create new folder") + .font(.custom(Styles.Fonts.semiBoldFontName, size: 18)) + .foregroundColor(.white) + .multilineTextAlignment(.center) + Text("Your reports will be uploaded to a new folder on your Google Drive. Choose a name for this folder here.") + .font(.custom(Styles.Fonts.regularFontName, size: 14)) + .foregroundColor(.white) + .multilineTextAlignment(.center) + }.padding(.horizontal, 20) + } + + var bottomView: some View { + BottomLockView(isValid: .constant(true), + nextButtonAction: .action, + shouldHideNext: false, + shouldHideBack: false, + nextAction: {}) + + } +} + +#Preview { + CreateDriveFolder() +} diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index 72b5b52c6..5aac6fb64 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -22,7 +22,7 @@ struct SelectDriveConnection: View { connectionsButtons Spacer() bottomView - }.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) + }.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) .toolbar { LeadingTitleToolbar(title: "Select Google drive") } @@ -77,7 +77,7 @@ struct SelectDriveConnection: View { case .shared: navigateTo(destination: SelectSharedDrive()) case .personal: - dump("personal") + navigateTo(destination: CreateDriveFolder()) default: break } From b2bff3e6a5ea375a5fa40cbc26d01c1ca8ee7e97 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 22 May 2024 16:32:09 -0300 Subject: [PATCH 007/167] basic implemantation of d-drive library --- Podfile | 3 +- Tella.xcodeproj/project.pbxproj | 8 ++++ Tella/Application/TellaApp.swift | 7 ++- .../ViewModel/GDriveAuthViewModel.swift | 30 +++++++++++++ .../ViewModel/GDriveServerViewModel.swift | 44 +++++++++++++++++++ .../GDrive/SelectDriveConnection.swift | 5 ++- .../Servers/GDrive/SelectSharedDrive.swift | 14 +++--- .../Views/Servers/ServerSelectionView.swift | 26 ++--------- 8 files changed, 105 insertions(+), 32 deletions(-) create mode 100644 Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift create mode 100644 Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift diff --git a/Podfile b/Podfile index 21a8ce69f..d2ebcb230 100644 --- a/Podfile +++ b/Podfile @@ -10,7 +10,8 @@ target 'Tella' do pod 'ZIPFoundation' pod 'Mantis', '~> 2.21.0' pod 'GoogleSignIn' - + pod 'GoogleAPIClientForREST/Drive' + target 'TellaTests' do inherit! :search_paths # Pods for testing diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 28ea0eac6..ccfc2ef3b 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -372,6 +372,8 @@ 15994A0C2BFBC6F40017F153 /* SelectDriveConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */; }; 15994A0E2BFBE15F0017F153 /* SelectSharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */; }; 15994A112BFBF0E50017F153 /* SharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A102BFBF0E50017F153 /* SharedDrive.swift */; }; + 15C51C442BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C51C432BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift */; }; + 15C51C462BFE769500DD9AD0 /* GDriveServerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C51C452BFE769500DD9AD0 /* GDriveServerViewModel.swift */; }; 15EE30FE2B5073E20033BBBB /* Pages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15EE30FD2B5073E20033BBBB /* Pages.swift */; }; 15F64C9D2B6D7904008A57AA /* DownloadedResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */; }; 15F64CA02B6D794B008A57AA /* SectionTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */; }; @@ -918,6 +920,8 @@ 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectDriveConnection.swift; sourceTree = ""; }; 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectSharedDrive.swift; sourceTree = ""; }; 15994A102BFBF0E50017F153 /* SharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedDrive.swift; sourceTree = ""; }; + 15C51C432BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveAuthViewModel.swift; sourceTree = ""; }; + 15C51C452BFE769500DD9AD0 /* GDriveServerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveServerViewModel.swift; sourceTree = ""; }; 15EE30FD2B5073E20033BBBB /* Pages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pages.swift; sourceTree = ""; }; 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResources.swift; sourceTree = ""; }; 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionTitle.swift; sourceTree = ""; }; @@ -2199,6 +2203,8 @@ 12730E68279F420400DC0135 /* SettingsViewModel.swift */, E108B75629FE79340045CCBE /* UwaziServerViewModel.swift */, 1293F6692AD7F29B00F6CFBD /* FeedbackViewModel.swift */, + 15C51C432BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift */, + 15C51C452BFE769500DD9AD0 /* GDriveServerViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -3539,6 +3545,7 @@ 125AAD3129534259002194D6 /* UploadProgressInfo.swift in Sources */, D572EAC9263A384B00CE191A /* FileGroupsView.swift in Sources */, 127C4AAF27E4A74B00B1A1D3 /* ShareFileView.swift in Sources */, + 15C51C462BFE769500DD9AD0 /* GDriveServerViewModel.swift in Sources */, 12567FEF2716B38F00A2D356 /* LockChoiceView.swift in Sources */, CC1313842A5CB3590057271C /* DeleteAfterFailView.swift in Sources */, 12964D922BAB44C8003E1E0A /* UwaziEntityInstanceFile.swift in Sources */, @@ -3562,6 +3569,7 @@ 12D37A982721EDB700E43BDB /* PinKeyboardModel.swift in Sources */, 12B370392B19109600DDA9E9 /* LocalizableBackgroundActivities.swift in Sources */, 122C54BE28C6351E003B2DBC /* AdvancedServerSettingsView.swift in Sources */, + 15C51C442BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift in Sources */, 122C54C028C63E8C003B2DBC /* SuccessAdvancedSettingsView.swift in Sources */, 12619B8B27A01F6600999FDA /* BundleExtension.swift in Sources */, 12283FA0295C6FB100580EFE /* DataExtension.swift in Sources */, diff --git a/Tella/Application/TellaApp.swift b/Tella/Application/TellaApp.swift index ff2943f15..c5c0673f9 100644 --- a/Tella/Application/TellaApp.swift +++ b/Tella/Application/TellaApp.swift @@ -28,8 +28,13 @@ struct TellaApp: App { self.saveData(lockApptype: .finishBackgroundTasks) } }.onAppear { + guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { + print("There is no root view controller!") + return + } + GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in - dump(user) + user?.addScopes(["https://www.googleapis.com/auth/drive"], presenting: rootViewController) } }.onOpenURL { url in dump(url) diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift new file mode 100644 index 000000000..31c5a541d --- /dev/null +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -0,0 +1,30 @@ +// +// GDriveAuthViewModel.swift +// Tella +// +// Created by gus valbuena on 5/22/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation +import GoogleSignIn +import GoogleAPIClientForREST + +class GDriveAuthViewModel: ObservableObject { + + func handleSignInButton(completion: @escaping () -> Void) { + guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { + print("There is no root view controller!") + return + } + + GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { signInResult, error in + if let error = error { + print("Error during Google Sign-In: \(error.localizedDescription)") + return + } else { + completion() + } + } + } +} diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift new file mode 100644 index 000000000..e6b429d24 --- /dev/null +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -0,0 +1,44 @@ +// +// GDriveServerViewModel.swift +// Tella +// +// Created by gus valbuena on 5/22/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation +import GoogleSignIn +import GoogleAPIClientForREST + +class GDriveServerViewModel: ObservableObject { + var googleUser:GIDGoogleUser? = nil + @Published var sharedDrives: [GTLRDrive_Drive] = [] + + init() { + GIDSignIn.sharedInstance.restorePreviousSignIn { [self] user, error in + self.googleUser = user + + getSharedDrives() + } + } + + func getSharedDrives() { + guard let user = self.googleUser else { return } + let driveService = GTLRDriveService() + driveService.authorizer = user.fetcherAuthorizer + + let query = GTLRDriveQuery_DrivesList.query() + + driveService.executeQuery(query) { ticket, response, error in + if let error = error { + print("Error fetching drives: \(error.localizedDescription)") + } + + guard let driveList = response as? GTLRDrive_DriveList, let drives = driveList.drives else { + return + } + + self.sharedDrives = drives + } + } +} diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index 5aac6fb64..3823b844b 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -14,6 +14,7 @@ enum DriveConnectionType { } struct SelectDriveConnection: View { @State var selectedDriveConnectionType: DriveConnectionType = .none + @ObservedObject var dGriveServerViewModel: GDriveServerViewModel var body: some View { ContainerView { VStack(spacing: 20) { @@ -75,7 +76,7 @@ struct SelectDriveConnection: View { nextAction: { switch selectedDriveConnectionType { case .shared: - navigateTo(destination: SelectSharedDrive()) + navigateTo(destination: SelectSharedDrive(sharedDrives: dGriveServerViewModel.sharedDrives)) case .personal: navigateTo(destination: CreateDriveFolder()) default: @@ -87,5 +88,5 @@ struct SelectDriveConnection: View { } #Preview { - SelectDriveConnection(selectedDriveConnectionType: .personal) + SelectDriveConnection(selectedDriveConnectionType: .personal, dGriveServerViewModel: GDriveServerViewModel()) } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index 37426b0fb..724daf390 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -7,13 +7,15 @@ // import SwiftUI +import GoogleAPIClientForREST struct SelectSharedDrive: View { @State var selectedDrive: String = "" + @State var sharedDrives: [GTLRDrive_Drive] = [] var body: some View { ContainerView { VStack(alignment: .leading){ - ForEach(SharedDrivesList, id: \.id) { drive in + ForEach(sharedDrives, id: \.identifier) { drive in DriveCardView(sharedDrive: drive, selectedDrive: $selectedDrive) } @@ -29,23 +31,23 @@ struct SelectSharedDrive: View { } struct DriveCardView: View { - var sharedDrive: SharedDrive + var sharedDrive: GTLRDrive_Drive @Binding var selectedDrive: String var body: some View { Button(action: { - self.selectedDrive = sharedDrive.name + self.selectedDrive = sharedDrive.identifier ?? "" }) { HStack { - Text(sharedDrive.name) + Text(sharedDrive.name ?? "") .font(.custom(Styles.Fonts.regularFontName, size: 16)) .foregroundColor(.white) Spacer() - if selectedDrive == sharedDrive.name { + if selectedDrive == sharedDrive.identifier { Image("settings.done") } } .padding(18) - .background(selectedDrive == sharedDrive.name ? Color.white.opacity(0.1) : Color.clear) + .background(selectedDrive == sharedDrive.identifier ? Color.white.opacity(0.1) : Color.clear) } } } diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index d5e1c55a1..19e389459 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -8,13 +8,12 @@ import SwiftUI -import GoogleSignIn - struct ServerSelectionView: View { @EnvironmentObject var serversViewModel : ServersViewModel @StateObject var serverViewModel : ServerViewModel @EnvironmentObject var mainAppModel : MainAppModel @State var selectedServerType: ServerConnectionType = .unknown + @ObservedObject var gDriveVM = GDriveAuthViewModel() @Environment(\.presentationMode) var presentationMode: Binding init(appModel:MainAppModel, server: TellaServer? = nil) { @@ -36,25 +35,6 @@ struct ServerSelectionView: View { } } - func handleSignInButton() { - guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { - print("There is no root view controller!") - return - } - -// GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { signInResult, error in -// if let error = error { -// print("Error during Google Sign-In: \(error.localizedDescription)") -// return -// } else { -// dump(signInResult) -// navigateTo(destination: SelectDriveConnection(), title: "Select Google drive") -// } -// } - navigateTo(destination: SelectDriveConnection()) - } - - fileprivate func buttonViews() -> Group> { return Group { TellaButtonView(title: LocalizableSettings.settServerTellaWeb.localized, @@ -74,7 +54,9 @@ struct ServerSelectionView: View { nextButtonAction: .action, isOverlay: selectedServerType == .gDrive, isValid: .constant(true), action: { - handleSignInButton() + gDriveVM.handleSignInButton { + navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") + } }).padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) } } From a5c20fb83c0b335a2f4c37a855632d99b833572e Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 23 May 2024 13:59:24 -0300 Subject: [PATCH 008/167] re-use successLoginView --- .../Servers/AddServer/ServerLoginView.swift | 13 ++----- .../Servers/AddServer/SuccessLoginView.swift | 36 ++++++++++++++----- .../Servers/GDrive/CreateDriveFolder.swift | 4 ++- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/Tella/Scenes/Settings/Views/Servers/AddServer/ServerLoginView.swift b/Tella/Scenes/Settings/Views/Servers/AddServer/ServerLoginView.swift index bb7f6d798..b9da81412 100644 --- a/Tella/Scenes/Settings/Views/Servers/AddServer/ServerLoginView.swift +++ b/Tella/Scenes/Settings/Views/Servers/AddServer/ServerLoginView.swift @@ -86,16 +86,9 @@ struct ServerLoginView: View { } private var successLoginView: some View { - - SuccessLoginView() - .environmentObject(serverViewModel) + SuccessLoginView(navigateToAction: { + navigateTo(destination: ReportsView(mainAppModel: mainAppModel)) + }).environmentObject(serverViewModel) } } -//struct ServerLoginView_Previews: PreviewProvider { -// static var previews: some View { -// ServerLoginView() -// .environmentObject(ServersViewModel(mainAppModel: MainAppModel())) -// .environmentObject(ServerViewModel(mainAppModel: MainAppModel(), currentServer: nil)) -// } -//} diff --git a/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift b/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift index 4e5b83682..5f04873cd 100644 --- a/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift +++ b/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift @@ -5,6 +5,21 @@ import SwiftUI +enum SuccessLoginType { + case gDrive + case tella + + var buttonContent: String { + switch self { + case .gDrive: + return "GO TO GOOGLE DRIVE" + case.tella: + return "GO TO REPORTS" + } + } + +} + struct SuccessLoginView: View { @EnvironmentObject var mainAppModel : MainAppModel @@ -13,7 +28,8 @@ struct SuccessLoginView: View { @EnvironmentObject private var appViewState: AppViewState @State var showNextView : Bool = false - + var navigateToAction: () -> Void + var type: SuccessLoginType = .tella var body: some View { ContainerView { @@ -27,21 +43,23 @@ struct SuccessLoginView: View { Spacer() .frame(height: 48) - TellaButtonView (title: "GO TO REPORTS", + TellaButtonView (title: type.buttonContent, nextButtonAction: .action, buttonType: .yellow, isValid: .constant(true)) { - navigateTo(destination: ReportsView(mainAppModel: mainAppModel)) + navigateToAction() } Spacer() .frame(height: 12) - TellaButtonView (title: "Advanced settings", - nextButtonAction: .destination, - destination: AdvancedServerSettingsView() - .environmentObject(serverViewModel), - isValid: .constant(true)) + if type == .tella { + TellaButtonView (title: "Advanced settings", + nextButtonAction: .destination, + destination: AdvancedServerSettingsView() + .environmentObject(serverViewModel), + isValid: .constant(true)) + } Spacer() } .padding(EdgeInsets(top: 0, leading: 26, bottom: 0, trailing: 26)) @@ -79,7 +97,7 @@ struct SuccessLoginView: View { struct SuccessLoginView_Previews: PreviewProvider { static var previews: some View { - SuccessLoginView() + SuccessLoginView(navigateToAction: {}) .environmentObject(MainAppModel.stub()) .environmentObject(ServersViewModel(mainAppModel: MainAppModel.stub())) } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift index a0648f565..567f7ab2d 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift @@ -43,7 +43,9 @@ struct CreateDriveFolder: View { nextButtonAction: .action, shouldHideNext: false, shouldHideBack: false, - nextAction: {}) + nextAction: { + navigateTo(destination: SuccessLoginView(navigateToAction: {}, type: .gDrive)) + }) } } From d4ef6a9fd8eb9193550955bf0eab58f8c2c94a82 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 23 May 2024 15:30:36 -0300 Subject: [PATCH 009/167] navigate from select shared drive to success --- .../Views/Servers/GDrive/SelectSharedDrive.swift | 11 +++++++++++ .../Settings/Views/Servers/ServerSelectionView.swift | 7 ++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index 724daf390..6ba3ab515 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -25,6 +25,16 @@ struct SelectSharedDrive: View { .background(Color.white.opacity(0.03)) .toolbar { LeadingTitleToolbar(title: "Select shared drive") + // remove this after merging with uwazi relationships + ToolbarItem(placement: .navigationBarTrailing) { + Button(action: { + navigateTo(destination: SuccessLoginView(navigateToAction: {}, type: .gDrive)) + }) { + Image("report.select-files") + .resizable() + .frame(width: 24, height: 24) + } + } } } } @@ -52,6 +62,7 @@ struct DriveCardView: View { } } + #Preview { SelectSharedDrive() } diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 19e389459..c7aa85371 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -54,9 +54,10 @@ struct ServerSelectionView: View { nextButtonAction: .action, isOverlay: selectedServerType == .gDrive, isValid: .constant(true), action: { - gDriveVM.handleSignInButton { - navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") - } +// gDriveVM.handleSignInButton { +// navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") +// } + navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") }).padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) } } From 4dc3e10a2dc7edc1d606cbad56d1f3f5faec8216 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 23 May 2024 16:28:33 -0300 Subject: [PATCH 010/167] final tweaks --- Tella.xcodeproj/project.pbxproj | 4 +++ Tella/Application/TellaApp.swift | 14 ++------- .../ViewModel/GDriveAuthViewModel.swift | 16 ++++++++++ .../Servers/GDrive/CreateDriveFolder.swift | 19 +++--------- .../Servers/GDrive/GDriveHeaderView.swift | 31 +++++++++++++++++++ .../GDrive/SelectDriveConnection.swift | 26 +++++++--------- .../Views/Servers/ServerSelectionView.swift | 7 ++--- 7 files changed, 72 insertions(+), 45 deletions(-) create mode 100644 Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index ccfc2ef3b..10edecb18 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -369,6 +369,7 @@ 15BD9CB12BC744BC00C3932B /* NavigationHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CB02BC744BC00C3932B /* NavigationHeaderView.swift */; }; 15BD9CB32BC7472A00C3932B /* UwaziRelationshipDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CB22BC7472A00C3932B /* UwaziRelationshipDTO.swift */; }; 15CD89102BF297BE00F724F5 /* SelectedEntityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */; }; + 15944F6F2BFFCE98008430BA /* GDriveHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15944F6E2BFFCE98008430BA /* GDriveHeaderView.swift */; }; 15994A0C2BFBC6F40017F153 /* SelectDriveConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */; }; 15994A0E2BFBE15F0017F153 /* SelectSharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */; }; 15994A112BFBF0E50017F153 /* SharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A102BFBF0E50017F153 /* SharedDrive.swift */; }; @@ -917,6 +918,7 @@ 15BD9CB02BC744BC00C3932B /* NavigationHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationHeaderView.swift; sourceTree = ""; }; 15BD9CB22BC7472A00C3932B /* UwaziRelationshipDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziRelationshipDTO.swift; sourceTree = ""; }; 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedEntityView.swift; sourceTree = ""; }; + 15944F6E2BFFCE98008430BA /* GDriveHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveHeaderView.swift; sourceTree = ""; }; 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectDriveConnection.swift; sourceTree = ""; }; 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectSharedDrive.swift; sourceTree = ""; }; 15994A102BFBF0E50017F153 /* SharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedDrive.swift; sourceTree = ""; }; @@ -2299,6 +2301,7 @@ 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */, 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */, 153F96482BFD306F00FE5464 /* CreateDriveFolder.swift */, + 15944F6E2BFFCE98008430BA /* GDriveHeaderView.swift */, ); path = GDrive; sourceTree = ""; @@ -3280,6 +3283,7 @@ 12782B4A2B8400E500B5BC36 /* Cryptor.swift in Sources */, 1293F6702AD8295400F6CFBD /* BorderedTextEditorView.swift in Sources */, 129B845928BFED9700F1B344 /* TellaButtonView.swift in Sources */, + 15944F6F2BFFCE98008430BA /* GDriveHeaderView.swift in Sources */, 123048D7295F95BB0015CD96 /* SubmittedDetailsItemView.swift in Sources */, E1CF5A272AB3488E00365036 /* JSONDecoderExtension.swift in Sources */, 1291F4F227B52BF9006A34D3 /* QueuePlayer.swift in Sources */, diff --git a/Tella/Application/TellaApp.swift b/Tella/Application/TellaApp.swift index c5c0673f9..3bda0ebe9 100644 --- a/Tella/Application/TellaApp.swift +++ b/Tella/Application/TellaApp.swift @@ -7,7 +7,6 @@ // import SwiftUI -import GoogleSignIn @main struct TellaApp: App { @@ -16,6 +15,7 @@ struct TellaApp: App { @Environment(\.scenePhase) var scenePhase @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate let delayTimeInSecond = 1.0 + let gDriveAuthViewModel = GDriveAuthViewModel() var body: some Scene { WindowGroup { @@ -28,17 +28,9 @@ struct TellaApp: App { self.saveData(lockApptype: .finishBackgroundTasks) } }.onAppear { - guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { - print("There is no root view controller!") - return - } - - GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in - user?.addScopes(["https://www.googleapis.com/auth/drive"], presenting: rootViewController) - } + gDriveAuthViewModel.restorePreviousSignIn() }.onOpenURL { url in - dump(url) - GIDSignIn.sharedInstance.handle(url) + gDriveAuthViewModel.handleUrl(url: url) } }.onChange(of: scenePhase) { phase in diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift index 31c5a541d..4e989b846 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -27,4 +27,20 @@ class GDriveAuthViewModel: ObservableObject { } } } + + func restorePreviousSignIn() { + guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { + print("There is no root view controller!") + return + } + + GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in + user?.addScopes(["https://www.googleapis.com/auth/drive"], presenting: rootViewController) + dump(user) + } + } + + func handleUrl(url: URL) { + GIDSignIn.sharedInstance.handle(url) + } } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift index 567f7ab2d..0c8464d05 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift @@ -14,7 +14,10 @@ struct CreateDriveFolder: View { ContainerView { VStack(spacing: 20) { Spacer() - headerView + GDriveHeaderView( + title: "Create new folder", + subtitle: "Your reports will be uploaded to a new folder on your Google Drive. Choose a name for this folder here." + ) TextfieldView(fieldContent: $fieldContent, isValid: .constant(true), shouldShowError: .constant(false), fieldType: .text, placeholder: "Folder name") .padding(.vertical, 12) Spacer() @@ -24,20 +27,6 @@ struct CreateDriveFolder: View { } } - var headerView: some View { - VStack(spacing: 20) { - Image("gdrive.icon") - Text("Create new folder") - .font(.custom(Styles.Fonts.semiBoldFontName, size: 18)) - .foregroundColor(.white) - .multilineTextAlignment(.center) - Text("Your reports will be uploaded to a new folder on your Google Drive. Choose a name for this folder here.") - .font(.custom(Styles.Fonts.regularFontName, size: 14)) - .foregroundColor(.white) - .multilineTextAlignment(.center) - }.padding(.horizontal, 20) - } - var bottomView: some View { BottomLockView(isValid: .constant(true), nextButtonAction: .action, diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift new file mode 100644 index 000000000..0e7b7fa3f --- /dev/null +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift @@ -0,0 +1,31 @@ +// +// GDriveHeaderView.swift +// Tella +// +// Created by gus valbuena on 5/23/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import SwiftUI + +struct GDriveHeaderView: View { + var title: String + var subtitle: String + var body: some View { + VStack(spacing: 20) { + Image("gdrive.icon") + Text(title) + .font(.custom(Styles.Fonts.semiBoldFontName, size: 18)) + .foregroundColor(.white) + .multilineTextAlignment(.center) + Text(subtitle) + .font(.custom(Styles.Fonts.regularFontName, size: 14)) + .foregroundColor(.white) + .multilineTextAlignment(.center) + }.padding(.horizontal, 20) + } +} + +#Preview { + GDriveHeaderView(title: "", subtitle: "") +} diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index 3823b844b..5d999f10f 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -19,7 +19,10 @@ struct SelectDriveConnection: View { ContainerView { VStack(spacing: 20) { Spacer() - headerView + GDriveHeaderView( + title: "Select a Drive to connect to", + subtitle: "You can either connect to an organizational Shared Drive or create a new folder in your personal Drive." + ) connectionsButtons Spacer() bottomView @@ -30,20 +33,6 @@ struct SelectDriveConnection: View { } } - var headerView: some View { - VStack(spacing: 20) { - Image("gdrive.icon") - Text("Select a Drive to connect to") - .font(.custom(Styles.Fonts.semiBoldFontName, size: 18)) - .foregroundColor(.white) - .multilineTextAlignment(.center) - Text("You can either connect to an organizational Shared Drive or create a new folder in your personal Drive.") - .font(.custom(Styles.Fonts.regularFontName, size: 14)) - .foregroundColor(.white) - .multilineTextAlignment(.center) - } - } - var connectionsButtons: some View { VStack { TellaButtonView( @@ -60,6 +49,13 @@ struct SelectDriveConnection: View { isValid: .constant(true), action: {selectedDriveConnectionType = .personal} ).padding(.vertical, 5) + moreInfoText + } + } + + + var moreInfoText: some View { + Link(destination: URL(string: "https://tella-app.org/gdrive")!) { Text("Learn more about the types of drives") .font(.custom(Styles.Fonts.regularFontName, size: 14)) .foregroundColor(Styles.Colors.yellow) diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index c7aa85371..19e389459 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -54,10 +54,9 @@ struct ServerSelectionView: View { nextButtonAction: .action, isOverlay: selectedServerType == .gDrive, isValid: .constant(true), action: { -// gDriveVM.handleSignInButton { -// navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") -// } - navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") + gDriveVM.handleSignInButton { + navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") + } }).padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) } } From 82e3746fedf37d56044f789fa5d60eced8dde461 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 28 May 2024 16:37:20 -0300 Subject: [PATCH 011/167] move google signIn to next button --- .../Settings/Views/Servers/ServerSelectionView.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 19e389459..f2ea63294 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -54,9 +54,7 @@ struct ServerSelectionView: View { nextButtonAction: .action, isOverlay: selectedServerType == .gDrive, isValid: .constant(true), action: { - gDriveVM.handleSignInButton { - navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") - } + selectedServerType = .gDrive }).padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) } } @@ -72,6 +70,10 @@ struct ServerSelectionView: View { navigateToTellaWebFlow() case .uwazi: navigateToUwaziFlow() + case .gDrive: + gDriveVM.handleSignInButton { + navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") + } default: break } From 4474e91e99a5f1d391715a011b34efd1b97c869a Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 28 May 2024 17:06:36 -0300 Subject: [PATCH 012/167] refactor buttonViews function in serverSelection class --- Tella.xcodeproj/project.pbxproj | 4 +++ .../Models/ServerConnectionButton.swift | 20 +++++++++++ .../Views/Servers/ServerSelectionView.swift | 35 ++++++++----------- 3 files changed, 38 insertions(+), 21 deletions(-) create mode 100644 Tella/Scenes/Settings/Models/ServerConnectionButton.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 10edecb18..30447f793 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -356,6 +356,7 @@ 153AACFB2BE41C010075D5B2 /* UwaziEntityRelationshipItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 153AACFA2BE41C010075D5B2 /* UwaziEntityRelationshipItem.swift */; }; 153F96492BFD306F00FE5464 /* CreateDriveFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 153F96482BFD306F00FE5464 /* CreateDriveFolder.swift */; }; 155369232B7E9CC100129F2F /* ResourceDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155369222B7E9CC100129F2F /* ResourceDatabase.swift */; }; + 155541B02C066F990031D3A5 /* ServerConnectionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155541AF2C066F990031D3A5 /* ServerConnectionButton.swift */; }; 15622F4A2B72B1FF00289816 /* DeleteConfirmation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15622F492B72B1FF00289816 /* DeleteConfirmation.swift */; }; 156986252B88FCB600534720 /* ResourcePDFView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 156986242B88FCB600534720 /* ResourcePDFView.swift */; }; 15791C1A2B6AC34100D67C74 /* ResourcesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15791C192B6AC34100D67C74 /* ResourcesView.swift */; }; @@ -903,6 +904,7 @@ 153AACFA2BE41C010075D5B2 /* UwaziEntityRelationshipItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziEntityRelationshipItem.swift; sourceTree = ""; }; 153F96482BFD306F00FE5464 /* CreateDriveFolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateDriveFolder.swift; sourceTree = ""; }; 155369222B7E9CC100129F2F /* ResourceDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceDatabase.swift; sourceTree = ""; }; + 155541AF2C066F990031D3A5 /* ServerConnectionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConnectionButton.swift; sourceTree = ""; }; 15622F492B72B1FF00289816 /* DeleteConfirmation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteConfirmation.swift; sourceTree = ""; }; 156986242B88FCB600534720 /* ResourcePDFView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourcePDFView.swift; sourceTree = ""; }; 15791C192B6AC34100D67C74 /* ResourcesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourcesView.swift; sourceTree = ""; }; @@ -2081,6 +2083,7 @@ CC1313812A5CB0DB0057271C /* DeleteAfterFailOption.swift */, CC1313872A5CB4550057271C /* DeleteAfterFailOptionsStatus.swift */, E1E7C56E2AA9822F00DDB07E /* DeleteServerTexts.swift */, + 155541AF2C066F990031D3A5 /* ServerConnectionButton.swift */, ); path = Models; sourceTree = ""; @@ -3414,6 +3417,7 @@ CCF8D5C42AE9AA08000D27C5 /* PrimaryDocuments.swift in Sources */, 1202D9582BF4CFF200EAFAB3 /* SelectValues.swift in Sources */, 1268554027D2994500385E18 /* VaultFileStatus.swift in Sources */, + 155541B02C066F990031D3A5 /* ServerConnectionButton.swift in Sources */, 0D4BC3C5267577F900DCDC30 /* ReportsView.swift in Sources */, 12776A9027BA742700CDC5DC /* CameraControlsView.swift in Sources */, 128D6E1A28045C090082AB18 /* ManageFileType.swift in Sources */, diff --git a/Tella/Scenes/Settings/Models/ServerConnectionButton.swift b/Tella/Scenes/Settings/Models/ServerConnectionButton.swift new file mode 100644 index 000000000..b7d7edcdb --- /dev/null +++ b/Tella/Scenes/Settings/Models/ServerConnectionButton.swift @@ -0,0 +1,20 @@ +// +// ServerConnectionButton.swift +// Tella +// +// Created by gus valbuena on 5/28/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +struct ServerConnectionButton { + let title: String + let type: ServerConnectionType +} + +let serverConnections: [ServerConnectionButton] = [ + ServerConnectionButton(title: LocalizableSettings.settServerTellaWeb.localized, type: .tella), + ServerConnectionButton(title: LocalizableSettings.settServerUwazi.localized, type: .uwazi), + ServerConnectionButton(title: "GOOGLE DRIVE", type: .gDrive) +] diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index f2ea63294..81e11b242 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -35,27 +35,20 @@ struct ServerSelectionView: View { } } - fileprivate func buttonViews() -> Group> { - return Group { - TellaButtonView(title: LocalizableSettings.settServerTellaWeb.localized, - nextButtonAction: .action, - isOverlay: selectedServerType == .tella, - isValid: .constant(true),action: { - selectedServerType = .tella - }) - .padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) - TellaButtonView(title: LocalizableSettings.settServerUwazi.localized, - nextButtonAction: .action, - isOverlay: selectedServerType == .uwazi, - isValid: .constant(true), action: { - selectedServerType = .uwazi - }).padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) - TellaButtonView(title: "GOOGLE DRIVE", - nextButtonAction: .action, - isOverlay: selectedServerType == .gDrive, - isValid: .constant(true), action: { - selectedServerType = .gDrive - }).padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) + fileprivate func buttonViews() -> some View { + Group { + ForEach(serverConnections, id: \.type) { connection in + TellaButtonView( + title: connection.title, + nextButtonAction: .action, + isOverlay: selectedServerType == connection.type, + isValid: .constant(true), + action: { + selectedServerType = connection.type + } + ) + .padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) + } } } From 38168f3a7b74dcf88b7bf15ed090871981e18202 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 28 May 2024 17:09:24 -0300 Subject: [PATCH 013/167] move gDrive login logic to separate function --- .../Settings/Views/Servers/ServerSelectionView.swift | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 81e11b242..47c778f1d 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -64,9 +64,7 @@ struct ServerSelectionView: View { case .uwazi: navigateToUwaziFlow() case .gDrive: - gDriveVM.handleSignInButton { - navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") - } + navigateToGDriveFlow() default: break } @@ -82,6 +80,12 @@ struct ServerSelectionView: View { .environmentObject(serverViewModel) .environmentObject(serversViewModel)) } + + fileprivate func navigateToGDriveFlow() { + gDriveVM.handleSignInButton { + navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") + } + } struct HeaderView: View { From c081b4a9856a22f5a35d42a0ee38bae2bf3975cf Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 28 May 2024 18:40:50 -0300 Subject: [PATCH 014/167] create gDrive repository and update view models --- Tella.xcodeproj/project.pbxproj | 4 + .../Repositories/GDriveRepository.swift | 78 +++++++++++++++++++ .../ViewModel/GDriveAuthViewModel.swift | 43 ++++------ .../ViewModel/GDriveServerViewModel.swift | 41 +++++----- .../Views/Servers/ServerSelectionView.swift | 2 +- 5 files changed, 117 insertions(+), 51 deletions(-) create mode 100644 Tella/Data/Networking/Repositories/GDriveRepository.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 30447f793..28cc3eb7a 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -357,6 +357,7 @@ 153F96492BFD306F00FE5464 /* CreateDriveFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 153F96482BFD306F00FE5464 /* CreateDriveFolder.swift */; }; 155369232B7E9CC100129F2F /* ResourceDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155369222B7E9CC100129F2F /* ResourceDatabase.swift */; }; 155541B02C066F990031D3A5 /* ServerConnectionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155541AF2C066F990031D3A5 /* ServerConnectionButton.swift */; }; + 155541B22C0672C20031D3A5 /* GDriveRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155541B12C0672C20031D3A5 /* GDriveRepository.swift */; }; 15622F4A2B72B1FF00289816 /* DeleteConfirmation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15622F492B72B1FF00289816 /* DeleteConfirmation.swift */; }; 156986252B88FCB600534720 /* ResourcePDFView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 156986242B88FCB600534720 /* ResourcePDFView.swift */; }; 15791C1A2B6AC34100D67C74 /* ResourcesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15791C192B6AC34100D67C74 /* ResourcesView.swift */; }; @@ -905,6 +906,7 @@ 153F96482BFD306F00FE5464 /* CreateDriveFolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateDriveFolder.swift; sourceTree = ""; }; 155369222B7E9CC100129F2F /* ResourceDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceDatabase.swift; sourceTree = ""; }; 155541AF2C066F990031D3A5 /* ServerConnectionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConnectionButton.swift; sourceTree = ""; }; + 155541B12C0672C20031D3A5 /* GDriveRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveRepository.swift; sourceTree = ""; }; 15622F492B72B1FF00289816 /* DeleteConfirmation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteConfirmation.swift; sourceTree = ""; }; 156986242B88FCB600534720 /* ResourcePDFView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourcePDFView.swift; sourceTree = ""; }; 15791C192B6AC34100D67C74 /* ResourcesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourcesView.swift; sourceTree = ""; }; @@ -2141,6 +2143,7 @@ E131BA3A2A1B45A30095BC91 /* UwaziServerRepositories.swift */, 1293F6742AD8853500F6CFBD /* FeedbackRepository.swift */, 15FABA352B73F96800B2EFEE /* ResourceRepository.swift */, + 155541B12C0672C20031D3A5 /* GDriveRepository.swift */, ); path = Repositories; sourceTree = ""; @@ -3257,6 +3260,7 @@ E108B75729FE79340045CCBE /* UwaziServerViewModel.swift in Sources */, 1293F66A2AD7F29B00F6CFBD /* FeedbackViewModel.swift in Sources */, 1289B98B27C53C2400315FCE /* CameraTypeItemView.swift in Sources */, + 155541B22C0672C20031D3A5 /* GDriveRepository.swift in Sources */, 126AD14A27C6D5EB00081CC9 /* LocalizableCamera.swift in Sources */, 1535A5F12BAA06490009EA42 /* DownloadedResource.swift in Sources */, E1E7C58B2AAB7F2000DDB07E /* UwaziTranslationContext.swift in Sources */, diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift new file mode 100644 index 000000000..99bd7da1d --- /dev/null +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -0,0 +1,78 @@ +// +// GDriveRepository.swift +// Tella +// +// Created by gus valbuena on 5/28/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation +import GoogleSignIn +import GoogleAPIClientForREST + +protocol GDriveRepositoryProtocol { + func handleSignInButton(completion: @escaping (Result) -> Void) + func restorePreviousSignIn(completion: ((_ user: GIDGoogleUser?) -> Void)?) + func handleUrl(url: URL) + func getSharedDrives(googleUser: GIDGoogleUser?, completion: @escaping (Result<[GTLRDrive_Drive], Error>) -> Void) +} + +struct GDriveRepository: GDriveRepositoryProtocol { + static let shared = GDriveRepository() + private var rootViewController: UIViewController? { + return UIApplication.shared.windows.first?.rootViewController + } + + func handleSignInButton(completion: @escaping (Result) -> Void) { + guard let rootViewController = self.rootViewController else { + print("There is no root view controller!") + return + } + + GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { signInResult, error in + if let error = error { + completion(.failure(error)) + return + } else { + completion(.success(())) + } + } + } + + func restorePreviousSignIn(completion: ((_ user: GIDGoogleUser?) -> Void)? = nil) { + guard let rootViewController = self.rootViewController else { + print("There is no root view controller!") + return + } + + GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in + user?.addScopes(["https://www.googleapis.com/auth/drive"], presenting: rootViewController) + + completion?(user) + } + } + + func handleUrl(url: URL) { + GIDSignIn.sharedInstance.handle(url) + } + + func getSharedDrives(googleUser: GIDGoogleUser?, completion: @escaping (Result<[GTLRDrive_Drive], Error>) -> Void) { + guard let user = googleUser else { return } + let driveService = GTLRDriveService() + driveService.authorizer = user.fetcherAuthorizer + + let query = GTLRDriveQuery_DrivesList.query() + + driveService.executeQuery(query) { ticket, response, error in + if let error = error { + print("Error fetching drives: \(error.localizedDescription)") + } + + guard let driveList = response as? GTLRDrive_DriveList, let drives = driveList.drives else { + return + } + + completion(.success(drives)) + } + } +} diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift index 4e989b846..77b878298 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -7,40 +7,27 @@ // import Foundation -import GoogleSignIn -import GoogleAPIClientForREST class GDriveAuthViewModel: ObservableObject { - - func handleSignInButton(completion: @escaping () -> Void) { - guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { - print("There is no root view controller!") - return - } - - GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { signInResult, error in - if let error = error { - print("Error during Google Sign-In: \(error.localizedDescription)") - return - } else { - completion() - } - } + private let gDriveRepository: GDriveRepositoryProtocol + + init(repository: GDriveRepositoryProtocol = GDriveRepository.shared) { + self.gDriveRepository = repository } - - func restorePreviousSignIn() { - guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { - print("There is no root view controller!") - return + + func handleSignInButton(completion: @escaping (Result) -> Void) { + gDriveRepository.handleSignInButton { result in + completion(result) } - - GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in - user?.addScopes(["https://www.googleapis.com/auth/drive"], presenting: rootViewController) - dump(user) + } + + func restorePreviousSignIn() { + gDriveRepository.restorePreviousSignIn() { _ in + } } - + func handleUrl(url: URL) { - GIDSignIn.sharedInstance.handle(url) + gDriveRepository.handleUrl(url: url) } } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index e6b429d24..7b8ca67d0 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -11,34 +11,31 @@ import GoogleSignIn import GoogleAPIClientForREST class GDriveServerViewModel: ObservableObject { - var googleUser:GIDGoogleUser? = nil + private let gDriveRepository: GDriveRepositoryProtocol + + @Published var googleUser: GIDGoogleUser? = nil @Published var sharedDrives: [GTLRDrive_Drive] = [] - - init() { - GIDSignIn.sharedInstance.restorePreviousSignIn { [self] user, error in - self.googleUser = user - - getSharedDrives() + + init(repository: GDriveRepositoryProtocol = GDriveRepository.shared) { + self.gDriveRepository = repository + restorePreviousSignIn() + } + + func restorePreviousSignIn() { + gDriveRepository.restorePreviousSignIn { [weak self] user in + self?.googleUser = user + self?.getSharedDrives() } } - + func getSharedDrives() { - guard let user = self.googleUser else { return } - let driveService = GTLRDriveService() - driveService.authorizer = user.fetcherAuthorizer - - let query = GTLRDriveQuery_DrivesList.query() - - driveService.executeQuery(query) { ticket, response, error in - if let error = error { + gDriveRepository.getSharedDrives(googleUser: googleUser) { [weak self] result in + switch result { + case .success(let drives): + self?.sharedDrives = drives + case .failure(let error): print("Error fetching drives: \(error.localizedDescription)") } - - guard let driveList = response as? GTLRDrive_DriveList, let drives = driveList.drives else { - return - } - - self.sharedDrives = drives } } } diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 47c778f1d..29db3dbf6 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -82,7 +82,7 @@ struct ServerSelectionView: View { } fileprivate func navigateToGDriveFlow() { - gDriveVM.handleSignInButton { + gDriveVM.handleSignInButton {_ in navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") } } From 05203a1bc471ff535ce2f775e4f91fd40968a8a7 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 28 May 2024 18:43:17 -0300 Subject: [PATCH 015/167] add gdrive url to TellaURL list --- .../Settings/Views/Servers/GDrive/SelectDriveConnection.swift | 2 +- Tella/Utils/Constants.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index 5d999f10f..e5e52f32c 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -55,7 +55,7 @@ struct SelectDriveConnection: View { var moreInfoText: some View { - Link(destination: URL(string: "https://tella-app.org/gdrive")!) { + Link(destination: URL(string: TellaUrls.gDriveURL)!) { Text("Learn more about the types of drives") .font(.custom(Styles.Fonts.regularFontName, size: 14)) .foregroundColor(Styles.Colors.yellow) diff --git a/Tella/Utils/Constants.swift b/Tella/Utils/Constants.swift index 8800bfb54..7c54773bd 100644 --- a/Tella/Utils/Constants.swift +++ b/Tella/Utils/Constants.swift @@ -8,5 +8,5 @@ struct TellaUrls { static let contactURL = "mailto:contact@tella-app.org" static let privacyURL = "https://tella-app.org/privacy/" static let feedbackURL = "https://tella-app.org/features#feedback" - + static let gDriveURL = "https://tella-app.org/gdrive" } From acb0400ffe268601706a618424dab10828224539 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 29 May 2024 15:25:53 -0300 Subject: [PATCH 016/167] add isValid constraint when creating a folder in gDrive --- Tella.xcodeproj/project.pbxproj | 40 ++----------------- .../ServerConnectionHeaderView.swift} | 8 ++-- .../Servers/GDrive/CreateDriveFolder.swift | 14 +++++-- .../GDrive/SelectDriveConnection.swift | 2 +- 4 files changed, 20 insertions(+), 44 deletions(-) rename Tella/{Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift => Components/ServerConnectionHeaderView.swift} (77%) diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 28cc3eb7a..3b93856df 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -348,6 +348,7 @@ 12FDEDD5272AFE99005C17AC /* LocalizableHome.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12FDEDD4272AFE99005C17AC /* LocalizableHome.swift */; }; 12FFEFA528BE96E00081DDB2 /* AddServerURLView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12FFEFA428BE96E00081DDB2 /* AddServerURLView.swift */; }; 1501401D2B71243A00991D69 /* LocalizableResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1501401C2B71243A00991D69 /* LocalizableResources.swift */; }; + 1503C87E2C07A080000F2209 /* ServerConnectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1503C87D2C07A080000F2209 /* ServerConnectionHeaderView.swift */; }; 150913422B841C3F001E782A /* ResourceActionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 150913412B841C3F001E782A /* ResourceActionType.swift */; }; 151308172BF3DBD9000C51D7 /* UwaziRelationshipList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 151308162BF3DBD9000C51D7 /* UwaziRelationshipList.swift */; }; 1519BED82B9A5A52006FD290 /* Resource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1519BED72B9A5A52006FD290 /* Resource.swift */; }; @@ -897,6 +898,7 @@ 12FDEDD4272AFE99005C17AC /* LocalizableHome.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizableHome.swift; sourceTree = ""; }; 12FFEFA428BE96E00081DDB2 /* AddServerURLView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddServerURLView.swift; sourceTree = ""; }; 1501401C2B71243A00991D69 /* LocalizableResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizableResources.swift; sourceTree = ""; }; + 1503C87D2C07A080000F2209 /* ServerConnectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConnectionHeaderView.swift; sourceTree = ""; }; 150913412B841C3F001E782A /* ResourceActionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceActionType.swift; sourceTree = ""; }; 151308162BF3DBD9000C51D7 /* UwaziRelationshipList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziRelationshipList.swift; sourceTree = ""; }; 1519BED72B9A5A52006FD290 /* Resource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Resource.swift; sourceTree = ""; }; @@ -2185,6 +2187,7 @@ 15791C1B2B6AC63200D67C74 /* ReloadButton.swift */, 15BD9CAC2BC7410E00C3932B /* SearchBarView.swift */, 15BD9CB02BC744BC00C3932B /* NavigationHeaderView.swift */, + 1503C87D2C07A080000F2209 /* ServerConnectionHeaderView.swift */, ); path = Components; sourceTree = ""; @@ -2307,7 +2310,6 @@ 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */, 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */, 153F96482BFD306F00FE5464 /* CreateDriveFolder.swift */, - 15944F6E2BFFCE98008430BA /* GDriveHeaderView.swift */, ); path = GDrive; sourceTree = ""; @@ -3032,40 +3034,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 11819532921BA895BF7C12D0 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 1ADB16E63DE3CFDCE1776489 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; 36C5FA1BF18AC473E32B7C1A /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -3290,7 +3258,6 @@ 12782B4A2B8400E500B5BC36 /* Cryptor.swift in Sources */, 1293F6702AD8295400F6CFBD /* BorderedTextEditorView.swift in Sources */, 129B845928BFED9700F1B344 /* TellaButtonView.swift in Sources */, - 15944F6F2BFFCE98008430BA /* GDriveHeaderView.swift in Sources */, 123048D7295F95BB0015CD96 /* SubmittedDetailsItemView.swift in Sources */, E1CF5A272AB3488E00365036 /* JSONDecoderExtension.swift in Sources */, 1291F4F227B52BF9006A34D3 /* QueuePlayer.swift in Sources */, @@ -3562,6 +3529,7 @@ CC1313842A5CB3590057271C /* DeleteAfterFailView.swift in Sources */, 12964D922BAB44C8003E1E0A /* UwaziEntityInstanceFile.swift in Sources */, 0DC267A6267AED7C00E55AFA /* VaultFile.swift in Sources */, + 1503C87E2C07A080000F2209 /* ServerConnectionHeaderView.swift in Sources */, 12751EAA2A13A22100FAD7C6 /* SettingsModel.swift in Sources */, 15994A0C2BFBC6F40017F153 /* SelectDriveConnection.swift in Sources */, 1203CDDE298D7C1300D09073 /* FileToUpload.swift in Sources */, diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift b/Tella/Components/ServerConnectionHeaderView.swift similarity index 77% rename from Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift rename to Tella/Components/ServerConnectionHeaderView.swift index 0e7b7fa3f..32ef71564 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift +++ b/Tella/Components/ServerConnectionHeaderView.swift @@ -1,14 +1,14 @@ // -// GDriveHeaderView.swift +// ServerConnectionHeaderView.swift // Tella // -// Created by gus valbuena on 5/23/24. +// Created by gus valbuena on 5/29/24. // Copyright © 2024 HORIZONTAL. All rights reserved. // import SwiftUI -struct GDriveHeaderView: View { +struct ServerConnectionHeaderView: View { var title: String var subtitle: String var body: some View { @@ -27,5 +27,5 @@ struct GDriveHeaderView: View { } #Preview { - GDriveHeaderView(title: "", subtitle: "") + ServerConnectionHeaderView(title: "title", subtitle: "subtitle") } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift index 0c8464d05..2ef6a1f07 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift @@ -10,16 +10,24 @@ import SwiftUI struct CreateDriveFolder: View { @State var fieldContent : String = "" + @State var isValid : Bool = false var body: some View { ContainerView { VStack(spacing: 20) { Spacer() - GDriveHeaderView( + ServerConnectionHeaderView( title: "Create new folder", subtitle: "Your reports will be uploaded to a new folder on your Google Drive. Choose a name for this folder here." ) - TextfieldView(fieldContent: $fieldContent, isValid: .constant(true), shouldShowError: .constant(false), fieldType: .text, placeholder: "Folder name") + TextfieldView(fieldContent: $fieldContent, + isValid: .constant(true), + shouldShowError: .constant(false), + fieldType: .text, + placeholder: "Folder name") .padding(.vertical, 12) + .onChange(of: fieldContent) { newValue in + isValid = !newValue.isEmpty + } Spacer() bottomView }.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) @@ -28,7 +36,7 @@ struct CreateDriveFolder: View { } var bottomView: some View { - BottomLockView(isValid: .constant(true), + BottomLockView(isValid: $isValid, nextButtonAction: .action, shouldHideNext: false, shouldHideBack: false, diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index e5e52f32c..b32c62556 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -19,7 +19,7 @@ struct SelectDriveConnection: View { ContainerView { VStack(spacing: 20) { Spacer() - GDriveHeaderView( + ServerConnectionHeaderView( title: "Select a Drive to connect to", subtitle: "You can either connect to an organizational Shared Drive or create a new folder in your personal Drive." ) From 0cdb2d0994636933af662758887147555f63f7ec Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 30 May 2024 11:29:01 -0300 Subject: [PATCH 017/167] fix hardcoded strings, add space to VStacks and overall refactor --- Tella/Components/ServerConnectionHeaderView.swift | 3 ++- Tella/Data/Networking/Repositories/GDriveRepository.swift | 6 +++--- Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift | 4 ++-- .../Settings/Views/Servers/GDrive/CreateDriveFolder.swift | 5 +---- .../Views/Servers/GDrive/SelectDriveConnection.swift | 8 ++++---- .../Settings/Views/Servers/ServerSelectionView.swift | 4 +++- Tella/Utils/Constants.swift | 4 ++++ 7 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Tella/Components/ServerConnectionHeaderView.swift b/Tella/Components/ServerConnectionHeaderView.swift index 32ef71564..b7c0b84a8 100644 --- a/Tella/Components/ServerConnectionHeaderView.swift +++ b/Tella/Components/ServerConnectionHeaderView.swift @@ -12,8 +12,9 @@ struct ServerConnectionHeaderView: View { var title: String var subtitle: String var body: some View { - VStack(spacing: 20) { + VStack(spacing: 8) { Image("gdrive.icon") + .padding(.bottom, 16) Text(title) .font(.custom(Styles.Fonts.semiBoldFontName, size: 18)) .foregroundColor(.white) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 99bd7da1d..2e7f24077 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -11,7 +11,7 @@ import GoogleSignIn import GoogleAPIClientForREST protocol GDriveRepositoryProtocol { - func handleSignInButton(completion: @escaping (Result) -> Void) + func handleSignIn(completion: @escaping (Result) -> Void) func restorePreviousSignIn(completion: ((_ user: GIDGoogleUser?) -> Void)?) func handleUrl(url: URL) func getSharedDrives(googleUser: GIDGoogleUser?, completion: @escaping (Result<[GTLRDrive_Drive], Error>) -> Void) @@ -23,7 +23,7 @@ struct GDriveRepository: GDriveRepositoryProtocol { return UIApplication.shared.windows.first?.rootViewController } - func handleSignInButton(completion: @escaping (Result) -> Void) { + func handleSignIn(completion: @escaping (Result) -> Void) { guard let rootViewController = self.rootViewController else { print("There is no root view controller!") return @@ -46,7 +46,7 @@ struct GDriveRepository: GDriveRepositoryProtocol { } GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in - user?.addScopes(["https://www.googleapis.com/auth/drive"], presenting: rootViewController) + user?.addScopes([GoogleAuthScopes.gDriveScopes], presenting: rootViewController) completion?(user) } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift index 77b878298..13f13127d 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -15,8 +15,8 @@ class GDriveAuthViewModel: ObservableObject { self.gDriveRepository = repository } - func handleSignInButton(completion: @escaping (Result) -> Void) { - gDriveRepository.handleSignInButton { result in + func handleSignIn(completion: @escaping (Result) -> Void) { + gDriveRepository.handleSignIn { result in completion(result) } } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift index 2ef6a1f07..2582bb319 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift @@ -20,14 +20,11 @@ struct CreateDriveFolder: View { subtitle: "Your reports will be uploaded to a new folder on your Google Drive. Choose a name for this folder here." ) TextfieldView(fieldContent: $fieldContent, - isValid: .constant(true), + isValid: $isValid, shouldShowError: .constant(false), fieldType: .text, placeholder: "Folder name") .padding(.vertical, 12) - .onChange(of: fieldContent) { newValue in - isValid = !newValue.isEmpty - } Spacer() bottomView }.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index b32c62556..92c55c22a 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -17,7 +17,7 @@ struct SelectDriveConnection: View { @ObservedObject var dGriveServerViewModel: GDriveServerViewModel var body: some View { ContainerView { - VStack(spacing: 20) { + VStack(spacing: 24) { Spacer() ServerConnectionHeaderView( title: "Select a Drive to connect to", @@ -34,21 +34,21 @@ struct SelectDriveConnection: View { } var connectionsButtons: some View { - VStack { + VStack(spacing: 14) { TellaButtonView( title: "USE SHARED DRIVE", nextButtonAction: .action, isOverlay: selectedDriveConnectionType == .shared, isValid: .constant(true), action: { selectedDriveConnectionType = .shared } - ).padding(.vertical, 5) + ) TellaButtonView( title: "USE PERSONAL DRIVE", nextButtonAction: .action, isOverlay: selectedDriveConnectionType == .personal, isValid: .constant(true), action: {selectedDriveConnectionType = .personal} - ).padding(.vertical, 5) + ) moreInfoText } } diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 29db3dbf6..9a8d1a13a 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -82,9 +82,11 @@ struct ServerSelectionView: View { } fileprivate func navigateToGDriveFlow() { - gDriveVM.handleSignInButton {_ in + gDriveVM.handleSignIn {_ in navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") } + +// navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") } diff --git a/Tella/Utils/Constants.swift b/Tella/Utils/Constants.swift index 7c54773bd..de5feaafe 100644 --- a/Tella/Utils/Constants.swift +++ b/Tella/Utils/Constants.swift @@ -10,3 +10,7 @@ struct TellaUrls { static let feedbackURL = "https://tella-app.org/features#feedback" static let gDriveURL = "https://tella-app.org/gdrive" } + +struct GoogleAuthScopes { + static let gDriveScopes = "https://www.googleapis.com/auth/drive" +} From cfebc5dcb0611120932ba28eeb3c3cf085bd5ca7 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 30 May 2024 12:13:02 -0300 Subject: [PATCH 018/167] add serverConnectinoType extension for successLoginView --- Tella/Domain/Entity/Report/ServerType.swift | 13 +++++++++++ .../Servers/AddServer/SuccessLoginView.swift | 22 +++---------------- .../Views/Servers/ServerSelectionView.swift | 2 -- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/Tella/Domain/Entity/Report/ServerType.swift b/Tella/Domain/Entity/Report/ServerType.swift index 805bd856e..15d4128cd 100644 --- a/Tella/Domain/Entity/Report/ServerType.swift +++ b/Tella/Domain/Entity/Report/ServerType.swift @@ -19,3 +19,16 @@ func mapServerTypeFromInt(_ serverTypeInt: Int?) -> ServerConnectionType { return .unknown } } + +extension ServerConnectionType { + var successConnectionButtonContent: String { + switch self { + case .gDrive: + return "GO TO GOOGLE DRIVE" + case.tella: + return "GO TO REPORTS" + default: + return "" + } + } +} diff --git a/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift b/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift index 5f04873cd..49e84cfdb 100644 --- a/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift +++ b/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift @@ -5,31 +5,15 @@ import SwiftUI -enum SuccessLoginType { - case gDrive - case tella - - var buttonContent: String { - switch self { - case .gDrive: - return "GO TO GOOGLE DRIVE" - case.tella: - return "GO TO REPORTS" - } - } - -} - struct SuccessLoginView: View { - @EnvironmentObject var mainAppModel : MainAppModel @EnvironmentObject var serversViewModel : ServersViewModel @EnvironmentObject var serverViewModel : ServerViewModel - @EnvironmentObject private var appViewState: AppViewState @State var showNextView : Bool = false + var navigateToAction: () -> Void - var type: SuccessLoginType = .tella + var type: ServerConnectionType = .tella var body: some View { ContainerView { @@ -43,7 +27,7 @@ struct SuccessLoginView: View { Spacer() .frame(height: 48) - TellaButtonView (title: type.buttonContent, + TellaButtonView (title: type.successConnectionButtonContent, nextButtonAction: .action, buttonType: .yellow, isValid: .constant(true)) { diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 9a8d1a13a..9b69e7465 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -85,8 +85,6 @@ struct ServerSelectionView: View { gDriveVM.handleSignIn {_ in navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") } - -// navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") } From 5cc647ed4590d380ad64d23ea5bdf32c03f0d19c Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 30 May 2024 15:28:09 -0300 Subject: [PATCH 019/167] add domain model for shared drives --- .../Repositories/GDriveRepository.swift | 24 ++++++++++++------- Tella/Domain/Entity/GDrive/SharedDrive.swift | 8 ------- .../ViewModel/GDriveAuthViewModel.swift | 4 +--- .../ViewModel/GDriveServerViewModel.swift | 12 ++++------ .../Servers/GDrive/SelectSharedDrive.swift | 15 ++++++------ 5 files changed, 28 insertions(+), 35 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 2e7f24077..fb10bce3b 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -12,13 +12,16 @@ import GoogleAPIClientForREST protocol GDriveRepositoryProtocol { func handleSignIn(completion: @escaping (Result) -> Void) - func restorePreviousSignIn(completion: ((_ user: GIDGoogleUser?) -> Void)?) + func restorePreviousSignIn(completion: (() -> Void)?) func handleUrl(url: URL) - func getSharedDrives(googleUser: GIDGoogleUser?, completion: @escaping (Result<[GTLRDrive_Drive], Error>) -> Void) + func getSharedDrives(completion: @escaping (Result<[SharedDrive], Error>) -> Void) } -struct GDriveRepository: GDriveRepositoryProtocol { +class GDriveRepository: GDriveRepositoryProtocol { static let shared = GDriveRepository() + + private var googleUser: GIDGoogleUser? + private var rootViewController: UIViewController? { return UIApplication.shared.windows.first?.rootViewController } @@ -39,7 +42,7 @@ struct GDriveRepository: GDriveRepositoryProtocol { } } - func restorePreviousSignIn(completion: ((_ user: GIDGoogleUser?) -> Void)? = nil) { + func restorePreviousSignIn(completion: (() -> Void)? = nil) { guard let rootViewController = self.rootViewController else { print("There is no root view controller!") return @@ -48,7 +51,8 @@ struct GDriveRepository: GDriveRepositoryProtocol { GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in user?.addScopes([GoogleAuthScopes.gDriveScopes], presenting: rootViewController) - completion?(user) + self.googleUser = user + completion?() } } @@ -56,8 +60,8 @@ struct GDriveRepository: GDriveRepositoryProtocol { GIDSignIn.sharedInstance.handle(url) } - func getSharedDrives(googleUser: GIDGoogleUser?, completion: @escaping (Result<[GTLRDrive_Drive], Error>) -> Void) { - guard let user = googleUser else { return } + func getSharedDrives(completion: @escaping (Result<[SharedDrive], Error>) -> Void) { + guard let user = self.googleUser else { return } let driveService = GTLRDriveService() driveService.authorizer = user.fetcherAuthorizer @@ -71,8 +75,12 @@ struct GDriveRepository: GDriveRepositoryProtocol { guard let driveList = response as? GTLRDrive_DriveList, let drives = driveList.drives else { return } + + let sharedDrives = drives.map { drive in + SharedDrive(id: drive.identifier ?? "", name: drive.name ?? "", kind: drive.kind ?? "") + } - completion(.success(drives)) + completion(.success(sharedDrives)) } } } diff --git a/Tella/Domain/Entity/GDrive/SharedDrive.swift b/Tella/Domain/Entity/GDrive/SharedDrive.swift index 684fb3f7d..6e1fce089 100644 --- a/Tella/Domain/Entity/GDrive/SharedDrive.swift +++ b/Tella/Domain/Entity/GDrive/SharedDrive.swift @@ -19,11 +19,3 @@ class SharedDrive: DomainModel { self.kind = kind } } - -var SharedDrivesList: [SharedDrive] = [ - SharedDrive(id: "1", name: "Admin", kind: "drive#drive"), - SharedDrive(id: "2", name: "Backup", kind: "drive#drive"), - SharedDrive(id: "3", name: "Community", kind: "drive#drive"), - SharedDrive(id: "4", name: "Contact database", kind: "drive#drive"), - SharedDrive(id: "5", name: "Incident reports", kind: "drive#drive") -] diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift index 13f13127d..b6acc6f4b 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -22,9 +22,7 @@ class GDriveAuthViewModel: ObservableObject { } func restorePreviousSignIn() { - gDriveRepository.restorePreviousSignIn() { _ in - - } + gDriveRepository.restorePreviousSignIn() {} } func handleUrl(url: URL) { diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 7b8ca67d0..661b636ea 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -7,14 +7,11 @@ // import Foundation -import GoogleSignIn -import GoogleAPIClientForREST class GDriveServerViewModel: ObservableObject { private let gDriveRepository: GDriveRepositoryProtocol - @Published var googleUser: GIDGoogleUser? = nil - @Published var sharedDrives: [GTLRDrive_Drive] = [] + @Published var sharedDrives: [SharedDrive] = [] init(repository: GDriveRepositoryProtocol = GDriveRepository.shared) { self.gDriveRepository = repository @@ -22,14 +19,13 @@ class GDriveServerViewModel: ObservableObject { } func restorePreviousSignIn() { - gDriveRepository.restorePreviousSignIn { [weak self] user in - self?.googleUser = user - self?.getSharedDrives() + gDriveRepository.restorePreviousSignIn { + self.getSharedDrives() } } func getSharedDrives() { - gDriveRepository.getSharedDrives(googleUser: googleUser) { [weak self] result in + gDriveRepository.getSharedDrives() { [weak self] result in switch result { case .success(let drives): self?.sharedDrives = drives diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index 6ba3ab515..12bd252e7 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -7,15 +7,14 @@ // import SwiftUI -import GoogleAPIClientForREST struct SelectSharedDrive: View { @State var selectedDrive: String = "" - @State var sharedDrives: [GTLRDrive_Drive] = [] + @State var sharedDrives: [SharedDrive] = [] var body: some View { ContainerView { VStack(alignment: .leading){ - ForEach(sharedDrives, id: \.identifier) { drive in + ForEach(sharedDrives, id: \.id) { drive in DriveCardView(sharedDrive: drive, selectedDrive: $selectedDrive) } @@ -41,23 +40,23 @@ struct SelectSharedDrive: View { } struct DriveCardView: View { - var sharedDrive: GTLRDrive_Drive + var sharedDrive: SharedDrive @Binding var selectedDrive: String var body: some View { Button(action: { - self.selectedDrive = sharedDrive.identifier ?? "" + self.selectedDrive = sharedDrive.id }) { HStack { - Text(sharedDrive.name ?? "") + Text(sharedDrive.name) .font(.custom(Styles.Fonts.regularFontName, size: 16)) .foregroundColor(.white) Spacer() - if selectedDrive == sharedDrive.identifier { + if selectedDrive == sharedDrive.id { Image("settings.done") } } .padding(18) - .background(selectedDrive == sharedDrive.identifier ? Color.white.opacity(0.1) : Color.clear) + .background(selectedDrive == sharedDrive.id ? Color.white.opacity(0.1) : Color.clear) } } } From 8cfd5284eeb7c6a05b2543ffa9b851db07e00354 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 3 Jun 2024 13:44:14 -0300 Subject: [PATCH 020/167] add combine in gDriveRepository --- .../Repositories/GDriveRepository.swift | 51 +++++++++++-------- .../ViewModel/GDriveServerViewModel.swift | 22 +++++--- 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index fb10bce3b..80f9d187f 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -9,12 +9,13 @@ import Foundation import GoogleSignIn import GoogleAPIClientForREST +import Combine protocol GDriveRepositoryProtocol { func handleSignIn(completion: @escaping (Result) -> Void) func restorePreviousSignIn(completion: (() -> Void)?) func handleUrl(url: URL) - func getSharedDrives(completion: @escaping (Result<[SharedDrive], Error>) -> Void) + func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> } class GDriveRepository: GDriveRepositoryProtocol { @@ -60,27 +61,37 @@ class GDriveRepository: GDriveRepositoryProtocol { GIDSignIn.sharedInstance.handle(url) } - func getSharedDrives(completion: @escaping (Result<[SharedDrive], Error>) -> Void) { - guard let user = self.googleUser else { return } - let driveService = GTLRDriveService() - driveService.authorizer = user.fetcherAuthorizer - - let query = GTLRDriveQuery_DrivesList.query() - - driveService.executeQuery(query) { ticket, response, error in - if let error = error { - print("Error fetching drives: \(error.localizedDescription)") - } + func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> { + Deferred { + Future { [weak self] promise in + guard let user = self?.googleUser else { return } + let driveService = GTLRDriveService() + driveService.authorizer = user.fetcherAuthorizer - guard let driveList = response as? GTLRDrive_DriveList, let drives = driveList.drives else { - return - } - - let sharedDrives = drives.map { drive in - SharedDrive(id: drive.identifier ?? "", name: drive.name ?? "", kind: drive.kind ?? "") - } + let query = GTLRDriveQuery_DrivesList.query() + + driveService.executeQuery(query) { ticket, response, error in + if let error = error { + print("Error fetching drives: \(error.localizedDescription)") + promise(.failure(error)) + } - completion(.success(sharedDrives)) + guard let driveList = response as? GTLRDrive_DriveList, + let drives = driveList.drives + else { + return + } + + let sharedDrives = drives.map { drive in + SharedDrive( + id: drive.identifier ?? "", name: drive.name ?? "", + kind: drive.kind ?? "") + } + + promise(.success(sharedDrives)) + } + } } + .eraseToAnyPublisher() } } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 661b636ea..a44691f3f 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -7,9 +7,11 @@ // import Foundation +import Combine class GDriveServerViewModel: ObservableObject { private let gDriveRepository: GDriveRepositoryProtocol + private var cancellables = Set() @Published var sharedDrives: [SharedDrive] = [] @@ -25,13 +27,19 @@ class GDriveServerViewModel: ObservableObject { } func getSharedDrives() { - gDriveRepository.getSharedDrives() { [weak self] result in - switch result { - case .success(let drives): + gDriveRepository.getSharedDrives() + .receive(on: DispatchQueue.main) + .sink(receiveCompletion: {completion in + switch completion { + case .finished: + break + case.failure(let error): + debugLog("error fetching drives: \(error.localizedDescription)") + } + }, + receiveValue: { [weak self] drives in self?.sharedDrives = drives - case .failure(let error): - print("Error fetching drives: \(error.localizedDescription)") - } - } + }) + .store(in: &cancellables) } } From 1a6aa4a278bc55cf8ec7876b39fefe4c2508197c Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 4 Jun 2024 13:30:56 -0300 Subject: [PATCH 021/167] add combine to the rest of the gDrive endpoints --- .../Repositories/GDriveRepository.swift | 67 +++++++++++-------- .../ViewModel/GDriveAuthViewModel.swift | 38 +++++++++-- .../ViewModel/GDriveServerViewModel.swift | 19 ++++-- .../Views/Servers/ServerSelectionView.swift | 2 +- 4 files changed, 89 insertions(+), 37 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 80f9d187f..7e8da39b4 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -12,8 +12,8 @@ import GoogleAPIClientForREST import Combine protocol GDriveRepositoryProtocol { - func handleSignIn(completion: @escaping (Result) -> Void) - func restorePreviousSignIn(completion: (() -> Void)?) + func handleSignIn() -> AnyPublisher + func restorePreviousSignIn() -> AnyPublisher func handleUrl(url: URL) func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> } @@ -27,34 +27,47 @@ class GDriveRepository: GDriveRepositoryProtocol { return UIApplication.shared.windows.first?.rootViewController } - func handleSignIn(completion: @escaping (Result) -> Void) { - guard let rootViewController = self.rootViewController else { - print("There is no root view controller!") - return - } - - GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { signInResult, error in - if let error = error { - completion(.failure(error)) - return - } else { - completion(.success(())) + func handleSignIn() -> AnyPublisher { + Deferred { + Future { [weak self] promise in + guard let rootViewController = self?.rootViewController else { + print("There is no root view controller!") + return + } + + GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { signInResult, error in + if let error = error { + promise(.failure(error)) + return + } else { + promise(.success(true)) + } + } } - } + }.eraseToAnyPublisher() } - func restorePreviousSignIn(completion: (() -> Void)? = nil) { - guard let rootViewController = self.rootViewController else { - print("There is no root view controller!") - return - } - - GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in - user?.addScopes([GoogleAuthScopes.gDriveScopes], presenting: rootViewController) - - self.googleUser = user - completion?() - } + func restorePreviousSignIn() -> AnyPublisher { + Deferred { + Future { [weak self] promise in + guard let rootViewController = self?.rootViewController else { + print("There is no root view controller!") + return + } + + GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in + if let error = error { + promise(.failure(error)) + return + } + user?.addScopes([GoogleAuthScopes.gDriveScopes], presenting: rootViewController) + + self?.googleUser = user + promise(.success(true)) + } + + } + }.eraseToAnyPublisher() } func handleUrl(url: URL) { diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift index b6acc6f4b..de729bc84 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -7,22 +7,50 @@ // import Foundation +import Combine class GDriveAuthViewModel: ObservableObject { private let gDriveRepository: GDriveRepositoryProtocol + private var cancellables = Set() init(repository: GDriveRepositoryProtocol = GDriveRepository.shared) { self.gDriveRepository = repository } - func handleSignIn(completion: @escaping (Result) -> Void) { - gDriveRepository.handleSignIn { result in - completion(result) - } + func handleSignIn(completion: @escaping () -> Void) { + gDriveRepository.handleSignIn() + .receive(on: DispatchQueue.main) + .sink( + receiveCompletion: { completion in + switch(completion) { + case .finished: + break + case .failure(let error): + Toast.displayToast(message: error.localizedDescription) + break + } + }, + receiveValue: {_ in + completion() + } + ).store(in: &cancellables) } func restorePreviousSignIn() { - gDriveRepository.restorePreviousSignIn() {} + gDriveRepository.restorePreviousSignIn() + .receive(on: DispatchQueue.main) + .sink(receiveCompletion: { completion in + switch(completion) { + case .finished: + break + case .failure(let error): + Toast.displayToast(message: error.localizedDescription) + break + } + }, receiveValue: { _ in + + }) + .store(in: &cancellables) } func handleUrl(url: URL) { diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index a44691f3f..ecf7a3063 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -21,9 +21,19 @@ class GDriveServerViewModel: ObservableObject { } func restorePreviousSignIn() { - gDriveRepository.restorePreviousSignIn { - self.getSharedDrives() - } + gDriveRepository.restorePreviousSignIn() + .receive(on: DispatchQueue.main) + .sink(receiveCompletion: { completion in + switch completion { + case .finished: + break + case .failure(let error): + Toast.displayToast(message: error.localizedDescription) + } + },receiveValue: {_ in + self.getSharedDrives() + }).store(in: &cancellables) + } func getSharedDrives() { @@ -34,7 +44,8 @@ class GDriveServerViewModel: ObservableObject { case .finished: break case.failure(let error): - debugLog("error fetching drives: \(error.localizedDescription)") + debugLog(error) + Toast.displayToast(message: error.localizedDescription) } }, receiveValue: { [weak self] drives in diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 9b69e7465..d3e183400 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -82,7 +82,7 @@ struct ServerSelectionView: View { } fileprivate func navigateToGDriveFlow() { - gDriveVM.handleSignIn {_ in + gDriveVM.handleSignIn { navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") } } From 28f6a060bea1dcf079e4bd2b344ecd70138c3da0 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 4 Jun 2024 15:28:22 -0300 Subject: [PATCH 022/167] remove toast if user is not authenticated --- Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift index de729bc84..8705f3b16 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -43,8 +43,7 @@ class GDriveAuthViewModel: ObservableObject { switch(completion) { case .finished: break - case .failure(let error): - Toast.displayToast(message: error.localizedDescription) + case .failure(_): break } }, receiveValue: { _ in From af3cab64c62451389fa3806ec51b0af2e1af4d68 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 5 Jun 2024 14:38:29 -0300 Subject: [PATCH 023/167] add async await for gDrive methods --- Tella/Application/TellaApp.swift | 2 - .../Repositories/GDriveRepository.swift | 39 ++++++++----------- .../ViewModel/GDriveAuthViewModel.swift | 38 +++++------------- .../ViewModel/GDriveServerViewModel.swift | 18 ++++----- 4 files changed, 33 insertions(+), 64 deletions(-) diff --git a/Tella/Application/TellaApp.swift b/Tella/Application/TellaApp.swift index 3bda0ebe9..829d0c0de 100644 --- a/Tella/Application/TellaApp.swift +++ b/Tella/Application/TellaApp.swift @@ -27,8 +27,6 @@ struct TellaApp: App { if value { self.saveData(lockApptype: .finishBackgroundTasks) } - }.onAppear { - gDriveAuthViewModel.restorePreviousSignIn() }.onOpenURL { url in gDriveAuthViewModel.handleUrl(url: url) } diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 7e8da39b4..055bb66d1 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -12,8 +12,8 @@ import GoogleAPIClientForREST import Combine protocol GDriveRepositoryProtocol { - func handleSignIn() -> AnyPublisher - func restorePreviousSignIn() -> AnyPublisher + func handleSignIn() async throws -> Void + func restorePreviousSignIn() async throws -> Void func handleUrl(url: URL) func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> } @@ -27,47 +27,42 @@ class GDriveRepository: GDriveRepositoryProtocol { return UIApplication.shared.windows.first?.rootViewController } - func handleSignIn() -> AnyPublisher { - Deferred { - Future { [weak self] promise in - guard let rootViewController = self?.rootViewController else { - print("There is no root view controller!") + func handleSignIn() async throws { + try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in + DispatchQueue.main.async { + guard let rootViewController = self.rootViewController else { return } - GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { signInResult, error in if let error = error { - promise(.failure(error)) - return + continuation.resume(throwing: error) } else { - promise(.success(true)) + continuation.resume(returning: ()) } } } - }.eraseToAnyPublisher() + } } - func restorePreviousSignIn() -> AnyPublisher { - Deferred { - Future { [weak self] promise in - guard let rootViewController = self?.rootViewController else { - print("There is no root view controller!") + func restorePreviousSignIn() async throws { + try await withCheckedThrowingContinuation{ (continuation: CheckedContinuation) in + DispatchQueue.main.async { + guard let rootViewController = self.rootViewController else { return } GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in if let error = error { - promise(.failure(error)) + continuation.resume(throwing: error) return } user?.addScopes([GoogleAuthScopes.gDriveScopes], presenting: rootViewController) - self?.googleUser = user - promise(.success(true)) + self.googleUser = user + continuation.resume(returning: ()) } - } - }.eraseToAnyPublisher() + } } func handleUrl(url: URL) { diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift index 8705f3b16..c5c1662ed 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -18,38 +18,18 @@ class GDriveAuthViewModel: ObservableObject { } func handleSignIn(completion: @escaping () -> Void) { - gDriveRepository.handleSignIn() - .receive(on: DispatchQueue.main) - .sink( - receiveCompletion: { completion in - switch(completion) { - case .finished: - break - case .failure(let error): - Toast.displayToast(message: error.localizedDescription) - break - } - }, - receiveValue: {_ in + Task { + do { + try await gDriveRepository.handleSignIn() + DispatchQueue.main.async { completion() } - ).store(in: &cancellables) - } - - func restorePreviousSignIn() { - gDriveRepository.restorePreviousSignIn() - .receive(on: DispatchQueue.main) - .sink(receiveCompletion: { completion in - switch(completion) { - case .finished: - break - case .failure(_): - break + } catch let error { + DispatchQueue.main.async { + Toast.displayToast(message: error.localizedDescription) } - }, receiveValue: { _ in - - }) - .store(in: &cancellables) + } + } } func handleUrl(url: URL) { diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index ecf7a3063..421426cb7 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -21,18 +21,14 @@ class GDriveServerViewModel: ObservableObject { } func restorePreviousSignIn() { - gDriveRepository.restorePreviousSignIn() - .receive(on: DispatchQueue.main) - .sink(receiveCompletion: { completion in - switch completion { - case .finished: - break - case .failure(let error): - Toast.displayToast(message: error.localizedDescription) - } - },receiveValue: {_ in + Task { + do { + try await gDriveRepository.restorePreviousSignIn() self.getSharedDrives() - }).store(in: &cancellables) + } catch let error { + Toast.displayToast(message: error.localizedDescription) + } + } } From 1c4e420078f28d2505ec607dd86ca2229dce6f53 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 9 May 2024 13:06:45 -0300 Subject: [PATCH 024/167] implementing google sdk --- Tella.xcodeproj/project.pbxproj | 34 +++++++++++++++++++ Tella/Application/TellaApp.swift | 1 + .../Views/Servers/ServerSelectionView.swift | 2 ++ 3 files changed, 37 insertions(+) diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 3b93856df..8114442da 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -3034,6 +3034,40 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 11819532921BA895BF7C12D0 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 1ADB16E63DE3CFDCE1776489 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 36C5FA1BF18AC473E32B7C1A /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/Tella/Application/TellaApp.swift b/Tella/Application/TellaApp.swift index 829d0c0de..0faa0a1fd 100644 --- a/Tella/Application/TellaApp.swift +++ b/Tella/Application/TellaApp.swift @@ -7,6 +7,7 @@ // import SwiftUI +import GoogleSignIn @main struct TellaApp: App { diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index d3e183400..514644652 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -8,6 +8,8 @@ import SwiftUI +import GoogleSignIn + struct ServerSelectionView: View { @EnvironmentObject var serversViewModel : ServersViewModel @StateObject var serverViewModel : ServerViewModel From 8bdd46e42ec41f8ab750ffbf4bf1ed3a2eb7d71b Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 22 May 2024 16:32:09 -0300 Subject: [PATCH 025/167] basic implemantation of d-drive library --- .../Settings/Views/Servers/GDrive/SelectSharedDrive.swift | 5 +++-- .../Scenes/Settings/Views/Servers/ServerSelectionView.swift | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index 12bd252e7..c3884eef0 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -7,6 +7,7 @@ // import SwiftUI +import GoogleAPIClientForREST struct SelectSharedDrive: View { @State var selectedDrive: String = "" @@ -40,14 +41,14 @@ struct SelectSharedDrive: View { } struct DriveCardView: View { - var sharedDrive: SharedDrive + var sharedDrive: GTLRDrive_Drive @Binding var selectedDrive: String var body: some View { Button(action: { self.selectedDrive = sharedDrive.id }) { HStack { - Text(sharedDrive.name) + Text(sharedDrive.name ?? "") .font(.custom(Styles.Fonts.regularFontName, size: 16)) .foregroundColor(.white) Spacer() diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 514644652..d3e183400 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -8,8 +8,6 @@ import SwiftUI -import GoogleSignIn - struct ServerSelectionView: View { @EnvironmentObject var serversViewModel : ServersViewModel @StateObject var serverViewModel : ServerViewModel From 49ce55014287ff3c18d4facce8ae4c8a9034ff5d Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 23 May 2024 16:28:33 -0300 Subject: [PATCH 026/167] final tweaks --- Tella.xcodeproj/project.pbxproj | 2 ++ Tella/Application/TellaApp.swift | 1 - .../ViewModel/GDriveAuthViewModel.swift | 16 ++++++++++ .../Servers/GDrive/GDriveHeaderView.swift | 31 +++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 8114442da..55d74d8d7 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -2310,6 +2310,7 @@ 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */, 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */, 153F96482BFD306F00FE5464 /* CreateDriveFolder.swift */, + 15944F6E2BFFCE98008430BA /* GDriveHeaderView.swift */, ); path = GDrive; sourceTree = ""; @@ -3292,6 +3293,7 @@ 12782B4A2B8400E500B5BC36 /* Cryptor.swift in Sources */, 1293F6702AD8295400F6CFBD /* BorderedTextEditorView.swift in Sources */, 129B845928BFED9700F1B344 /* TellaButtonView.swift in Sources */, + 15944F6F2BFFCE98008430BA /* GDriveHeaderView.swift in Sources */, 123048D7295F95BB0015CD96 /* SubmittedDetailsItemView.swift in Sources */, E1CF5A272AB3488E00365036 /* JSONDecoderExtension.swift in Sources */, 1291F4F227B52BF9006A34D3 /* QueuePlayer.swift in Sources */, diff --git a/Tella/Application/TellaApp.swift b/Tella/Application/TellaApp.swift index 0faa0a1fd..829d0c0de 100644 --- a/Tella/Application/TellaApp.swift +++ b/Tella/Application/TellaApp.swift @@ -7,7 +7,6 @@ // import SwiftUI -import GoogleSignIn @main struct TellaApp: App { diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift index c5c1662ed..8164e37ab 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -35,4 +35,20 @@ class GDriveAuthViewModel: ObservableObject { func handleUrl(url: URL) { gDriveRepository.handleUrl(url: url) } + + func restorePreviousSignIn() { + guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { + print("There is no root view controller!") + return + } + + GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in + user?.addScopes(["https://www.googleapis.com/auth/drive"], presenting: rootViewController) + dump(user) + } + } + + func handleUrl(url: URL) { + GIDSignIn.sharedInstance.handle(url) + } } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift new file mode 100644 index 000000000..0e7b7fa3f --- /dev/null +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift @@ -0,0 +1,31 @@ +// +// GDriveHeaderView.swift +// Tella +// +// Created by gus valbuena on 5/23/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import SwiftUI + +struct GDriveHeaderView: View { + var title: String + var subtitle: String + var body: some View { + VStack(spacing: 20) { + Image("gdrive.icon") + Text(title) + .font(.custom(Styles.Fonts.semiBoldFontName, size: 18)) + .foregroundColor(.white) + .multilineTextAlignment(.center) + Text(subtitle) + .font(.custom(Styles.Fonts.regularFontName, size: 14)) + .foregroundColor(.white) + .multilineTextAlignment(.center) + }.padding(.horizontal, 20) + } +} + +#Preview { + GDriveHeaderView(title: "", subtitle: "") +} From 83df53588ab904c6f0046b18f04c75ab36cc05d0 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 29 May 2024 15:25:53 -0300 Subject: [PATCH 027/167] add isValid constraint when creating a folder in gDrive --- Tella.xcodeproj/project.pbxproj | 36 ------------------- .../Servers/GDrive/CreateDriveFolder.swift | 3 ++ .../Servers/GDrive/GDriveHeaderView.swift | 31 ---------------- 3 files changed, 3 insertions(+), 67 deletions(-) delete mode 100644 Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 55d74d8d7..3b93856df 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -2310,7 +2310,6 @@ 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */, 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */, 153F96482BFD306F00FE5464 /* CreateDriveFolder.swift */, - 15944F6E2BFFCE98008430BA /* GDriveHeaderView.swift */, ); path = GDrive; sourceTree = ""; @@ -3035,40 +3034,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 11819532921BA895BF7C12D0 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 1ADB16E63DE3CFDCE1776489 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; 36C5FA1BF18AC473E32B7C1A /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -3293,7 +3258,6 @@ 12782B4A2B8400E500B5BC36 /* Cryptor.swift in Sources */, 1293F6702AD8295400F6CFBD /* BorderedTextEditorView.swift in Sources */, 129B845928BFED9700F1B344 /* TellaButtonView.swift in Sources */, - 15944F6F2BFFCE98008430BA /* GDriveHeaderView.swift in Sources */, 123048D7295F95BB0015CD96 /* SubmittedDetailsItemView.swift in Sources */, E1CF5A272AB3488E00365036 /* JSONDecoderExtension.swift in Sources */, 1291F4F227B52BF9006A34D3 /* QueuePlayer.swift in Sources */, diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift index 2582bb319..fe628a4c8 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift @@ -25,6 +25,9 @@ struct CreateDriveFolder: View { fieldType: .text, placeholder: "Folder name") .padding(.vertical, 12) + .onChange(of: fieldContent) { newValue in + isValid = !newValue.isEmpty + } Spacer() bottomView }.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift deleted file mode 100644 index 0e7b7fa3f..000000000 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/GDriveHeaderView.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// GDriveHeaderView.swift -// Tella -// -// Created by gus valbuena on 5/23/24. -// Copyright © 2024 HORIZONTAL. All rights reserved. -// - -import SwiftUI - -struct GDriveHeaderView: View { - var title: String - var subtitle: String - var body: some View { - VStack(spacing: 20) { - Image("gdrive.icon") - Text(title) - .font(.custom(Styles.Fonts.semiBoldFontName, size: 18)) - .foregroundColor(.white) - .multilineTextAlignment(.center) - Text(subtitle) - .font(.custom(Styles.Fonts.regularFontName, size: 14)) - .foregroundColor(.white) - .multilineTextAlignment(.center) - }.padding(.horizontal, 20) - } -} - -#Preview { - GDriveHeaderView(title: "", subtitle: "") -} From c12a50ed81e00972056e390ad8e0c7856bdd7e19 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 9 May 2024 13:06:45 -0300 Subject: [PATCH 028/167] implementing google sdk --- Tella.xcodeproj/project.pbxproj | 34 +++++++++++++++++++ Tella/Application/TellaApp.swift | 1 + .../Views/Servers/ServerSelectionView.swift | 2 ++ 3 files changed, 37 insertions(+) diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 3b93856df..8114442da 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -3034,6 +3034,40 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 11819532921BA895BF7C12D0 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 1ADB16E63DE3CFDCE1776489 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 36C5FA1BF18AC473E32B7C1A /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/Tella/Application/TellaApp.swift b/Tella/Application/TellaApp.swift index 829d0c0de..0faa0a1fd 100644 --- a/Tella/Application/TellaApp.swift +++ b/Tella/Application/TellaApp.swift @@ -7,6 +7,7 @@ // import SwiftUI +import GoogleSignIn @main struct TellaApp: App { diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index d3e183400..514644652 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -8,6 +8,8 @@ import SwiftUI +import GoogleSignIn + struct ServerSelectionView: View { @EnvironmentObject var serversViewModel : ServersViewModel @StateObject var serverViewModel : ServerViewModel From 5055d2736e3e1dc9814463091f312b31fa29cd5a Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 22 May 2024 16:32:09 -0300 Subject: [PATCH 029/167] basic implemantation of d-drive library --- Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 514644652..d3e183400 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -8,8 +8,6 @@ import SwiftUI -import GoogleSignIn - struct ServerSelectionView: View { @EnvironmentObject var serversViewModel : ServersViewModel @StateObject var serverViewModel : ServerViewModel From 8f77e2f93b15fed85e216f64147ad3e8085c5f48 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 24 May 2024 13:39:21 -0300 Subject: [PATCH 030/167] create folder in g-drive --- .../ViewModel/GDriveServerViewModel.swift | 25 +++++++++++++++++++ .../Servers/GDrive/CreateDriveFolder.swift | 5 +++- .../GDrive/SelectDriveConnection.swift | 8 +++--- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 421426cb7..ea060f11d 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -49,4 +49,29 @@ class GDriveServerViewModel: ObservableObject { }) .store(in: &cancellables) } + + func createDriveFolder(folderName: String, completion: @escaping () -> Void) { + guard let user = googleUser else { + print("User not authenticated") + return + } + + let driveService = GTLRDriveService() + driveService.authorizer = user.fetcherAuthorizer + + let folder = GTLRDrive_File() + folder.name = folderName + folder.mimeType = "application/vnd.google-apps.folder" + + let query = GTLRDriveQuery_FilesCreate.query(withObject: folder, uploadParameters: nil) + + driveService.executeQuery(query) { (ticket, file, error) in + if let error = error { + print("Error creating folder: \(error.localizedDescription)") + return + } + + completion() + } + } } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift index fe628a4c8..9efc584ab 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift @@ -11,6 +11,7 @@ import SwiftUI struct CreateDriveFolder: View { @State var fieldContent : String = "" @State var isValid : Bool = false + @EnvironmentObject var gDriveServerViewModel: GDriveServerViewModel var body: some View { ContainerView { VStack(spacing: 20) { @@ -41,7 +42,9 @@ struct CreateDriveFolder: View { shouldHideNext: false, shouldHideBack: false, nextAction: { - navigateTo(destination: SuccessLoginView(navigateToAction: {}, type: .gDrive)) + gDriveServerViewModel.createDriveFolder(folderName: fieldContent) { + navigateTo(destination: SuccessLoginView(navigateToAction: {}, type: .gDrive)) + } }) } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index 92c55c22a..e9122dcdb 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -14,7 +14,7 @@ enum DriveConnectionType { } struct SelectDriveConnection: View { @State var selectedDriveConnectionType: DriveConnectionType = .none - @ObservedObject var dGriveServerViewModel: GDriveServerViewModel + @ObservedObject var gDriveServerViewModel: GDriveServerViewModel var body: some View { ContainerView { VStack(spacing: 24) { @@ -72,9 +72,9 @@ struct SelectDriveConnection: View { nextAction: { switch selectedDriveConnectionType { case .shared: - navigateTo(destination: SelectSharedDrive(sharedDrives: dGriveServerViewModel.sharedDrives)) + navigateTo(destination: SelectSharedDrive(sharedDrives: gDriveServerViewModel.sharedDrives)) case .personal: - navigateTo(destination: CreateDriveFolder()) + navigateTo(destination: CreateDriveFolder().environmentObject(gDriveServerViewModel)) default: break } @@ -84,5 +84,5 @@ struct SelectDriveConnection: View { } #Preview { - SelectDriveConnection(selectedDriveConnectionType: .personal, dGriveServerViewModel: GDriveServerViewModel()) + SelectDriveConnection(selectedDriveConnectionType: .personal, gDriveServerViewModel: GDriveServerViewModel()) } From f6d378acf09581829a0b3a2e561c7cd87f78b390 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 27 May 2024 15:16:59 -0300 Subject: [PATCH 031/167] save server connection --- Tella.xcodeproj/project.pbxproj | 8 +++ .../Database/Common/DatabaseConstants.swift | 4 ++ Tella/Data/Database/GDriveDatabase.swift | 56 ++++++++++++++++ Tella/Data/Database/TellaData.swift | 21 +++++- Tella/Data/Database/TellaDataBase.swift | 3 + Tella/Domain/Entity/GDrive/GDriveServer.swift | 50 +++++++++++++++ .../Settings/Models/DeleteServerTexts.swift | 64 +++++++++++++++---- .../ViewModel/GDriveServerViewModel.swift | 12 ++++ .../GDrive/SelectDriveConnection.swift | 2 +- 9 files changed, 205 insertions(+), 15 deletions(-) create mode 100644 Tella/Data/Database/GDriveDatabase.swift create mode 100644 Tella/Domain/Entity/GDrive/GDriveServer.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 8114442da..1d411f7a5 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -359,6 +359,8 @@ 155369232B7E9CC100129F2F /* ResourceDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155369222B7E9CC100129F2F /* ResourceDatabase.swift */; }; 155541B02C066F990031D3A5 /* ServerConnectionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155541AF2C066F990031D3A5 /* ServerConnectionButton.swift */; }; 155541B22C0672C20031D3A5 /* GDriveRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155541B12C0672C20031D3A5 /* GDriveRepository.swift */; }; + 155879FF2C0106FA0071389E /* GDriveDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155879FE2C0106FA0071389E /* GDriveDatabase.swift */; }; + 15587A012C010F1E0071389E /* GDriveServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15587A002C010F1E0071389E /* GDriveServer.swift */; }; 15622F4A2B72B1FF00289816 /* DeleteConfirmation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15622F492B72B1FF00289816 /* DeleteConfirmation.swift */; }; 156986252B88FCB600534720 /* ResourcePDFView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 156986242B88FCB600534720 /* ResourcePDFView.swift */; }; 15791C1A2B6AC34100D67C74 /* ResourcesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15791C192B6AC34100D67C74 /* ResourcesView.swift */; }; @@ -909,6 +911,8 @@ 155369222B7E9CC100129F2F /* ResourceDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceDatabase.swift; sourceTree = ""; }; 155541AF2C066F990031D3A5 /* ServerConnectionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConnectionButton.swift; sourceTree = ""; }; 155541B12C0672C20031D3A5 /* GDriveRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveRepository.swift; sourceTree = ""; }; + 155879FE2C0106FA0071389E /* GDriveDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveDatabase.swift; sourceTree = ""; }; + 15587A002C010F1E0071389E /* GDriveServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveServer.swift; sourceTree = ""; }; 15622F492B72B1FF00289816 /* DeleteConfirmation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteConfirmation.swift; sourceTree = ""; }; 156986242B88FCB600534720 /* ResourcePDFView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourcePDFView.swift; sourceTree = ""; }; 15791C192B6AC34100D67C74 /* ResourcesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourcesView.swift; sourceTree = ""; }; @@ -1223,6 +1227,7 @@ E1CF5A242AB3477C00365036 /* UwaziDatabase.swift */, E1CF5A2A2AB3533100365036 /* ServerDatabase.swift */, 155369222B7E9CC100129F2F /* ResourceDatabase.swift */, + 155879FE2C0106FA0071389E /* GDriveDatabase.swift */, ); path = Database; sourceTree = ""; @@ -2318,6 +2323,7 @@ isa = PBXGroup; children = ( 15994A102BFBF0E50017F153 /* SharedDrive.swift */, + 15587A002C010F1E0071389E /* GDriveServer.swift */, ); path = GDrive; sourceTree = ""; @@ -3650,8 +3656,10 @@ CC1C734D2AF5439600D736F8 /* UwaziMultipartData.swift in Sources */, 12781F4427E9FCE200FE9609 /* PasswordTypeEnum.swift in Sources */, D5DA7F9B2648D05400B00FDA /* FileListView.swift in Sources */, + 155879FF2C0106FA0071389E /* GDriveDatabase.swift in Sources */, E1E7C5712AAB2BAB00DDB07E /* UwaziLanguageRow.swift in Sources */, 1237A71C278F5B2E00D7BC0F /* DateExtension.swift in Sources */, + 15587A012C010F1E0071389E /* GDriveServer.swift in Sources */, 122E4D55291ADEB300562EB1 /* AddFilesToDraftView.swift in Sources */, 125299DD2AD02E6F00191CAB /* ImportVaultFileResult.swift in Sources */, 122DA89129CB1F45003801CD /* FileAPI.swift in Sources */, diff --git a/Tella/Data/Database/Common/DatabaseConstants.swift b/Tella/Data/Database/Common/DatabaseConstants.swift index 5958aaf71..152e7f7c5 100644 --- a/Tella/Data/Database/Common/DatabaseConstants.swift +++ b/Tella/Data/Database/Common/DatabaseConstants.swift @@ -34,6 +34,7 @@ struct D { static let tUwaziEntityInstanceVaultFile = "t_uwazi_entity_instance_vault_file" static let tFeedback = "t_feedback" static let tResource = "t_resource" + static let tGDriveServer = "t_drive_server" /* DATABASE COLUMNS */ // MARK: - DATABASE COLUMNS @@ -90,6 +91,9 @@ struct D { static let cFilename = "c_filename" static let cExternalId = "c_external_id" static let cSize = "c_size" + + //gDrive + static let cRootFolder = "c_root_folder" } diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift new file mode 100644 index 000000000..b03403db1 --- /dev/null +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -0,0 +1,56 @@ +// +// GDriveDatabase.swift +// Tella +// +// Created by gus valbuena on 5/24/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +extension TellaDataBase { + func createGDriveServerTable() { + let columns = [ + cddl(D.cServerId, D.integer, primaryKey: true, autoIncrement: true), + cddl(D.cName, D.text), + cddl(D.cRootFolder, D.text) + ] + + statementBuilder.createTable(tableName: D.tGDriveServer, columns: columns) + } + + func addGDriveServer(gDriveServer: GDriveServer) -> Result { + do { + let valuesToAdd = [KeyValue(key: D.cName, value: gDriveServer.name), + KeyValue(key: D.cRootFolder, value: gDriveServer.rootFolder) + ] + + let serverId = try statementBuilder.insertInto(tableName: D.tGDriveServer, keyValue: valuesToAdd) + return .success(serverId) + } catch let error { + return .failure(error) + } + } + + func getDriveServers() -> [GDriveServer] { + do { + let serversDict = try statementBuilder.selectQuery(tableName: D.tGDriveServer, andCondition: []) + + let driveServer = try serversDict.decode(GDriveServer.self) + return driveServer + } catch { + debugLog("Error while fetching servers from \(D.tGDriveServer): \(error)") + return [] + } + } + + func deleteGDriveServer(serverId: Int) { + do { + try statementBuilder.delete(tableName: D.tGDriveServer, + primarykeyValue: [KeyValue(key: D.cServerId, value: serverId)]) + } catch let error { + debugLog(error) + } + } + +} diff --git a/Tella/Data/Database/TellaData.swift b/Tella/Data/Database/TellaData.swift index d631457c8..74a3ce972 100644 --- a/Tella/Data/Database/TellaData.swift +++ b/Tella/Data/Database/TellaData.swift @@ -15,6 +15,7 @@ class TellaData : ObservableObject { var servers = CurrentValueSubject<[Server], Error>([]) var tellaServers = CurrentValueSubject<[TellaServer], Error>([]) var uwaziServers = CurrentValueSubject<[UwaziServer], Error>([]) + var gDriveServers = CurrentValueSubject<[GDriveServer], Error>([]) // Reports var draftReports = CurrentValueSubject<[Report], Error>([]) @@ -45,6 +46,13 @@ class TellaData : ObservableObject { return id } + func addGDriveServer(server: GDriveServer) -> Result{ + let id = database.addGDriveServer(gDriveServer: server) + getServers() + + return id + } + @discardableResult func updateServer(server : TellaServer) -> Result { let updateServerResult = database.updateServer(server: server) @@ -68,7 +76,6 @@ class TellaData : ObservableObject { func deleteServer(server: Server) { guard let serverId = server.id else { return } - switch (server.serverType) { case .tella: let resourcesId = getResourceByServerId(serverId: serverId) @@ -77,6 +84,8 @@ class TellaData : ObservableObject { deleteTellaServer(serverId: serverId) case .uwazi: deleteUwaziServer(serverId: serverId) + case .gDrive: + deleteGDriveServer(serverId: serverId) default: break } @@ -101,12 +110,20 @@ class TellaData : ObservableObject { getServers() } + func deleteGDriveServer(serverId: Int) { + database.deleteGDriveServer(serverId: serverId) + getServers() + } + func getServers(){ DispatchQueue.main.async { self.tellaServers.value = self.database.getTellaServers() self.uwaziServers.value = self.database.getUwaziServers() + self.gDriveServers.value = self.database.getDriveServers() + + self.servers.value = self.tellaServers.value + self.uwaziServers.value + self.gDriveServers.value - self.servers.value = self.tellaServers.value + self.uwaziServers.value + dump(self.servers) } } diff --git a/Tella/Data/Database/TellaDataBase.swift b/Tella/Data/Database/TellaDataBase.swift index 93d23407a..0ba6b8053 100644 --- a/Tella/Data/Database/TellaDataBase.swift +++ b/Tella/Data/Database/TellaDataBase.swift @@ -39,6 +39,8 @@ class TellaDataBase : DataBase { createUwaziEntityInstancesTable() createUwaziEntityInstanceVaultFileTable() addRelationshipColumnToUwaziTemplate() + case 5: + createGDriveServerTable() default : break } @@ -59,6 +61,7 @@ class TellaDataBase : DataBase { createUwaziEntityInstancesTable() createUwaziEntityInstanceVaultFileTable() addRelationshipColumnToUwaziTemplate() + createGDriveServerTable() } func createReportTable() { diff --git a/Tella/Domain/Entity/GDrive/GDriveServer.swift b/Tella/Domain/Entity/GDrive/GDriveServer.swift new file mode 100644 index 000000000..5b26463e3 --- /dev/null +++ b/Tella/Domain/Entity/GDrive/GDriveServer.swift @@ -0,0 +1,50 @@ +// +// GDriveServer.swift +// Tella +// +// Created by gus valbuena on 5/24/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +class GDriveServer: Server { + var rootFolder: String? + + enum CodingKeys: String, CodingKey { + case rootFolder = "c_root_folder" + } + + init(id: Int? = nil, + name: String? = "Google Drive", + serverURL: String? = nil, + username: String? = nil, + password: String? = nil, + accessToken: String? = nil, + rootFolder: String, + serverType: ServerConnectionType? = .gDrive + ) { + self.rootFolder = rootFolder + super.init(id: id, + name: name, + serverURL: serverURL, + username: username, + password: password, + accessToken: accessToken, + serverType: serverType + ) + } + + required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.rootFolder = try container.decode(String?.self, forKey: .rootFolder) + try super.init(from: decoder) + self.serverType = .gDrive + } + + override func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(rootFolder, forKey: .rootFolder) + try super.encode(to: encoder) + } +} diff --git a/Tella/Scenes/Settings/Models/DeleteServerTexts.swift b/Tella/Scenes/Settings/Models/DeleteServerTexts.swift index 396e3a1c0..390c1146f 100644 --- a/Tella/Scenes/Settings/Models/DeleteServerTexts.swift +++ b/Tella/Scenes/Settings/Models/DeleteServerTexts.swift @@ -9,18 +9,58 @@ import Foundation // TODO: Maybe use another class name -struct DeleteServerTexts { - var titleText: String = "" - var messageText: String = "" - let cancelText = "CANCEL" - let actionText = "DELETE" +enum DeleteServerTexts { + case tella(String) + case uwazi(String) + case gDrive(String) + case unknown + + var titleText: String { + switch self { + case .tella(let name): + return "Delete \(name) server?" + case .uwazi(let name): + return "Delete \"\(name)\" connection?" + case .gDrive(let name): + return "Delete \"\(name)\" connection?" + case .unknown: + return "" + } + } + + var messageText: String { + switch self { + case .tella: + return "if you delete this server, all draft and submitted forms will be deleted from your device." + case .uwazi: + return "If you delete this server, all draft and submitted entities will be deleted from your device. Delete anyway?" + case .gDrive: + return "If you delete this server, all draft and submitted reports will be deleted from your device." + case .unknown: + return "" + } + } + + var cancelText: String { + return "CANCEL" + } + + var actionText: String { + return "Delete" + } +} + +extension DeleteServerTexts { init(server: Server) { - if server.serverType == .tella { - titleText = "Delete \(server.name ?? "") server?" - messageText = "f you delete this server, all draft and submitted forms will be deleted from your device." - } else if server.serverType == .uwazi { - titleText = "Delete \"\(server.name ?? "")\" connection?" - messageText = "If you delete this server, all draft and submitted entities will be deleted from your device. Delete anyway?" - } else {} + switch server.serverType { + case .tella: + self = .tella(server.name ?? "") + case .uwazi: + self = .uwazi(server.name ?? "") + case .gDrive: + self = .gDrive(server.name ?? "") + default: + self = .unknown + } } } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index ea060f11d..07105211c 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -10,6 +10,7 @@ import Foundation import Combine class GDriveServerViewModel: ObservableObject { + var mainAppModel : MainAppModel private let gDriveRepository: GDriveRepositoryProtocol private var cancellables = Set() @@ -71,7 +72,18 @@ class GDriveServerViewModel: ObservableObject { return } + guard let createdFile = file as? GTLRDrive_File else { + return + } + + self.addServer(rootFolder: createdFile.identifier ?? "") completion() } } + + func addServer(rootFolder: String) { + let server = GDriveServer(rootFolder: rootFolder) + + _ = mainAppModel.tellaData?.addGDriveServer(server: server) + } } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index e9122dcdb..612847fc1 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -84,5 +84,5 @@ struct SelectDriveConnection: View { } #Preview { - SelectDriveConnection(selectedDriveConnectionType: .personal, gDriveServerViewModel: GDriveServerViewModel()) + SelectDriveConnection(selectedDriveConnectionType: .personal, gDriveServerViewModel: GDriveServerViewModel(mainAppModel: MainAppModel.stub())) } From c0389d59ade7e7f514c69dfb1ea79b568a203401 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 27 May 2024 15:45:31 -0300 Subject: [PATCH 032/167] save shared drive connection and remove edit option from gDrive connection item --- .../Settings/ViewModel/GDriveServerViewModel.swift | 11 +++++++---- .../Views/Servers/GDrive/CreateDriveFolder.swift | 2 +- .../Views/Servers/GDrive/SelectDriveConnection.swift | 9 +++++++-- .../Views/Servers/GDrive/SelectSharedDrive.swift | 8 +++++--- .../Settings/Views/Servers/ServersListView.swift | 3 ++- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 07105211c..57d814983 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -76,14 +76,17 @@ class GDriveServerViewModel: ObservableObject { return } - self.addServer(rootFolder: createdFile.identifier ?? "") - completion() + self.addServer(rootFolder: createdFile.identifier ?? "") { + completion() + } } } - func addServer(rootFolder: String) { + func addServer(rootFolder: String, completion: @escaping() -> Void ) { let server = GDriveServer(rootFolder: rootFolder) - + _ = mainAppModel.tellaData?.addGDriveServer(server: server) + + completion() } } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift index 9efc584ab..2cae70c71 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift @@ -43,7 +43,7 @@ struct CreateDriveFolder: View { shouldHideBack: false, nextAction: { gDriveServerViewModel.createDriveFolder(folderName: fieldContent) { - navigateTo(destination: SuccessLoginView(navigateToAction: {}, type: .gDrive)) + navigateTo(destination: SuccessLoginView(navigateToAction: {self.popToRoot()}, type: .gDrive)) } }) diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index 612847fc1..518378989 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -72,9 +72,14 @@ struct SelectDriveConnection: View { nextAction: { switch selectedDriveConnectionType { case .shared: - navigateTo(destination: SelectSharedDrive(sharedDrives: gDriveServerViewModel.sharedDrives)) + navigateTo( + destination: SelectSharedDrive() + .environmentObject(gDriveServerViewModel) + ) case .personal: - navigateTo(destination: CreateDriveFolder().environmentObject(gDriveServerViewModel)) + navigateTo( + destination: CreateDriveFolder() + .environmentObject(gDriveServerViewModel)) default: break } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index c3884eef0..be3f9aca0 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -11,11 +11,11 @@ import GoogleAPIClientForREST struct SelectSharedDrive: View { @State var selectedDrive: String = "" - @State var sharedDrives: [SharedDrive] = [] + @EnvironmentObject var gDriveServerViewModel: GDriveServerViewModel var body: some View { ContainerView { VStack(alignment: .leading){ - ForEach(sharedDrives, id: \.id) { drive in + ForEach(gDriveServerViewModel.sharedDrives, id: \.identifier) { drive in DriveCardView(sharedDrive: drive, selectedDrive: $selectedDrive) } @@ -28,7 +28,9 @@ struct SelectSharedDrive: View { // remove this after merging with uwazi relationships ToolbarItem(placement: .navigationBarTrailing) { Button(action: { - navigateTo(destination: SuccessLoginView(navigateToAction: {}, type: .gDrive)) + gDriveServerViewModel.addServer(rootFolder: selectedDrive) { + navigateTo(destination: SuccessLoginView(navigateToAction: {self.popToRoot()}, type: .gDrive)) + } }) { Image("report.select-files") .resizable() diff --git a/Tella/Scenes/Settings/Views/Servers/ServersListView.swift b/Tella/Scenes/Settings/Views/Servers/ServersListView.swift index fbfad80ad..f782c563f 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServersListView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServersListView.swift @@ -51,8 +51,9 @@ struct ServersListView: View { } private func showServerActionBottomSheet(server:Server) { + let filteredActionItems = server.serverType == .gDrive ? serverActionItems.filter { $0.type as? ServerActionType != .edit } : serverActionItems sheetManager.showBottomSheet(modalHeight: 176) { - ActionListBottomSheet(items: serverActionItems, + ActionListBottomSheet(items: filteredActionItems, headerTitle: LocalizableVault.manageFilesSheetTitle.localized, action: {item in From 9562dde53fb5ad504d148e342e1e467d0ec26190 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 29 May 2024 17:41:14 -0300 Subject: [PATCH 033/167] some fixes after rebase --- Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 57d814983..152d1a920 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -16,7 +16,8 @@ class GDriveServerViewModel: ObservableObject { @Published var sharedDrives: [SharedDrive] = [] - init(repository: GDriveRepositoryProtocol = GDriveRepository.shared) { + init(repository: GDriveRepositoryProtocol = GDriveRepository.shared, mainAppModel: MainAppModel) { + self.mainAppModel = mainAppModel self.gDriveRepository = repository restorePreviousSignIn() } From fc7be574b75a59a39a9bc1baeb4694168b533432 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 29 May 2024 18:26:28 -0300 Subject: [PATCH 034/167] refactor folder creation logic --- .../Repositories/GDriveRepository.swift | 33 ++++++++++++++++++ .../ViewModel/GDriveServerViewModel.swift | 34 ++++--------------- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 055bb66d1..a844a90f7 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -102,4 +102,37 @@ class GDriveRepository: GDriveRepositoryProtocol { } .eraseToAnyPublisher() } + + func createDriveFolder( + googleUser: GIDGoogleUser?, + folderName: String, + completion: @escaping (String) -> Void + ) { + guard let user = googleUser else { + print("User not authenticated") + return + } + + let driveService = GTLRDriveService() + driveService.authorizer = user.fetcherAuthorizer + + let folder = GTLRDrive_File() + folder.name = folderName + folder.mimeType = "application/vnd.google-apps.folder" + + let query = GTLRDriveQuery_FilesCreate.query(withObject: folder, uploadParameters: nil) + + driveService.executeQuery(query) { (ticket, file, error) in + if let error = error { + print("Error creating folder: \(error.localizedDescription)") + return + } + + guard let createdFile = file as? GTLRDrive_File else { + return + } + + completion(createdFile.identifier ?? "") + } + } } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 152d1a920..5eb33ad16 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -52,35 +52,15 @@ class GDriveServerViewModel: ObservableObject { .store(in: &cancellables) } + func createDriveFolder(folderName: String, completion: @escaping () -> Void) { - guard let user = googleUser else { - print("User not authenticated") - return - } - - let driveService = GTLRDriveService() - driveService.authorizer = user.fetcherAuthorizer - - let folder = GTLRDrive_File() - folder.name = folderName - folder.mimeType = "application/vnd.google-apps.folder" - - let query = GTLRDriveQuery_FilesCreate.query(withObject: folder, uploadParameters: nil) - - driveService.executeQuery(query) { (ticket, file, error) in - if let error = error { - print("Error creating folder: \(error.localizedDescription)") - return - } - - guard let createdFile = file as? GTLRDrive_File else { - return - } - - self.addServer(rootFolder: createdFile.identifier ?? "") { - completion() + gDriveRepository.createDriveFolder( + googleUser: self.googleUser, + folderName: folderName) { folderName in + self.addServer(rootFolder: folderName) { + completion() + } } - } } func addServer(rootFolder: String, completion: @escaping() -> Void ) { From c834bb77aeb8d1014fc01e1b575139d24ecd8d40 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 30 May 2024 15:44:43 -0300 Subject: [PATCH 035/167] fix rebase conflicts --- Tella/Application/TellaApp.swift | 1 - Tella/Data/Networking/Repositories/GDriveRepository.swift | 3 +-- Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift | 1 - .../Settings/Views/Servers/GDrive/SelectSharedDrive.swift | 2 +- 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Tella/Application/TellaApp.swift b/Tella/Application/TellaApp.swift index 0faa0a1fd..829d0c0de 100644 --- a/Tella/Application/TellaApp.swift +++ b/Tella/Application/TellaApp.swift @@ -7,7 +7,6 @@ // import SwiftUI -import GoogleSignIn @main struct TellaApp: App { diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index a844a90f7..7f11b0d56 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -104,11 +104,10 @@ class GDriveRepository: GDriveRepositoryProtocol { } func createDriveFolder( - googleUser: GIDGoogleUser?, folderName: String, completion: @escaping (String) -> Void ) { - guard let user = googleUser else { + guard let user = self.googleUser else { print("User not authenticated") return } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 5eb33ad16..143999c5f 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -55,7 +55,6 @@ class GDriveServerViewModel: ObservableObject { func createDriveFolder(folderName: String, completion: @escaping () -> Void) { gDriveRepository.createDriveFolder( - googleUser: self.googleUser, folderName: folderName) { folderName in self.addServer(rootFolder: folderName) { completion() diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index be3f9aca0..503a00ff9 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -15,7 +15,7 @@ struct SelectSharedDrive: View { var body: some View { ContainerView { VStack(alignment: .leading){ - ForEach(gDriveServerViewModel.sharedDrives, id: \.identifier) { drive in + ForEach(gDriveServerViewModel.sharedDrives, id: \.id) { drive in DriveCardView(sharedDrive: drive, selectedDrive: $selectedDrive) } From ed0bdea4c300898006601d279a64b3f0960ebee6 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 30 May 2024 20:06:59 -0300 Subject: [PATCH 036/167] disable gDrive connection if is already connected --- Tella/Domain/Entity/GDrive/GDriveServer.swift | 4 ++- Tella/Domain/Entity/Report/Project.swift | 4 ++- Tella/Domain/Entity/Report/ServerType.swift | 25 +++++++++---------- .../Resources/Views/AvailableResources.swift | 2 +- .../Resources/Views/Common/SectionTitle.swift | 1 - .../Resources/Views/DownloadedResources.swift | 2 +- .../Settings/ViewModel/ServersViewModel.swift | 14 +++++++++++ .../Views/Servers/ServerSelectionView.swift | 25 +++++++++++++++---- 8 files changed, 54 insertions(+), 23 deletions(-) diff --git a/Tella/Domain/Entity/GDrive/GDriveServer.swift b/Tella/Domain/Entity/GDrive/GDriveServer.swift index 5b26463e3..ee4fc859c 100644 --- a/Tella/Domain/Entity/GDrive/GDriveServer.swift +++ b/Tella/Domain/Entity/GDrive/GDriveServer.swift @@ -22,7 +22,8 @@ class GDriveServer: Server { password: String? = nil, accessToken: String? = nil, rootFolder: String, - serverType: ServerConnectionType? = .gDrive + serverType: ServerConnectionType? = .gDrive, + allowMultiple: Bool? = false ) { self.rootFolder = rootFolder super.init(id: id, @@ -40,6 +41,7 @@ class GDriveServer: Server { self.rootFolder = try container.decode(String?.self, forKey: .rootFolder) try super.init(from: decoder) self.serverType = .gDrive + self.allowMultiple = false } override func encode(to encoder: Encoder) throws { diff --git a/Tella/Domain/Entity/Report/Project.swift b/Tella/Domain/Entity/Report/Project.swift index 6b787527a..3a1c75b77 100644 --- a/Tella/Domain/Entity/Report/Project.swift +++ b/Tella/Domain/Entity/Report/Project.swift @@ -13,6 +13,7 @@ class Server: Codable, Equatable, Hashable { var password: String? var accessToken: String? var serverType: ServerConnectionType? + var allowMultiple: Bool? enum CodingKeys: String, CodingKey { case id = "c_server_id" @@ -30,7 +31,8 @@ class Server: Codable, Equatable, Hashable { username: String? = nil, password: String? = nil, accessToken: String? = nil, - serverType: ServerConnectionType? = nil + serverType: ServerConnectionType? = nil, + allowMultipleConnections: Bool? = true ) { self.id = id self.name = name diff --git a/Tella/Domain/Entity/Report/ServerType.swift b/Tella/Domain/Entity/Report/ServerType.swift index 15d4128cd..11e4952d0 100644 --- a/Tella/Domain/Entity/Report/ServerType.swift +++ b/Tella/Domain/Entity/Report/ServerType.swift @@ -5,19 +5,9 @@ import Foundation enum ServerConnectionType: Int, Codable { - case tella = 0 - case uwazi = 1 - case odkCollect = 3 - case gDrive = 4 - case unknown -} - -func mapServerTypeFromInt(_ serverTypeInt: Int?) -> ServerConnectionType { - if let serverType = serverTypeInt { - return ServerConnectionType(rawValue: serverType) ?? .unknown - } else { - return .unknown - } + case tella + case uwazi + case gDrive } extension ServerConnectionType { @@ -31,4 +21,13 @@ extension ServerConnectionType { return "" } } + + var serverTitle: String { + switch self { + case .gDrive: + "GOOGLE DRIVE" + default: + "" + } + } } diff --git a/Tella/Scenes/Resources/Views/AvailableResources.swift b/Tella/Scenes/Resources/Views/AvailableResources.swift index f990ca7ef..35cd19eb8 100644 --- a/Tella/Scenes/Resources/Views/AvailableResources.swift +++ b/Tella/Scenes/Resources/Views/AvailableResources.swift @@ -11,7 +11,7 @@ import SwiftUI struct AvailableResources: View { @EnvironmentObject var viewModel : ResourcesViewModel var body: some View { - VStack { + VStack(spacing: 8) { SectionTitle(text: LocalizableResources.resourcesAvailableTitle.localized) availableResourceContent } diff --git a/Tella/Scenes/Resources/Views/Common/SectionTitle.swift b/Tella/Scenes/Resources/Views/Common/SectionTitle.swift index bc38597e1..bea2b9648 100644 --- a/Tella/Scenes/Resources/Views/Common/SectionTitle.swift +++ b/Tella/Scenes/Resources/Views/Common/SectionTitle.swift @@ -15,7 +15,6 @@ struct SectionTitle: View { .foregroundColor(.white) .font(.custom(Styles.Fonts.boldFontName, size: 14)) .fontWeight(.semibold) - .padding(.bottom, 8) .frame(maxWidth: .infinity, alignment: .leading) } } diff --git a/Tella/Scenes/Resources/Views/DownloadedResources.swift b/Tella/Scenes/Resources/Views/DownloadedResources.swift index 415ae34a2..d1f41e27a 100644 --- a/Tella/Scenes/Resources/Views/DownloadedResources.swift +++ b/Tella/Scenes/Resources/Views/DownloadedResources.swift @@ -13,7 +13,7 @@ struct DownloadedResources: View { @EnvironmentObject var viewModel: ResourcesViewModel var body: some View { - VStack { + VStack(spacing: 8) { SectionTitle(text: LocalizableResources.resourcesDownloadedTitle.localized) if viewModel.downloadedResources.isEmpty && viewModel.availableResources.isEmpty { emptyView } diff --git a/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift b/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift index 9c56bf01d..83ef7432a 100644 --- a/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift @@ -12,6 +12,7 @@ class ServersViewModel: ObservableObject { @Published var currentServer : Server? @Published var serverArray : [Server] = [] + @Published var unavailableServers: [Server] = [] private var subscribers = Set() @@ -22,6 +23,8 @@ class ServersViewModel: ObservableObject { mainAppModel.tellaData?.servers.sink { completion in } receiveValue: { serverArray in self.serverArray = serverArray + self.unavailableServers = serverArray.filter { $0.allowMultiple == false } + dump(self.unavailableServers.isEmpty) }.store(in: &subscribers) } @@ -34,4 +37,15 @@ class ServersViewModel: ObservableObject { func deleteAllServersConnection() { mainAppModel.tellaData?.deleteAllServers() } + + func filterServerConnections() -> [ServerConnectionButton] { + if(self.unavailableServers.isEmpty) { + return serverConnections + } + + return serverConnections.filter { connection in + unavailableServers.contains{ connection.type != $0.serverType } + } + + } } diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index d3e183400..1c663ace3 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -12,7 +12,7 @@ struct ServerSelectionView: View { @EnvironmentObject var serversViewModel : ServersViewModel @StateObject var serverViewModel : ServerViewModel @EnvironmentObject var mainAppModel : MainAppModel - @State var selectedServerType: ServerConnectionType = .unknown + @State var selectedServerType: ServerConnectionType? = nil @ObservedObject var gDriveVM = GDriveAuthViewModel() @Environment(\.presentationMode) var presentationMode: Binding @@ -21,11 +21,13 @@ struct ServerSelectionView: View { } var body: some View { ContainerView { - VStack(spacing: 20) { Spacer() HeaderView() buttonViews() + if(!serversViewModel.unavailableServers.isEmpty) { + unavailableConnectionsView() + } Spacer() bottomView() } @@ -36,8 +38,8 @@ struct ServerSelectionView: View { } fileprivate func buttonViews() -> some View { - Group { - ForEach(serverConnections, id: \.type) { connection in + return Group { + ForEach(serversViewModel.filterServerConnections(), id: \.type) { connection in TellaButtonView( title: connection.title, nextButtonAction: .action, @@ -87,6 +89,19 @@ struct ServerSelectionView: View { } } + fileprivate func unavailableConnectionsView() -> some View { + VStack(spacing: 20) { + SectionTitle(text: "Unavailable connections") + SectionMessage(text: "For the following categories, only one connection can be enabled at a time. To add a new connection, please delete the current one by going to Connections Settings.") + ForEach(serversViewModel.unavailableServers, id: \.id) { server in + TellaButtonView( + title: server.serverType?.serverTitle ?? "", + nextButtonAction: .action, + isValid: .constant(false) + ) + } + }.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) + } struct HeaderView: View { var body: some View { @@ -100,7 +115,7 @@ struct ServerSelectionView: View { .font(.custom(Styles.Fonts.regularFontName, size: 14)) .foregroundColor(.white) .multilineTextAlignment(.center) - } + }.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) } } } From 4584df2844bbec77f8cfcc0858781d2895078a0a Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 4 Jun 2024 13:44:07 -0300 Subject: [PATCH 037/167] fix rebase conflicts --- Tella/Data/Networking/Repositories/GDriveRepository.swift | 1 + .../Scenes/Settings/Views/Servers/ServerSelectionView.swift | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 7f11b0d56..72a4958ce 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -16,6 +16,7 @@ protocol GDriveRepositoryProtocol { func restorePreviousSignIn() async throws -> Void func handleUrl(url: URL) func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> + func createDriveFolder(folderName: String, completion: @escaping (String) -> Void) } class GDriveRepository: GDriveRepositoryProtocol { diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 1c663ace3..381396b82 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -85,7 +85,10 @@ struct ServerSelectionView: View { fileprivate func navigateToGDriveFlow() { gDriveVM.handleSignIn { - navigateTo(destination: SelectDriveConnection( dGriveServerViewModel: GDriveServerViewModel()), title: "Select Google drive") + navigateTo( + destination: SelectDriveConnection(gDriveServerViewModel: GDriveServerViewModel(mainAppModel: mainAppModel)), + title: "Select Google drive" + ) } } From 7bfd102e607ce183055001ada9c23d85e755a537 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 4 Jun 2024 15:21:31 -0300 Subject: [PATCH 038/167] fix create folder and remove token if the user remove a gDrive connection --- Tella/Data/Database/TellaData.swift | 1 + .../Repositories/GDriveRepository.swift | 67 +++++++++++-------- .../ViewModel/GDriveServerViewModel.swift | 18 +++-- 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/Tella/Data/Database/TellaData.swift b/Tella/Data/Database/TellaData.swift index 74a3ce972..c4aeb0ba2 100644 --- a/Tella/Data/Database/TellaData.swift +++ b/Tella/Data/Database/TellaData.swift @@ -111,6 +111,7 @@ class TellaData : ObservableObject { } func deleteGDriveServer(serverId: Int) { + GDriveRepository().signOut() database.deleteGDriveServer(serverId: serverId) getServers() } diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 72a4958ce..8ed2fe1f4 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -16,7 +16,8 @@ protocol GDriveRepositoryProtocol { func restorePreviousSignIn() async throws -> Void func handleUrl(url: URL) func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> - func createDriveFolder(folderName: String, completion: @escaping (String) -> Void) + func createDriveFolder(folderName: String) -> AnyPublisher + func signOut() -> Void } class GDriveRepository: GDriveRepositoryProtocol { @@ -105,34 +106,42 @@ class GDriveRepository: GDriveRepositoryProtocol { } func createDriveFolder( - folderName: String, - completion: @escaping (String) -> Void - ) { - guard let user = self.googleUser else { - print("User not authenticated") - return - } - - let driveService = GTLRDriveService() - driveService.authorizer = user.fetcherAuthorizer - - let folder = GTLRDrive_File() - folder.name = folderName - folder.mimeType = "application/vnd.google-apps.folder" - - let query = GTLRDriveQuery_FilesCreate.query(withObject: folder, uploadParameters: nil) - - driveService.executeQuery(query) { (ticket, file, error) in - if let error = error { - print("Error creating folder: \(error.localizedDescription)") - return - } - - guard let createdFile = file as? GTLRDrive_File else { - return + folderName: String + ) -> AnyPublisher { + Deferred { + Future { [weak self] promise in + guard let user = self?.googleUser else { + print("User not authenticated") + return + } + + let driveService = GTLRDriveService() + driveService.authorizer = user.fetcherAuthorizer + + let folder = GTLRDrive_File() + folder.name = folderName + folder.mimeType = "application/vnd.google-apps.folder" + + let query = GTLRDriveQuery_FilesCreate.query(withObject: folder, uploadParameters: nil) + + driveService.executeQuery(query) { (ticket, file, error) in + if let error = error { + print("Error creating folder: \(error.localizedDescription)") + promise(.failure(error)) + return + } + + guard let createdFile = file as? GTLRDrive_File else { + return + } + + promise(.success(createdFile.identifier ?? "")) + } } - - completion(createdFile.identifier ?? "") - } + }.eraseToAnyPublisher() + } + + func signOut() { + GIDSignIn.sharedInstance.signOut() } } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 143999c5f..a939c201c 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -54,12 +54,22 @@ class GDriveServerViewModel: ObservableObject { func createDriveFolder(folderName: String, completion: @escaping () -> Void) { - gDriveRepository.createDriveFolder( - folderName: folderName) { folderName in - self.addServer(rootFolder: folderName) { + + gDriveRepository.createDriveFolder(folderName: folderName) + .receive(on: DispatchQueue.main) + .sink(receiveCompletion: { completion in + switch completion { + case .finished: + break + case .failure(let error): + Toast.displayToast(message: error.localizedDescription) + } + }, receiveValue: { folderId in + self.addServer(rootFolder: folderId) { completion() } - } + }) + .store(in: &cancellables) } func addServer(rootFolder: String, completion: @escaping() -> Void ) { From f27e0ad393210d2e9ae30ce49a603d197678fd1d Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 4 Jun 2024 17:16:38 -0300 Subject: [PATCH 039/167] fix issues after rebase with develop --- Tella/Data/Database/TellaData.swift | 2 -- .../Settings/ViewModel/GDriveAuthViewModel.swift | 16 ---------------- .../Settings/ViewModel/ServersViewModel.swift | 1 - .../Views/Servers/GDrive/SelectSharedDrive.swift | 4 ++-- 4 files changed, 2 insertions(+), 21 deletions(-) diff --git a/Tella/Data/Database/TellaData.swift b/Tella/Data/Database/TellaData.swift index c4aeb0ba2..998c3d95a 100644 --- a/Tella/Data/Database/TellaData.swift +++ b/Tella/Data/Database/TellaData.swift @@ -123,8 +123,6 @@ class TellaData : ObservableObject { self.gDriveServers.value = self.database.getDriveServers() self.servers.value = self.tellaServers.value + self.uwaziServers.value + self.gDriveServers.value - - dump(self.servers) } } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift index 8164e37ab..c5c1662ed 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -35,20 +35,4 @@ class GDriveAuthViewModel: ObservableObject { func handleUrl(url: URL) { gDriveRepository.handleUrl(url: url) } - - func restorePreviousSignIn() { - guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { - print("There is no root view controller!") - return - } - - GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in - user?.addScopes(["https://www.googleapis.com/auth/drive"], presenting: rootViewController) - dump(user) - } - } - - func handleUrl(url: URL) { - GIDSignIn.sharedInstance.handle(url) - } } diff --git a/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift b/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift index 83ef7432a..a78f5a230 100644 --- a/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift @@ -24,7 +24,6 @@ class ServersViewModel: ObservableObject { } receiveValue: { serverArray in self.serverArray = serverArray self.unavailableServers = serverArray.filter { $0.allowMultiple == false } - dump(self.unavailableServers.isEmpty) }.store(in: &subscribers) } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index 503a00ff9..4e65daffe 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -43,14 +43,14 @@ struct SelectSharedDrive: View { } struct DriveCardView: View { - var sharedDrive: GTLRDrive_Drive + var sharedDrive: SharedDrive @Binding var selectedDrive: String var body: some View { Button(action: { self.selectedDrive = sharedDrive.id }) { HStack { - Text(sharedDrive.name ?? "") + Text(sharedDrive.name) .font(.custom(Styles.Fonts.regularFontName, size: 16)) .foregroundColor(.white) Spacer() From 4eeb2cfe907729802a91785374fff179e9ad3a91 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 5 Jun 2024 17:00:01 -0300 Subject: [PATCH 040/167] add navbar to gDrive views --- Tella.xcodeproj/project.pbxproj | 57 ++++--------------- Tella/Components/NavigationHeaderView.swift | 9 +-- .../Settings/Models/DriveConnectionType.swift | 15 +++++ .../GDrive/SelectDriveConnection.swift | 40 +++++++------ .../Servers/GDrive/SelectSharedDrive.swift | 42 +++++++------- .../Uwazi/Views/Entity/CreateEntityView.swift | 2 +- 6 files changed, 78 insertions(+), 87 deletions(-) create mode 100644 Tella/Scenes/Settings/Models/DriveConnectionType.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 1d411f7a5..be033d9c1 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -356,6 +356,7 @@ 153AACF72BE40BEA0075D5B2 /* UwaziEntityFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 153AACF62BE40BEA0075D5B2 /* UwaziEntityFetcher.swift */; }; 153AACFB2BE41C010075D5B2 /* UwaziEntityRelationshipItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 153AACFA2BE41C010075D5B2 /* UwaziEntityRelationshipItem.swift */; }; 153F96492BFD306F00FE5464 /* CreateDriveFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 153F96482BFD306F00FE5464 /* CreateDriveFolder.swift */; }; + 154B029C2C10FAD0007A5D2B /* DriveConnectionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 154B029B2C10FAD0007A5D2B /* DriveConnectionType.swift */; }; 155369232B7E9CC100129F2F /* ResourceDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155369222B7E9CC100129F2F /* ResourceDatabase.swift */; }; 155541B02C066F990031D3A5 /* ServerConnectionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155541AF2C066F990031D3A5 /* ServerConnectionButton.swift */; }; 155541B22C0672C20031D3A5 /* GDriveRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 155541B12C0672C20031D3A5 /* GDriveRepository.swift */; }; @@ -368,18 +369,17 @@ 15791C232B6C2E9100D67C74 /* ResourcesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15791C222B6C2E9100D67C74 /* ResourcesViewModel.swift */; }; 157E4F532BA385B500147345 /* PDFKitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 157E4F522BA385B500147345 /* PDFKitView.swift */; }; 15917D752B90FCC3005655AC /* ResourceCardType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15917D742B90FCC3005655AC /* ResourceCardType.swift */; }; + 15994A0C2BFBC6F40017F153 /* SelectDriveConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */; }; + 15994A0E2BFBE15F0017F153 /* SelectSharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */; }; + 15994A112BFBF0E50017F153 /* SharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A102BFBF0E50017F153 /* SharedDrive.swift */; }; 15BD9CA92BC740B300C3932B /* UwaziRelationshipWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CA82BC740B300C3932B /* UwaziRelationshipWidget.swift */; }; 15BD9CAB2BC740D700C3932B /* EntitySelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CAA2BC740D700C3932B /* EntitySelectorView.swift */; }; 15BD9CAD2BC7410E00C3932B /* SearchBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CAC2BC7410E00C3932B /* SearchBarView.swift */; }; 15BD9CB12BC744BC00C3932B /* NavigationHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CB02BC744BC00C3932B /* NavigationHeaderView.swift */; }; 15BD9CB32BC7472A00C3932B /* UwaziRelationshipDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CB22BC7472A00C3932B /* UwaziRelationshipDTO.swift */; }; - 15CD89102BF297BE00F724F5 /* SelectedEntityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */; }; - 15944F6F2BFFCE98008430BA /* GDriveHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15944F6E2BFFCE98008430BA /* GDriveHeaderView.swift */; }; - 15994A0C2BFBC6F40017F153 /* SelectDriveConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */; }; - 15994A0E2BFBE15F0017F153 /* SelectSharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */; }; - 15994A112BFBF0E50017F153 /* SharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A102BFBF0E50017F153 /* SharedDrive.swift */; }; 15C51C442BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C51C432BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift */; }; 15C51C462BFE769500DD9AD0 /* GDriveServerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C51C452BFE769500DD9AD0 /* GDriveServerViewModel.swift */; }; + 15CD89102BF297BE00F724F5 /* SelectedEntityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */; }; 15EE30FE2B5073E20033BBBB /* Pages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15EE30FD2B5073E20033BBBB /* Pages.swift */; }; 15F64C9D2B6D7904008A57AA /* DownloadedResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */; }; 15F64CA02B6D794B008A57AA /* SectionTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */; }; @@ -908,6 +908,7 @@ 153AACF62BE40BEA0075D5B2 /* UwaziEntityFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziEntityFetcher.swift; sourceTree = ""; }; 153AACFA2BE41C010075D5B2 /* UwaziEntityRelationshipItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziEntityRelationshipItem.swift; sourceTree = ""; }; 153F96482BFD306F00FE5464 /* CreateDriveFolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateDriveFolder.swift; sourceTree = ""; }; + 154B029B2C10FAD0007A5D2B /* DriveConnectionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DriveConnectionType.swift; sourceTree = ""; }; 155369222B7E9CC100129F2F /* ResourceDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceDatabase.swift; sourceTree = ""; }; 155541AF2C066F990031D3A5 /* ServerConnectionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConnectionButton.swift; sourceTree = ""; }; 155541B12C0672C20031D3A5 /* GDriveRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveRepository.swift; sourceTree = ""; }; @@ -922,18 +923,17 @@ 1589A6202B7672390048C775 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 1589A6212B7672430048C775 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; 15917D742B90FCC3005655AC /* ResourceCardType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceCardType.swift; sourceTree = ""; }; + 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectDriveConnection.swift; sourceTree = ""; }; + 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectSharedDrive.swift; sourceTree = ""; }; + 15994A102BFBF0E50017F153 /* SharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedDrive.swift; sourceTree = ""; }; 15BD9CA82BC740B300C3932B /* UwaziRelationshipWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziRelationshipWidget.swift; sourceTree = ""; }; 15BD9CAA2BC740D700C3932B /* EntitySelectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntitySelectorView.swift; sourceTree = ""; }; 15BD9CAC2BC7410E00C3932B /* SearchBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBarView.swift; sourceTree = ""; }; 15BD9CB02BC744BC00C3932B /* NavigationHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationHeaderView.swift; sourceTree = ""; }; 15BD9CB22BC7472A00C3932B /* UwaziRelationshipDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziRelationshipDTO.swift; sourceTree = ""; }; - 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedEntityView.swift; sourceTree = ""; }; - 15944F6E2BFFCE98008430BA /* GDriveHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveHeaderView.swift; sourceTree = ""; }; - 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectDriveConnection.swift; sourceTree = ""; }; - 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectSharedDrive.swift; sourceTree = ""; }; - 15994A102BFBF0E50017F153 /* SharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedDrive.swift; sourceTree = ""; }; 15C51C432BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveAuthViewModel.swift; sourceTree = ""; }; 15C51C452BFE769500DD9AD0 /* GDriveServerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveServerViewModel.swift; sourceTree = ""; }; + 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedEntityView.swift; sourceTree = ""; }; 15EE30FD2B5073E20033BBBB /* Pages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pages.swift; sourceTree = ""; }; 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResources.swift; sourceTree = ""; }; 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionTitle.swift; sourceTree = ""; }; @@ -2093,6 +2093,7 @@ CC1313872A5CB4550057271C /* DeleteAfterFailOptionsStatus.swift */, E1E7C56E2AA9822F00DDB07E /* DeleteServerTexts.swift */, 155541AF2C066F990031D3A5 /* ServerConnectionButton.swift */, + 154B029B2C10FAD0007A5D2B /* DriveConnectionType.swift */, ); path = Models; sourceTree = ""; @@ -3040,40 +3041,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 11819532921BA895BF7C12D0 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tella/Pods-Tella-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 1ADB16E63DE3CFDCE1776489 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tella-TellaUITests/Pods-Tella-TellaUITests-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; 36C5FA1BF18AC473E32B7C1A /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -3500,6 +3467,7 @@ 12607D5A2790457600E2B8CC /* VideoViewer.swift in Sources */, 125B79FA2C2213920061CF84 /* AVCaptureMovieFileOutputExtension.swift in Sources */, 153AACFB2BE41C010075D5B2 /* UwaziEntityRelationshipItem.swift in Sources */, + 154B029C2C10FAD0007A5D2B /* DriveConnectionType.swift in Sources */, 12A8B09D2AFC0CEE007C838F /* LocalizableCommon.swift in Sources */, 1242135529B774A40002402D /* DeleteReportConfirmationView.swift in Sources */, 12B5257E2849037E00B3D1C0 /* LockTimeoutOptionsStatus.swift in Sources */, @@ -3645,7 +3613,6 @@ 122E6A5529A396C400BDACAD /* ServerFileSize.swift in Sources */, 125EFACD274A447100D93DF6 /* FileSortMenu.swift in Sources */, 15FABA362B73F96800B2EFEE /* ResourceRepository.swift in Sources */, - CCD586C72A7ABDE800014F87 /* TemplateCardView.swift in Sources */, 15994A112BFBF0E50017F153 /* SharedDrive.swift in Sources */, 12607D58279042CE00E2B8CC /* VideoPlayer.swift in Sources */, 121AD8222943A2F00056AC2A /* ReportRepository.swift in Sources */, diff --git a/Tella/Components/NavigationHeaderView.swift b/Tella/Components/NavigationHeaderView.swift index 55cf5e42f..221d488a7 100644 --- a/Tella/Components/NavigationHeaderView.swift +++ b/Tella/Components/NavigationHeaderView.swift @@ -10,6 +10,7 @@ import SwiftUI enum NavigationType { case save + case draft case validate case reload case none @@ -17,17 +18,17 @@ enum NavigationType { var imageName: String { switch self { - case .save: return "reports.save" + case .draft: return "reports.save" case .validate: return "report.select-files" case .reload: return "arrow.clockwise" case .delete: return "report.delete-outbox" - case .none: return "" + case .none, .save: return "" } } var backButtonIcon: String { switch self { - case .save: return "close" + case .save, .draft: return "close" default: return "back" } } @@ -46,7 +47,7 @@ struct NavigationHeaderView: View { backButton headerTitleView Spacer() - if(type != .none) { + if(!type.imageName.isEmpty) { rightButton } }.frame(height: 56) diff --git a/Tella/Scenes/Settings/Models/DriveConnectionType.swift b/Tella/Scenes/Settings/Models/DriveConnectionType.swift new file mode 100644 index 000000000..8fb839fc0 --- /dev/null +++ b/Tella/Scenes/Settings/Models/DriveConnectionType.swift @@ -0,0 +1,15 @@ +// +// DriveConnectionType.swift +// Tella +// +// Created by gus valbuena on 6/5/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +enum DriveConnectionType { + case shared + case personal + case none +} diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index 518378989..87407ae8b 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -7,32 +7,38 @@ // import SwiftUI -enum DriveConnectionType { - case shared - case personal - case none -} + struct SelectDriveConnection: View { @State var selectedDriveConnectionType: DriveConnectionType = .none @ObservedObject var gDriveServerViewModel: GDriveServerViewModel var body: some View { ContainerView { - VStack(spacing: 24) { - Spacer() - ServerConnectionHeaderView( - title: "Select a Drive to connect to", - subtitle: "You can either connect to an organizational Shared Drive or create a new folder in your personal Drive." - ) - connectionsButtons - Spacer() - bottomView - }.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) - .toolbar { - LeadingTitleToolbar(title: "Select Google drive") + VStack { + selectDriveToolbar + VStack(spacing: 24) { + Spacer() + headerView + connectionsButtons + Spacer() + bottomView + } + .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) } + .navigationBarHidden(true) } } + var selectDriveToolbar: some View { + NavigationHeaderView(title: "Select Google drive" ,type: .none) + } + + var headerView: some View { + ServerConnectionHeaderView( + title: "Select a Drive to connect to", + subtitle: "You can either connect to an organizational Shared Drive or create a new folder in your personal Drive." + ) + } + var connectionsButtons: some View { VStack(spacing: 14) { TellaButtonView( diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index 4e65daffe..6abea5d3d 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -15,29 +15,31 @@ struct SelectSharedDrive: View { var body: some View { ContainerView { VStack(alignment: .leading){ - ForEach(gDriveServerViewModel.sharedDrives, id: \.id) { drive in - DriveCardView(sharedDrive: drive, selectedDrive: $selectedDrive) - } - - Spacer() - } - .padding(.vertical, 8) - .background(Color.white.opacity(0.03)) - .toolbar { - LeadingTitleToolbar(title: "Select shared drive") - // remove this after merging with uwazi relationships - ToolbarItem(placement: .navigationBarTrailing) { - Button(action: { - gDriveServerViewModel.addServer(rootFolder: selectedDrive) { - navigateTo(destination: SuccessLoginView(navigateToAction: {self.popToRoot()}, type: .gDrive)) - } - }) { - Image("report.select-files") - .resizable() - .frame(width: 24, height: 24) + selectSharedDriveHeader + VStack(alignment: .leading) { + ForEach(gDriveServerViewModel.sharedDrives, id: \.id) { drive in + DriveCardView(sharedDrive: drive, selectedDrive: $selectedDrive) } + + Spacer() } + .padding(.vertical, 8) + .background(Color.white.opacity(0.03)) } + .navigationBarHidden(true) + + } + } + + var selectSharedDriveHeader: some View { + NavigationHeaderView(backButtonAction:{ backButtonAction() }, + title: "Select shared drive", + type: .save) + } + + func backButtonAction() -> Void { + gDriveServerViewModel.addServer(rootFolder: selectedDrive) { + navigateTo(destination: SuccessLoginView(navigateToAction: {self.popToRoot()}, type: .gDrive)) } } } diff --git a/Tella/Scenes/Uwazi/Views/Entity/CreateEntityView.swift b/Tella/Scenes/Uwazi/Views/Entity/CreateEntityView.swift index 1cf5bffb7..1c184a6fa 100644 --- a/Tella/Scenes/Uwazi/Views/Entity/CreateEntityView.swift +++ b/Tella/Scenes/Uwazi/Views/Entity/CreateEntityView.swift @@ -51,7 +51,7 @@ struct CreateEntityView: View { backButtonAction: { showSaveEntityConfirmationView() }, rightButtonAction: {entityViewModel.saveEntityDraft() }, title: entityViewModel.templateName, - type: .save + type: .draft ) } From 4417cf8051b249a437659d8a2197253aa2f54da8 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 5 Jun 2024 17:57:08 -0300 Subject: [PATCH 041/167] add translations --- Tella/Domain/Entity/Report/ServerType.swift | 6 +++--- .../Models/ServerConnectionButton.swift | 2 +- .../Servers/GDrive/CreateDriveFolder.swift | 6 +++--- .../GDrive/SelectDriveConnection.swift | 12 ++++++------ .../Views/Servers/ServerSelectionView.swift | 14 +++++++++----- .../en.lproj/Localizable.strings | 17 +++++++++++++++++ .../Localizable/LocalizableSettings.swift | 19 ++++++++++++++++++- 7 files changed, 57 insertions(+), 19 deletions(-) diff --git a/Tella/Domain/Entity/Report/ServerType.swift b/Tella/Domain/Entity/Report/ServerType.swift index 11e4952d0..110cb721e 100644 --- a/Tella/Domain/Entity/Report/ServerType.swift +++ b/Tella/Domain/Entity/Report/ServerType.swift @@ -14,9 +14,9 @@ extension ServerConnectionType { var successConnectionButtonContent: String { switch self { case .gDrive: - return "GO TO GOOGLE DRIVE" + return LocalizableSettings.GDriveSuccessMessage.localized case.tella: - return "GO TO REPORTS" + return LocalizableSettings.settServerReportsSuccessMessage.localized default: return "" } @@ -25,7 +25,7 @@ extension ServerConnectionType { var serverTitle: String { switch self { case .gDrive: - "GOOGLE DRIVE" + LocalizableSettings.settServerGDrive.localized default: "" } diff --git a/Tella/Scenes/Settings/Models/ServerConnectionButton.swift b/Tella/Scenes/Settings/Models/ServerConnectionButton.swift index b7d7edcdb..604c1013e 100644 --- a/Tella/Scenes/Settings/Models/ServerConnectionButton.swift +++ b/Tella/Scenes/Settings/Models/ServerConnectionButton.swift @@ -16,5 +16,5 @@ struct ServerConnectionButton { let serverConnections: [ServerConnectionButton] = [ ServerConnectionButton(title: LocalizableSettings.settServerTellaWeb.localized, type: .tella), ServerConnectionButton(title: LocalizableSettings.settServerUwazi.localized, type: .uwazi), - ServerConnectionButton(title: "GOOGLE DRIVE", type: .gDrive) + ServerConnectionButton(title: LocalizableSettings.settServerGDrive.localized, type: .gDrive) ] diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift index 2cae70c71..675b3239d 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift @@ -17,14 +17,14 @@ struct CreateDriveFolder: View { VStack(spacing: 20) { Spacer() ServerConnectionHeaderView( - title: "Create new folder", - subtitle: "Your reports will be uploaded to a new folder on your Google Drive. Choose a name for this folder here." + title: LocalizableSettings.GDriveCreatePersonalFolderTitle.localized, + subtitle: LocalizableSettings.GDriveCreatePersonalFolderDesc.localized ) TextfieldView(fieldContent: $fieldContent, isValid: $isValid, shouldShowError: .constant(false), fieldType: .text, - placeholder: "Folder name") + placeholder: LocalizableSettings.GDriveCreatePersonalFolderPlaceholder.localized) .padding(.vertical, 12) .onChange(of: fieldContent) { newValue in isValid = !newValue.isEmpty diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index 87407ae8b..2232f0c97 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -29,27 +29,27 @@ struct SelectDriveConnection: View { } var selectDriveToolbar: some View { - NavigationHeaderView(title: "Select Google drive" ,type: .none) + NavigationHeaderView(title: LocalizableSettings.GDriveSelectTypeToolbar.localized ,type: .none) } var headerView: some View { ServerConnectionHeaderView( - title: "Select a Drive to connect to", - subtitle: "You can either connect to an organizational Shared Drive or create a new folder in your personal Drive." + title: LocalizableSettings.GDriveSelectTypeTitle.localized, + subtitle: LocalizableSettings.GDriveSelectTypeDesc.localized ) } var connectionsButtons: some View { VStack(spacing: 14) { TellaButtonView( - title: "USE SHARED DRIVE", + title: LocalizableSettings.GDriveSelectTypeShared.localized, nextButtonAction: .action, isOverlay: selectedDriveConnectionType == .shared, isValid: .constant(true), action: { selectedDriveConnectionType = .shared } ) TellaButtonView( - title: "USE PERSONAL DRIVE", + title: LocalizableSettings.GDriveSelectTypePersonal.localized, nextButtonAction: .action, isOverlay: selectedDriveConnectionType == .personal, isValid: .constant(true), @@ -62,7 +62,7 @@ struct SelectDriveConnection: View { var moreInfoText: some View { Link(destination: URL(string: TellaUrls.gDriveURL)!) { - Text("Learn more about the types of drives") + Text(LocalizableSettings.GDriveSelectTypeMoreInfo.localized) .font(.custom(Styles.Fonts.regularFontName, size: 14)) .foregroundColor(Styles.Colors.yellow) .multilineTextAlignment(.center) diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 381396b82..969f1181b 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -87,20 +87,24 @@ struct ServerSelectionView: View { gDriveVM.handleSignIn { navigateTo( destination: SelectDriveConnection(gDriveServerViewModel: GDriveServerViewModel(mainAppModel: mainAppModel)), - title: "Select Google drive" + title: LocalizableSettings.settServerGDrive.localized ) } } fileprivate func unavailableConnectionsView() -> some View { VStack(spacing: 20) { - SectionTitle(text: "Unavailable connections") - SectionMessage(text: "For the following categories, only one connection can be enabled at a time. To add a new connection, please delete the current one by going to Connections Settings.") + SectionTitle(text: LocalizableSettings.settServerUnavailableConnectionsTitle.localized) + SectionMessage(text: LocalizableSettings.settServerUnavailableConnectionsDesc.localized) ForEach(serversViewModel.unavailableServers, id: \.id) { server in TellaButtonView( - title: server.serverType?.serverTitle ?? "", + title: server.serverType?.serverTitle ?? "" , nextButtonAction: .action, - isValid: .constant(false) + isOverlay: selectedServerType == server.serverType, + isValid: .constant(true), + action: { + selectedServerType = server.serverType + } ) } }.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) diff --git a/Tella/Supporting Files/en.lproj/Localizable.strings b/Tella/Supporting Files/en.lproj/Localizable.strings index 2ae8bd261..ed8c356bb 100644 --- a/Tella/Supporting Files/en.lproj/Localizable.strings +++ b/Tella/Supporting Files/en.lproj/Localizable.strings @@ -240,8 +240,11 @@ If you want to take a picture or a video, proceed in the following way:\ "Setting_SettServer_Selection_Message" = "If you are not sure, please ask your organization."; "Setting_SettServer_TellaWeb" = "TELLA WEB"; "Setting_SettServer_Uwazi" = "UWAZI"; +"Setting_SettServer_GDrive" = "GOOGLE DRIVE"; "Setting_SettServer_No_Internet" = "No Internet connection. Try again when you are connected to the Internet."; "Setting_SettServer_Server_URL_Incorrect" = "Error: The server URL is incorrect"; +"Setting_SettServer_UnavailableConnections_Title" = "Unavailable connections"; +"Setting_SettServer_UnavailableConnections_Description" = "For the following categories, only one connection can be enabled at a time. To add a new connection, please delete the current one by going to Connections Settings."; "Home_RecentFiles_Subhead" = "Recent files"; @@ -264,6 +267,20 @@ If you want to take a picture or a video, proceed in the following way:\ "Setting_Server_Uwazi_Connect_Server" = "Connected to server"; "Setting_Server_Uwazi_Success_Message" = "You have successfully connected to the server and will be able to share your data."; +"Setting_Server_GDrive_Select_Type_Toolbar" = "Select Google drive"; +"Setting_Server_GDrive_Select_Type_Title" = "Select a Drive to connect to"; +"Setting_Server_GDrive_Select_Type_Desc" = "You can either connect to an organizational Shared Drive or create a new folder in your personal Drive."; +"Setting_Server_GDrive_Select_Type_Shared" = "USE SHARED DRIVE"; +"Setting_Server_GDrive_Select_Type_Personal" = "USE PERSONAL DRIVE"; +"Setting_Server_GDrive_Select_Type_More_Info" = "Learn more about the types of drives"; +"Setting_Server_GDrive_Select_Shared_Toolbar" = "Select shared drive"; +"Setting_Server_GDrive_Create_Personal_Title" = "Create new folder"; +"Setting_Server_GDrive_Create_Personal_Desc" = "Your reports will be uploaded to a new folder on your Google Drive. Choose a name for this folder here."; +"Setting_Server_GDrive_Create_Personal_Placeholder" = "Folder name"; +"Setting_Server_GDrive_Success_Message" = "GO TO GOOGLE DRIVE"; + +"Setting_Server_Reports_Success_Message" = "GO TO REPORTS"; + "Settings_SettAbout_AppBar" = "About & Help"; "Settings_SettAbout_Head" = "Tella"; "Settings_SettAbout_Subhead" = "Version"; diff --git a/Tella/Utils/Localizable/LocalizableSettings.swift b/Tella/Utils/Localizable/LocalizableSettings.swift index cb8eb6dd0..6fd12a4c7 100644 --- a/Tella/Utils/Localizable/LocalizableSettings.swift +++ b/Tella/Utils/Localizable/LocalizableSettings.swift @@ -88,8 +88,11 @@ enum LocalizableSettings: String, LocalizableDelegate { case settServerSelectionMessage = "Setting_SettServer_Selection_Message" case settServerTellaWeb = "Setting_SettServer_TellaWeb" case settServerUwazi = "Setting_SettServer_Uwazi" + case settServerGDrive = "Setting_SettServer_GDrive" case settServerNoInternetConnection = "Setting_SettServer_No_Internet" case settServerServerURLIncorrect = "Setting_SettServer_Server_URL_Incorrect" + case settServerUnavailableConnectionsTitle = "Setting_SettServer_UnavailableConnections_Title" + case settServerUnavailableConnectionsDesc = "Setting_SettServer_UnavailableConnections_Description" // Uwazi case UwaziServerURL = "Setting_Server_Uwazi_Server_URL" @@ -110,6 +113,18 @@ enum LocalizableSettings: String, LocalizableDelegate { case UwaziSuccess = "Setting_Server_Uwazi_Connect_Server" case UwaziSuccessMessage = "Setting_Server_Uwazi_Success_Message" + //GDrive + case GDriveSelectTypeToolbar = "Setting_Server_GDrive_Select_Type_Toolbar" + case GDriveSelectTypeTitle = "Setting_Server_GDrive_Select_Type_Title" + case GDriveSelectTypeDesc = "Setting_Server_GDrive_Select_Type_Desc" + case GDriveSelectTypeShared = "Setting_Server_GDrive_Select_Type_Shared" + case GDriveSelectTypePersonal = "Setting_Server_GDrive_Select_Type_Personal" + case GDriveSelectTypeMoreInfo = "Setting_Server_GDrive_Select_Type_More_Info" + case GDriveSelectSharedDriveToolbar = "Setting_Server_GDrive_Select_Shared_Toolbar" + case GDriveCreatePersonalFolderTitle = "Setting_Server_GDrive_Create_Personal_Title" + case GDriveCreatePersonalFolderDesc = "Setting_Server_GDrive_Create_Personal_Desc" + case GDriveCreatePersonalFolderPlaceholder = "Setting_Server_GDrive_Create_Personal_Placeholder" + case GDriveSuccessMessage = "Setting_Server_GDrive_Success_Message" // About & Help case settAboutAppBar = "Settings_SettAbout_AppBar" @@ -133,7 +148,9 @@ enum LocalizableSettings: String, LocalizableDelegate { case exitFeedbackSheetExpl = "Settings_SettFeedback_ExitFeedback_SheetExpl" case exitFeedbackSheetAction = "Settings_SettFeedback_ExitFeedback_Exit_SheetAction" case exitFeedbackSaveSheetAction = "Settings_SettFeedback_ExitFeedback_Save_SheetAction" - + + // Reports + case settServerReportsSuccessMessage = "Setting_Server_Reports_Success_Message" } From e8bcb02b106d612a200eadf2bbb064a606e45b0c Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 6 Jun 2024 12:48:22 -0300 Subject: [PATCH 042/167] remove void from async auth function in gDrive repository --- Tella/Data/Networking/Repositories/GDriveRepository.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 8ed2fe1f4..5f65f167d 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -12,8 +12,8 @@ import GoogleAPIClientForREST import Combine protocol GDriveRepositoryProtocol { - func handleSignIn() async throws -> Void - func restorePreviousSignIn() async throws -> Void + func handleSignIn() async throws + func restorePreviousSignIn() async throws func handleUrl(url: URL) func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> func createDriveFolder(folderName: String) -> AnyPublisher From 61ff31bf2aa10a8e3e7ee499271bee01ced9f6a1 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 6 Jun 2024 16:54:00 -0300 Subject: [PATCH 043/167] refactor sharedDriveView --- .../ViewModel/GDriveServerViewModel.swift | 2 +- .../Servers/GDrive/SelectSharedDrive.swift | 38 +++++++++++-------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index a939c201c..5b58367f8 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -15,7 +15,7 @@ class GDriveServerViewModel: ObservableObject { private var cancellables = Set() @Published var sharedDrives: [SharedDrive] = [] - + @Published var selectedDrive: SharedDrive? = nil init(repository: GDriveRepositoryProtocol = GDriveRepository.shared, mainAppModel: MainAppModel) { self.mainAppModel = mainAppModel self.gDriveRepository = repository diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index 6abea5d3d..426a3a149 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -10,35 +10,40 @@ import SwiftUI import GoogleAPIClientForREST struct SelectSharedDrive: View { - @State var selectedDrive: String = "" @EnvironmentObject var gDriveServerViewModel: GDriveServerViewModel var body: some View { ContainerView { VStack(alignment: .leading){ selectSharedDriveHeader - VStack(alignment: .leading) { - ForEach(gDriveServerViewModel.sharedDrives, id: \.id) { drive in - DriveCardView(sharedDrive: drive, selectedDrive: $selectedDrive) - } - - Spacer() - } - .padding(.vertical, 8) - .background(Color.white.opacity(0.03)) + sharedDriveList } .navigationBarHidden(true) } } + var sharedDriveList: some View { + VStack(alignment: .leading) { + ForEach(gDriveServerViewModel.sharedDrives, id: \.id) { drive in + DriveCardView(sharedDrive: drive, + isSelected: drive.id == gDriveServerViewModel.selectedDrive?.id + ) + } + + Spacer() + } + .padding(.vertical, 8) + .background(Color.white.opacity(0.03)) + } + var selectSharedDriveHeader: some View { NavigationHeaderView(backButtonAction:{ backButtonAction() }, - title: "Select shared drive", + title: LocalizableSettings.GDriveSelectSharedDriveToolbar.localized, type: .save) } func backButtonAction() -> Void { - gDriveServerViewModel.addServer(rootFolder: selectedDrive) { + gDriveServerViewModel.addServer(rootFolder: gDriveServerViewModel.selectedDrive?.id ?? "") { navigateTo(destination: SuccessLoginView(navigateToAction: {self.popToRoot()}, type: .gDrive)) } } @@ -46,22 +51,23 @@ struct SelectSharedDrive: View { struct DriveCardView: View { var sharedDrive: SharedDrive - @Binding var selectedDrive: String + var isSelected: Bool + @EnvironmentObject var gDriveServerViewModel: GDriveServerViewModel var body: some View { Button(action: { - self.selectedDrive = sharedDrive.id + gDriveServerViewModel.selectedDrive = sharedDrive }) { HStack { Text(sharedDrive.name) .font(.custom(Styles.Fonts.regularFontName, size: 16)) .foregroundColor(.white) Spacer() - if selectedDrive == sharedDrive.id { + if isSelected { Image("settings.done") } } .padding(18) - .background(selectedDrive == sharedDrive.id ? Color.white.opacity(0.1) : Color.clear) + .background(isSelected ? Color.white.opacity(0.1) : Color.clear) } } } From e0882ccd15e37f5c5c848bb3916484a6bec19a93 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 7 Jun 2024 13:10:39 -0300 Subject: [PATCH 044/167] move selected shared drive action to vm --- Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift | 4 ++++ .../Settings/Views/Servers/GDrive/SelectSharedDrive.swift | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 5b58367f8..9c4ddce44 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -79,4 +79,8 @@ class GDriveServerViewModel: ObservableObject { completion() } + + func handleSelectedDrive(drive: SharedDrive) -> Void { + self.selectedDrive = drive + } } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index 426a3a149..e31d09622 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -55,7 +55,7 @@ struct DriveCardView: View { @EnvironmentObject var gDriveServerViewModel: GDriveServerViewModel var body: some View { Button(action: { - gDriveServerViewModel.selectedDrive = sharedDrive + gDriveServerViewModel.handleSelectedDrive(drive: sharedDrive) }) { HStack { Text(sharedDrive.name) From cf7d920e23833d0270e36591a3a8f72ef091fc41 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 10 Jun 2024 16:07:23 -0300 Subject: [PATCH 045/167] add state manager to shared drive view model --- .../ViewModel/GDriveServerViewModel.swift | 15 ++++++--- .../Servers/GDrive/SelectSharedDrive.swift | 31 ++++++++++++++----- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 9c4ddce44..c8619a3a0 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -9,13 +9,20 @@ import Foundation import Combine +enum ViewModelState { + case loading + case loaded(T) + case error(String) +} + class GDriveServerViewModel: ObservableObject { var mainAppModel : MainAppModel private let gDriveRepository: GDriveRepositoryProtocol private var cancellables = Set() - @Published var sharedDrives: [SharedDrive] = [] @Published var selectedDrive: SharedDrive? = nil + @Published var sharedDriveState: ViewModelState<[SharedDrive]>? = nil + init(repository: GDriveRepositoryProtocol = GDriveRepository.shared, mainAppModel: MainAppModel) { self.mainAppModel = mainAppModel self.gDriveRepository = repository @@ -35,6 +42,7 @@ class GDriveServerViewModel: ObservableObject { } func getSharedDrives() { + self.sharedDriveState = .loading gDriveRepository.getSharedDrives() .receive(on: DispatchQueue.main) .sink(receiveCompletion: {completion in @@ -42,12 +50,11 @@ class GDriveServerViewModel: ObservableObject { case .finished: break case.failure(let error): - debugLog(error) - Toast.displayToast(message: error.localizedDescription) + self.sharedDriveState = .error(error.localizedDescription) } }, receiveValue: { [weak self] drives in - self?.sharedDrives = drives + self?.sharedDriveState = .loaded(drives) }) .store(in: &cancellables) } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index e31d09622..1499d5237 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -15,27 +15,44 @@ struct SelectSharedDrive: View { ContainerView { VStack(alignment: .leading){ selectSharedDriveHeader - sharedDriveList + sharedDriveContent } .navigationBarHidden(true) } + .onAppear { + if case .error(let message) = gDriveServerViewModel.sharedDriveState { + Toast.displayToast(message: message) + } + } } - var sharedDriveList: some View { + var sharedDriveContent: some View { VStack(alignment: .leading) { - ForEach(gDriveServerViewModel.sharedDrives, id: \.id) { drive in - DriveCardView(sharedDrive: drive, - isSelected: drive.id == gDriveServerViewModel.selectedDrive?.id - ) + switch gDriveServerViewModel.sharedDriveState { + case .loading: + CircularActivityIndicatory() + case .loaded(let drives): + sharedDriveList(drives: drives) + default: + EmptyView() } - + Spacer() } .padding(.vertical, 8) .background(Color.white.opacity(0.03)) } + @ViewBuilder + func sharedDriveList(drives: [SharedDrive]) -> some View { + ForEach(drives, id: \.id) {drive in + DriveCardView(sharedDrive: drive, + isSelected: drive.id == gDriveServerViewModel.selectedDrive?.id + ) + } + } + var selectSharedDriveHeader: some View { NavigationHeaderView(backButtonAction:{ backButtonAction() }, title: LocalizableSettings.GDriveSelectSharedDriveToolbar.localized, From 500e9367a70f1199e325132595edb337b9864bab Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 10 Jun 2024 16:47:27 -0300 Subject: [PATCH 046/167] add state management in create folder --- Tella/Domain/Entity/GDrive/SharedDrive.swift | 6 ++- .../ViewModel/GDriveServerViewModel.swift | 23 +++++++++-- .../Servers/GDrive/CreateDriveFolder.swift | 40 ++++++++++++------- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/Tella/Domain/Entity/GDrive/SharedDrive.swift b/Tella/Domain/Entity/GDrive/SharedDrive.swift index 6e1fce089..bfda108a6 100644 --- a/Tella/Domain/Entity/GDrive/SharedDrive.swift +++ b/Tella/Domain/Entity/GDrive/SharedDrive.swift @@ -8,7 +8,7 @@ import Foundation -class SharedDrive: DomainModel { +class SharedDrive: DomainModel, Equatable { var id: String var name: String var kind: String @@ -18,4 +18,8 @@ class SharedDrive: DomainModel { self.name = name self.kind = kind } + + static func == (lhs: SharedDrive, rhs: SharedDrive) -> Bool { + return lhs.id == rhs.id && lhs.name == rhs.name && lhs.kind == rhs.kind + } } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index c8619a3a0..2c9b32c2c 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -9,10 +9,23 @@ import Foundation import Combine -enum ViewModelState { +enum ViewModelState: Equatable { case loading case loaded(T) case error(String) + + static func == (lhs: ViewModelState, rhs: ViewModelState) -> Bool { + switch (lhs, rhs) { + case (.loading, .loading): + return true + case (.error(let lhsError), .error(let rhsError)): + return lhsError == rhsError + case (.loaded(let lhsValue), .loaded(let rhsValue)): + return lhsValue == rhsValue + default: + return false + } + } } class GDriveServerViewModel: ObservableObject { @@ -22,7 +35,8 @@ class GDriveServerViewModel: ObservableObject { @Published var selectedDrive: SharedDrive? = nil @Published var sharedDriveState: ViewModelState<[SharedDrive]>? = nil - + @Published var createFolderState: ViewModelState? = nil + init(repository: GDriveRepositoryProtocol = GDriveRepository.shared, mainAppModel: MainAppModel) { self.mainAppModel = mainAppModel self.gDriveRepository = repository @@ -61,7 +75,7 @@ class GDriveServerViewModel: ObservableObject { func createDriveFolder(folderName: String, completion: @escaping () -> Void) { - + self.createFolderState = .loading gDriveRepository.createDriveFolder(folderName: folderName) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in @@ -69,9 +83,10 @@ class GDriveServerViewModel: ObservableObject { case .finished: break case .failure(let error): - Toast.displayToast(message: error.localizedDescription) + self.createFolderState = .error(error.localizedDescription) } }, receiveValue: { folderId in + self.createFolderState = .loaded(folderId) self.addServer(rootFolder: folderId) { completion() } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift index 675b3239d..44037b900 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift @@ -16,30 +16,42 @@ struct CreateDriveFolder: View { ContainerView { VStack(spacing: 20) { Spacer() - ServerConnectionHeaderView( - title: LocalizableSettings.GDriveCreatePersonalFolderTitle.localized, - subtitle: LocalizableSettings.GDriveCreatePersonalFolderDesc.localized - ) - TextfieldView(fieldContent: $fieldContent, - isValid: $isValid, - shouldShowError: .constant(false), - fieldType: .text, - placeholder: LocalizableSettings.GDriveCreatePersonalFolderPlaceholder.localized) - .padding(.vertical, 12) - .onChange(of: fieldContent) { newValue in - isValid = !newValue.isEmpty - } + headerView + textField Spacer() bottomView }.padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) .navigationBarHidden(true) + }.onReceive(gDriveServerViewModel.$createFolderState) {createFolderState in + if case .error(let message) = createFolderState { + Toast.displayToast(message: message) + } } } + var headerView: some View { + ServerConnectionHeaderView( + title: LocalizableSettings.GDriveCreatePersonalFolderTitle.localized, + subtitle: LocalizableSettings.GDriveCreatePersonalFolderDesc.localized + ) + } + + var textField: some View { + TextfieldView(fieldContent: $fieldContent, + isValid: $isValid, + shouldShowError: .constant(false), + fieldType: .text, + placeholder: LocalizableSettings.GDriveCreatePersonalFolderPlaceholder.localized) + .padding(.vertical, 12) + .onChange(of: fieldContent) { newValue in + isValid = !newValue.isEmpty + } + } + var bottomView: some View { BottomLockView(isValid: $isValid, nextButtonAction: .action, - shouldHideNext: false, + shouldHideNext: gDriveServerViewModel.createFolderState == .loading, shouldHideBack: false, nextAction: { gDriveServerViewModel.createDriveFolder(folderName: fieldContent) { From 752a24ef7188eeb55c61811f0424f4501d361db5 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 10 Jun 2024 17:01:16 -0300 Subject: [PATCH 047/167] move viewModelState into a separate file --- Tella.xcodeproj/project.pbxproj | 4 +++ Tella/Domain/Entity/ViewModelState.swift | 28 +++++++++++++++++++ .../ViewModel/GDriveServerViewModel.swift | 19 ------------- 3 files changed, 32 insertions(+), 19 deletions(-) create mode 100644 Tella/Domain/Entity/ViewModelState.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index be033d9c1..dc8cfb864 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -387,6 +387,7 @@ 15F64CA42B6D7CA1008A57AA /* AvailableResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64CA32B6D7CA1008A57AA /* AvailableResources.swift */; }; 15F64CA62B6D80F7008A57AA /* ResourceCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64CA52B6D80F7008A57AA /* ResourceCardViewModel.swift */; }; 15F64CA82B6D852D008A57AA /* ResourceCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64CA72B6D852D008A57AA /* ResourceCard.swift */; }; + 15F924482C17929300C436C5 /* ViewModelState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F924472C17929300C436C5 /* ViewModelState.swift */; }; 15FABA362B73F96800B2EFEE /* ResourceRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15FABA352B73F96800B2EFEE /* ResourceRepository.swift */; }; 15FABA382B7405B800B2EFEE /* ResourceDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15FABA372B7405B800B2EFEE /* ResourceDTO.swift */; }; 1E67B39223FC9067001F3D64 /* ImagePickerSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E67B39123FC9067001F3D64 /* ImagePickerSheet.swift */; }; @@ -941,6 +942,7 @@ 15F64CA32B6D7CA1008A57AA /* AvailableResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvailableResources.swift; sourceTree = ""; }; 15F64CA52B6D80F7008A57AA /* ResourceCardViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceCardViewModel.swift; sourceTree = ""; }; 15F64CA72B6D852D008A57AA /* ResourceCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceCard.swift; sourceTree = ""; }; + 15F924472C17929300C436C5 /* ViewModelState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModelState.swift; sourceTree = ""; }; 15FABA352B73F96800B2EFEE /* ResourceRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceRepository.swift; sourceTree = ""; }; 15FABA372B7405B800B2EFEE /* ResourceDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceDTO.swift; sourceTree = ""; }; 1E67B39123FC9067001F3D64 /* ImagePickerSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePickerSheet.swift; sourceTree = ""; }; @@ -1456,6 +1458,7 @@ 121C5D7829422DF400A64123 /* DomainModel.swift */, 1231A45C294C771E0057DA85 /* Report */, 1205F9C12BA1DE52003DB9ED /* ImportedFile.swift */, + 15F924472C17929300C436C5 /* ViewModelState.swift */, ); path = Entity; sourceTree = ""; @@ -3218,6 +3221,7 @@ CCC1B43B2AC75BED0075B819 /* UwaziEntityParserProtocol.swift in Sources */, D57F5E9026152A4800C1DA47 /* Datable.swift in Sources */, CC1313822A5CB0DB0057271C /* DeleteAfterFailOption.swift in Sources */, + 15F924482C17929300C436C5 /* ViewModelState.swift in Sources */, 1203CDEB2992C1CB00D09073 /* HTTPCodes.swift in Sources */, 15BD9CAB2BC740D700C3932B /* EntitySelectorView.swift in Sources */, 122389B7293635790058593B /* SetExtension.swift in Sources */, diff --git a/Tella/Domain/Entity/ViewModelState.swift b/Tella/Domain/Entity/ViewModelState.swift new file mode 100644 index 000000000..ad5848516 --- /dev/null +++ b/Tella/Domain/Entity/ViewModelState.swift @@ -0,0 +1,28 @@ +// +// ViewModelState.swift +// Tella +// +// Created by gus valbuena on 6/10/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +enum ViewModelState: Equatable { + case loading + case loaded(T) + case error(String) + + static func == (lhs: ViewModelState, rhs: ViewModelState) -> Bool { + switch (lhs, rhs) { + case (.loading, .loading): + return true + case (.error(let lhsError), .error(let rhsError)): + return lhsError == rhsError + case (.loaded(let lhsValue), .loaded(let rhsValue)): + return lhsValue == rhsValue + default: + return false + } + } +} diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 2c9b32c2c..e90be7dd9 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -9,25 +9,6 @@ import Foundation import Combine -enum ViewModelState: Equatable { - case loading - case loaded(T) - case error(String) - - static func == (lhs: ViewModelState, rhs: ViewModelState) -> Bool { - switch (lhs, rhs) { - case (.loading, .loading): - return true - case (.error(let lhsError), .error(let rhsError)): - return lhsError == rhsError - case (.loaded(let lhsValue), .loaded(let rhsValue)): - return lhsValue == rhsValue - default: - return false - } - } -} - class GDriveServerViewModel: ObservableObject { var mainAppModel : MainAppModel private let gDriveRepository: GDriveRepositoryProtocol From a2288b2eee59947302f3ec90f326bb6ddd7d2848 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 10 Jun 2024 17:03:18 -0300 Subject: [PATCH 048/167] fix issue in server selection --- .../Settings/Views/Servers/ServerSelectionView.swift | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 969f1181b..9999064c2 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -98,13 +98,9 @@ struct ServerSelectionView: View { SectionMessage(text: LocalizableSettings.settServerUnavailableConnectionsDesc.localized) ForEach(serversViewModel.unavailableServers, id: \.id) { server in TellaButtonView( - title: server.serverType?.serverTitle ?? "" , + title: server.serverType?.serverTitle ?? "", nextButtonAction: .action, - isOverlay: selectedServerType == server.serverType, - isValid: .constant(true), - action: { - selectedServerType = server.serverType - } + isValid: .constant(false) ) } }.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) From 4e7b508790b48ff6530fd0ec60e7dcd907ba5093 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 11 Jun 2024 15:11:07 -0300 Subject: [PATCH 049/167] move restoreSignIn to a private method inside the repository --- Tella/Data/Networking/APICall/APIError.swift | 3 +++ .../Repositories/GDriveRepository.swift | 21 ++++++++++++++++--- .../ViewModel/GDriveServerViewModel.swift | 14 +------------ .../ViewModel/UwaziServerViewModel.swift | 4 ++++ 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/Tella/Data/Networking/APICall/APIError.swift b/Tella/Data/Networking/APICall/APIError.swift index 3b8fbafd9..ed941688a 100644 --- a/Tella/Data/Networking/APICall/APIError.swift +++ b/Tella/Data/Networking/APICall/APIError.swift @@ -11,6 +11,7 @@ enum APIError: Swift.Error { case unexpectedResponse case noInternetConnection case badServer + case noToken } extension APIError: LocalizedError { @@ -27,6 +28,8 @@ extension APIError: LocalizedError { return LocalizableSettings.settServerNoInternetConnection.localized case .badServer: return LocalizableSettings.settServerServerURLIncorrect.localized + case .noToken: + return "No token present, please connect again" } } private func customErrorMessage(errorCode : Int) -> String { diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 5f65f167d..3b2edbda4 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -29,6 +29,20 @@ class GDriveRepository: GDriveRepositoryProtocol { return UIApplication.shared.windows.first?.rootViewController } + init() { + Task { + await initializeRepository() + } + } + + private func initializeRepository() async { + do { + try await restorePreviousSignIn() + } catch { + print("Failed to restore previous sign in") + } + } + func handleSignIn() async throws { try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in DispatchQueue.main.async { @@ -74,7 +88,9 @@ class GDriveRepository: GDriveRepositoryProtocol { func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> { Deferred { Future { [weak self] promise in - guard let user = self?.googleUser else { return } + guard let user = self?.googleUser else { + return promise(.failure(APIError.noToken)) + } let driveService = GTLRDriveService() driveService.authorizer = user.fetcherAuthorizer @@ -111,8 +127,7 @@ class GDriveRepository: GDriveRepositoryProtocol { Deferred { Future { [weak self] promise in guard let user = self?.googleUser else { - print("User not authenticated") - return + return promise(.failure(APIError.noToken)) } let driveService = GTLRDriveService() diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index e90be7dd9..63532bae4 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -21,19 +21,7 @@ class GDriveServerViewModel: ObservableObject { init(repository: GDriveRepositoryProtocol = GDriveRepository.shared, mainAppModel: MainAppModel) { self.mainAppModel = mainAppModel self.gDriveRepository = repository - restorePreviousSignIn() - } - - func restorePreviousSignIn() { - Task { - do { - try await gDriveRepository.restorePreviousSignIn() - self.getSharedDrives() - } catch let error { - Toast.displayToast(message: error.localizedDescription) - } - } - + self.getSharedDrives() } func getSharedDrives() { diff --git a/Tella/Scenes/Settings/ViewModel/UwaziServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/UwaziServerViewModel.swift index e913fc415..2fc473bf9 100644 --- a/Tella/Scenes/Settings/ViewModel/UwaziServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/UwaziServerViewModel.swift @@ -244,6 +244,8 @@ class UwaziServerViewModel: ObservableObject { } case .noInternetConnection: Toast.displayToast(message: error.errorDescription ?? error.localizedDescription) + default: + break } case .finished: self.shouldShowLoginError = false @@ -303,6 +305,8 @@ class UwaziServerViewModel: ObservableObject { } case .noInternetConnection: Toast.displayToast(message: error.errorDescription ?? error.localizedDescription) + default: + break } self.shouldShowAuthenticationError = true case .finished: From 2cbd7ffd45139ebe2f6ed5b0070dbdd4817a9ccd Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 11 Jun 2024 15:24:48 -0300 Subject: [PATCH 050/167] add no token error localization --- Tella/Data/Networking/APICall/APIError.swift | 2 +- Tella/Data/Networking/Repositories/GDriveRepository.swift | 1 + Tella/Supporting Files/en.lproj/Localizable.strings | 1 + Tella/Utils/Localizable/LocalizableSettings.swift | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Tella/Data/Networking/APICall/APIError.swift b/Tella/Data/Networking/APICall/APIError.swift index ed941688a..445fe7920 100644 --- a/Tella/Data/Networking/APICall/APIError.swift +++ b/Tella/Data/Networking/APICall/APIError.swift @@ -29,7 +29,7 @@ extension APIError: LocalizedError { case .badServer: return LocalizableSettings.settServerServerURLIncorrect.localized case .noToken: - return "No token present, please connect again" + return LocalizableSettings.settServerNoTokenPresent.localized } } private func customErrorMessage(errorCode : Int) -> String { diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 3b2edbda4..07cb6f395 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -53,6 +53,7 @@ class GDriveRepository: GDriveRepositoryProtocol { if let error = error { continuation.resume(throwing: error) } else { + self.googleUser = signInResult?.user continuation.resume(returning: ()) } } diff --git a/Tella/Supporting Files/en.lproj/Localizable.strings b/Tella/Supporting Files/en.lproj/Localizable.strings index ed8c356bb..33ee9b311 100644 --- a/Tella/Supporting Files/en.lproj/Localizable.strings +++ b/Tella/Supporting Files/en.lproj/Localizable.strings @@ -245,6 +245,7 @@ If you want to take a picture or a video, proceed in the following way:\ "Setting_SettServer_Server_URL_Incorrect" = "Error: The server URL is incorrect"; "Setting_SettServer_UnavailableConnections_Title" = "Unavailable connections"; "Setting_SettServer_UnavailableConnections_Description" = "For the following categories, only one connection can be enabled at a time. To add a new connection, please delete the current one by going to Connections Settings."; +"Setting_SettServer_No_Token" = "No token present, please connect again"; "Home_RecentFiles_Subhead" = "Recent files"; diff --git a/Tella/Utils/Localizable/LocalizableSettings.swift b/Tella/Utils/Localizable/LocalizableSettings.swift index 6fd12a4c7..289ac6bf3 100644 --- a/Tella/Utils/Localizable/LocalizableSettings.swift +++ b/Tella/Utils/Localizable/LocalizableSettings.swift @@ -93,6 +93,7 @@ enum LocalizableSettings: String, LocalizableDelegate { case settServerServerURLIncorrect = "Setting_SettServer_Server_URL_Incorrect" case settServerUnavailableConnectionsTitle = "Setting_SettServer_UnavailableConnections_Title" case settServerUnavailableConnectionsDesc = "Setting_SettServer_UnavailableConnections_Description" + case settServerNoTokenPresent = "Setting_SettServer_No_Token" // Uwazi case UwaziServerURL = "Setting_Server_Uwazi_Server_URL" From f5174e5ee724a2d13d367d099ab74cbb882c04d1 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 11 Jun 2024 17:38:38 -0300 Subject: [PATCH 051/167] apply DI to gDriveRepository --- Tella/Application/TellaApp.swift | 3 --- .../Repositories/GDriveRepository.swift | 23 +++++++++---------- .../ViewModel/GDriveAuthViewModel.swift | 10 ++++---- .../ViewModel/GDriveServerViewModel.swift | 2 +- .../AddServer/SettingsAddServerCardView.swift | 4 ++-- .../GDrive/SelectDriveConnection.swift | 2 +- .../Servers/GDrive/SelectSharedDrive.swift | 2 +- .../Views/Servers/ServerSelectionView.swift | 19 +++++++++++---- 8 files changed, 35 insertions(+), 30 deletions(-) diff --git a/Tella/Application/TellaApp.swift b/Tella/Application/TellaApp.swift index 829d0c0de..fd7fd745e 100644 --- a/Tella/Application/TellaApp.swift +++ b/Tella/Application/TellaApp.swift @@ -15,7 +15,6 @@ struct TellaApp: App { @Environment(\.scenePhase) var scenePhase @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate let delayTimeInSecond = 1.0 - let gDriveAuthViewModel = GDriveAuthViewModel() var body: some Scene { WindowGroup { @@ -27,8 +26,6 @@ struct TellaApp: App { if value { self.saveData(lockApptype: .finishBackgroundTasks) } - }.onOpenURL { url in - gDriveAuthViewModel.handleUrl(url: url) } }.onChange(of: scenePhase) { phase in diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 07cb6f395..e2bac83e9 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -21,25 +21,15 @@ protocol GDriveRepositoryProtocol { } class GDriveRepository: GDriveRepositoryProtocol { - static let shared = GDriveRepository() - private var googleUser: GIDGoogleUser? private var rootViewController: UIViewController? { return UIApplication.shared.windows.first?.rootViewController } - init() { - Task { - await initializeRepository() - } - } - - private func initializeRepository() async { - do { + private func ensureSignedIn() async throws { + if self.googleUser == nil { try await restorePreviousSignIn() - } catch { - print("Failed to restore previous sign in") } } @@ -161,3 +151,12 @@ class GDriveRepository: GDriveRepositoryProtocol { GIDSignIn.sharedInstance.signOut() } } + + +struct GDriveDIContainer { + let gDriveRepository: GDriveRepositoryProtocol + + init(gDriveRepository: GDriveRepositoryProtocol = GDriveRepository()) { + self.gDriveRepository = gDriveRepository + } +} diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift index c5c1662ed..c437d5cf0 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -12,22 +12,22 @@ import Combine class GDriveAuthViewModel: ObservableObject { private let gDriveRepository: GDriveRepositoryProtocol private var cancellables = Set() - - init(repository: GDriveRepositoryProtocol = GDriveRepository.shared) { + @Published var signInState: ViewModelState? = nil + init(repository: GDriveRepositoryProtocol) { self.gDriveRepository = repository } func handleSignIn(completion: @escaping () -> Void) { + self.signInState = .loading Task { do { try await gDriveRepository.handleSignIn() DispatchQueue.main.async { + self.signInState = .loaded("") completion() } } catch let error { - DispatchQueue.main.async { - Toast.displayToast(message: error.localizedDescription) - } + self.signInState = .error(error.localizedDescription) } } } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 63532bae4..971095ea5 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -18,7 +18,7 @@ class GDriveServerViewModel: ObservableObject { @Published var sharedDriveState: ViewModelState<[SharedDrive]>? = nil @Published var createFolderState: ViewModelState? = nil - init(repository: GDriveRepositoryProtocol = GDriveRepository.shared, mainAppModel: MainAppModel) { + init(repository: GDriveRepositoryProtocol, mainAppModel: MainAppModel) { self.mainAppModel = mainAppModel self.gDriveRepository = repository self.getSharedDrives() diff --git a/Tella/Scenes/Settings/Views/Servers/AddServer/SettingsAddServerCardView.swift b/Tella/Scenes/Settings/Views/Servers/AddServer/SettingsAddServerCardView.swift index 2e6e393ba..d07912a6f 100644 --- a/Tella/Scenes/Settings/Views/Servers/AddServer/SettingsAddServerCardView.swift +++ b/Tella/Scenes/Settings/Views/Servers/AddServer/SettingsAddServerCardView.swift @@ -10,7 +10,7 @@ struct SettingsAddServerCardView: View { @EnvironmentObject var serversViewModel : ServersViewModel @EnvironmentObject var mainAppModel : MainAppModel @EnvironmentObject var settingViewModel: SettingsViewModel - + let gDriveDIContainer = GDriveDIContainer() var body: some View { ZStack { HStack{ @@ -28,7 +28,7 @@ struct SettingsAddServerCardView: View { Button { //navigateTo(destination: AddServerURLView(appModel: mainAppModel)) - navigateTo(destination: ServerSelectionView(appModel: mainAppModel).environmentObject(serversViewModel)) + navigateTo(destination: ServerSelectionView(appModel: mainAppModel, gDriveDIContainer: gDriveDIContainer).environmentObject(serversViewModel)) } label: { Image("settings.add") .padding(.all, 14) diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index 2232f0c97..1deeded66 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -95,5 +95,5 @@ struct SelectDriveConnection: View { } #Preview { - SelectDriveConnection(selectedDriveConnectionType: .personal, gDriveServerViewModel: GDriveServerViewModel(mainAppModel: MainAppModel.stub())) + SelectDriveConnection(selectedDriveConnectionType: .personal, gDriveServerViewModel: GDriveServerViewModel(repository: GDriveRepository(),mainAppModel: MainAppModel.stub())) } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index 1499d5237..b3e9b7ce9 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -33,7 +33,7 @@ struct SelectSharedDrive: View { case .loading: CircularActivityIndicatory() case .loaded(let drives): - sharedDriveList(drives: drives) + sharedDriveList(drives: drives ?? []) default: EmptyView() } diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 9999064c2..1177020e1 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -13,11 +13,14 @@ struct ServerSelectionView: View { @StateObject var serverViewModel : ServerViewModel @EnvironmentObject var mainAppModel : MainAppModel @State var selectedServerType: ServerConnectionType? = nil - @ObservedObject var gDriveVM = GDriveAuthViewModel() + @ObservedObject var gDriveVM: GDriveAuthViewModel @Environment(\.presentationMode) var presentationMode: Binding + let gDriveDIContainer: GDriveDIContainer - init(appModel:MainAppModel, server: TellaServer? = nil) { + init(appModel:MainAppModel, server: TellaServer? = nil, gDriveDIContainer: GDriveDIContainer) { + self.gDriveDIContainer = gDriveDIContainer _serverViewModel = StateObject(wrappedValue: ServerViewModel(mainAppModel: appModel, currentServer: server)) + _gDriveVM = ObservedObject(wrappedValue: GDriveAuthViewModel(repository: gDriveDIContainer.gDriveRepository)) } var body: some View { ContainerView { @@ -34,7 +37,12 @@ struct ServerSelectionView: View { .toolbar { LeadingTitleToolbar(title: LocalizableSettings.settServersAppBar.localized) } - } + }.onChange(of: gDriveVM.signInState, perform: { state in + if case .error(let message) = state { + Toast.displayToast(message: message) + } + }) + } fileprivate func buttonViews() -> some View { @@ -85,8 +93,9 @@ struct ServerSelectionView: View { fileprivate func navigateToGDriveFlow() { gDriveVM.handleSignIn { + let gDriveServerViewModel = GDriveServerViewModel(repository: gDriveDIContainer.gDriveRepository, mainAppModel: mainAppModel) navigateTo( - destination: SelectDriveConnection(gDriveServerViewModel: GDriveServerViewModel(mainAppModel: mainAppModel)), + destination: SelectDriveConnection(gDriveServerViewModel: gDriveServerViewModel), title: LocalizableSettings.settServerGDrive.localized ) } @@ -125,7 +134,7 @@ struct ServerSelectionView: View { struct ServerSelectionView_Previews: PreviewProvider { static var previews: some View { - ServerSelectionView(appModel: MainAppModel.stub()) + ServerSelectionView(appModel: MainAppModel.stub(), gDriveDIContainer: GDriveDIContainer()) .environmentObject(MainAppModel.stub()) .environmentObject(ServersViewModel(mainAppModel: MainAppModel.stub())) } From da2a7ecfa6a111a90543df45f2d3c00c077b11fe Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 11 Jun 2024 17:44:22 -0300 Subject: [PATCH 052/167] move mimeTypes to constants --- Tella/Data/Networking/Repositories/GDriveRepository.swift | 4 ++-- Tella/Utils/Constants.swift | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index e2bac83e9..546446c94 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -63,7 +63,7 @@ class GDriveRepository: GDriveRepositoryProtocol { continuation.resume(throwing: error) return } - user?.addScopes([GoogleAuthScopes.gDriveScopes], presenting: rootViewController) + user?.addScopes([GoogleAuthConstants.gDriveScopes], presenting: rootViewController) self.googleUser = user continuation.resume(returning: ()) @@ -126,7 +126,7 @@ class GDriveRepository: GDriveRepositoryProtocol { let folder = GTLRDrive_File() folder.name = folderName - folder.mimeType = "application/vnd.google-apps.folder" + folder.mimeType = GoogleAuthConstants.gDriveFolderMimeType let query = GTLRDriveQuery_FilesCreate.query(withObject: folder, uploadParameters: nil) diff --git a/Tella/Utils/Constants.swift b/Tella/Utils/Constants.swift index de5feaafe..3584ca22e 100644 --- a/Tella/Utils/Constants.swift +++ b/Tella/Utils/Constants.swift @@ -11,6 +11,7 @@ struct TellaUrls { static let gDriveURL = "https://tella-app.org/gdrive" } -struct GoogleAuthScopes { +struct GoogleAuthConstants { static let gDriveScopes = "https://www.googleapis.com/auth/drive" + static let gDriveFolderMimeType = "application/vnd.google-apps.folder" } From 361027359852e5fbf8e21624c445443c8da626c8 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 12 Jun 2024 12:46:13 -0300 Subject: [PATCH 053/167] some refactors on gDriveSeverViewModel and state management --- .../Repositories/GDriveRepository.swift | 1 + .../ViewModel/GDriveServerViewModel.swift | 6 ++---- .../Servers/GDrive/SelectSharedDrive.swift | 19 +++++++++++++------ .../Views/Servers/ServerSelectionView.swift | 8 +++++--- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 546446c94..c30adb712 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -43,6 +43,7 @@ class GDriveRepository: GDriveRepositoryProtocol { if let error = error { continuation.resume(throwing: error) } else { + signInResult?.user.addScopes([GoogleAuthConstants.gDriveScopes], presenting: rootViewController) self.googleUser = signInResult?.user continuation.resume(returning: ()) } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 971095ea5..ad235c579 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -15,17 +15,15 @@ class GDriveServerViewModel: ObservableObject { private var cancellables = Set() @Published var selectedDrive: SharedDrive? = nil - @Published var sharedDriveState: ViewModelState<[SharedDrive]>? = nil - @Published var createFolderState: ViewModelState? = nil + @Published var sharedDriveState: ViewModelState<[SharedDrive]> = .loading + @Published var createFolderState: ViewModelState = .loaded("") init(repository: GDriveRepositoryProtocol, mainAppModel: MainAppModel) { self.mainAppModel = mainAppModel self.gDriveRepository = repository - self.getSharedDrives() } func getSharedDrives() { - self.sharedDriveState = .loading gDriveRepository.getSharedDrives() .receive(on: DispatchQueue.main) .sink(receiveCompletion: {completion in diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index b3e9b7ce9..515b3e0a6 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -21,9 +21,7 @@ struct SelectSharedDrive: View { } .onAppear { - if case .error(let message) = gDriveServerViewModel.sharedDriveState { - Toast.displayToast(message: message) - } + gDriveServerViewModel.getSharedDrives() } } @@ -33,9 +31,9 @@ struct SelectSharedDrive: View { case .loading: CircularActivityIndicatory() case .loaded(let drives): - sharedDriveList(drives: drives ?? []) - default: - EmptyView() + sharedDriveList(drives: drives) + case .error(_): + sharedDriveError } Spacer() @@ -53,6 +51,15 @@ struct SelectSharedDrive: View { } } + var sharedDriveError: some View { + EmptyView() + .onReceive(gDriveServerViewModel.$sharedDriveState){ sharedDriveState in + if case .error(let message) = sharedDriveState { + Toast.displayToast(message: message) + } + } + } + var selectSharedDriveHeader: some View { NavigationHeaderView(backButtonAction:{ backButtonAction() }, title: LocalizableSettings.GDriveSelectSharedDriveToolbar.localized, diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 1177020e1..f9ea289a4 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -14,6 +14,7 @@ struct ServerSelectionView: View { @EnvironmentObject var mainAppModel : MainAppModel @State var selectedServerType: ServerConnectionType? = nil @ObservedObject var gDriveVM: GDriveAuthViewModel + @ObservedObject var gDriveServerVM: GDriveServerViewModel @Environment(\.presentationMode) var presentationMode: Binding let gDriveDIContainer: GDriveDIContainer @@ -21,7 +22,9 @@ struct ServerSelectionView: View { self.gDriveDIContainer = gDriveDIContainer _serverViewModel = StateObject(wrappedValue: ServerViewModel(mainAppModel: appModel, currentServer: server)) _gDriveVM = ObservedObject(wrappedValue: GDriveAuthViewModel(repository: gDriveDIContainer.gDriveRepository)) + _gDriveServerVM = ObservedObject(wrappedValue:GDriveServerViewModel(repository: gDriveDIContainer.gDriveRepository, mainAppModel: appModel)) } + var body: some View { ContainerView { VStack(spacing: 20) { @@ -92,10 +95,9 @@ struct ServerSelectionView: View { } fileprivate func navigateToGDriveFlow() { - gDriveVM.handleSignIn { - let gDriveServerViewModel = GDriveServerViewModel(repository: gDriveDIContainer.gDriveRepository, mainAppModel: mainAppModel) + gDriveVM.handleSignIn { navigateTo( - destination: SelectDriveConnection(gDriveServerViewModel: gDriveServerViewModel), + destination: SelectDriveConnection(gDriveServerViewModel: gDriveServerVM), title: LocalizableSettings.settServerGDrive.localized ) } From defe9899269bc66fbf8f882fbbb66d1ef80d2a16 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 12 Jun 2024 12:47:57 -0300 Subject: [PATCH 054/167] change state management on gDriveAuthVM --- Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift index c437d5cf0..e91a2bb8d 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -12,7 +12,7 @@ import Combine class GDriveAuthViewModel: ObservableObject { private let gDriveRepository: GDriveRepositoryProtocol private var cancellables = Set() - @Published var signInState: ViewModelState? = nil + @Published var signInState: ViewModelState = .loaded("") init(repository: GDriveRepositoryProtocol) { self.gDriveRepository = repository } From 49d69839661178d1d6fc464130cc344ae0d4dec4 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 12 Jun 2024 12:56:53 -0300 Subject: [PATCH 055/167] change onChange for onReceive --- .../Scenes/Settings/Views/Servers/ServerSelectionView.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index f9ea289a4..5a43aba62 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -40,11 +40,11 @@ struct ServerSelectionView: View { .toolbar { LeadingTitleToolbar(title: LocalizableSettings.settServersAppBar.localized) } - }.onChange(of: gDriveVM.signInState, perform: { state in - if case .error(let message) = state { + }.onReceive(gDriveVM.$signInState){ signInState in + if case .error(let message) = signInState { Toast.displayToast(message: message) } - }) + } } From 56601efbd5456553387f2cd9676c7c279ffff6ca Mon Sep 17 00:00:00 2001 From: rimKtarii Date: Fri, 14 Jun 2024 15:19:18 +0200 Subject: [PATCH 056/167] Update Toast display --- Tella/Components/ToastView.swift | 46 +++++++++++-------- .../Servers/GDrive/SelectSharedDrive.swift | 12 +---- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/Tella/Components/ToastView.swift b/Tella/Components/ToastView.swift index 305b277a0..bcf610969 100644 --- a/Tella/Components/ToastView.swift +++ b/Tella/Components/ToastView.swift @@ -5,31 +5,37 @@ import SwiftUI struct ToastView: View { - - @State var isShowingView : Bool = true - var message : String - var width = CGFloat.infinity - + var message: String + @State private var isShowing = true + var body: some View { - - VStack { - - Spacer() - - Text(message) - .font(.custom(Styles.Fonts.regularFontName, size: 14)) - .foregroundColor(.black) - .padding() - .frame(maxWidth: width) - .background(Color.white) - .cornerRadius(4) - .padding() + ZStack { + if isShowing { + Text(message) + .font(.custom(Styles.Fonts.regularFontName, size: 14)) + .foregroundColor(.black) + .padding() + .frame(maxWidth: .infinity) + .background(Color.white) + .cornerRadius(4) + .padding() + .onAppear { + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + withAnimation { + isShowing = false + } + } + } + } } + .padding() } } - struct ToastView_Previews: PreviewProvider { static var previews: some View { - ToastView( message: "Message") + ZStack { + Styles.Colors.backgroundMain + ToastView( message: "Message") + } } } diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index 515b3e0a6..edd978268 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -32,8 +32,8 @@ struct SelectSharedDrive: View { CircularActivityIndicatory() case .loaded(let drives): sharedDriveList(drives: drives) - case .error(_): - sharedDriveError + case .error(let message): + ToastView(message: message) } Spacer() @@ -51,14 +51,6 @@ struct SelectSharedDrive: View { } } - var sharedDriveError: some View { - EmptyView() - .onReceive(gDriveServerViewModel.$sharedDriveState){ sharedDriveState in - if case .error(let message) = sharedDriveState { - Toast.displayToast(message: message) - } - } - } var selectSharedDriveHeader: some View { NavigationHeaderView(backButtonAction:{ backButtonAction() }, From 2bfaf6d051b634cab5dffb2f3101e1f30786b64b Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 12 Jun 2024 15:54:12 -0300 Subject: [PATCH 057/167] add drive to homeView --- .../HomeView/ViewModel/HomeViewModel.swift | 21 +++++++++++++------ .../Home/Connections/ConnectionsView.swift | 6 +++--- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Tella/Scenes/HomeView/ViewModel/HomeViewModel.swift b/Tella/Scenes/HomeView/ViewModel/HomeViewModel.swift index 8e5f988dc..13991fb32 100644 --- a/Tella/Scenes/HomeView/ViewModel/HomeViewModel.swift +++ b/Tella/Scenes/HomeView/ViewModel/HomeViewModel.swift @@ -33,12 +33,21 @@ class HomeViewModel: ObservableObject { } receiveValue: { serverArray in self.serverDataItemArray.removeAll() if !serverArray.isEmpty { - // here i group all the tella servers in one array and the third party services in diferents arrays - let uwaziConnections = serverArray.filter { $0.serverType == .uwazi } - let tellaUploadServers = serverArray.filter { $0.serverType == .tella } - if !uwaziConnections.isEmpty { self.serverDataItemArray.append(ServerDataItem(servers: uwaziConnections, serverType: .uwazi)) } - if !tellaUploadServers.isEmpty { self.serverDataItemArray.append(ServerDataItem(servers: tellaUploadServers, serverType: .tella)) } - + + var serverConnections: [ServerConnectionType: [Server]] = [:] + + for server in serverArray { + guard let serverType = server.serverType else { return } + if serverConnections[serverType] != nil { + serverConnections[serverType] = [server] + } else { + serverConnections[serverType] = [server] + } + } + + for (serverType, servers) in serverConnections { + self.serverDataItemArray.append(ServerDataItem(servers: servers, serverType: serverType )) + } } }.store(in: &subscribers) } diff --git a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift index 218a58e19..91b511123 100644 --- a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift +++ b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift @@ -52,10 +52,10 @@ struct ConnectionsView: View { ConnectionsItemView(title: LocalizableHome.uwaziServerTitle.localized, image: "home.uwazi", destination: UwaziView().environmentObject(UwaziViewModel(mainAppModel: appModel, server: parseUwaziServer(server: server.servers[0])))) - default: - ConnectionsItemView(title: LocalizableReport.reportsTitle.localized, + case .gDrive: + ConnectionsItemView(title: "Drive", image: "home.report", - destination: ReportsView(mainAppModel: appModel)) + destination: EmptyView()) } } From f7e5e0ec47032694c6bf5036bc70ed25d5fe99ac Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 13 Jun 2024 15:18:21 -0300 Subject: [PATCH 058/167] add pageView navigation inside gDriveView --- Tella.xcodeproj/project.pbxproj | 48 ++++++++++++++--- .../Connections/ConnectionEmptyView.swift | 27 ++++++++++ Tella/Domain/Entity/Report/ServerType.swift | 11 ++++ .../drive.empty.imageset/Contents.json | 21 ++++++++ .../drive.empty.imageset/gdrive.svg | 9 ++++ .../GDrive/ViewModel/GDriveViewModel.swift | 30 +++++++++++ .../Scenes/GDrive/Views/GDriveListView.swift | 20 +++++++ Tella/Scenes/GDrive/Views/GDriveView.swift | 52 +++++++++++++++++++ .../Home/Connections/ConnectionsView.swift | 2 +- .../Reports/Draft/EmptyReportView.swift | 30 ----------- .../Reports/ReportList/ReportListView.swift | 2 +- .../Uwazi/Views/Common/UwaziEmptyView.swift | 31 ----------- .../Views/EntityInstances/UwaziListView.swift | 2 +- .../Views/Template/AddTemplatesView.swift | 2 +- 14 files changed, 214 insertions(+), 73 deletions(-) create mode 100644 Tella/Components/Connections/ConnectionEmptyView.swift create mode 100644 Tella/NewAssets.xcassets/drive.empty.imageset/Contents.json create mode 100644 Tella/NewAssets.xcassets/drive.empty.imageset/gdrive.svg create mode 100644 Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift create mode 100644 Tella/Scenes/GDrive/Views/GDriveListView.swift create mode 100644 Tella/Scenes/GDrive/Views/GDriveView.swift delete mode 100644 Tella/Scenes/Reports/Draft/EmptyReportView.swift delete mode 100644 Tella/Scenes/Uwazi/Views/Common/UwaziEmptyView.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index dc8cfb864..fb192efbf 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -68,7 +68,6 @@ 121C5D7929422DF400A64123 /* DomainModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121C5D7829422DF400A64123 /* DomainModel.swift */; }; 121C5D7B29424F4E00A64123 /* ReportAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121C5D7A29424F4E00A64123 /* ReportAPI.swift */; }; 121C5D7D2942710600A64123 /* ProjectAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121C5D7C2942710600A64123 /* ProjectAPI.swift */; }; - 121C945E28FF3DCC00570EB4 /* EmptyReportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121C945D28FF3DCC00570EB4 /* EmptyReportView.swift */; }; 121F87AA2964383D00E6BA0D /* SubmittedReportVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121F87A92964383D00E6BA0D /* SubmittedReportVM.swift */; }; 1220A72E292EB11B000BC24C /* ReportFileGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1220A72D292EB11B000BC24C /* ReportFileGridView.swift */; }; 1220F22B2C17165400CFD20C /* ViewClassType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1220F22A2C17165400CFD20C /* ViewClassType.swift */; }; @@ -372,6 +371,8 @@ 15994A0C2BFBC6F40017F153 /* SelectDriveConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */; }; 15994A0E2BFBE15F0017F153 /* SelectSharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */; }; 15994A112BFBF0E50017F153 /* SharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A102BFBF0E50017F153 /* SharedDrive.swift */; }; + 15B81F382C1A2806007C0E88 /* GDriveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B81F372C1A2806007C0E88 /* GDriveView.swift */; }; + 15B81F3A2C1A281C007C0E88 /* GDriveViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B81F392C1A281C007C0E88 /* GDriveViewModel.swift */; }; 15BD9CA92BC740B300C3932B /* UwaziRelationshipWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CA82BC740B300C3932B /* UwaziRelationshipWidget.swift */; }; 15BD9CAB2BC740D700C3932B /* EntitySelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CAA2BC740D700C3932B /* EntitySelectorView.swift */; }; 15BD9CAD2BC7410E00C3932B /* SearchBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CAC2BC7410E00C3932B /* SearchBarView.swift */; }; @@ -380,6 +381,8 @@ 15C51C442BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C51C432BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift */; }; 15C51C462BFE769500DD9AD0 /* GDriveServerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C51C452BFE769500DD9AD0 /* GDriveServerViewModel.swift */; }; 15CD89102BF297BE00F724F5 /* SelectedEntityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */; }; + 15E3D5032C1B522500B7FECC /* GDriveListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D5022C1B522500B7FECC /* GDriveListView.swift */; }; + 15E3D5052C1B531700B7FECC /* ConnectionEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D5042C1B531700B7FECC /* ConnectionEmptyView.swift */; }; 15EE30FE2B5073E20033BBBB /* Pages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15EE30FD2B5073E20033BBBB /* Pages.swift */; }; 15F64C9D2B6D7904008A57AA /* DownloadedResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */; }; 15F64CA02B6D794B008A57AA /* SectionTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */; }; @@ -431,7 +434,6 @@ CCC1B4392AC75B8D0075B819 /* UwaziEntityParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCC1B4382AC75B8D0075B819 /* UwaziEntityParser.swift */; }; CCC1B43B2AC75BED0075B819 /* UwaziEntityParserProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCC1B43A2AC75BED0075B819 /* UwaziEntityParserProtocol.swift */; }; CCC1B43D2AC75C5D0075B819 /* UwaziConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCC1B43C2AC75C5D0075B819 /* UwaziConstants.swift */; }; - CCC60CD22B0D2C5B00A3DB8C /* UwaziEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCC60CD12B0D2C5B00A3DB8C /* UwaziEmptyView.swift */; }; CCD586CD2A7AD94B00014F87 /* ConnectionCardDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCD586CC2A7AD94B00014F87 /* ConnectionCardDetail.swift */; }; CCD586CF2A7AD9E400014F87 /* MoreButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCD586CE2A7AD9E400014F87 /* MoreButtonView.swift */; }; CCD586D12A7C096C00014F87 /* AddTemplatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCD586D02A7C096B00014F87 /* AddTemplatesView.swift */; }; @@ -624,7 +626,6 @@ 121C5D7829422DF400A64123 /* DomainModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainModel.swift; sourceTree = ""; }; 121C5D7A29424F4E00A64123 /* ReportAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportAPI.swift; sourceTree = ""; }; 121C5D7C2942710600A64123 /* ProjectAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProjectAPI.swift; sourceTree = ""; }; - 121C945D28FF3DCC00570EB4 /* EmptyReportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyReportView.swift; sourceTree = ""; }; 121F87A92964383D00E6BA0D /* SubmittedReportVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubmittedReportVM.swift; sourceTree = ""; }; 1220A72D292EB11B000BC24C /* ReportFileGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportFileGridView.swift; sourceTree = ""; }; 1220F22A2C17165400CFD20C /* ViewClassType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewClassType.swift; sourceTree = ""; }; @@ -927,6 +928,8 @@ 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectDriveConnection.swift; sourceTree = ""; }; 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectSharedDrive.swift; sourceTree = ""; }; 15994A102BFBF0E50017F153 /* SharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedDrive.swift; sourceTree = ""; }; + 15B81F372C1A2806007C0E88 /* GDriveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveView.swift; sourceTree = ""; }; + 15B81F392C1A281C007C0E88 /* GDriveViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveViewModel.swift; sourceTree = ""; }; 15BD9CA82BC740B300C3932B /* UwaziRelationshipWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziRelationshipWidget.swift; sourceTree = ""; }; 15BD9CAA2BC740D700C3932B /* EntitySelectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntitySelectorView.swift; sourceTree = ""; }; 15BD9CAC2BC7410E00C3932B /* SearchBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBarView.swift; sourceTree = ""; }; @@ -935,6 +938,8 @@ 15C51C432BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveAuthViewModel.swift; sourceTree = ""; }; 15C51C452BFE769500DD9AD0 /* GDriveServerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveServerViewModel.swift; sourceTree = ""; }; 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedEntityView.swift; sourceTree = ""; }; + 15E3D5022C1B522500B7FECC /* GDriveListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveListView.swift; sourceTree = ""; }; + 15E3D5042C1B531700B7FECC /* ConnectionEmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionEmptyView.swift; sourceTree = ""; }; 15EE30FD2B5073E20033BBBB /* Pages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pages.swift; sourceTree = ""; }; 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResources.swift; sourceTree = ""; }; 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionTitle.swift; sourceTree = ""; }; @@ -991,7 +996,6 @@ CCC1B4382AC75B8D0075B819 /* UwaziEntityParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziEntityParser.swift; sourceTree = ""; }; CCC1B43A2AC75BED0075B819 /* UwaziEntityParserProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziEntityParserProtocol.swift; sourceTree = ""; }; CCC1B43C2AC75C5D0075B819 /* UwaziConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziConstants.swift; sourceTree = ""; }; - CCC60CD12B0D2C5B00A3DB8C /* UwaziEmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziEmptyView.swift; sourceTree = ""; }; CCD586CC2A7AD94B00014F87 /* ConnectionCardDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionCardDetail.swift; sourceTree = ""; }; CCD586CE2A7AD9E400014F87 /* MoreButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreButtonView.swift; sourceTree = ""; }; CCD586D02A7C096B00014F87 /* AddTemplatesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddTemplatesView.swift; sourceTree = ""; }; @@ -1368,7 +1372,6 @@ isa = PBXGroup; children = ( 1236644E28FFECEF00FA839B /* DraftReportView.swift */, - 121C945D28FF3DCC00570EB4 /* EmptyReportView.swift */, 1220A72D292EB11B000BC24C /* ReportFileGridView.swift */, 122E4D54291ADEB300562EB1 /* AddFilesToDraftView.swift */, ); @@ -2332,6 +2335,32 @@ path = GDrive; sourceTree = ""; }; + 15B81F332C1A2779007C0E88 /* GDrive */ = { + isa = PBXGroup; + children = ( + 15E3D5012C1B51D700B7FECC /* Views */, + 15B81F342C1A27E0007C0E88 /* ViewModel */, + ); + path = GDrive; + sourceTree = ""; + }; + 15B81F342C1A27E0007C0E88 /* ViewModel */ = { + isa = PBXGroup; + children = ( + 15B81F392C1A281C007C0E88 /* GDriveViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; + 15E3D5012C1B51D700B7FECC /* Views */ = { + isa = PBXGroup; + children = ( + 15B81F372C1A2806007C0E88 /* GDriveView.swift */, + 15E3D5022C1B522500B7FECC /* GDriveListView.swift */, + ); + path = Views; + sourceTree = ""; + }; 15F64C9B2B6D78D8008A57AA /* Views */ = { isa = PBXGroup; children = ( @@ -2440,7 +2469,6 @@ CCC60CD02B0D2C3700A3DB8C /* Common */ = { isa = PBXGroup; children = ( - CCC60CD12B0D2C5B00A3DB8C /* UwaziEmptyView.swift */, ); path = Common; sourceTree = ""; @@ -2483,6 +2511,7 @@ isa = PBXGroup; children = ( CCD586C92A7AD85400014F87 /* Card */, + 15E3D5042C1B531700B7FECC /* ConnectionEmptyView.swift */, ); path = Connections; sourceTree = ""; @@ -2512,6 +2541,7 @@ D53B76DA2601C9E50001CD34 /* Scenes */ = { isa = PBXGroup; children = ( + 15B81F332C1A2779007C0E88 /* GDrive */, 15791C182B6AC32B00D67C74 /* Resources */, CC43D9DF2A72F7FB0030192E /* Uwazi */, D5D5696C262747E100C45416 /* MainView.swift */, @@ -3222,6 +3252,7 @@ D57F5E9026152A4800C1DA47 /* Datable.swift in Sources */, CC1313822A5CB0DB0057271C /* DeleteAfterFailOption.swift in Sources */, 15F924482C17929300C436C5 /* ViewModelState.swift in Sources */, + 15E3D5032C1B522500B7FECC /* GDriveListView.swift in Sources */, 1203CDEB2992C1CB00D09073 /* HTTPCodes.swift in Sources */, 15BD9CAB2BC740D700C3932B /* EntitySelectorView.swift in Sources */, 122389B7293635790058593B /* SetExtension.swift in Sources */, @@ -3421,6 +3452,7 @@ 1519BED82B9A5A52006FD290 /* Resource.swift in Sources */, 128BEB202B1E4B3D00420923 /* FeedbackOperation.swift in Sources */, 128EDB92280980DB00747B98 /* SequenceExtension.swift in Sources */, + 15B81F382C1A2806007C0E88 /* GDriveView.swift in Sources */, 1289B98727C5397200315FCE /* ScreenExtension.swift in Sources */, 1227FC8F2922BDBC002FD6FB /* CameraModel.swift in Sources */, E1EEE29629E6796E009FE227 /* ServerSelectionView.swift in Sources */, @@ -3430,12 +3462,12 @@ CC9DEE5F2AE80ED400C8ED29 /* UwaziFileSelector.swift in Sources */, 122DBE012A5C1E0500D6561A /* Toast.swift in Sources */, 1236EE8228E1E1D700973EEA /* DatabaseExtension.swift in Sources */, + 15B81F3A2C1A281C007C0E88 /* GDriveViewModel.swift in Sources */, 121F87AA2964383D00E6BA0D /* SubmittedReportVM.swift in Sources */, 0DD99E052692D24D009327B3 /* SwipeToDeleteView.swift in Sources */, 121C5D7529422C0800A64123 /* ProjectDetailsResult.swift in Sources */, 15EE30FE2B5073E20033BBBB /* Pages.swift in Sources */, CCC1B4272AC75A380075B819 /* CreateEntityView.swift in Sources */, - 121C945E28FF3DCC00570EB4 /* EmptyReportView.swift in Sources */, CCF47F442ABE18D7000ABBBC /* TemplateActionType.swift in Sources */, 1251C3902BB45616002E9898 /* UwaziListView.swift in Sources */, CC0797BE2A8D46CB00AAE63F /* UnlockView.swift in Sources */, @@ -3507,7 +3539,6 @@ E1EEE29E29EEDA4B009FE227 /* UwaziServerAccessSelectionView.swift in Sources */, 1252F7072BDAB2000076DF4B /* EntityAttachment.swift in Sources */, E17736402A83FFA200FE01C0 /* UwaziDictionaryDTO.swift in Sources */, - CCC60CD22B0D2C5B00A3DB8C /* UwaziEmptyView.swift in Sources */, E11968B12A1F409D00BA7B56 /* UwaziLanguageDTO.swift in Sources */, 12607D5327903E9E00E2B8CC /* CustomVideoControlsView.swift in Sources */, 1216F8742901823100F5AEA5 /* UnderlinedTextEditorView.swift in Sources */, @@ -3541,6 +3572,7 @@ CC1313842A5CB3590057271C /* DeleteAfterFailView.swift in Sources */, 12964D922BAB44C8003E1E0A /* UwaziEntityInstanceFile.swift in Sources */, 0DC267A6267AED7C00E55AFA /* VaultFile.swift in Sources */, + 15E3D5052C1B531700B7FECC /* ConnectionEmptyView.swift in Sources */, 1503C87E2C07A080000F2209 /* ServerConnectionHeaderView.swift in Sources */, 12751EAA2A13A22100FAD7C6 /* SettingsModel.swift in Sources */, 15994A0C2BFBC6F40017F153 /* SelectDriveConnection.swift in Sources */, diff --git a/Tella/Components/Connections/ConnectionEmptyView.swift b/Tella/Components/Connections/ConnectionEmptyView.swift new file mode 100644 index 000000000..f8d08a2ab --- /dev/null +++ b/Tella/Components/Connections/ConnectionEmptyView.swift @@ -0,0 +1,27 @@ +// +// ConnectionEmptyView.swift +// Tella +// +// Created by gus valbuena on 6/13/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import SwiftUI + +struct ConnectionEmptyView: View { + var message: String + var type: ServerConnectionType + var body: some View { + VStack(alignment: .center, spacing: 22) { + Image(type.emptyIcon) + Text(message) + .font(.custom(Styles.Fonts.regularFontName, size: 14)) + .foregroundColor(.white) + .multilineTextAlignment(.center) + }.padding(EdgeInsets(top: 0, leading: 31, bottom: 0, trailing: 31)) + } +} + +#Preview { + ConnectionEmptyView(message: "You have no draft reports", type: .tella) +} diff --git a/Tella/Domain/Entity/Report/ServerType.swift b/Tella/Domain/Entity/Report/ServerType.swift index 110cb721e..3618bbbdc 100644 --- a/Tella/Domain/Entity/Report/ServerType.swift +++ b/Tella/Domain/Entity/Report/ServerType.swift @@ -30,4 +30,15 @@ extension ServerConnectionType { "" } } + + var emptyIcon: String { + switch self { + case .gDrive: + return "drive.empty" + case .uwazi: + return "uwazi.empty" + case.tella: + return "reports.report" + } + } } diff --git a/Tella/NewAssets.xcassets/drive.empty.imageset/Contents.json b/Tella/NewAssets.xcassets/drive.empty.imageset/Contents.json new file mode 100644 index 000000000..4698a1d7a --- /dev/null +++ b/Tella/NewAssets.xcassets/drive.empty.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "gdrive.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Tella/NewAssets.xcassets/drive.empty.imageset/gdrive.svg b/Tella/NewAssets.xcassets/drive.empty.imageset/gdrive.svg new file mode 100644 index 000000000..8195fadb6 --- /dev/null +++ b/Tella/NewAssets.xcassets/drive.empty.imageset/gdrive.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift new file mode 100644 index 000000000..a69faef56 --- /dev/null +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -0,0 +1,30 @@ +// +// GDriveViewModel.swift +// Tella +// +// Created by gus valbuena on 6/12/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +class GDriveViewModel: ObservableObject { + var mainAppModel: MainAppModel + var pageViewItems: [PageViewItem] { + [ + PageViewItem(title: LocalizableReport.draftTitle.localized, + page: .draft, + number: 0), + PageViewItem(title: LocalizableReport.outboxTitle.localized, + page: .outbox, + number: 0), + PageViewItem(title: LocalizableReport.submittedTitle.localized, + page: .submitted, + number: 0)] + } + @Published var selectedCell = Pages.draft + + init(mainAppModel: MainAppModel) { + self.mainAppModel = mainAppModel + } +} diff --git a/Tella/Scenes/GDrive/Views/GDriveListView.swift b/Tella/Scenes/GDrive/Views/GDriveListView.swift new file mode 100644 index 000000000..be99dda74 --- /dev/null +++ b/Tella/Scenes/GDrive/Views/GDriveListView.swift @@ -0,0 +1,20 @@ +// +// GDriveListView.swift +// Tella +// +// Created by gus valbuena on 6/13/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import SwiftUI + +struct GDriveListView: View { + var message: String + var body: some View { + ConnectionEmptyView(message: message, type: .gDrive) + } +} + +#Preview { + GDriveListView(message: "You have no drafts") +} diff --git a/Tella/Scenes/GDrive/Views/GDriveView.swift b/Tella/Scenes/GDrive/Views/GDriveView.swift new file mode 100644 index 000000000..d5b76e775 --- /dev/null +++ b/Tella/Scenes/GDrive/Views/GDriveView.swift @@ -0,0 +1,52 @@ +// +// GDriveView.swift +// Tella +// +// Created by gus valbuena on 6/12/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import SwiftUI + +struct GDriveView: View { + @EnvironmentObject var mainAppModel: MainAppModel + @StateObject var gDriveViewModel: GDriveViewModel + + init(mainAppModel: MainAppModel) { + _gDriveViewModel = StateObject(wrappedValue: GDriveViewModel(mainAppModel: mainAppModel)) + } + + var body: some View { + contentView + .navigationBarTitle(LocalizableSettings.settServerGDrive.localized.capitalized, displayMode: .large) + } + + var contentView: some View { + ContainerView { + VStack(alignment: .center) { + PageView(selectedOption: self.$gDriveViewModel.selectedCell, pageViewItems: gDriveViewModel.pageViewItems) + .frame(maxWidth: .infinity, maxHeight: 40, alignment: .leading) + + VStack { + Spacer() + switch self.gDriveViewModel.selectedCell { + case .draft: + GDriveListView(message: "You have no draft reports.") + case .outbox: + GDriveListView(message: "You have no outbox reports.") + case .submitted: + GDriveListView(message: "You have no submitted reports.") + default: + EmptyView() + } + Spacer() + } + } + .padding(EdgeInsets(top: 15, leading: 20, bottom: 16, trailing: 20)) + } + } +} + +#Preview { + GDriveView(mainAppModel: MainAppModel.stub()) +} diff --git a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift index 91b511123..47b8f62fd 100644 --- a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift +++ b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift @@ -55,7 +55,7 @@ struct ConnectionsView: View { case .gDrive: ConnectionsItemView(title: "Drive", image: "home.report", - destination: EmptyView()) + destination: GDriveView(mainAppModel: appModel)) } } diff --git a/Tella/Scenes/Reports/Draft/EmptyReportView.swift b/Tella/Scenes/Reports/Draft/EmptyReportView.swift deleted file mode 100644 index b74f3549e..000000000 --- a/Tella/Scenes/Reports/Draft/EmptyReportView.swift +++ /dev/null @@ -1,30 +0,0 @@ -// Tella -// -// Copyright © 2022 INTERNEWS. All rights reserved. -// - -import SwiftUI - -struct EmptyReportView: View { - - var message : String - - var body: some View { - VStack(alignment: .center, spacing: 22) { - Image("reports.report") - Text(message) - .font(.custom(Styles.Fonts.regularFontName, size: 14)) - .foregroundColor(.white) - .multilineTextAlignment(.center) - }.padding(EdgeInsets(top: 0, leading: 31, bottom: 0, trailing: 31)) - } -} - -struct EmptyReportView_Previews: PreviewProvider { - static var previews: some View { - ZStack { - Styles.Colors.backgroundMain - EmptyReportView(message: LocalizableReport.reportsDraftEmpty.localized) - } - } -} diff --git a/Tella/Scenes/Reports/ReportList/ReportListView.swift b/Tella/Scenes/Reports/ReportList/ReportListView.swift index 936952c2c..f01875c7d 100644 --- a/Tella/Scenes/Reports/ReportList/ReportListView.swift +++ b/Tella/Scenes/Reports/ReportList/ReportListView.swift @@ -24,7 +24,7 @@ struct ReportListView: View { } } } else { - EmptyReportView(message: message) + ConnectionEmptyView(message: message, type: .tella) } } } diff --git a/Tella/Scenes/Uwazi/Views/Common/UwaziEmptyView.swift b/Tella/Scenes/Uwazi/Views/Common/UwaziEmptyView.swift deleted file mode 100644 index d4e16da4d..000000000 --- a/Tella/Scenes/Uwazi/Views/Common/UwaziEmptyView.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// UwaziEmptyView.swift -// Tella -// -// Created by Gustavo on 21/11/2023. -// Copyright © 2023 HORIZONTAL. All rights reserved. -// - -import SwiftUI - -struct UwaziEmptyView: View { - var message : String - - var body: some View { - VStack(alignment: .center, spacing: 22) { - Image("uwazi.empty") - Text(message) - .font(.custom(Styles.Fonts.regularFontName, size: 14)) - .foregroundColor(.white) - .multilineTextAlignment(.center) - }.padding(EdgeInsets(top: 0, leading: 31, bottom: 0, trailing: 31)) - } -} - -struct UwaziEmptyView_Previews: PreviewProvider { - static var previews: some View { - ZStack { - EmptyReportView(message: LocalizableReport.reportsDraftEmpty.localized) - } - } -} diff --git a/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift b/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift index 410b38de0..6ff4a361b 100644 --- a/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift +++ b/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift @@ -22,7 +22,7 @@ struct UwaziListView: View { if cardsViewModel.isEmpty { - UwaziEmptyView(message: emptyMessage) + ConnectionEmptyView(message: emptyMessage, type: .uwazi) } else { diff --git a/Tella/Scenes/Uwazi/Views/Template/AddTemplatesView.swift b/Tella/Scenes/Uwazi/Views/Template/AddTemplatesView.swift index bc21f8862..61a78e56b 100644 --- a/Tella/Scenes/Uwazi/Views/Template/AddTemplatesView.swift +++ b/Tella/Scenes/Uwazi/Views/Template/AddTemplatesView.swift @@ -80,7 +80,7 @@ struct AddTemplatesView: View { } else { Group { Spacer() - UwaziEmptyView(message: LocalizableUwazi.uwaziAddTemplateEmptydExpl.localized) + ConnectionEmptyView(message: LocalizableUwazi.uwaziAddTemplateEmptydExpl.localized, type: .uwazi) Spacer() } } From 382cded0f5b31ce5cba31c89007589a8d3b4e0e5 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 13 Jun 2024 17:33:16 -0300 Subject: [PATCH 059/167] add title and description to gDriveDraftView --- Tella.xcodeproj/project.pbxproj | 16 ++++ .../ViewModel/GDriveDraftViewModel.swift | 24 +++++ .../GDrive/Views/Draft/GDriveDraftView.swift | 88 +++++++++++++++++++ Tella/Scenes/GDrive/Views/GDriveView.swift | 10 +++ 4 files changed, 138 insertions(+) create mode 100644 Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift create mode 100644 Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index fb192efbf..7e61c0a79 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -383,6 +383,8 @@ 15CD89102BF297BE00F724F5 /* SelectedEntityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */; }; 15E3D5032C1B522500B7FECC /* GDriveListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D5022C1B522500B7FECC /* GDriveListView.swift */; }; 15E3D5052C1B531700B7FECC /* ConnectionEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D5042C1B531700B7FECC /* ConnectionEmptyView.swift */; }; + 15E3D50A2C1B71E200B7FECC /* GDriveDraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D5092C1B71E200B7FECC /* GDriveDraftView.swift */; }; + 15E3D50E2C1B87AC00B7FECC /* GDriveDraftViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D50D2C1B87AC00B7FECC /* GDriveDraftViewModel.swift */; }; 15EE30FE2B5073E20033BBBB /* Pages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15EE30FD2B5073E20033BBBB /* Pages.swift */; }; 15F64C9D2B6D7904008A57AA /* DownloadedResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */; }; 15F64CA02B6D794B008A57AA /* SectionTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */; }; @@ -940,6 +942,8 @@ 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedEntityView.swift; sourceTree = ""; }; 15E3D5022C1B522500B7FECC /* GDriveListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveListView.swift; sourceTree = ""; }; 15E3D5042C1B531700B7FECC /* ConnectionEmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionEmptyView.swift; sourceTree = ""; }; + 15E3D5092C1B71E200B7FECC /* GDriveDraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveDraftView.swift; sourceTree = ""; }; + 15E3D50D2C1B87AC00B7FECC /* GDriveDraftViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveDraftViewModel.swift; sourceTree = ""; }; 15EE30FD2B5073E20033BBBB /* Pages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pages.swift; sourceTree = ""; }; 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResources.swift; sourceTree = ""; }; 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionTitle.swift; sourceTree = ""; }; @@ -2348,6 +2352,7 @@ isa = PBXGroup; children = ( 15B81F392C1A281C007C0E88 /* GDriveViewModel.swift */, + 15E3D50D2C1B87AC00B7FECC /* GDriveDraftViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -2355,12 +2360,21 @@ 15E3D5012C1B51D700B7FECC /* Views */ = { isa = PBXGroup; children = ( + 15E3D5062C1B712300B7FECC /* Draft */, 15B81F372C1A2806007C0E88 /* GDriveView.swift */, 15E3D5022C1B522500B7FECC /* GDriveListView.swift */, ); path = Views; sourceTree = ""; }; + 15E3D5062C1B712300B7FECC /* Draft */ = { + isa = PBXGroup; + children = ( + 15E3D5092C1B71E200B7FECC /* GDriveDraftView.swift */, + ); + path = Draft; + sourceTree = ""; + }; 15F64C9B2B6D78D8008A57AA /* Views */ = { isa = PBXGroup; children = ( @@ -3534,6 +3548,7 @@ 1285BF402A3C5D63005D5D23 /* OpenXmlFormats.swift in Sources */, CC4864E92AF94AF300293F62 /* SummaryEntityView.swift in Sources */, 1252F7052BDAB1C30076DF4B /* EntityInstanceToSend.swift in Sources */, + 15E3D50A2C1B71E200B7FECC /* GDriveDraftView.swift in Sources */, 128FD0B427F774FB00B24915 /* RecentFile.swift in Sources */, 12D37A962721A49D00E43BDB /* NavigationContainerView.swift in Sources */, E1EEE29E29EEDA4B009FE227 /* UwaziServerAccessSelectionView.swift in Sources */, @@ -3594,6 +3609,7 @@ 12B370392B19109600DDA9E9 /* LocalizableBackgroundActivities.swift in Sources */, 122C54BE28C6351E003B2DBC /* AdvancedServerSettingsView.swift in Sources */, 15C51C442BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift in Sources */, + 15E3D50E2C1B87AC00B7FECC /* GDriveDraftViewModel.swift in Sources */, 122C54C028C63E8C003B2DBC /* SuccessAdvancedSettingsView.swift in Sources */, 12619B8B27A01F6600999FDA /* BundleExtension.swift in Sources */, 12283FA0295C6FB100580EFE /* DataExtension.swift in Sources */, diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift new file mode 100644 index 000000000..e01eb2f35 --- /dev/null +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -0,0 +1,24 @@ +// +// GDriveDraftViewModel.swift +// Tella +// +// Created by gus valbuena on 6/13/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +class GDriveDraftViewModel: ObservableObject { + var mainAppModel: MainAppModel + + @Published var title: String = "" + @Published var description: String = "" + + @Published var isValidTitle : Bool = false + @Published var isValidDescription : Bool = false + @Published var shouldShowError : Bool = false + + init(mainAppModel: MainAppModel) { + self.mainAppModel = mainAppModel + } +} diff --git a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift new file mode 100644 index 000000000..914e33b1f --- /dev/null +++ b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift @@ -0,0 +1,88 @@ +// +// GDriveDraftView.swift +// Tella +// +// Created by gus valbuena on 6/13/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import SwiftUI + +struct GDriveDraftView: View { + @StateObject var gDriveDraftVM: GDriveDraftViewModel + + init(mainAppModel: MainAppModel) { + _gDriveDraftVM = StateObject(wrappedValue: GDriveDraftViewModel(mainAppModel: mainAppModel)) + } + var body: some View { + ContainerView { + VStack(alignment: .leading) { + headerView + contentView + Spacer() + bottomButtonsView + } + }.navigationBarHidden(true) + } + + var headerView: some View { + NavigationHeaderView(type: .draft) + } + + var contentView: some View { + VStack { + TextfieldView( + fieldContent: $gDriveDraftVM.title, + isValid: $gDriveDraftVM.isValidTitle, + shouldShowError: $gDriveDraftVM.shouldShowError, + fieldType: .text, + placeholder: LocalizableReport.reportsListTitle.localized, + shouldShowTitle: true) + + Spacer() + .frame(height: 34) + + UnderlinedTextEditorView( + placeholder: LocalizableReport.reportsListDescription.localized, + fieldContent: $gDriveDraftVM.description, + isValid: $gDriveDraftVM.isValidDescription, + shouldShowError: $gDriveDraftVM.shouldShowError, + shouldShowTitle: true) + + Spacer() + .frame(height: 24) + }.padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) + } + + var bottomButtonsView: some View { + HStack { + submitLaterButton + submitButton + }.padding(EdgeInsets(top: 0, leading: 24, bottom: 16, trailing: 24)) + } + + var submitLaterButton: some View { + Button { + + } label: { + Image("reports.submit-later") + .opacity(0.4) + }.disabled(true) + } + + var submitButton: some View { + TellaButtonView( + title: LocalizableReport.reportsSubmit.localized, + nextButtonAction: .action, + buttonType: .yellow, + isValid: .constant(true) + ) { + + }.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8)) + } + +} + +#Preview { + GDriveDraftView(mainAppModel: MainAppModel.stub()) +} diff --git a/Tella/Scenes/GDrive/Views/GDriveView.swift b/Tella/Scenes/GDrive/Views/GDriveView.swift index d5b76e775..38b9c5eb2 100644 --- a/Tella/Scenes/GDrive/Views/GDriveView.swift +++ b/Tella/Scenes/GDrive/Views/GDriveView.swift @@ -41,10 +41,20 @@ struct GDriveView: View { } Spacer() } + createGDriveReportButton } .padding(EdgeInsets(top: 15, leading: 20, bottom: 16, trailing: 20)) } } + + var createGDriveReportButton: some View { + TellaButtonView (title: LocalizableReport.reportsCreateNew.localized, + nextButtonAction: .action, + buttonType: .yellow, + isValid: .constant(true)) { + navigateTo(destination: GDriveDraftView(mainAppModel: mainAppModel)) + } .padding(EdgeInsets(top: 30, leading: 0, bottom: 0, trailing: 0)) + } } #Preview { From 9a0fdc2e15b28af1f03c834f8ed380779c7ff024 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 14 Jun 2024 11:43:22 -0300 Subject: [PATCH 060/167] create folder inside the root folder --- .../Repositories/GDriveRepository.swift | 77 ++++++++++++------- .../ViewModel/GDriveDraftViewModel.swift | 31 +++++++- .../GDrive/Views/Draft/GDriveDraftView.swift | 13 +++- Tella/Scenes/GDrive/Views/GDriveView.swift | 3 +- .../ViewModel/GDriveServerViewModel.swift | 2 +- 5 files changed, 93 insertions(+), 33 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index c30adb712..47ddc1244 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -16,7 +16,7 @@ protocol GDriveRepositoryProtocol { func restorePreviousSignIn() async throws func handleUrl(url: URL) func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> - func createDriveFolder(folderName: String) -> AnyPublisher + func createDriveFolder(folderName: String, parentId: String?) -> AnyPublisher func signOut() -> Void } @@ -114,40 +114,65 @@ class GDriveRepository: GDriveRepositoryProtocol { } func createDriveFolder( - folderName: String + folderName: String, + parentId: String? = nil ) -> AnyPublisher { Deferred { - Future { [weak self] promise in - guard let user = self?.googleUser else { - return promise(.failure(APIError.noToken)) - } - - let driveService = GTLRDriveService() - driveService.authorizer = user.fetcherAuthorizer - - let folder = GTLRDrive_File() - folder.name = folderName - folder.mimeType = GoogleAuthConstants.gDriveFolderMimeType - - let query = GTLRDriveQuery_FilesCreate.query(withObject: folder, uploadParameters: nil) - - driveService.executeQuery(query) { (ticket, file, error) in - if let error = error { - print("Error creating folder: \(error.localizedDescription)") + Future { promise in + Task { + do { + try await self.ensureSignedIn() + self.performCreateDriveFolder( + folderName: folderName, + parentId: parentId, + promise: promise) + } catch { promise(.failure(error)) - return - } - - guard let createdFile = file as? GTLRDrive_File else { - return } - - promise(.success(createdFile.identifier ?? "")) } } }.eraseToAnyPublisher() } + private func performCreateDriveFolder( + folderName: String, + parentId: String?, + promise: @escaping (Result) -> Void + ) { + guard let user = googleUser else { + promise(.failure(APIError.noToken)) + return + } + + let driveService = GTLRDriveService() + driveService.authorizer = user.fetcherAuthorizer + + let folder = GTLRDrive_File() + folder.name = folderName + folder.mimeType = GoogleAuthConstants.gDriveFolderMimeType + + if let parentID = parentId { + folder.parents = [parentID] + } + + let query = GTLRDriveQuery_FilesCreate.query(withObject: folder, uploadParameters: nil) + + driveService.executeQuery(query) { (ticket, file, error) in + if let error = error { + print("Error creating folder: \(error.localizedDescription)") + promise(.failure(error)) + return + } + + guard let createdFile = file as? GTLRDrive_File else { + promise(.failure(APIError.unexpectedResponse)) + return + } + + promise(.success(createdFile.identifier ?? "")) + } + } + func signOut() { GIDSignIn.sharedInstance.signOut() } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index e01eb2f35..3b1ef640d 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -7,9 +7,14 @@ // import Foundation +import Combine class GDriveDraftViewModel: ObservableObject { var mainAppModel: MainAppModel + private let gDriveRepository: GDriveRepositoryProtocol + private var cancellables = Set() + + var server: GDriveServer? @Published var title: String = "" @Published var description: String = "" @@ -18,7 +23,31 @@ class GDriveDraftViewModel: ObservableObject { @Published var isValidDescription : Bool = false @Published var shouldShowError : Bool = false - init(mainAppModel: MainAppModel) { + init(mainAppModel: MainAppModel, repository: GDriveRepositoryProtocol) { self.mainAppModel = mainAppModel + self.gDriveRepository = repository + self.getServer() + } + + func submitReport() { + gDriveRepository.createDriveFolder(folderName: title, parentId: server?.rootFolder) + .receive(on: DispatchQueue.main) + .sink( + receiveCompletion: { completion in + switch completion { + case .finished: + break + case .failure(let error): + debugLog(error) + } + }, + receiveValue: { result in + dump(result) + } + ).store(in: &cancellables) + } + + private func getServer() { + self.server = mainAppModel.tellaData?.gDriveServers.value.first } } diff --git a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift index 914e33b1f..c61d11ee4 100644 --- a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift +++ b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift @@ -10,9 +10,14 @@ import SwiftUI struct GDriveDraftView: View { @StateObject var gDriveDraftVM: GDriveDraftViewModel + let gDriveDIContainer: GDriveDIContainer - init(mainAppModel: MainAppModel) { - _gDriveDraftVM = StateObject(wrappedValue: GDriveDraftViewModel(mainAppModel: mainAppModel)) + init(mainAppModel: MainAppModel, gDriveDIContainer: GDriveDIContainer) { + self.gDriveDIContainer = gDriveDIContainer + _gDriveDraftVM = StateObject(wrappedValue: GDriveDraftViewModel( + mainAppModel: mainAppModel, + repository: gDriveDIContainer.gDriveRepository) + ) } var body: some View { ContainerView { @@ -77,12 +82,12 @@ struct GDriveDraftView: View { buttonType: .yellow, isValid: .constant(true) ) { - + gDriveDraftVM.submitReport() }.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8)) } } #Preview { - GDriveDraftView(mainAppModel: MainAppModel.stub()) + GDriveDraftView(mainAppModel: MainAppModel.stub(), gDriveDIContainer: GDriveDIContainer()) } diff --git a/Tella/Scenes/GDrive/Views/GDriveView.swift b/Tella/Scenes/GDrive/Views/GDriveView.swift index 38b9c5eb2..bb32c79c3 100644 --- a/Tella/Scenes/GDrive/Views/GDriveView.swift +++ b/Tella/Scenes/GDrive/Views/GDriveView.swift @@ -11,6 +11,7 @@ import SwiftUI struct GDriveView: View { @EnvironmentObject var mainAppModel: MainAppModel @StateObject var gDriveViewModel: GDriveViewModel + let gDriveDIContainer = GDriveDIContainer() init(mainAppModel: MainAppModel) { _gDriveViewModel = StateObject(wrappedValue: GDriveViewModel(mainAppModel: mainAppModel)) @@ -52,7 +53,7 @@ struct GDriveView: View { nextButtonAction: .action, buttonType: .yellow, isValid: .constant(true)) { - navigateTo(destination: GDriveDraftView(mainAppModel: mainAppModel)) + navigateTo(destination: GDriveDraftView(mainAppModel: mainAppModel, gDriveDIContainer: gDriveDIContainer)) } .padding(EdgeInsets(top: 30, leading: 0, bottom: 0, trailing: 0)) } } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index ad235c579..9e8cf5e0f 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -43,7 +43,7 @@ class GDriveServerViewModel: ObservableObject { func createDriveFolder(folderName: String, completion: @escaping () -> Void) { self.createFolderState = .loading - gDriveRepository.createDriveFolder(folderName: folderName) + gDriveRepository.createDriveFolder(folderName: folderName, parentId: nil) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { From 42bfcd2e94eef5c21028fde8f72aeb9c12e63347 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 14 Jun 2024 11:49:20 -0300 Subject: [PATCH 061/167] fix to supports all drives --- Tella/Data/Networking/Repositories/GDriveRepository.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 47ddc1244..64be7caf4 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -156,7 +156,8 @@ class GDriveRepository: GDriveRepositoryProtocol { } let query = GTLRDriveQuery_FilesCreate.query(withObject: folder, uploadParameters: nil) - + query.supportsAllDrives = true + driveService.executeQuery(query) { (ticket, file, error) in if let error = error { print("Error creating folder: \(error.localizedDescription)") From efd833b2f3f36a322743bf2b663989794374b457 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 18 Jun 2024 11:37:10 -0300 Subject: [PATCH 062/167] create report folder with title and description --- .../Repositories/GDriveRepository.swift | 11 ++++++++-- .../home.drive.imageset/Contents.json | 21 +++++++++++++++++++ .../home.drive.imageset/drive-home.svg | 9 ++++++++ .../ViewModel/GDriveDraftViewModel.swift | 6 +++++- .../Home/Connections/ConnectionsView.swift | 2 +- .../ViewModel/GDriveServerViewModel.swift | 2 +- 6 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 Tella/NewAssets.xcassets/home.drive.imageset/Contents.json create mode 100644 Tella/NewAssets.xcassets/home.drive.imageset/drive-home.svg diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 64be7caf4..38d420ce5 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -16,7 +16,7 @@ protocol GDriveRepositoryProtocol { func restorePreviousSignIn() async throws func handleUrl(url: URL) func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> - func createDriveFolder(folderName: String, parentId: String?) -> AnyPublisher + func createDriveFolder(folderName: String, parentId: String?, description: String?) -> AnyPublisher func signOut() -> Void } @@ -115,7 +115,8 @@ class GDriveRepository: GDriveRepositoryProtocol { func createDriveFolder( folderName: String, - parentId: String? = nil + parentId: String? = nil, + description: String? ) -> AnyPublisher { Deferred { Future { promise in @@ -125,6 +126,7 @@ class GDriveRepository: GDriveRepositoryProtocol { self.performCreateDriveFolder( folderName: folderName, parentId: parentId, + description: description, promise: promise) } catch { promise(.failure(error)) @@ -137,6 +139,7 @@ class GDriveRepository: GDriveRepositoryProtocol { private func performCreateDriveFolder( folderName: String, parentId: String?, + description: String?, promise: @escaping (Result) -> Void ) { guard let user = googleUser else { @@ -154,6 +157,10 @@ class GDriveRepository: GDriveRepositoryProtocol { if let parentID = parentId { folder.parents = [parentID] } + + if let description = description { + folder.descriptionProperty = description + } let query = GTLRDriveQuery_FilesCreate.query(withObject: folder, uploadParameters: nil) query.supportsAllDrives = true diff --git a/Tella/NewAssets.xcassets/home.drive.imageset/Contents.json b/Tella/NewAssets.xcassets/home.drive.imageset/Contents.json new file mode 100644 index 000000000..cb16253a9 --- /dev/null +++ b/Tella/NewAssets.xcassets/home.drive.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "drive-home.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Tella/NewAssets.xcassets/home.drive.imageset/drive-home.svg b/Tella/NewAssets.xcassets/home.drive.imageset/drive-home.svg new file mode 100644 index 000000000..c0de05f50 --- /dev/null +++ b/Tella/NewAssets.xcassets/home.drive.imageset/drive-home.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index 3b1ef640d..fcddac597 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -30,7 +30,11 @@ class GDriveDraftViewModel: ObservableObject { } func submitReport() { - gDriveRepository.createDriveFolder(folderName: title, parentId: server?.rootFolder) + gDriveRepository.createDriveFolder( + folderName: self.title, + parentId: server?.rootFolder, + description: self.description + ) .receive(on: DispatchQueue.main) .sink( receiveCompletion: { completion in diff --git a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift index 47b8f62fd..cb03f512e 100644 --- a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift +++ b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift @@ -54,7 +54,7 @@ struct ConnectionsView: View { destination: UwaziView().environmentObject(UwaziViewModel(mainAppModel: appModel, server: parseUwaziServer(server: server.servers[0])))) case .gDrive: ConnectionsItemView(title: "Drive", - image: "home.report", + image: "home.drive", destination: GDriveView(mainAppModel: appModel)) } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 9e8cf5e0f..99cdb0860 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -43,7 +43,7 @@ class GDriveServerViewModel: ObservableObject { func createDriveFolder(folderName: String, completion: @escaping () -> Void) { self.createFolderState = .loading - gDriveRepository.createDriveFolder(folderName: folderName, parentId: nil) + gDriveRepository.createDriveFolder(folderName: folderName, parentId: nil, description: nil) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { completion in switch completion { From cace5c0237f8bd12c6a069ac99fc033f68894fc4 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 24 Jun 2024 18:10:37 -0300 Subject: [PATCH 063/167] add files to GDrive report --- Tella.xcodeproj/project.pbxproj | 28 ++++++++-- .../Reports/Draft/AddFilesToDraftView.swift | 17 ++---- .../Draft/DraftViewModelProtocol.swift | 20 +++++++ .../Repositories/GDriveRepository.swift | 43 ++++++++++++++ Tella/Data/VaultManager/VaultManager.swift | 2 +- .../ViewModel/GDriveDraftViewModel.swift | 56 ++++++++++++++++++- .../GDrive/Views/Draft/GDriveDraftView.swift | 35 +++++++++++- .../Reports/Draft/DraftReportView.swift | 3 +- .../Reports/View Model/DraftReportVM.swift | 2 +- 9 files changed, 186 insertions(+), 20 deletions(-) rename Tella/{Scenes => Components}/Reports/Draft/AddFilesToDraftView.swift (88%) create mode 100644 Tella/Components/Reports/Draft/DraftViewModelProtocol.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 7e61c0a79..ece89d2fc 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -95,7 +95,6 @@ 122DA89729CB2709003801CD /* SettingsBottomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 122DA89629CB2709003801CD /* SettingsBottomView.swift */; }; 122DBE012A5C1E0500D6561A /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 122DBE002A5C1E0500D6561A /* Toast.swift */; }; 122E0AEE2A33B788009B1E33 /* FileDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 122E0AED2A33B788009B1E33 /* FileDetails.swift */; }; - 122E4D55291ADEB300562EB1 /* AddFilesToDraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 122E4D54291ADEB300562EB1 /* AddFilesToDraftView.swift */; }; 122E6A5329A3812A00BDACAD /* ReportViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 122E6A5229A3812A00BDACAD /* ReportViewModel.swift */; }; 122E6A5529A396C400BDACAD /* ServerFileSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 122E6A5429A396C400BDACAD /* ServerFileSize.swift */; }; 123048D2295F84BD0015CD96 /* ProgressFileItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123048D1295F84BD0015CD96 /* ProgressFileItemViewModel.swift */; }; @@ -385,6 +384,8 @@ 15E3D5052C1B531700B7FECC /* ConnectionEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D5042C1B531700B7FECC /* ConnectionEmptyView.swift */; }; 15E3D50A2C1B71E200B7FECC /* GDriveDraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D5092C1B71E200B7FECC /* GDriveDraftView.swift */; }; 15E3D50E2C1B87AC00B7FECC /* GDriveDraftViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D50D2C1B87AC00B7FECC /* GDriveDraftViewModel.swift */; }; + 15E656AB2C2A147E00BDEC91 /* AddFilesToDraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */; }; + 15E656AD2C2A14F500BDEC91 /* DraftViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E656AC2C2A14F500BDEC91 /* DraftViewModelProtocol.swift */; }; 15EE30FE2B5073E20033BBBB /* Pages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15EE30FD2B5073E20033BBBB /* Pages.swift */; }; 15F64C9D2B6D7904008A57AA /* DownloadedResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */; }; 15F64CA02B6D794B008A57AA /* SectionTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */; }; @@ -655,7 +656,6 @@ 122DA89629CB2709003801CD /* SettingsBottomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsBottomView.swift; sourceTree = ""; }; 122DBE002A5C1E0500D6561A /* Toast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toast.swift; sourceTree = ""; }; 122E0AED2A33B788009B1E33 /* FileDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileDetails.swift; sourceTree = ""; }; - 122E4D54291ADEB300562EB1 /* AddFilesToDraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFilesToDraftView.swift; sourceTree = ""; }; 122E6A5229A3812A00BDACAD /* ReportViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportViewModel.swift; sourceTree = ""; }; 122E6A5429A396C400BDACAD /* ServerFileSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerFileSize.swift; sourceTree = ""; }; 123048D1295F84BD0015CD96 /* ProgressFileItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressFileItemViewModel.swift; sourceTree = ""; }; @@ -944,6 +944,8 @@ 15E3D5042C1B531700B7FECC /* ConnectionEmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionEmptyView.swift; sourceTree = ""; }; 15E3D5092C1B71E200B7FECC /* GDriveDraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveDraftView.swift; sourceTree = ""; }; 15E3D50D2C1B87AC00B7FECC /* GDriveDraftViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveDraftViewModel.swift; sourceTree = ""; }; + 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFilesToDraftView.swift; sourceTree = ""; }; + 15E656AC2C2A14F500BDEC91 /* DraftViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftViewModelProtocol.swift; sourceTree = ""; }; 15EE30FD2B5073E20033BBBB /* Pages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pages.swift; sourceTree = ""; }; 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResources.swift; sourceTree = ""; }; 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionTitle.swift; sourceTree = ""; }; @@ -1377,7 +1379,6 @@ children = ( 1236644E28FFECEF00FA839B /* DraftReportView.swift */, 1220A72D292EB11B000BC24C /* ReportFileGridView.swift */, - 122E4D54291ADEB300562EB1 /* AddFilesToDraftView.swift */, ); path = Draft; sourceTree = ""; @@ -2169,6 +2170,7 @@ 12D7F5F52743F28700EBA3A2 /* Components */ = { isa = PBXGroup; children = ( + 15E656A92C2A142300BDEC91 /* Reports */, CCF47F3F2ABE11F3000ABBBC /* Connections */, 12C07F032B0748BE0030AD6E /* TopSheetView */, 122E4D53291AD99A00562EB1 /* TellaButton */, @@ -2375,6 +2377,23 @@ path = Draft; sourceTree = ""; }; + 15E656A92C2A142300BDEC91 /* Reports */ = { + isa = PBXGroup; + children = ( + 15E656AE2C2A14FA00BDEC91 /* Draft */, + ); + path = Reports; + sourceTree = ""; + }; + 15E656AE2C2A14FA00BDEC91 /* Draft */ = { + isa = PBXGroup; + children = ( + 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */, + 15E656AC2C2A14F500BDEC91 /* DraftViewModelProtocol.swift */, + ); + path = Draft; + sourceTree = ""; + }; 15F64C9B2B6D78D8008A57AA /* Views */ = { isa = PBXGroup; children = ( @@ -3222,6 +3241,7 @@ CC13138A2A5DB68E0057271C /* BottomSheetTitleView.swift in Sources */, E1E7C5842AAB70A500DDB07E /* UwaziDictionaryRow.swift in Sources */, 1240E6B02907E14400692232 /* ReportCardView.swift in Sources */, + 15E656AB2C2A147E00BDEC91 /* AddFilesToDraftView.swift in Sources */, 12A1489A2720B53800A1ADDC /* ConfirmPasswordErrorView.swift in Sources */, 128B15CB27DA30C800E1C1E0 /* OnboardingEndView.swift in Sources */, 125D2328271F8B6600250FBB /* LockConfirmPinView.swift in Sources */, @@ -3438,6 +3458,7 @@ 125BC1DE2B21F08200A117D0 /* VaultFileDetailsToMerge.swift in Sources */, 12E0882027AD29E400CEB198 /* SaveAudioConfirmationView.swift in Sources */, 125A895F2A965C33009347C3 /* VaultFileType.swift in Sources */, + 15E656AD2C2A14F500BDEC91 /* DraftViewModelProtocol.swift in Sources */, 123AE5A129CFAD7F00814CC7 /* OutboxReportVM.swift in Sources */, 12FDEDD5272AFE99005C17AC /* LocalizableHome.swift in Sources */, D572EAC7263A383900CE191A /* RecentFileCell.swift in Sources */, @@ -3679,7 +3700,6 @@ E1E7C5712AAB2BAB00DDB07E /* UwaziLanguageRow.swift in Sources */, 1237A71C278F5B2E00D7BC0F /* DateExtension.swift in Sources */, 15587A012C010F1E0071389E /* GDriveServer.swift in Sources */, - 122E4D55291ADEB300562EB1 /* AddFilesToDraftView.swift in Sources */, 125299DD2AD02E6F00191CAB /* ImportVaultFileResult.swift in Sources */, 122DA89129CB1F45003801CD /* FileAPI.swift in Sources */, 127C155C27DA69FF009EC15B /* TransitionViewData.swift in Sources */, diff --git a/Tella/Scenes/Reports/Draft/AddFilesToDraftView.swift b/Tella/Components/Reports/Draft/AddFilesToDraftView.swift similarity index 88% rename from Tella/Scenes/Reports/Draft/AddFilesToDraftView.swift rename to Tella/Components/Reports/Draft/AddFilesToDraftView.swift index 603fa35e3..3b38cd0b0 100644 --- a/Tella/Scenes/Reports/Draft/AddFilesToDraftView.swift +++ b/Tella/Components/Reports/Draft/AddFilesToDraftView.swift @@ -1,15 +1,18 @@ +// +// AddFilesToDraftView.swift // Tella // -// Copyright © 2022 INTERNEWS. All rights reserved. +// Created by gus valbuena on 6/24/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. // import SwiftUI -struct AddFilesToDraftView: View { +struct AddFilesToDraftView: View { @EnvironmentObject var appModel: MainAppModel @EnvironmentObject var sheetManager: SheetManager - @EnvironmentObject var draftReportVM: DraftReportVM + @EnvironmentObject var draftReportVM: VM private let gridLayout: [GridItem] = [GridItem(spacing: 12), GridItem(spacing: 12), @@ -102,11 +105,3 @@ struct AddFilesToDraftView: View { } } } - -struct AddFilesToDraftView_Previews: PreviewProvider { - static var previews: some View { - AddFileView() - .environmentObject(MainAppModel.stub()) - .environmentObject(FileListViewModel.stub()) - } -} diff --git a/Tella/Components/Reports/Draft/DraftViewModelProtocol.swift b/Tella/Components/Reports/Draft/DraftViewModelProtocol.swift new file mode 100644 index 000000000..ed563743e --- /dev/null +++ b/Tella/Components/Reports/Draft/DraftViewModelProtocol.swift @@ -0,0 +1,20 @@ +// +// DraftViewModelProtocol.swift +// Tella +// +// Created by gus valbuena on 6/24/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +protocol DraftViewModelProtocol: ObservableObject { + var files: Set { get set } + var resultFile: [VaultFileDB]? { get set } + var addFileToDraftItems: [ListActionSheetItem] { get } + var showingImagePicker: Bool { get set } + var showingImportDocumentPicker: Bool { get set } + var showingFileList: Bool { get set } + var showingRecordView: Bool { get set } + var showingCamera: Bool { get set } +} diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 38d420ce5..a75f90585 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -17,6 +17,7 @@ protocol GDriveRepositoryProtocol { func handleUrl(url: URL) func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> func createDriveFolder(folderName: String, parentId: String?, description: String?) -> AnyPublisher + func uploadFile(fileURL: URL, mimeType: String, folderId: String) -> AnyPublisher func signOut() -> Void } @@ -181,6 +182,48 @@ class GDriveRepository: GDriveRepositoryProtocol { } } + func uploadFile( + fileURL: URL, + mimeType: String, + folderId: String + ) -> AnyPublisher { + Deferred { + Future { [weak self] promise in + guard let user = self?.googleUser else { + return promise(.failure(APIError.noToken)) + } + + let driveService = GTLRDriveService() + driveService.authorizer = user.fetcherAuthorizer + + let file = GTLRDrive_File() + file.name = fileURL.lastPathComponent + file.mimeType = mimeType + file.parents = [folderId] + + let uploadParameters = GTLRUploadParameters(fileURL: fileURL, mimeType: mimeType) + uploadParameters.shouldUploadWithSingleRequest = false + + let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: uploadParameters) + + driveService.executeQuery(query) { (ticket, file, error) in + if let error = error { + print("Error uploading file: \(error.localizedDescription)") + promise(.failure(error)) + return + } + + guard let uploadedFile = file as? GTLRDrive_File else { + promise(.failure(APIError.unexpectedResponse)) + return + } + + promise(.success(uploadedFile.identifier ?? "")) + } + } + }.eraseToAnyPublisher() + } + func signOut() { GIDSignIn.sharedInstance.signOut() } diff --git a/Tella/Data/VaultManager/VaultManager.swift b/Tella/Data/VaultManager/VaultManager.swift index 1ecc25888..0c91ef1ef 100644 --- a/Tella/Data/VaultManager/VaultManager.swift +++ b/Tella/Data/VaultManager/VaultManager.swift @@ -80,7 +80,7 @@ class VaultManager : VaultManagerInterface, ObservableObject{ func loadVaultFileToURL(file vaultFile: VaultFileDB) -> URL? { - let tmpFileURL = createTempFileURL(pathExtension: vaultFile.fileExtension) + let tmpFileURL = createTempFileURL(fileName: vaultFile.name ,pathExtension: vaultFile.fileExtension) guard (fileManager.createEmptyFile(atPath: tmpFileURL)) else { debugLog("File not created.") diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index fcddac597..09a914ccf 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -9,7 +9,7 @@ import Foundation import Combine -class GDriveDraftViewModel: ObservableObject { +class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { var mainAppModel: MainAppModel private let gDriveRepository: GDriveRepositoryProtocol private var cancellables = Set() @@ -23,10 +23,40 @@ class GDriveDraftViewModel: ObservableObject { @Published var isValidDescription : Bool = false @Published var shouldShowError : Bool = false + // files + @Published var files : Set = [] + @Published var resultFile : [VaultFileDB]? + + @Published var showingImagePicker : Bool = false + @Published var showingImportDocumentPicker : Bool = false + @Published var showingFileList : Bool = false + @Published var showingRecordView : Bool = false + @Published var showingCamera : Bool = false + + private var subscribers = Set() + + var addFileToDraftItems : [ListActionSheetItem] { return [ + + ListActionSheetItem(imageName: "report.camera-filled", + content: LocalizableReport.cameraFilled.localized, + type: ManageFileType.camera), + ListActionSheetItem(imageName: "report.mic-filled", + content: LocalizableReport.micFilled.localized, + type: ManageFileType.recorder), + ListActionSheetItem(imageName: "report.gallery", + content: LocalizableReport.galleryFilled.localized, + type: ManageFileType.tellaFile), + ListActionSheetItem(imageName: "report.phone", + content: LocalizableReport.phoneFilled.localized, + type: ManageFileType.fromDevice) + ]} + init(mainAppModel: MainAppModel, repository: GDriveRepositoryProtocol) { self.mainAppModel = mainAppModel self.gDriveRepository = repository self.getServer() + + self.bindVaultFileTaken() } func submitReport() { @@ -36,6 +66,9 @@ class GDriveDraftViewModel: ObservableObject { description: self.description ) .receive(on: DispatchQueue.main) + .flatMap { folderId in + self.uploadFiles(to: folderId) + } .sink( receiveCompletion: { completion in switch completion { @@ -54,4 +87,25 @@ class GDriveDraftViewModel: ObservableObject { private func getServer() { self.server = mainAppModel.tellaData?.gDriveServers.value.first } + + private func uploadFiles(to folderId: String) -> AnyPublisher { + let uploadPublishers = files.map { file -> AnyPublisher in + guard let fileUrl = self.mainAppModel.vaultManager.loadVaultFileToURL(file: file) else { + return Fail(error: APIError.unexpectedResponse).eraseToAnyPublisher() + } + return gDriveRepository.uploadFile(fileURL: fileUrl, mimeType: file.mimeType ?? "", folderId: folderId) + } + + return Publishers.MergeMany(uploadPublishers) + .collect() + .map { _ in () } + .eraseToAnyPublisher() + } + + private func bindVaultFileTaken() { + $resultFile.sink(receiveValue: { value in + guard let value else { return } + self.files.insert(value) + }).store(in: &subscribers) + } } diff --git a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift index c61d11ee4..d9078c9a2 100644 --- a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift +++ b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift @@ -10,6 +10,7 @@ import SwiftUI struct GDriveDraftView: View { @StateObject var gDriveDraftVM: GDriveDraftViewModel + @EnvironmentObject var mainAppModel : MainAppModel let gDriveDIContainer: GDriveDIContainer init(mainAppModel: MainAppModel, gDriveDIContainer: GDriveDIContainer) { @@ -19,6 +20,7 @@ struct GDriveDraftView: View { repository: gDriveDIContainer.gDriveRepository) ) } + var body: some View { ContainerView { VStack(alignment: .leading) { @@ -26,8 +28,12 @@ struct GDriveDraftView: View { contentView Spacer() bottomButtonsView + photoVideoPickerView } - }.navigationBarHidden(true) + } + .navigationBarHidden(true) + .overlay(recordView) + .overlay(cameraView) } var headerView: some View { @@ -56,9 +62,36 @@ struct GDriveDraftView: View { Spacer() .frame(height: 24) + + AddFilesToDraftView() + .environmentObject(gDriveDraftVM) }.padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) } + var cameraView : some View { + gDriveDraftVM.showingCamera ? + CameraView(sourceView: SourceView.addReportFile, + showingCameraView: $gDriveDraftVM.showingCamera, + resultFile: $gDriveDraftVM.resultFile, + mainAppModel: mainAppModel) : nil + } + + var recordView : some View { + gDriveDraftVM.showingRecordView ? + RecordView(appModel: mainAppModel, + sourceView: .addReportFile, + showingRecoredrView: $gDriveDraftVM.showingRecordView, + resultFile: $gDriveDraftVM.resultFile) : nil + } + + var photoVideoPickerView : some View { + PhotoVideoPickerView(showingImagePicker: $gDriveDraftVM.showingImagePicker, + showingImportDocumentPicker: $gDriveDraftVM.showingImportDocumentPicker, + appModel: mainAppModel, + resultFile: $gDriveDraftVM.resultFile, + shouldReloadVaultFiles: .constant(false)) + } + var bottomButtonsView: some View { HStack { submitLaterButton diff --git a/Tella/Scenes/Reports/Draft/DraftReportView.swift b/Tella/Scenes/Reports/Draft/DraftReportView.swift index 849de9c24..e3be4a636 100644 --- a/Tella/Scenes/Reports/Draft/DraftReportView.swift +++ b/Tella/Scenes/Reports/Draft/DraftReportView.swift @@ -157,7 +157,8 @@ struct DraftReportView: View { Spacer() .frame(height: 24) - AddFilesToDraftView() + AddFilesToDraftView() + .environmentObject(reportViewModel) Spacer() diff --git a/Tella/Scenes/Reports/View Model/DraftReportVM.swift b/Tella/Scenes/Reports/View Model/DraftReportVM.swift index 48eac403b..eccd8602b 100644 --- a/Tella/Scenes/Reports/View Model/DraftReportVM.swift +++ b/Tella/Scenes/Reports/View Model/DraftReportVM.swift @@ -7,7 +7,7 @@ import Foundation import Combine import SwiftUI -class DraftReportVM: ObservableObject { +class DraftReportVM: ObservableObject, DraftViewModelProtocol { var mainAppModel : MainAppModel From 6aa05c3ea0c047470a92ba9a550c9ec2b5bc94ce Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 27 Jun 2024 17:41:36 -0300 Subject: [PATCH 064/167] create unify draft view --- Tella.xcodeproj/project.pbxproj | 4 + Tella/Components/NavigationHeaderView.swift | 3 + .../Components/Reports/Draft/DraftView.swift | 210 ++++++++++++ .../Draft/DraftViewModelProtocol.swift | 26 +- .../ViewModel/GDriveDraftViewModel.swift | 17 + .../GDrive/Views/Draft/GDriveDraftView.swift | 98 +----- .../Reports/Draft/DraftReportView.swift | 299 +----------------- .../Reports/View Model/DraftReportVM.swift | 7 + 8 files changed, 270 insertions(+), 394 deletions(-) create mode 100644 Tella/Components/Reports/Draft/DraftView.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index ece89d2fc..115f758ac 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -350,6 +350,7 @@ 150913422B841C3F001E782A /* ResourceActionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 150913412B841C3F001E782A /* ResourceActionType.swift */; }; 151308172BF3DBD9000C51D7 /* UwaziRelationshipList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 151308162BF3DBD9000C51D7 /* UwaziRelationshipList.swift */; }; 1519BED82B9A5A52006FD290 /* Resource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1519BED72B9A5A52006FD290 /* Resource.swift */; }; + 152D38512C2C61DF00323CE7 /* DraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152D38502C2C61DF00323CE7 /* DraftView.swift */; }; 1535A5F12BAA06490009EA42 /* DownloadedResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1535A5F02BAA06490009EA42 /* DownloadedResource.swift */; }; 153AACF72BE40BEA0075D5B2 /* UwaziEntityFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 153AACF62BE40BEA0075D5B2 /* UwaziEntityFetcher.swift */; }; 153AACFB2BE41C010075D5B2 /* UwaziEntityRelationshipItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 153AACFA2BE41C010075D5B2 /* UwaziEntityRelationshipItem.swift */; }; @@ -908,6 +909,7 @@ 150913412B841C3F001E782A /* ResourceActionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceActionType.swift; sourceTree = ""; }; 151308162BF3DBD9000C51D7 /* UwaziRelationshipList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziRelationshipList.swift; sourceTree = ""; }; 1519BED72B9A5A52006FD290 /* Resource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Resource.swift; sourceTree = ""; }; + 152D38502C2C61DF00323CE7 /* DraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftView.swift; sourceTree = ""; }; 1535A5F02BAA06490009EA42 /* DownloadedResource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResource.swift; sourceTree = ""; }; 153AACF62BE40BEA0075D5B2 /* UwaziEntityFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziEntityFetcher.swift; sourceTree = ""; }; 153AACFA2BE41C010075D5B2 /* UwaziEntityRelationshipItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziEntityRelationshipItem.swift; sourceTree = ""; }; @@ -2388,6 +2390,7 @@ 15E656AE2C2A14FA00BDEC91 /* Draft */ = { isa = PBXGroup; children = ( + 152D38502C2C61DF00323CE7 /* DraftView.swift */, 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */, 15E656AC2C2A14F500BDEC91 /* DraftViewModelProtocol.swift */, ); @@ -3516,6 +3519,7 @@ 12CCDC5428D8E05300C3BE4E /* Project.swift in Sources */, 126818C12A38B0C2004606BD /* FileInformation.swift in Sources */, 156986252B88FCB600534720 /* ResourcePDFView.swift in Sources */, + 152D38512C2C61DF00323CE7 /* DraftView.swift in Sources */, 129354772949F04700735ED0 /* EmptyResult.swift in Sources */, 1290743B274CEB9B00F38A81 /* FileGridItem.swift in Sources */, 1289B45A28B64221005DA687 /* UIDeviceOrientationExtension.swift in Sources */, diff --git a/Tella/Components/NavigationHeaderView.swift b/Tella/Components/NavigationHeaderView.swift index 221d488a7..08a6aeba2 100644 --- a/Tella/Components/NavigationHeaderView.swift +++ b/Tella/Components/NavigationHeaderView.swift @@ -41,6 +41,7 @@ struct NavigationHeaderView: View { var rightButtonAction: (() -> Void)? var title: String = "" var type: NavigationType + var isRightButtonEnabled: Bool = true var body: some View { HStack(spacing: 0) { @@ -79,7 +80,9 @@ struct NavigationHeaderView: View { Image(type.imageName) .resizable() .frame(width: 24, height: 24) + .opacity(isRightButtonEnabled ? 1 : 0.4) } + .disabled(!isRightButtonEnabled) } } diff --git a/Tella/Components/Reports/Draft/DraftView.swift b/Tella/Components/Reports/Draft/DraftView.swift new file mode 100644 index 000000000..8994d0bf0 --- /dev/null +++ b/Tella/Components/Reports/Draft/DraftView.swift @@ -0,0 +1,210 @@ +// +// DraftView.swift +// Tella +// +// Created by gus valbuena on 6/26/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import SwiftUI + +struct DraftView: View { + @StateObject var viewModel: VM + + @State private var menuFrame : CGRect = CGRectZero + @State private var shouldShowMenu : Bool = false + + @EnvironmentObject var mainAppModel: MainAppModel + @EnvironmentObject var sheetManager: SheetManager + @EnvironmentObject var reportsViewModel : ReportsViewModel + @Environment(\.presentationMode) var presentationMode: Binding + + var body: some View { + // TO DO: INCLUDE SERVER SELECTION VIEW!!!!!! + ContainerView { + contentView + .environmentObject(viewModel) + photoVideoPickerView + } + .navigationBarHidden(true) + .onReceive(viewModel.successSavingReportPublisher) { successSavingReport in + if successSavingReport { + handleSuccessSavingReport() + } + } + .onReceive(viewModel.failureSavingReportPublisher) { failureSavingReport in + if failureSavingReport { + handleReportFailure() + } + } + .overlay(recordView) + .overlay(cameraView) + } + + var draftHeaderView: some View { + NavigationHeaderView( + backButtonAction: { + UIApplication.shared.endEditing() + showSaveReportConfirmationView() + }, + rightButtonAction: { viewModel.saveDraftReport() }, + type: .draft, + isRightButtonEnabled: viewModel.reportIsDraft + ) + } + + + var contentView: some View { + VStack(alignment: .leading) { + draftHeaderView + draftContentView + bottomDraftView + } + } + + var draftContentView: some View { + GeometryReader { geometry in + ScrollView { + VStack(alignment: .leading) { + TextfieldView(fieldContent: $viewModel.title, + isValid: $viewModel.isValidTitle, + shouldShowError: $viewModel.shouldShowError, + fieldType: .text, + placeholder: LocalizableReport.reportsListTitle.localized, + shouldShowTitle: true) + + Spacer() + .frame(height: 34) + + UnderlinedTextEditorView(placeholder: LocalizableReport.reportsListDescription.localized, + fieldContent: $viewModel.description, + isValid: $viewModel.isValidDescription, + shouldShowError: $viewModel.shouldShowError, + shouldShowTitle: true) + + Spacer() + .frame(height: 24) + + AddFilesToDraftView() + .environmentObject(viewModel) + + Spacer() + }.padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) + } + } + } + + var bottomDraftView: some View { + HStack { + submitLaterButton + submitButton + }.padding(EdgeInsets(top: 0, leading: 24, bottom: 16, trailing: 24)) + } + + var submitLaterButton: some View { + Button { + viewModel.saveFinalizedReport() + } label: { + Image("reports.submit-later") + .opacity(viewModel.reportIsValid ? 1 : 0.4) + }.disabled(!viewModel.reportIsValid) + } + + var submitButton: some View { + TellaButtonView( + title: LocalizableReport.reportsSubmit.localized, + nextButtonAction: .action, + buttonType: .yellow, + isValid: .constant(true) + ) { + viewModel.submitReport() + }.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8)) + } + + var outboxDetailsView: some View { + OutboxDetailsView(appModel: mainAppModel, + reportsViewModel: reportsViewModel, + reportId: viewModel.reportId, + shouldStartUpload: true) + .environmentObject(reportsViewModel) + } + + var photoVideoPickerView: some View { + PhotoVideoPickerView(showingImagePicker: $viewModel.showingImagePicker, + showingImportDocumentPicker: $viewModel.showingImportDocumentPicker, + appModel: mainAppModel, + resultFile: $viewModel.resultFile, + shouldReloadVaultFiles: .constant(false)) + } + + var recordView: some View { + viewModel.showingRecordView ? + RecordView(appModel: mainAppModel, + sourceView: .addReportFile, + showingRecoredrView: $viewModel.showingRecordView, + resultFile: $viewModel.resultFile) : nil + } + + var cameraView: some View { + viewModel.showingCamera ? + CameraView(sourceView: SourceView.addReportFile, + showingCameraView: $viewModel.showingCamera, + resultFile: $viewModel.resultFile, + mainAppModel: mainAppModel) : nil + } + + private func showSaveReportConfirmationView() { + sheetManager.showBottomSheet(modalHeight: 200) { + ConfirmBottomSheet(titleText: LocalizableReport.exitTitle.localized, + msgText: LocalizableReport.exitMessage.localized, + cancelText: LocalizableReport.exitCancel.localized.uppercased(), + actionText:LocalizableReport.exitSave.localized.uppercased(), didConfirmAction: { + viewModel.saveDraftReport() + }, didCancelAction: { + dismissViews() + }) + } + } + + private func handleSuccessSavingReport() { + switch viewModel.status { + case .draft: + handleSuccessSavingDraft() + case .finalized: + handleSuccessSavingOutbox() + case .submissionScheduled: + handleSuccessSavingReportForSubmission() + default: + break + } + } + + private func handleReportFailure() { + dismissViews() + Toast.displayToast(message: LocalizableCommon.commonError.localized) + } + + private func handleSuccessSavingDraft() { + reportsViewModel.selectedCell = .draft + dismissViews() + Toast.displayToast(message: LocalizableReport.draftSavedToast.localized) + } + + private func handleSuccessSavingOutbox() { + reportsViewModel.selectedCell = .outbox + dismissViews() + Toast.displayToast(message: LocalizableReport.outboxSavedToast.localized) + } + + private func handleSuccessSavingReportForSubmission() { + DispatchQueue.main.async { + navigateTo(destination: outboxDetailsView) + } + } + + private func dismissViews() { + sheetManager.hide() + self.presentationMode.wrappedValue.dismiss() + } + +} diff --git a/Tella/Components/Reports/Draft/DraftViewModelProtocol.swift b/Tella/Components/Reports/Draft/DraftViewModelProtocol.swift index ed563743e..6613aafd9 100644 --- a/Tella/Components/Reports/Draft/DraftViewModelProtocol.swift +++ b/Tella/Components/Reports/Draft/DraftViewModelProtocol.swift @@ -7,8 +7,27 @@ // import Foundation - +import Combine protocol DraftViewModelProtocol: ObservableObject { + //report + var reportId: Int? { get set } + var title: String { get set } + var description: String { get set } + var status: ReportStatus? { get set } + + + //validation + var isValidTitle: Bool { get set } + var isValidDescription: Bool { get set } + var shouldShowError: Bool { get set } + var reportIsValid: Bool { get set } + var reportIsDraft: Bool { get set} + var successSavingReport: Bool { get set } + var failureSavingReport: Bool { get set } + var successSavingReportPublisher: Published.Publisher { get } + var failureSavingReportPublisher: Published.Publisher { get } + + //files var files: Set { get set } var resultFile: [VaultFileDB]? { get set } var addFileToDraftItems: [ListActionSheetItem] { get } @@ -17,4 +36,9 @@ protocol DraftViewModelProtocol: ObservableObject { var showingFileList: Bool { get set } var showingRecordView: Bool { get set } var showingCamera: Bool { get set } + + //actions + func submitReport() + func saveDraftReport() + func saveFinalizedReport() } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index 09a914ccf..30852f12a 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -16,12 +16,21 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { var server: GDriveServer? + @Published var reportId : Int? @Published var title: String = "" @Published var description: String = "" @Published var isValidTitle : Bool = false @Published var isValidDescription : Bool = false @Published var shouldShowError : Bool = false + @Published var reportIsValid : Bool = false + @Published var reportIsDraft : Bool = false + + @Published var status: ReportStatus? + @Published var successSavingReport: Bool = false + @Published var failureSavingReport: Bool = false + var successSavingReportPublisher: Published.Publisher { $successSavingReport } + var failureSavingReportPublisher: Published.Publisher { $failureSavingReport } // files @Published var files : Set = [] @@ -84,6 +93,14 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { ).store(in: &cancellables) } + func saveDraftReport() { + self.status = .draft + } + + func saveFinalizedReport() { + self.status = .finalized + } + private func getServer() { self.server = mainAppModel.tellaData?.gDriveServers.value.first } diff --git a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift index d9078c9a2..11fba4435 100644 --- a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift +++ b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift @@ -22,103 +22,9 @@ struct GDriveDraftView: View { } var body: some View { - ContainerView { - VStack(alignment: .leading) { - headerView - contentView - Spacer() - bottomButtonsView - photoVideoPickerView - } - } - .navigationBarHidden(true) - .overlay(recordView) - .overlay(cameraView) + DraftView(viewModel: gDriveDraftVM) + .environmentObject(mainAppModel) } - - var headerView: some View { - NavigationHeaderView(type: .draft) - } - - var contentView: some View { - VStack { - TextfieldView( - fieldContent: $gDriveDraftVM.title, - isValid: $gDriveDraftVM.isValidTitle, - shouldShowError: $gDriveDraftVM.shouldShowError, - fieldType: .text, - placeholder: LocalizableReport.reportsListTitle.localized, - shouldShowTitle: true) - - Spacer() - .frame(height: 34) - - UnderlinedTextEditorView( - placeholder: LocalizableReport.reportsListDescription.localized, - fieldContent: $gDriveDraftVM.description, - isValid: $gDriveDraftVM.isValidDescription, - shouldShowError: $gDriveDraftVM.shouldShowError, - shouldShowTitle: true) - - Spacer() - .frame(height: 24) - - AddFilesToDraftView() - .environmentObject(gDriveDraftVM) - }.padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) - } - - var cameraView : some View { - gDriveDraftVM.showingCamera ? - CameraView(sourceView: SourceView.addReportFile, - showingCameraView: $gDriveDraftVM.showingCamera, - resultFile: $gDriveDraftVM.resultFile, - mainAppModel: mainAppModel) : nil - } - - var recordView : some View { - gDriveDraftVM.showingRecordView ? - RecordView(appModel: mainAppModel, - sourceView: .addReportFile, - showingRecoredrView: $gDriveDraftVM.showingRecordView, - resultFile: $gDriveDraftVM.resultFile) : nil - } - - var photoVideoPickerView : some View { - PhotoVideoPickerView(showingImagePicker: $gDriveDraftVM.showingImagePicker, - showingImportDocumentPicker: $gDriveDraftVM.showingImportDocumentPicker, - appModel: mainAppModel, - resultFile: $gDriveDraftVM.resultFile, - shouldReloadVaultFiles: .constant(false)) - } - - var bottomButtonsView: some View { - HStack { - submitLaterButton - submitButton - }.padding(EdgeInsets(top: 0, leading: 24, bottom: 16, trailing: 24)) - } - - var submitLaterButton: some View { - Button { - - } label: { - Image("reports.submit-later") - .opacity(0.4) - }.disabled(true) - } - - var submitButton: some View { - TellaButtonView( - title: LocalizableReport.reportsSubmit.localized, - nextButtonAction: .action, - buttonType: .yellow, - isValid: .constant(true) - ) { - gDriveDraftVM.submitReport() - }.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8)) - } - } #Preview { diff --git a/Tella/Scenes/Reports/Draft/DraftReportView.swift b/Tella/Scenes/Reports/Draft/DraftReportView.swift index e3be4a636..80bf25461 100644 --- a/Tella/Scenes/Reports/Draft/DraftReportView.swift +++ b/Tella/Scenes/Reports/Draft/DraftReportView.swift @@ -22,303 +22,8 @@ struct DraftReportView: View { } var body: some View { - - ContainerView { - - contentView - .environmentObject(reportViewModel) - - serverListMenuView - - photoVideoPickerView - - } - .navigationBarHidden(true) - .onTapGesture { - shouldShowMenu = false - } - .onReceive(reportViewModel.$successSavingReport) { successSavingReport in - if successSavingReport { - handleSuccessSavingReport() - } - } - .onReceive(reportViewModel.$failureSavingReport) { failureSavingReport in - if failureSavingReport { - handleReportFailure() - } - } - - .overlay(recordView) - - .overlay(cameraView) - } - - var contentView: some View { - - VStack(alignment: .leading) { - - draftReportHeaderView - - draftContentView - - bottomDraftView - } - } - - var draftReportHeaderView: some View { - - HStack(spacing: 0) { - - Button { - UIApplication.shared.endEditing() - showSaveReportConfirmationView() - } label: { - Image("close") - .padding(EdgeInsets(top: 10, leading: 12, bottom: 5, trailing: 16)) - } - - Text(LocalizableReport.reportsText.localized) - .font(.custom(Styles.Fonts.semiBoldFontName, size: 18)) - .foregroundColor(Color.white) - - Spacer() - - - Button { - reportViewModel.saveDraftReport() - } label: { - Image("reports.save") - .padding(EdgeInsets(top: 16, leading: 16, bottom: 16, trailing: 16)) - .opacity(reportViewModel.reportIsDraft ? 1 : 0.4) - }.disabled(!reportViewModel.reportIsDraft) - - - }.frame(height: 56) - } - - var draftContentView: some View { - - GeometryReader { geometry in - ScrollView { - - VStack(alignment: .leading) { - - if reportViewModel.hasMoreServer { - - Text(LocalizableReport.reportsSendTo.localized) - .font(.custom(Styles.Fonts.regularFontName, size: 14)) - .foregroundColor(Color.white) - - Button { - DispatchQueue.main.async { - self.menuFrame = geometry.frame(in: CoordinateSpace.global) - shouldShowMenu = true - } - - } label: { - HStack { - Text(reportViewModel.serverName) - .font(.custom(Styles.Fonts.regularFontName, size: 14)) - .foregroundColor(Color.white.opacity(0.87)) - .padding() - .frame(maxWidth: .infinity, alignment: .leading) - - Image("reports.arrow-down") - .padding() - - } - }.background(Color.white.opacity(0.08)) - .cornerRadius(12) - - Spacer() - .frame(height: 55) - - } else { - Spacer() - .frame(height: 5) - } - - TextfieldView(fieldContent: $reportViewModel.title, - isValid: $reportViewModel.isValidTitle, - shouldShowError: $reportViewModel.shouldShowError, - fieldType: .text, - placeholder : LocalizableReport.reportsListTitle.localized, - shouldShowTitle: true) - - Spacer() - .frame(height: 34) - - UnderlinedTextEditorView(placeholder: LocalizableReport.reportsListDescription.localized, - fieldContent: $reportViewModel.description, - isValid: $reportViewModel.isValidDescription, - shouldShowError: $reportViewModel.shouldShowError, - shouldShowTitle: true) - - Spacer() - .frame(height: 24) - - AddFilesToDraftView() - .environmentObject(reportViewModel) - - Spacer() - - }.padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) - } - } - } - - @ViewBuilder - var serverListMenuView: some View { - - if shouldShowMenu { - VStack { - Spacer() - .frame(height: menuFrame.origin.y + 10) - ScrollView { - - VStack(spacing: 0) { - - ForEach(reportViewModel.serverArray, id: \.self) { server in - - Button { - shouldShowMenu = false - reportViewModel.server = server - - } label: { - Text(server.name ?? "") - .font(.custom(Styles.Fonts.regularFontName, size: 14)) - .frame(maxWidth: .infinity, alignment: .leading) - .foregroundColor(.white) - .padding(.all, 14) - }.background(server.id == reportViewModel.server?.id ? Color.white.opacity(0.16) : Color.white.opacity(0.08)) - } - }.frame(minHeight: 40, maxHeight: 250) - .background(Styles.Colors.backgroundMain) - .cornerRadius(12) - } - Spacer() - } - .padding() - - .background(Color.clear) - } - } - - var bottomDraftView: some View { - - HStack { - - // Submit later button - Button { - reportViewModel.saveFinalizedReport() - } label: { - Image("reports.submit-later") - .opacity(reportViewModel.reportIsValid ? 1 : 0.4) - }.disabled(!reportViewModel.reportIsValid) - - // Submit button - TellaButtonView (title: reportViewModel.isNewDraft ? LocalizableReport.reportsSubmit.localized : LocalizableReport.reportsSend.localized, - nextButtonAction: .action, - buttonType: .yellow, - isValid: $reportViewModel.reportIsValid) { - submitReport() - } .padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8)) - } - .padding(EdgeInsets(top: 0, leading: 24, bottom: 16, trailing: 24)) - } - - var outboxDetailsView: some View { - OutboxDetailsView(appModel: mainAppModel, - reportsViewModel: reportsViewModel, - reportId: reportViewModel.reportId, - shouldStartUpload: true) - .environmentObject(reportsViewModel) - } - - var cameraView : some View { - reportViewModel.showingCamera ? - CameraView(sourceView: SourceView.addReportFile, - showingCameraView: $reportViewModel.showingCamera, - resultFile: $reportViewModel.resultFile, - mainAppModel: mainAppModel) : nil - } - - var recordView : some View { - reportViewModel.showingRecordView ? - RecordView(appModel: mainAppModel, - sourceView: .addReportFile, - showingRecoredrView: $reportViewModel.showingRecordView, - resultFile: $reportViewModel.resultFile) : nil - } - - var photoVideoPickerView : some View { - PhotoVideoPickerView(showingImagePicker: $reportViewModel.showingImagePicker, - showingImportDocumentPicker: $reportViewModel.showingImportDocumentPicker, - appModel: mainAppModel, - resultFile: $reportViewModel.resultFile, - shouldReloadVaultFiles: .constant(false)) - } - - - private func submitReport() { - - reportViewModel.saveReportForSubmission() - - } - - private func showSaveReportConfirmationView() { - sheetManager.showBottomSheet(modalHeight: 200) { - ConfirmBottomSheet(titleText: LocalizableReport.exitTitle.localized, - msgText: LocalizableReport.exitMessage.localized, - cancelText: LocalizableReport.exitCancel.localized.uppercased(), - actionText:LocalizableReport.exitSave.localized.uppercased(), didConfirmAction: { - reportViewModel.saveDraftReport() - }, didCancelAction: { - dismissViews() - }) - } - } - - private func handleSuccessSavingReport() { - switch reportViewModel.status { - case .draft: - handleSuccessSavingDraft() - case .finalized: - handleSuccessSavingOutbox() - case .submissionScheduled: - handleSuccessSavingReportForSubmission() - default: - break - } - } - - private func handleReportFailure() { - dismissViews() - Toast.displayToast(message: LocalizableCommon.commonError.localized) - } - - private func handleSuccessSavingDraft() { - reportsViewModel.selectedCell = .draft - dismissViews() - Toast.displayToast(message: LocalizableReport.draftSavedToast.localized) - } - - private func handleSuccessSavingOutbox() { - reportsViewModel.selectedCell = .outbox - dismissViews() - Toast.displayToast(message: LocalizableReport.outboxSavedToast.localized) - } - - private func handleSuccessSavingReportForSubmission() { - DispatchQueue.main.async { - navigateTo(destination: outboxDetailsView) - } - } - - - private func dismissViews() { - sheetManager.hide() - self.presentationMode.wrappedValue.dismiss() + DraftView(viewModel: reportViewModel) + .environmentObject(reportsViewModel) } } diff --git a/Tella/Scenes/Reports/View Model/DraftReportVM.swift b/Tella/Scenes/Reports/View Model/DraftReportVM.swift index eccd8602b..ad61aed56 100644 --- a/Tella/Scenes/Reports/View Model/DraftReportVM.swift +++ b/Tella/Scenes/Reports/View Model/DraftReportVM.swift @@ -38,6 +38,10 @@ class DraftReportVM: ObservableObject, DraftViewModelProtocol { @Published var successSavingReport : Bool = false @Published var failureSavingReport : Bool = false + var successSavingReportPublisher: Published.Publisher { $successSavingReport } + var failureSavingReportPublisher: Published.Publisher { $failureSavingReport } + + var serverArray : [TellaServer] = [] var cancellable : Cancellable? = nil @@ -164,6 +168,9 @@ class DraftReportVM: ObservableObject, DraftViewModelProtocol { self.saveReport() } + func submitReport() { + saveReportForSubmission() + } func saveReport() { let report = Report(id: reportId, From 24c38e63aadba2a8b71c949a00d29aab22b2c3d7 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 27 Jun 2024 20:28:52 -0300 Subject: [PATCH 065/167] create a general baseReportsViewModel to handle list item navigation --- Tella.xcodeproj/project.pbxproj | 4 ++++ .../Reports/BaseReportsViewModel.swift | 23 +++++++++++++++++++ .../Components/Reports/Draft/DraftView.swift | 2 +- .../GDrive/ViewModel/GDriveViewModel.swift | 8 +++---- .../Reports/Draft/DraftReportView.swift | 4 ++-- .../Reports/Outbox/OutboxDetailsView.swift | 4 ++-- .../Reports/ReportList/ReportCardView.swift | 6 ++--- Tella/Scenes/Reports/ReportsView.swift | 2 +- .../Submitted/SubmittedDetailsView.swift | 2 +- .../Reports/View Model/OutboxReportVM.swift | 4 ++-- .../Reports/View Model/ReportsViewModel.swift | 9 +++----- 11 files changed, 45 insertions(+), 23 deletions(-) create mode 100644 Tella/Components/Reports/BaseReportsViewModel.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 115f758ac..efa810011 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -388,6 +388,7 @@ 15E656AB2C2A147E00BDEC91 /* AddFilesToDraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */; }; 15E656AD2C2A14F500BDEC91 /* DraftViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E656AC2C2A14F500BDEC91 /* DraftViewModelProtocol.swift */; }; 15EE30FE2B5073E20033BBBB /* Pages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15EE30FD2B5073E20033BBBB /* Pages.swift */; }; + 15F1AA542C2E07F50002A7D8 /* BaseReportsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F1AA532C2E07F50002A7D8 /* BaseReportsViewModel.swift */; }; 15F64C9D2B6D7904008A57AA /* DownloadedResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */; }; 15F64CA02B6D794B008A57AA /* SectionTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */; }; 15F64CA22B6D797C008A57AA /* SectionMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64CA12B6D797C008A57AA /* SectionMessage.swift */; }; @@ -949,6 +950,7 @@ 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFilesToDraftView.swift; sourceTree = ""; }; 15E656AC2C2A14F500BDEC91 /* DraftViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftViewModelProtocol.swift; sourceTree = ""; }; 15EE30FD2B5073E20033BBBB /* Pages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pages.swift; sourceTree = ""; }; + 15F1AA532C2E07F50002A7D8 /* BaseReportsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseReportsViewModel.swift; sourceTree = ""; }; 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResources.swift; sourceTree = ""; }; 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionTitle.swift; sourceTree = ""; }; 15F64CA12B6D797C008A57AA /* SectionMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionMessage.swift; sourceTree = ""; }; @@ -2383,6 +2385,7 @@ isa = PBXGroup; children = ( 15E656AE2C2A14FA00BDEC91 /* Draft */, + 15F1AA532C2E07F50002A7D8 /* BaseReportsViewModel.swift */, ); path = Reports; sourceTree = ""; @@ -3589,6 +3592,7 @@ 1289B45828B63187005DA687 /* RotationViewModifier.swift in Sources */, 126818BF2A376A0E004606BD /* OOXMLContentTypeParser.swift in Sources */, 125D2326271F896400250FBB /* CustomPinView.swift in Sources */, + 15F1AA542C2E07F50002A7D8 /* BaseReportsViewModel.swift in Sources */, E1EEE29A29EECF25009FE227 /* UwaziAddServerURLView.swift in Sources */, CC13138C2A5DB79B0057271C /* BottomButtonsView.swift in Sources */, 150913422B841C3F001E782A /* ResourceActionType.swift in Sources */, diff --git a/Tella/Components/Reports/BaseReportsViewModel.swift b/Tella/Components/Reports/BaseReportsViewModel.swift new file mode 100644 index 000000000..bd299578e --- /dev/null +++ b/Tella/Components/Reports/BaseReportsViewModel.swift @@ -0,0 +1,23 @@ +// +// BaseReportsViewModel.swift +// Tella +// +// Created by gus valbuena on 6/27/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +protocol ReportsViewModelProtocol: ObservableObject { + var selectedCell: Pages { get set } +} + +class BaseReportsViewModel: ObservableObject, ReportsViewModelProtocol { + var mainAppModel: MainAppModel + + @Published var selectedCell: Pages = .draft + + init(mainAppModel: MainAppModel) { + self.mainAppModel = mainAppModel + } +} diff --git a/Tella/Components/Reports/Draft/DraftView.swift b/Tella/Components/Reports/Draft/DraftView.swift index 8994d0bf0..ad9eb7888 100644 --- a/Tella/Components/Reports/Draft/DraftView.swift +++ b/Tella/Components/Reports/Draft/DraftView.swift @@ -16,7 +16,7 @@ struct DraftView: View { @EnvironmentObject var mainAppModel: MainAppModel @EnvironmentObject var sheetManager: SheetManager - @EnvironmentObject var reportsViewModel : ReportsViewModel + @EnvironmentObject var reportsViewModel : BaseReportsViewModel @Environment(\.presentationMode) var presentationMode: Binding var body: some View { diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift index a69faef56..3647b83b8 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -8,8 +8,7 @@ import Foundation -class GDriveViewModel: ObservableObject { - var mainAppModel: MainAppModel +class GDriveViewModel: BaseReportsViewModel { var pageViewItems: [PageViewItem] { [ PageViewItem(title: LocalizableReport.draftTitle.localized, @@ -22,9 +21,8 @@ class GDriveViewModel: ObservableObject { page: .submitted, number: 0)] } - @Published var selectedCell = Pages.draft - init(mainAppModel: MainAppModel) { - self.mainAppModel = mainAppModel + override init(mainAppModel: MainAppModel) { + super.init(mainAppModel: mainAppModel) } } diff --git a/Tella/Scenes/Reports/Draft/DraftReportView.swift b/Tella/Scenes/Reports/Draft/DraftReportView.swift index 80bf25461..0a98b653e 100644 --- a/Tella/Scenes/Reports/Draft/DraftReportView.swift +++ b/Tella/Scenes/Reports/Draft/DraftReportView.swift @@ -14,7 +14,7 @@ struct DraftReportView: View { @EnvironmentObject var mainAppModel : MainAppModel @EnvironmentObject var sheetManager : SheetManager - @EnvironmentObject var reportsViewModel : ReportsViewModel + @EnvironmentObject var reportsViewModel : BaseReportsViewModel @Environment(\.presentationMode) var presentationMode: Binding init(mainAppModel: MainAppModel, reportId:Int? = nil) { @@ -31,7 +31,7 @@ struct DraftReportView_Previews: PreviewProvider { static var previews: some View { DraftReportView(mainAppModel: MainAppModel.stub()) - .environmentObject(ReportsViewModel(mainAppModel: MainAppModel.stub())) + .environmentObject(BaseReportsViewModel(mainAppModel: MainAppModel.stub())) } } diff --git a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift index 7ef7e11d6..e34c8e999 100644 --- a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift +++ b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift @@ -7,12 +7,12 @@ import SwiftUI struct OutboxDetailsView: View { @StateObject var outboxReportVM : OutboxReportVM - @EnvironmentObject var reportsViewModel : ReportsViewModel + @EnvironmentObject var reportsViewModel : BaseReportsViewModel @EnvironmentObject var mainAppModel : MainAppModel @Environment(\.presentationMode) var presentationMode: Binding @EnvironmentObject private var sheetManager: SheetManager - init(appModel: MainAppModel,reportsViewModel: ReportsViewModel, reportId : Int?, shouldStartUpload: Bool = false) { + init(appModel: MainAppModel,reportsViewModel: BaseReportsViewModel, reportId : Int?, shouldStartUpload: Bool = false) { _outboxReportVM = StateObject(wrappedValue: OutboxReportVM(mainAppModel: appModel, reportsViewModel: reportsViewModel, reportId:reportId, shouldStartUpload: shouldStartUpload)) } diff --git a/Tella/Scenes/Reports/ReportList/ReportCardView.swift b/Tella/Scenes/Reports/ReportList/ReportCardView.swift index d61bcc904..3100b7dcd 100644 --- a/Tella/Scenes/Reports/ReportList/ReportCardView.swift +++ b/Tella/Scenes/Reports/ReportList/ReportCardView.swift @@ -86,20 +86,20 @@ struct ReportCardView : View { private var editDraftReportView: some View { DraftReportView(mainAppModel: mainAppModel, reportId: reportsViewModel.selectedReport?.id) - .environmentObject(reportsViewModel) + .environmentObject(reportsViewModel as BaseReportsViewModel) } private var submittedDetailsView: some View { SubmittedDetailsView(appModel: mainAppModel, reportId: reportsViewModel.selectedReport?.id) - .environmentObject(reportsViewModel) + .environmentObject(reportsViewModel as BaseReportsViewModel) } private var outboxDetailsView: some View { OutboxDetailsView(appModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: reportsViewModel.selectedReport?.id) - .environmentObject(reportsViewModel) + .environmentObject(reportsViewModel as BaseReportsViewModel) } private var deleteMessage : String { diff --git a/Tella/Scenes/Reports/ReportsView.swift b/Tella/Scenes/Reports/ReportsView.swift index 39c10b844..11d282959 100644 --- a/Tella/Scenes/Reports/ReportsView.swift +++ b/Tella/Scenes/Reports/ReportsView.swift @@ -83,7 +83,7 @@ struct ReportsView: View { } private var newDraftReportView: some View { - DraftReportView(mainAppModel: mainAppModel).environmentObject(reportsViewModel) + DraftReportView(mainAppModel: mainAppModel).environmentObject(reportsViewModel as BaseReportsViewModel) } private func showDeleteReportConfirmationView() { diff --git a/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift b/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift index 3b627a5d6..e58b2eaf0 100644 --- a/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift +++ b/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift @@ -8,7 +8,7 @@ import SwiftUI struct SubmittedDetailsView: View { @StateObject var submittedReportVM : SubmittedReportVM - @EnvironmentObject var reportsViewModel : ReportsViewModel + @EnvironmentObject var reportsViewModel : BaseReportsViewModel @EnvironmentObject var mainAppModel : MainAppModel @Environment(\.presentationMode) var presentationMode: Binding @EnvironmentObject private var sheetManager: SheetManager diff --git a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift index b76584b23..0b64e3475 100644 --- a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift +++ b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift @@ -8,7 +8,7 @@ import Combine class OutboxReportVM: ObservableObject { var mainAppModel : MainAppModel - var reportsViewModel : ReportsViewModel + var reportsViewModel : BaseReportsViewModel @Published var reportViewModel : ReportViewModel = ReportViewModel() @Published var progressFileItems : [ProgressFileItemViewModel] = [] @@ -53,7 +53,7 @@ class OutboxReportVM: ObservableObject { } - init(mainAppModel: MainAppModel, reportsViewModel : ReportsViewModel, reportId : Int?, shouldStartUpload: Bool = false) { + init(mainAppModel: MainAppModel, reportsViewModel : BaseReportsViewModel, reportId : Int?, shouldStartUpload: Bool = false) { self.mainAppModel = mainAppModel self.reportsViewModel = reportsViewModel diff --git a/Tella/Scenes/Reports/View Model/ReportsViewModel.swift b/Tella/Scenes/Reports/View Model/ReportsViewModel.swift index 25a32e42a..6812a0703 100644 --- a/Tella/Scenes/Reports/View Model/ReportsViewModel.swift +++ b/Tella/Scenes/Reports/View Model/ReportsViewModel.swift @@ -7,15 +7,12 @@ import Foundation import Combine import SwiftUI -class ReportsViewModel: ObservableObject { - - var mainAppModel : MainAppModel +class ReportsViewModel: BaseReportsViewModel { @Published var draftReports : [Report] = [] @Published var outboxedReports : [Report] = [] @Published var submittedReports : [Report] = [] @Published var selectedReport : Report? - @Published var selectedCell = Pages.draft var pageViewItems : [PageViewItem] { [PageViewItem(title: LocalizableReport.draftTitle.localized, page: .draft, number: draftReports.count), @@ -35,9 +32,9 @@ class ReportsViewModel: ObservableObject { private var subscribers = Set() private var delayTime = 0.1 - init(mainAppModel : MainAppModel) { + override init(mainAppModel : MainAppModel) { - self.mainAppModel = mainAppModel + super.init(mainAppModel: mainAppModel) self.getReports() } From b5333d6790f05dcece3edd567091bb574f093212 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 28 Jun 2024 15:09:30 -0300 Subject: [PATCH 066/167] add isValid constraint to GDriveDraftVM --- .../Components/Reports/Draft/DraftView.swift | 2 +- .../ViewModel/GDriveDraftViewModel.swift | 22 +++++++++++++++++++ .../GDrive/Views/Draft/GDriveDraftView.swift | 2 ++ Tella/Scenes/GDrive/Views/GDriveView.swift | 7 +++++- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Tella/Components/Reports/Draft/DraftView.swift b/Tella/Components/Reports/Draft/DraftView.swift index ad9eb7888..913cdfdec 100644 --- a/Tella/Components/Reports/Draft/DraftView.swift +++ b/Tella/Components/Reports/Draft/DraftView.swift @@ -115,7 +115,7 @@ struct DraftView: View { title: LocalizableReport.reportsSubmit.localized, nextButtonAction: .action, buttonType: .yellow, - isValid: .constant(true) + isValid: $viewModel.reportIsValid ) { viewModel.submitReport() }.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8)) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index 30852f12a..f1a3aebbe 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -63,12 +63,31 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { init(mainAppModel: MainAppModel, repository: GDriveRepositoryProtocol) { self.mainAppModel = mainAppModel self.gDriveRepository = repository + self.validateReport() self.getServer() self.bindVaultFileTaken() } + private func validateReport() { + Publishers.CombineLatest($title, $description) + .map { !$0.0.isEmpty && !$0.1.isEmpty } + .assign(to: \.reportIsValid, on: self) + .store(in: &subscribers) + + $title + .map { !$0.isEmpty } + .assign(to: \.reportIsDraft, on: self) + .store(in: &subscribers) + } + func submitReport() { + self.status = .submissionScheduled + performSubmission() + } + + + func performSubmission() { gDriveRepository.createDriveFolder( folderName: self.title, parentId: server?.rootFolder, @@ -82,6 +101,7 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { receiveCompletion: { completion in switch completion { case .finished: + self.saveFinalizedReport() break case .failure(let error): debugLog(error) @@ -95,10 +115,12 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { func saveDraftReport() { self.status = .draft + self.successSavingReport = true } func saveFinalizedReport() { self.status = .finalized + self.successSavingReport = true } private func getServer() { diff --git a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift index 11fba4435..c27a2d0e0 100644 --- a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift +++ b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift @@ -11,6 +11,7 @@ import SwiftUI struct GDriveDraftView: View { @StateObject var gDriveDraftVM: GDriveDraftViewModel @EnvironmentObject var mainAppModel : MainAppModel + @EnvironmentObject var reportsViewModel : BaseReportsViewModel let gDriveDIContainer: GDriveDIContainer init(mainAppModel: MainAppModel, gDriveDIContainer: GDriveDIContainer) { @@ -24,6 +25,7 @@ struct GDriveDraftView: View { var body: some View { DraftView(viewModel: gDriveDraftVM) .environmentObject(mainAppModel) + .environmentObject(reportsViewModel) } } diff --git a/Tella/Scenes/GDrive/Views/GDriveView.swift b/Tella/Scenes/GDrive/Views/GDriveView.swift index bb32c79c3..d0ba9f042 100644 --- a/Tella/Scenes/GDrive/Views/GDriveView.swift +++ b/Tella/Scenes/GDrive/Views/GDriveView.swift @@ -53,9 +53,14 @@ struct GDriveView: View { nextButtonAction: .action, buttonType: .yellow, isValid: .constant(true)) { - navigateTo(destination: GDriveDraftView(mainAppModel: mainAppModel, gDriveDIContainer: gDriveDIContainer)) + navigateTo(destination: newGDriveDraftView) } .padding(EdgeInsets(top: 30, leading: 0, bottom: 0, trailing: 0)) } + + private var newGDriveDraftView: some View { + GDriveDraftView(mainAppModel: mainAppModel, gDriveDIContainer: gDriveDIContainer) + .environmentObject(gDriveViewModel as BaseReportsViewModel) + } } #Preview { From ca4068f5e3184cdf337db040da7bc82eaa7b4b7c Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 1 Jul 2024 11:11:24 -0300 Subject: [PATCH 067/167] save gDrive draft report --- Tella.xcodeproj/project.pbxproj | 4 + .../Database/Common/DatabaseConstants.swift | 2 + Tella/Data/Database/GDriveData.swift | 21 +++++ Tella/Data/Database/GDriveDatabase.swift | 83 +++++++++++++++++++ Tella/Data/Database/TellaDataBase.swift | 2 + Tella/Domain/Entity/Report/Report.swift | 64 ++++++++++++-- .../ViewModel/GDriveDraftViewModel.swift | 27 +++++- .../GDrive/ViewModel/GDriveViewModel.swift | 3 + 8 files changed, 196 insertions(+), 10 deletions(-) create mode 100644 Tella/Data/Database/GDriveData.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index efa810011..bd4b859d3 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -371,6 +371,7 @@ 15994A0C2BFBC6F40017F153 /* SelectDriveConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */; }; 15994A0E2BFBE15F0017F153 /* SelectSharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */; }; 15994A112BFBF0E50017F153 /* SharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A102BFBF0E50017F153 /* SharedDrive.swift */; }; + 15A505B32C2F623C0028C7CB /* GDriveData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15A505B22C2F623C0028C7CB /* GDriveData.swift */; }; 15B81F382C1A2806007C0E88 /* GDriveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B81F372C1A2806007C0E88 /* GDriveView.swift */; }; 15B81F3A2C1A281C007C0E88 /* GDriveViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B81F392C1A281C007C0E88 /* GDriveViewModel.swift */; }; 15BD9CA92BC740B300C3932B /* UwaziRelationshipWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CA82BC740B300C3932B /* UwaziRelationshipWidget.swift */; }; @@ -933,6 +934,7 @@ 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectDriveConnection.swift; sourceTree = ""; }; 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectSharedDrive.swift; sourceTree = ""; }; 15994A102BFBF0E50017F153 /* SharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedDrive.swift; sourceTree = ""; }; + 15A505B22C2F623C0028C7CB /* GDriveData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveData.swift; sourceTree = ""; }; 15B81F372C1A2806007C0E88 /* GDriveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveView.swift; sourceTree = ""; }; 15B81F392C1A281C007C0E88 /* GDriveViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveViewModel.swift; sourceTree = ""; }; 15BD9CA82BC740B300C3932B /* UwaziRelationshipWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziRelationshipWidget.swift; sourceTree = ""; }; @@ -1244,6 +1246,7 @@ E1CF5A2A2AB3533100365036 /* ServerDatabase.swift */, 155369222B7E9CC100129F2F /* ResourceDatabase.swift */, 155879FE2C0106FA0071389E /* GDriveDatabase.swift */, + 15A505B22C2F623C0028C7CB /* GDriveData.swift */, ); path = Database; sourceTree = ""; @@ -3581,6 +3584,7 @@ 12D37A962721A49D00E43BDB /* NavigationContainerView.swift in Sources */, E1EEE29E29EEDA4B009FE227 /* UwaziServerAccessSelectionView.swift in Sources */, 1252F7072BDAB2000076DF4B /* EntityAttachment.swift in Sources */, + 15A505B32C2F623C0028C7CB /* GDriveData.swift in Sources */, E17736402A83FFA200FE01C0 /* UwaziDictionaryDTO.swift in Sources */, E11968B12A1F409D00BA7B56 /* UwaziLanguageDTO.swift in Sources */, 12607D5327903E9E00E2B8CC /* CustomVideoControlsView.swift in Sources */, diff --git a/Tella/Data/Database/Common/DatabaseConstants.swift b/Tella/Data/Database/Common/DatabaseConstants.swift index 152e7f7c5..28aa56db4 100644 --- a/Tella/Data/Database/Common/DatabaseConstants.swift +++ b/Tella/Data/Database/Common/DatabaseConstants.swift @@ -35,6 +35,8 @@ struct D { static let tFeedback = "t_feedback" static let tResource = "t_resource" static let tGDriveServer = "t_drive_server" + static let tGDriveReport = "t_drive_report_table" + static let tGDriveInstanceVaultFile = "t_drive_instance_vault_file" /* DATABASE COLUMNS */ // MARK: - DATABASE COLUMNS diff --git a/Tella/Data/Database/GDriveData.swift b/Tella/Data/Database/GDriveData.swift new file mode 100644 index 000000000..acbda310e --- /dev/null +++ b/Tella/Data/Database/GDriveData.swift @@ -0,0 +1,21 @@ +// +// GDriveData.swift +// Tella +// +// Created by gus valbuena on 6/28/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +extension TellaData { + func addGDriveReport(report : GDriveReport) -> Result { + let id = database.addGDriveReport(report: report) + + return id + } + + func getDraftGDriveReport() { + self.database.getDraftGDriveReports() + } +} diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index b03403db1..2a1a9be4d 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -8,6 +8,7 @@ import Foundation +// GDrive Server extension TellaDataBase { func createGDriveServerTable() { let columns = [ @@ -54,3 +55,85 @@ extension TellaDataBase { } } + +// GDrive Reports +extension TellaDataBase { + func createGDriveReportTable() { + let columns = [ + cddl(D.cId, D.integer, primaryKey: true, autoIncrement: true), + cddl(D.cTitle, D.text), + cddl(D.cDescription, D.text), + cddl(D.cCreatedDate, D.float), + cddl(D.cUpdatedDate, D.float), + cddl(D.cStatus, D.integer), + cddl(D.cServerId, D.integer, tableName: D.tGDriveServer, referenceKey: D.cServerId)// update ref key after merge with server subclass PR + ] + + statementBuilder.createTable(tableName: D.tGDriveReport, columns: columns) + } + func createGDriveReportFilesTable() { + + let columns = [ + cddl(D.cId, D.integer, primaryKey: true, autoIncrement: true), + cddl(D.cVaultFileInstanceId, D.text), + cddl(D.cStatus, D.integer), + cddl(D.cBytesSent, D.integer), + cddl(D.cCreatedDate, D.float), + cddl(D.cUpdatedDate, D.float), + cddl(D.cReportInstanceId, D.integer, tableName: D.tGDriveReport, referenceKey: D.cId) + + ] + statementBuilder.createTable(tableName: D.tGDriveInstanceVaultFile, columns: columns) + + } + + func addGDriveReport(report: GDriveReport) -> Result { + do { + let currentUpload = ((report.currentUpload == false) || (report.currentUpload == nil)) ? 0 : 1 + + let reportValuesToAdd = [KeyValue(key: D.cTitle, value: report.title), + KeyValue(key: D.cDescription, value: report.description), + KeyValue(key: D.cCreatedDate, value: Date().getDateDouble()), + KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()), + KeyValue(key: D.cStatus, value: report.status?.rawValue), + KeyValue(key: D.cServerId, value: report.server?.id)] + + let reportId = try statementBuilder.insertInto(tableName: D.tGDriveReport, keyValue: reportValuesToAdd) + + try report.reportFiles?.forEach( { reportFile in + let reportFileValuesToAdd = [KeyValue(key: D.cReportInstanceId, value: reportId), + KeyValue(key: D.cVaultFileInstanceId, value: reportFile.fileId), + KeyValue(key: D.cStatus, value: reportFile.status?.rawValue), + KeyValue(key: D.cBytesSent, value: 0), + KeyValue(key: D.cCreatedDate, value: Date().getDateDouble()), + KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble())] + + try statementBuilder.insertInto(tableName: D.tGDriveInstanceVaultFile, keyValue: reportFileValuesToAdd) + }) + + return .success(reportId) + + } catch let error { + debugLog(error) + return .failure(error) + } + } + + func getDraftGDriveReports() { + do { + let joinCondition = [JoinCondition(tableName: D.tGDriveServer, + firstItem: JoinItem(tableName: D.tGDriveReport, columnName: D.cServerId), + secondItem: JoinItem(tableName: D.tGDriveServer, columnName: D.cServerId))] + + let reportsCondition = [KeyValue(key: D.cStatus, value: ReportStatus.draft.rawValue)] + + let gDriveReportsDict = try statementBuilder.getSelectQuery(tableName: D.tGDriveReport, + equalCondition: reportsCondition, + joinCondition: joinCondition + ) + + } catch let error { + debugLog(error) + } + } +} diff --git a/Tella/Data/Database/TellaDataBase.swift b/Tella/Data/Database/TellaDataBase.swift index 0ba6b8053..08b78a0ae 100644 --- a/Tella/Data/Database/TellaDataBase.swift +++ b/Tella/Data/Database/TellaDataBase.swift @@ -41,6 +41,8 @@ class TellaDataBase : DataBase { addRelationshipColumnToUwaziTemplate() case 5: createGDriveServerTable() + createGDriveReportTable() + createGDriveReportFilesTable() default : break } diff --git a/Tella/Domain/Entity/Report/Report.swift b/Tella/Domain/Entity/Report/Report.swift index 8a3547c2c..8284999e8 100644 --- a/Tella/Domain/Entity/Report/Report.swift +++ b/Tella/Domain/Entity/Report/Report.swift @@ -5,7 +5,7 @@ import Foundation -class Report : Hashable { +class BaseReport : Hashable { var id : Int? var title : String? @@ -13,9 +13,7 @@ class Report : Hashable { var createdDate : Date? var updatedDate : Date? var status : ReportStatus? - var server : TellaServer? var reportFiles : [ReportFile]? - var apiID : String? var currentUpload: Bool? init(id: Int? = nil, @@ -24,9 +22,7 @@ class Report : Hashable { createdDate: Date? = nil, updatedDate: Date? = nil, status: ReportStatus? = nil, - server: TellaServer? = nil, vaultFiles: [ReportFile]? = nil, - apiID: String? = nil, currentUpload: Bool? = nil ) { self.id = id self.title = title @@ -34,14 +30,12 @@ class Report : Hashable { self.createdDate = createdDate self.updatedDate = updatedDate self.status = status - self.server = server self.reportFiles = vaultFiles - self.apiID = apiID self.currentUpload = currentUpload } - static func == (lhs: Report, rhs: Report) -> Bool { + static func == (lhs: BaseReport, rhs: BaseReport) -> Bool { lhs.id == rhs.id } @@ -50,7 +44,7 @@ class Report : Hashable { } } -extension Report { +extension BaseReport { var getReportDate: String { guard let status = self.status else { return "" @@ -74,3 +68,55 @@ extension Report { } } + +// Report + +class Report: BaseReport { + var server: TellaServer? + var apiID: String? + + init(id: Int? = nil, + title: String? = nil, + description: String? = nil, + createdDate: Date? = nil, + updatedDate: Date? = nil, + status: ReportStatus? = nil, + server: TellaServer? = nil, + vaultFiles: [ReportFile]? = nil, + apiID: String? = nil, + currentUpload: Bool? = nil) { + self.server = server + self.apiID = apiID + super.init(id: id, title: title, description: description, createdDate: createdDate, updatedDate: updatedDate, status: status, vaultFiles: vaultFiles, currentUpload: currentUpload) + } +} + +// GDriveReport +class GDriveReport: BaseReport { + var server: GDriveServer? + + enum CodingKeys: String, CodingKey { + case id = "c_id" + case title = "c_title" + case description = "c_description" + case createdDate = "c_created_date" + case updatedDate = "c_updated_date" + case status = "c_status" + case server = "c_server_id" + } + + // Keep the existing initializer + init(id: Int? = nil, + title: String? = nil, + description: String? = nil, + createdDate: Date? = nil, + updatedDate: Date? = nil, + status: ReportStatus? = nil, + server: GDriveServer? = nil, + vaultFiles: [ReportFile]? = nil, + currentUpload: Bool? = nil) { + self.server = server + super.init(id: id, title: title, description: description, createdDate: createdDate, updatedDate: updatedDate, status: status, vaultFiles: vaultFiles, currentUpload: currentUpload) + } +} + diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index f1a3aebbe..0417aead5 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -115,7 +115,20 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { func saveDraftReport() { self.status = .draft - self.successSavingReport = true + + let gDriveReport = GDriveReport( + id: reportId, + title: title, + description: description, + status: status, + server: server, + vaultFiles: self.files.compactMap { ReportFile( fileId: $0.id, + status: .notSubmitted, + bytesSent: 0, + createdDate: Date())} + ) + + addReport(report: gDriveReport) } func saveFinalizedReport() { @@ -123,6 +136,18 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { self.successSavingReport = true } + func addReport(report: GDriveReport) { + let idResult = mainAppModel.tellaData?.addGDriveReport(report: report) + + switch idResult { + case .success(let id ): + dump(id) + self.reportId = id + self.successSavingReport = true + default: + self.failureSavingReport = true + } + } private func getServer() { self.server = mainAppModel.tellaData?.gDriveServers.value.first } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift index 3647b83b8..7db319885 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -9,6 +9,7 @@ import Foundation class GDriveViewModel: BaseReportsViewModel { + var draftReports: [GDriveReport] = [] var pageViewItems: [PageViewItem] { [ PageViewItem(title: LocalizableReport.draftTitle.localized, @@ -24,5 +25,7 @@ class GDriveViewModel: BaseReportsViewModel { override init(mainAppModel: MainAppModel) { super.init(mainAppModel: mainAppModel) + + self.mainAppModel.tellaData?.getDraftGDriveReport() } } From d868f896661735255bca5bb57987337a2158e06d Mon Sep 17 00:00:00 2001 From: dhekra-rouatbi <91288060+dhekra-rouatbi@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:12:16 +0100 Subject: [PATCH 068/167] Fix server subclassing (#165) * Fix server subclassing * Initialize allowMultiple to false --- Tella.xcodeproj/project.pbxproj | 24 ++++- .../Database/Common/SQLStatementBuilder.swift | 8 -- Tella/Data/Database/GDriveDatabase.swift | 6 +- Tella/Domain/Entity/CommonServer/Server.swift | 43 ++++++++ .../Entity/CommonServer/WebServer.swift | 47 +++++++++ Tella/Domain/Entity/GDrive/GDriveServer.swift | 17 +--- Tella/Domain/Entity/Report/Project.swift | 98 ------------------- Tella/Domain/Entity/Report/TellaServer.swift | 60 ++++++++++++ Tella/Domain/Entity/Uwazi/UwaziServer.swift | 16 ++- .../Home/Connections/ConnectionsView.swift | 12 +-- .../Views/Servers/ServersListView.swift | 7 +- .../Uwazi/ViewModel/AddTemplateVM.swift | 4 +- .../Uwazi/ViewModel/UwaziViewModel.swift | 10 +- Tella/Scenes/Uwazi/Views/UwaziView.swift | 2 +- 14 files changed, 201 insertions(+), 153 deletions(-) create mode 100644 Tella/Domain/Entity/CommonServer/Server.swift create mode 100644 Tella/Domain/Entity/CommonServer/WebServer.swift delete mode 100644 Tella/Domain/Entity/Report/Project.swift create mode 100644 Tella/Domain/Entity/Report/TellaServer.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index bd4b859d3..80178ab6e 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -206,6 +206,8 @@ 126ECFEA27C57FA600ED5161 /* CameraState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126ECFE927C57FA600ED5161 /* CameraState.swift */; }; 126FE4D727A427E200AE4188 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126FE4D627A427E200AE4188 /* Constants.swift */; }; 126FEE0A2AC4993900B99298 /* ReportPages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126FEE092AC4993900B99298 /* ReportPages.swift */; }; + 127092DA2C2EE4E3002030AA /* Server.swift in Sources */ = {isa = PBXBuildFile; fileRef = 127092D92C2EE4E3002030AA /* Server.swift */; }; + 127092DC2C2EE7AD002030AA /* WebServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 127092DB2C2EE7AD002030AA /* WebServer.swift */; }; 1272F25D27C91ACD0054F2E2 /* ImportFileProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1272F25C27C91ACD0054F2E2 /* ImportFileProgress.swift */; }; 1272F25F27C91BD70054F2E2 /* ImportFilesFromCameraProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1272F25E27C91BD70054F2E2 /* ImportFilesFromCameraProgress.swift */; }; 1272F26127C91CD90054F2E2 /* ImportFilesProgressModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1272F26027C91CD90054F2E2 /* ImportFilesProgressModels.swift */; }; @@ -321,7 +323,7 @@ 12C07ECC2B06603A0030AD6E /* EncryptionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C07ECB2B06603A0030AD6E /* EncryptionService.swift */; }; 12C07F052B0748D50030AD6E /* TopSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C07F042B0748D50030AD6E /* TopSheetView.swift */; }; 12C2BDE82847676100488060 /* LockTimeoutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C2BDE72847676100488060 /* LockTimeoutView.swift */; }; - 12CCDC5428D8E05300C3BE4E /* Project.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12CCDC5328D8E05300C3BE4E /* Project.swift */; }; + 12CCDC5428D8E05300C3BE4E /* TellaServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12CCDC5328D8E05300C3BE4E /* TellaServer.swift */; }; 12D37A942721752B00E43BDB /* TellaApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D37A932721752B00E43BDB /* TellaApp.swift */; }; 12D37A962721A49D00E43BDB /* NavigationContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D37A952721A49D00E43BDB /* NavigationContainerView.swift */; }; 12D37A982721EDB700E43BDB /* PinKeyboardModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D37A972721EDB600E43BDB /* PinKeyboardModel.swift */; }; @@ -766,6 +768,8 @@ 126ECFE927C57FA600ED5161 /* CameraState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraState.swift; sourceTree = ""; }; 126FE4D627A427E200AE4188 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 126FEE092AC4993900B99298 /* ReportPages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportPages.swift; sourceTree = ""; }; + 127092D92C2EE4E3002030AA /* Server.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Server.swift; sourceTree = ""; }; + 127092DB2C2EE7AD002030AA /* WebServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebServer.swift; sourceTree = ""; }; 1270EA9E2A4B4B07000851BA /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; 1270EAA02A4B4B07000851BA /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/Localizable.strings; sourceTree = ""; }; 1270EAA22A4B4B07000851BA /* my */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = my; path = my.lproj/Localizable.strings; sourceTree = ""; }; @@ -884,7 +888,7 @@ 12C07ECB2B06603A0030AD6E /* EncryptionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionService.swift; sourceTree = ""; }; 12C07F042B0748D50030AD6E /* TopSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopSheetView.swift; sourceTree = ""; }; 12C2BDE72847676100488060 /* LockTimeoutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockTimeoutView.swift; sourceTree = ""; }; - 12CCDC5328D8E05300C3BE4E /* Project.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Project.swift; sourceTree = ""; }; + 12CCDC5328D8E05300C3BE4E /* TellaServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TellaServer.swift; sourceTree = ""; }; 12D37A932721752B00E43BDB /* TellaApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TellaApp.swift; sourceTree = ""; }; 12D37A952721A49D00E43BDB /* NavigationContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationContainerView.swift; sourceTree = ""; }; 12D37A972721EDB600E43BDB /* PinKeyboardModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinKeyboardModel.swift; sourceTree = ""; }; @@ -1464,6 +1468,7 @@ 1231A45B294C76990057DA85 /* Entity */ = { isa = PBXGroup; children = ( + 127092D82C2EE4D0002030AA /* CommonServer */, 15994A0F2BFBF0C70017F153 /* GDrive */, 1519BED42B9A5A2B006FD290 /* Resource */, E18BD4312AA0C2EB00EE62E2 /* Uwazi */, @@ -1492,7 +1497,7 @@ 1231A45D294C779D0057DA85 /* ReportStatus.swift */, 1203CDDB298C5B9100D09073 /* ReportActionType.swift */, 12351C1928D2209400F3CB7C /* Report.swift */, - 12CCDC5328D8E05300C3BE4E /* Project.swift */, + 12CCDC5328D8E05300C3BE4E /* TellaServer.swift */, 12A43B4E29941574003EF33E /* ReportFile.swift */, 122389B829367ABA0058593B /* ServerType.swift */, 12623DCB299EA31400E033ED /* ReportVaultFile.swift */, @@ -1697,6 +1702,15 @@ path = Models; sourceTree = ""; }; + 127092D82C2EE4D0002030AA /* CommonServer */ = { + isa = PBXGroup; + children = ( + 127092D92C2EE4E3002030AA /* Server.swift */, + 127092DB2C2EE7AD002030AA /* WebServer.swift */, + ); + path = CommonServer; + sourceTree = ""; + }; 1272F25A27C919E40054F2E2 /* ImportFilesProgressView */ = { isa = PBXGroup; children = ( @@ -3390,6 +3404,7 @@ 12730E67279F11C300DC0135 /* LanguageListView.swift in Sources */, 0ECC7817267A533E00A2ACF2 /* PageViewCell.swift in Sources */, 128B929727D7920300E92ACF /* SelectingFilesHeaderView.swift in Sources */, + 127092DA2C2EE4E3002030AA /* Server.swift in Sources */, 1236EE8028E1B40200973EEA /* DataBaseHelper.swift in Sources */, 125299E12AD0515600191CAB /* VaultFilesManager.swift in Sources */, 1237A719278F172E00D7BC0F /* NSUIImage.swift in Sources */, @@ -3404,6 +3419,7 @@ 126684412B18B67500561650 /* BackgroundActivityModel.swift in Sources */, CCBC2F6929A93E4900888779 /* SettingCheckboxItem.swift in Sources */, 1293547B294A454900735ED0 /* AppDelegate.swift in Sources */, + 127092DC2C2EE7AD002030AA /* WebServer.swift in Sources */, 12B52580284903AE00B3D1C0 /* AboutAndHelpItem.swift in Sources */, CCC1B4332AC75B410075B819 /* UwaziEntityMandatoryTextView.swift in Sources */, 12E9DD9927DF65E80002FD00 /* MoveFilesView.swift in Sources */, @@ -3522,7 +3538,7 @@ 128C7BC42745AB0100A680B3 /* FileListViewModel.swift in Sources */, 127D4A812C1B2ED700E82EA8 /* VaultFilesManagerExtension.swift in Sources */, E1EAA0552AA74FEC00492078 /* UwaziLanguageContext.swift in Sources */, - 12CCDC5428D8E05300C3BE4E /* Project.swift in Sources */, + 12CCDC5428D8E05300C3BE4E /* TellaServer.swift in Sources */, 126818C12A38B0C2004606BD /* FileInformation.swift in Sources */, 156986252B88FCB600534720 /* ResourcePDFView.swift in Sources */, 152D38512C2C61DF00323CE7 /* DraftView.swift in Sources */, diff --git a/Tella/Data/Database/Common/SQLStatementBuilder.swift b/Tella/Data/Database/Common/SQLStatementBuilder.swift index e8b3aded3..81d0a2945 100644 --- a/Tella/Data/Database/Common/SQLStatementBuilder.swift +++ b/Tella/Data/Database/Common/SQLStatementBuilder.swift @@ -48,14 +48,6 @@ class SQLiteStatementBuilder { } } - func addColumnToExistingTable(tableName: String, column: String) { - let sqlExpression = "ALTER TABLE " + tableName + " ADD COLUMN " + column - let ret = sqlite3_exec(dbPointer, sqlExpression, nil, nil, nil) - - if (ret != SQLITE_OK) { // corrupt database. - logDbErr("Error altering db table - \(tableName)") - } - } func setNewDatabaseVersion(version:Int) throws { let sql = ("PRAGMA user_version = \(version)") diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index 2a1a9be4d..218aef950 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -10,13 +10,13 @@ import Foundation // GDrive Server extension TellaDataBase { + func createGDriveServerTable() { let columns = [ - cddl(D.cServerId, D.integer, primaryKey: true, autoIncrement: true), + cddl(D.cId, D.integer, primaryKey: true, autoIncrement: true), cddl(D.cName, D.text), cddl(D.cRootFolder, D.text) ] - statementBuilder.createTable(tableName: D.tGDriveServer, columns: columns) } @@ -48,7 +48,7 @@ extension TellaDataBase { func deleteGDriveServer(serverId: Int) { do { try statementBuilder.delete(tableName: D.tGDriveServer, - primarykeyValue: [KeyValue(key: D.cServerId, value: serverId)]) + primarykeyValue: [KeyValue(key: D.cId, value: serverId)]) } catch let error { debugLog(error) } diff --git a/Tella/Domain/Entity/CommonServer/Server.swift b/Tella/Domain/Entity/CommonServer/Server.swift new file mode 100644 index 000000000..4d2c18d48 --- /dev/null +++ b/Tella/Domain/Entity/CommonServer/Server.swift @@ -0,0 +1,43 @@ +// +// Server.swift +// Tella +// +// Created by Dhekra Rouatbi on 28/6/2024. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +class Server: Codable, Equatable, Hashable { + + var id: Int? + var name: String? + var serverType: ServerConnectionType? + var allowMultiple: Bool? + + enum CodingKeys: String, CodingKey { + case id = "c_id" + case name = "c_name" + } + + init(id: Int? = nil, + name: String? = nil, + serverType: ServerConnectionType? = nil, + allowMultipleConnections: Bool? = true + ) { + self.id = id + self.name = name + self.serverType = serverType + self.allowMultiple = allowMultipleConnections + } + + static func == (lhs: Server, rhs: Server) -> Bool { + return lhs.id == rhs.id + } + + func hash(into hasher: inout Hasher){ + hasher.combine(id.hashValue) + } +} + + diff --git a/Tella/Domain/Entity/CommonServer/WebServer.swift b/Tella/Domain/Entity/CommonServer/WebServer.swift new file mode 100644 index 000000000..e59c99ee4 --- /dev/null +++ b/Tella/Domain/Entity/CommonServer/WebServer.swift @@ -0,0 +1,47 @@ +// +// WebServer.swift +// Tella +// +// Created by Dhekra Rouatbi on 28/6/2024. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +class WebServer: Server { + + var url: String? + var username: String? + var password: String? + var accessToken: String? + + enum CodingKeys: String, CodingKey { + case url = "c_url" + case username = "c_username" + case password = "c_password" + case accessToken = "c_access_token" + } + + init(id: Int? = nil, + name: String? = nil, + serverURL: String? = nil, + username: String? = nil, + password: String? = nil, + accessToken: String? = nil, + serverType: ServerConnectionType? = nil) { + self.url = serverURL + self.username = username + self.password = password + self.accessToken = accessToken + + super.init(id: id, + name: name, + serverType: serverType) + } + + required init(from decoder: Decoder) throws { + try super.init(from: decoder) + } +} + + diff --git a/Tella/Domain/Entity/GDrive/GDriveServer.swift b/Tella/Domain/Entity/GDrive/GDriveServer.swift index ee4fc859c..77cb41c3d 100644 --- a/Tella/Domain/Entity/GDrive/GDriveServer.swift +++ b/Tella/Domain/Entity/GDrive/GDriveServer.swift @@ -17,23 +17,14 @@ class GDriveServer: Server { init(id: Int? = nil, name: String? = "Google Drive", - serverURL: String? = nil, - username: String? = nil, - password: String? = nil, - accessToken: String? = nil, rootFolder: String, - serverType: ServerConnectionType? = .gDrive, - allowMultiple: Bool? = false - ) { + serverType: ServerConnectionType? = .gDrive) { + self.rootFolder = rootFolder super.init(id: id, name: name, - serverURL: serverURL, - username: username, - password: password, - accessToken: accessToken, - serverType: serverType - ) + serverType: serverType, + allowMultipleConnections: false) } required init(from decoder: Decoder) throws { diff --git a/Tella/Domain/Entity/Report/Project.swift b/Tella/Domain/Entity/Report/Project.swift deleted file mode 100644 index 3a1c75b77..000000000 --- a/Tella/Domain/Entity/Report/Project.swift +++ /dev/null @@ -1,98 +0,0 @@ -// Tella -// -// Copyright © 2022 INTERNEWS. All rights reserved. -// - -import Foundation - -class Server: Codable, Equatable, Hashable { - var id: Int? - var name: String? - var url: String? - var username: String? - var password: String? - var accessToken: String? - var serverType: ServerConnectionType? - var allowMultiple: Bool? - - enum CodingKeys: String, CodingKey { - case id = "c_server_id" - case name = "c_name" - case url = "c_url" - case username = "c_username" - case password = "c_password" - case accessToken = "c_access_token" - case serverType - } - - init(id: Int? = nil, - name: String? = nil, - serverURL: String? = nil, - username: String? = nil, - password: String? = nil, - accessToken: String? = nil, - serverType: ServerConnectionType? = nil, - allowMultipleConnections: Bool? = true - ) { - self.id = id - self.name = name - self.url = serverURL - self.username = username - self.password = password - self.accessToken = accessToken - self.serverType = serverType - } - - - static func == (lhs: Server, rhs: Server) -> Bool { - return lhs.id == rhs.id - } - - func hash(into hasher: inout Hasher){ - hasher.combine(id.hashValue) - } -} - - -class TellaServer : Server { - var activatedMetadata : Bool? - var backgroundUpload : Bool? - var projectId : String? - var slug : String? - var autoUpload: Bool? - var autoDelete: Bool? - - init(id: Int? = nil, - name: String? = nil, - serverURL: String? = nil, - username: String? = nil, - password: String? = nil, - accessToken: String? = nil, - activatedMetadata: Bool? = nil, - backgroundUpload: Bool? = nil, - projectId: String? = nil, - slug: String? = nil, - autoUpload: Bool, - autoDelete: Bool, - serverType: ServerConnectionType? = .tella - ) { - self.activatedMetadata = activatedMetadata - self.backgroundUpload = backgroundUpload - self.projectId = projectId - self.slug = slug - self.autoUpload = autoUpload - self.autoDelete = autoDelete - super.init(id: id, - name: name, - serverURL: serverURL, - username: username, - password: password, - accessToken: accessToken, - serverType: serverType - ) - } - - required init(from decoder: Decoder) throws { - try super.init(from: decoder) - } -} diff --git a/Tella/Domain/Entity/Report/TellaServer.swift b/Tella/Domain/Entity/Report/TellaServer.swift new file mode 100644 index 000000000..eecc70667 --- /dev/null +++ b/Tella/Domain/Entity/Report/TellaServer.swift @@ -0,0 +1,60 @@ +// Tella +// +// Copyright © 2022 INTERNEWS. All rights reserved. +// + +import Foundation + +class TellaServer : WebServer { + + var activatedMetadata : Bool? + var backgroundUpload : Bool? + var projectId : String? + var slug : String? + var autoUpload: Bool? + var autoDelete: Bool? + + enum CodingKeys: String, CodingKey { + case id = "c_server_id" + case activatedMetadata = "c_activated_metadata" + case backgroundUpload = "c_background_upload" + case projectId = "c_api_project_id" + case slug = "c_slug" + case autoUpload = "c_auto_upload" + case autoDelete = "c_auto_delete" + } + + init(id: Int? = nil, + name: String? = nil, + serverURL: String? = nil, + username: String? = nil, + password: String? = nil, + accessToken: String? = nil, + activatedMetadata: Bool? = nil, + backgroundUpload: Bool? = nil, + projectId: String? = nil, + slug: String? = nil, + autoUpload: Bool, + autoDelete: Bool, + serverType: ServerConnectionType? = .tella) { + + self.activatedMetadata = activatedMetadata + self.backgroundUpload = backgroundUpload + self.projectId = projectId + self.slug = slug + self.autoUpload = autoUpload + self.autoDelete = autoDelete + + super.init(id: id, + name: name, + serverURL: serverURL, + username: username, + password: password, + accessToken: accessToken, + serverType: serverType) + } + + required init(from decoder: Decoder) throws { + try super.init(from: decoder) + } +} diff --git a/Tella/Domain/Entity/Uwazi/UwaziServer.swift b/Tella/Domain/Entity/Uwazi/UwaziServer.swift index 1ebcb72b6..4002a4438 100644 --- a/Tella/Domain/Entity/Uwazi/UwaziServer.swift +++ b/Tella/Domain/Entity/Uwazi/UwaziServer.swift @@ -8,7 +8,7 @@ import Foundation -class UwaziServer : Server { +class UwaziServer : WebServer { var locale: String? var cookie: String? @@ -19,17 +19,23 @@ class UwaziServer : Server { password: String? = nil, accessToken: String? = nil, locale: String? = nil, - serverType: ServerConnectionType? = .uwazi - ) { + serverType: ServerConnectionType? = .uwazi) { + + super.init(id: id, + name: name, + serverURL: serverURL, + username: username, + password: password, + accessToken: accessToken, + serverType: serverType) self.locale = locale - super.init(id: id, name: name, serverURL: serverURL, username: username, password: password, accessToken: accessToken, serverType: serverType) self.cookie = createCookie() } required init(from decoder: Decoder) throws { try super.init(from: decoder) } - + private func createCookie() -> String { let accessTokenValue = accessToken ?? "" let localeValue = locale ?? "" diff --git a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift index cb03f512e..2a4f7ac86 100644 --- a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift +++ b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift @@ -51,7 +51,7 @@ struct ConnectionsView: View { case .uwazi: ConnectionsItemView(title: LocalizableHome.uwaziServerTitle.localized, image: "home.uwazi", - destination: UwaziView().environmentObject(UwaziViewModel(mainAppModel: appModel, server: parseUwaziServer(server: server.servers[0])))) + destination: UwaziView().environmentObject(UwaziViewModel(mainAppModel: appModel, server: server.servers.first))) case .gDrive: ConnectionsItemView(title: "Drive", image: "home.drive", @@ -64,16 +64,6 @@ struct ConnectionsView: View { }.padding(.trailing, 17) } - - private func parseUwaziServer(server: Server) -> UwaziServer { - return UwaziServer( - id: server.id, - name: server.name, - username: server.username, - password: server.password, - accessToken: server.accessToken - ) - } } struct ConnectionsItemView: View { diff --git a/Tella/Scenes/Settings/Views/Servers/ServersListView.swift b/Tella/Scenes/Settings/Views/Servers/ServersListView.swift index f782c563f..becfc92fe 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServersListView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServersListView.swift @@ -80,10 +80,9 @@ struct ServersListView: View { case .tella: shouldShowEditServer = true case .uwazi: - navigateToUwaziAddServerView( - UwaziServer( - id: server.id, name: server.name, serverURL: server.url, accessToken: server.accessToken) - ) + guard let server = server as? UwaziServer else {return} + navigateToUwaziAddServerView( server) + default: break } diff --git a/Tella/Scenes/Uwazi/ViewModel/AddTemplateVM.swift b/Tella/Scenes/Uwazi/ViewModel/AddTemplateVM.swift index a7fe6d88a..d0a3b7a3e 100644 --- a/Tella/Scenes/Uwazi/ViewModel/AddTemplateVM.swift +++ b/Tella/Scenes/Uwazi/ViewModel/AddTemplateVM.swift @@ -29,10 +29,10 @@ class AddTemplateViewModel: ObservableObject { return self.mainAppModel.tellaData } - init(mainAppModel : MainAppModel, serverId: Int) { + init(mainAppModel : MainAppModel, serverId: Int?) { self.mainAppModel = mainAppModel - self.server = self.getServerById(id: serverId) + self.server = self.getServerById(id: serverId!) self.serverName = server?.name ?? "" self.entityFetcher = UwaziEntityFetcher( server: self.server, subscribers: subscribers diff --git a/Tella/Scenes/Uwazi/ViewModel/UwaziViewModel.swift b/Tella/Scenes/Uwazi/ViewModel/UwaziViewModel.swift index 25a0dd261..049929544 100644 --- a/Tella/Scenes/Uwazi/ViewModel/UwaziViewModel.swift +++ b/Tella/Scenes/Uwazi/ViewModel/UwaziViewModel.swift @@ -24,7 +24,7 @@ class UwaziViewModel: ObservableObject { @Published var selectedCell = Pages.template @Published var isLoading: Bool = false - @Published var serverName : String + @Published var serverName : String = "" @Published var shouldShowToast : Bool = false @Published var toastMessage : String = "" @@ -43,18 +43,20 @@ class UwaziViewModel: ObservableObject { page: .submitted, number: submittedEntitiesViewModel.count)]} - var server: UwaziServer + var server: UwaziServer? var tellaData: TellaData? { return self.mainAppModel.tellaData } private var subscribers = Set() - init(mainAppModel : MainAppModel, server: UwaziServer) { + init(mainAppModel : MainAppModel, server: Server?) { self.mainAppModel = mainAppModel + + guard let server = server as? UwaziServer else {return} self.server = server self.serverName = server.name ?? "" - + self.getDownloadedTemplates() self.getUwaziInstances() diff --git a/Tella/Scenes/Uwazi/Views/UwaziView.swift b/Tella/Scenes/Uwazi/Views/UwaziView.swift index d90cdaf96..a545dea29 100644 --- a/Tella/Scenes/Uwazi/Views/UwaziView.swift +++ b/Tella/Scenes/Uwazi/Views/UwaziView.swift @@ -55,7 +55,7 @@ struct UwaziView: View { AddFileYellowButton(action: { navigateTo(destination: AddTemplatesView() - .environmentObject(AddTemplateViewModel(mainAppModel: uwaziViewModel.mainAppModel, serverId: uwaziViewModel.server.id!))) + .environmentObject(AddTemplateViewModel(mainAppModel: uwaziViewModel.mainAppModel, serverId: uwaziViewModel.server?.id))) }).frame(maxWidth: .infinity, maxHeight: 40, alignment: .leading) }.background(Styles.Colors.backgroundMain) From 9873fbf8a626ac9ef57fbd90877d0fcfbd3c8522 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 2 Jul 2024 17:22:54 -0300 Subject: [PATCH 069/167] create base report class and get GDrive drafts --- Tella/Data/Database/GDriveData.swift | 2 +- Tella/Data/Database/GDriveDatabase.swift | 21 ++++---- Tella/Data/Database/TellaDataBase.swift | 2 + .../Repositories/GDriveRepository.swift | 1 + Tella/Domain/Entity/Report/Report.swift | 53 +++++++++++++++---- Tella/Domain/Entity/Report/ReportFile.swift | 2 +- Tella/Domain/Entity/Report/ReportStatus.swift | 2 +- .../GDrive/ViewModel/GDriveViewModel.swift | 2 +- 8 files changed, 63 insertions(+), 22 deletions(-) diff --git a/Tella/Data/Database/GDriveData.swift b/Tella/Data/Database/GDriveData.swift index acbda310e..b6a95b017 100644 --- a/Tella/Data/Database/GDriveData.swift +++ b/Tella/Data/Database/GDriveData.swift @@ -15,7 +15,7 @@ extension TellaData { return id } - func getDraftGDriveReport() { + func getDraftGDriveReport() -> [GDriveReport] { self.database.getDraftGDriveReports() } } diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index 218aef950..6d82b003e 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -66,7 +66,7 @@ extension TellaDataBase { cddl(D.cCreatedDate, D.float), cddl(D.cUpdatedDate, D.float), cddl(D.cStatus, D.integer), - cddl(D.cServerId, D.integer, tableName: D.tGDriveServer, referenceKey: D.cServerId)// update ref key after merge with server subclass PR + cddl(D.cServerId, D.integer, tableName: D.tGDriveServer, referenceKey: D.cId) ] statementBuilder.createTable(tableName: D.tGDriveReport, columns: columns) @@ -89,8 +89,6 @@ extension TellaDataBase { func addGDriveReport(report: GDriveReport) -> Result { do { - let currentUpload = ((report.currentUpload == false) || (report.currentUpload == nil)) ? 0 : 1 - let reportValuesToAdd = [KeyValue(key: D.cTitle, value: report.title), KeyValue(key: D.cDescription, value: report.description), KeyValue(key: D.cCreatedDate, value: Date().getDateDouble()), @@ -119,21 +117,26 @@ extension TellaDataBase { } } - func getDraftGDriveReports() { + func getDraftGDriveReports() -> [GDriveReport] { do { - let joinCondition = [JoinCondition(tableName: D.tGDriveServer, - firstItem: JoinItem(tableName: D.tGDriveReport, columnName: D.cServerId), - secondItem: JoinItem(tableName: D.tGDriveServer, columnName: D.cServerId))] let reportsCondition = [KeyValue(key: D.cStatus, value: ReportStatus.draft.rawValue)] let gDriveReportsDict = try statementBuilder.getSelectQuery(tableName: D.tGDriveReport, - equalCondition: reportsCondition, - joinCondition: joinCondition + equalCondition: reportsCondition ) + + let decodedReports = try gDriveReportsDict.compactMap ({ dict in + var gDriveReport = try dict.decode(GDriveReport.self) + + return gDriveReport + }) + + return decodedReports } catch let error { debugLog(error) + return [] } } } diff --git a/Tella/Data/Database/TellaDataBase.swift b/Tella/Data/Database/TellaDataBase.swift index 08b78a0ae..2a33220d0 100644 --- a/Tella/Data/Database/TellaDataBase.swift +++ b/Tella/Data/Database/TellaDataBase.swift @@ -64,6 +64,8 @@ class TellaDataBase : DataBase { createUwaziEntityInstanceVaultFileTable() addRelationshipColumnToUwaziTemplate() createGDriveServerTable() + createGDriveReportTable() + createGDriveReportFilesTable() } func createReportTable() { diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index a75f90585..3b60d1b56 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -205,6 +205,7 @@ class GDriveRepository: GDriveRepositoryProtocol { uploadParameters.shouldUploadWithSingleRequest = false let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: uploadParameters) + query.supportsAllDrives = true driveService.executeQuery(query) { (ticket, file, error) in if let error = error { diff --git a/Tella/Domain/Entity/Report/Report.swift b/Tella/Domain/Entity/Report/Report.swift index 8284999e8..298d421a9 100644 --- a/Tella/Domain/Entity/Report/Report.swift +++ b/Tella/Domain/Entity/Report/Report.swift @@ -5,7 +5,19 @@ import Foundation -class BaseReport : Hashable { +protocol BaseReportProtocol: Hashable { + var id: Int? { get } + var title: String? { get } + var description: String? { get } + var createdDate: Date? { get } + var updatedDate: Date? { get } + var status: ReportStatus? { get } + var reportFiles: [ReportFile]? { get } + + var getReportDate: String { get } +} + +class BaseReport : Hashable, Codable, BaseReportProtocol { var id : Int? var title : String? @@ -16,6 +28,17 @@ class BaseReport : Hashable { var reportFiles : [ReportFile]? var currentUpload: Bool? + enum CodingKeys: String, CodingKey { + case id = "c_id" + case title = "c_title" + case description = "c_description" + case createdDate = "c_created_date" + case updatedDate = "c_updated_date" + case status = "c_status" + case reportFiles = "c_report_files" + case currentUpload = "c_current_upload" + } + init(id: Int? = nil, title: String? = nil, description: String? = nil, @@ -42,6 +65,14 @@ class BaseReport : Hashable { func hash(into hasher: inout Hasher) { hasher.combine(id.hashValue) } + +// required init(from decoder: Decoder) throws { +// +// let container = try decoder.container(keyedBy: CodingKeys.self) +// +// self.id = try container.decode(Int.self, forKey: .id) +// self.title = try container.decode(String.self, forKey: .title) +// } } extension BaseReport { @@ -89,6 +120,10 @@ class Report: BaseReport { self.apiID = apiID super.init(id: id, title: title, description: description, createdDate: createdDate, updatedDate: updatedDate, status: status, vaultFiles: vaultFiles, currentUpload: currentUpload) } + + required init(from decoder: any Decoder) throws { + try super.init(from: decoder) + } } // GDriveReport @@ -96,15 +131,8 @@ class GDriveReport: BaseReport { var server: GDriveServer? enum CodingKeys: String, CodingKey { - case id = "c_id" - case title = "c_title" - case description = "c_description" - case createdDate = "c_created_date" - case updatedDate = "c_updated_date" - case status = "c_status" - case server = "c_server_id" + case server = "c_server" } - // Keep the existing initializer init(id: Int? = nil, title: String? = nil, @@ -118,5 +146,12 @@ class GDriveReport: BaseReport { self.server = server super.init(id: id, title: title, description: description, createdDate: createdDate, updatedDate: updatedDate, status: status, vaultFiles: vaultFiles, currentUpload: currentUpload) } + + required init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.server = try container.decodeIfPresent(GDriveServer.self, forKey: .server) + + try super.init(from: decoder) + } } diff --git a/Tella/Domain/Entity/Report/ReportFile.swift b/Tella/Domain/Entity/Report/ReportFile.swift index ed0d8a045..ee4defc0a 100644 --- a/Tella/Domain/Entity/Report/ReportFile.swift +++ b/Tella/Domain/Entity/Report/ReportFile.swift @@ -4,7 +4,7 @@ import Foundation -class ReportFile : Hashable { +class ReportFile : Hashable, Codable { var id : Int? var fileId : String? diff --git a/Tella/Domain/Entity/Report/ReportStatus.swift b/Tella/Domain/Entity/Report/ReportStatus.swift index 5bd34e077..65a84c897 100644 --- a/Tella/Domain/Entity/Report/ReportStatus.swift +++ b/Tella/Domain/Entity/Report/ReportStatus.swift @@ -4,7 +4,7 @@ import Foundation -enum ReportStatus : Int { +enum ReportStatus : Int, Codable { case unknown = 0 case draft = 1 case finalized = 2 diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift index 7db319885..85ef07864 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -26,6 +26,6 @@ class GDriveViewModel: BaseReportsViewModel { override init(mainAppModel: MainAppModel) { super.init(mainAppModel: mainAppModel) - self.mainAppModel.tellaData?.getDraftGDriveReport() + self.draftReports = self.mainAppModel.tellaData?.getDraftGDriveReport() ?? [] } } From 83d5a09ac57654b5799b42e1028ffe6cacb1914a Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 3 Jul 2024 12:41:20 -0300 Subject: [PATCH 070/167] add gDriveList and show files saved in draft --- Tella.xcodeproj/project.pbxproj | 14 +- Tella/Data/Database/GDriveData.swift | 4 + Tella/Data/Database/GDriveDatabase.swift | 38 +++++- Tella/Domain/Entity/Report/ReportFile.swift | 9 ++ .../ViewModel/GDriveDraftViewModel.swift | 23 +++- .../GDrive/ViewModel/GDriveViewModel.swift | 21 ++- .../GDrive/Views/Draft/GDriveDraftView.swift | 5 +- .../Views/GDriveList/GDriveCardView.swift | 120 ++++++++++++++++++ .../Views/GDriveList/GDriveListView.swift | 29 +++++ .../Scenes/GDrive/Views/GDriveListView.swift | 20 --- Tella/Scenes/GDrive/Views/GDriveView.swift | 7 +- 11 files changed, 258 insertions(+), 32 deletions(-) create mode 100644 Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift create mode 100644 Tella/Scenes/GDrive/Views/GDriveList/GDriveListView.swift delete mode 100644 Tella/Scenes/GDrive/Views/GDriveListView.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 80178ab6e..9dec5f443 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -370,6 +370,7 @@ 15791C232B6C2E9100D67C74 /* ResourcesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15791C222B6C2E9100D67C74 /* ResourcesViewModel.swift */; }; 157E4F532BA385B500147345 /* PDFKitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 157E4F522BA385B500147345 /* PDFKitView.swift */; }; 15917D752B90FCC3005655AC /* ResourceCardType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15917D742B90FCC3005655AC /* ResourceCardType.swift */; }; + 159229D92C34A37C003FAC9A /* GDriveCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 159229D82C34A37C003FAC9A /* GDriveCardView.swift */; }; 15994A0C2BFBC6F40017F153 /* SelectDriveConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */; }; 15994A0E2BFBE15F0017F153 /* SelectSharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */; }; 15994A112BFBF0E50017F153 /* SharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A102BFBF0E50017F153 /* SharedDrive.swift */; }; @@ -935,6 +936,7 @@ 1589A6202B7672390048C775 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 1589A6212B7672430048C775 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; 15917D742B90FCC3005655AC /* ResourceCardType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceCardType.swift; sourceTree = ""; }; + 159229D82C34A37C003FAC9A /* GDriveCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveCardView.swift; sourceTree = ""; }; 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectDriveConnection.swift; sourceTree = ""; }; 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectSharedDrive.swift; sourceTree = ""; }; 15994A102BFBF0E50017F153 /* SharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedDrive.swift; sourceTree = ""; }; @@ -2343,6 +2345,15 @@ path = ViewModel; sourceTree = ""; }; + 159229D72C34A2BF003FAC9A /* GDriveList */ = { + isa = PBXGroup; + children = ( + 15E3D5022C1B522500B7FECC /* GDriveListView.swift */, + 159229D82C34A37C003FAC9A /* GDriveCardView.swift */, + ); + path = GDriveList; + sourceTree = ""; + }; 15994A0A2BFBC6B10017F153 /* GDrive */ = { isa = PBXGroup; children = ( @@ -2383,9 +2394,9 @@ 15E3D5012C1B51D700B7FECC /* Views */ = { isa = PBXGroup; children = ( + 159229D72C34A2BF003FAC9A /* GDriveList */, 15E3D5062C1B712300B7FECC /* Draft */, 15B81F372C1A2806007C0E88 /* GDriveView.swift */, - 15E3D5022C1B522500B7FECC /* GDriveListView.swift */, ); path = Views; sourceTree = ""; @@ -3410,6 +3421,7 @@ 1237A719278F172E00D7BC0F /* NSUIImage.swift in Sources */, 126818C32A38B69E004606BD /* FileTypeHelper.swift in Sources */, D572EACB263A43C100CE191A /* FileDetailView.swift in Sources */, + 159229D92C34A37C003FAC9A /* GDriveCardView.swift in Sources */, 127B56D5279AC28300F902C9 /* CancelImportView.swift in Sources */, 125D233C2B17344D001EFB8B /* BackgroundActivitiesView.swift in Sources */, 1293F6752AD8853500F6CFBD /* FeedbackRepository.swift in Sources */, diff --git a/Tella/Data/Database/GDriveData.swift b/Tella/Data/Database/GDriveData.swift index b6a95b017..fe4a6e5e7 100644 --- a/Tella/Data/Database/GDriveData.swift +++ b/Tella/Data/Database/GDriveData.swift @@ -18,4 +18,8 @@ extension TellaData { func getDraftGDriveReport() -> [GDriveReport] { self.database.getDraftGDriveReports() } + + func getDriveReport(id: Int) -> GDriveReport? { + self.database.getGDriveReport(id: id) + } } diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index 6d82b003e..0eee58502 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -127,9 +127,7 @@ extension TellaDataBase { ) let decodedReports = try gDriveReportsDict.compactMap ({ dict in - var gDriveReport = try dict.decode(GDriveReport.self) - - return gDriveReport + return try dict.decode(GDriveReport.self) }) return decodedReports @@ -139,4 +137,38 @@ extension TellaDataBase { return [] } } + + func getGDriveReport(id: Int) -> GDriveReport? { + do{ + let reportsCondition = [KeyValue(key: D.cId, value: id)] + let gDriveReportsDict = try statementBuilder.getSelectQuery(tableName: D.tGDriveReport, + equalCondition: reportsCondition + ) + + let decodedReports = try gDriveReportsDict.first?.decode(GDriveReport.self) + let reportFiles = getDriveVaultFiles(reportId: decodedReports?.id) + decodedReports?.reportFiles = reportFiles + return decodedReports + } catch let error { + debugLog(error) + return nil + } + } + + func getDriveVaultFiles(reportId: Int?) -> [ReportFile] { + do { + let reportFilesCondition = [KeyValue(key: D.cReportInstanceId, value: reportId)] + let responseDict = try statementBuilder.selectQuery(tableName: D.tGDriveInstanceVaultFile, andCondition: reportFilesCondition) + + let decodedFiles = try responseDict.compactMap ({ dict in + return try dict.decode(ReportFile.self) + }) + + return decodedFiles + } catch let error { + debugLog(error) + + return [] + } + } } diff --git a/Tella/Domain/Entity/Report/ReportFile.swift b/Tella/Domain/Entity/Report/ReportFile.swift index ee4defc0a..a4f94660a 100644 --- a/Tella/Domain/Entity/Report/ReportFile.swift +++ b/Tella/Domain/Entity/Report/ReportFile.swift @@ -13,6 +13,15 @@ class ReportFile : Hashable, Codable { var createdDate : Date? var updatedDate : Date? + enum CodingKeys: String, CodingKey { + case id = "c_id" + case fileId = "c_vault_file_instance_id" + case status = "c_status" + case bytesSent = "c_bytes_Sent" + case createdDate = "c_created_date" + case updatedDate = "c_updated_date" + } + init(id: Int? = nil, fileId: String? = nil, status: FileStatus? = nil, diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index 0417aead5..7c2368242 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -60,13 +60,15 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { type: ManageFileType.fromDevice) ]} - init(mainAppModel: MainAppModel, repository: GDriveRepositoryProtocol) { + init(mainAppModel: MainAppModel, repository: GDriveRepositoryProtocol, reportID: Int?) { self.mainAppModel = mainAppModel self.gDriveRepository = repository self.validateReport() self.getServer() + self.reportId = reportID self.bindVaultFileTaken() + self.fillReportVM() } private func validateReport() { @@ -113,6 +115,19 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { ).store(in: &cancellables) } + func fillReportVM() { + if let reportId = self.reportId, let report = self.mainAppModel.tellaData?.getDriveReport(id: reportId) { + self.title = report.title ?? "" + self.description = report.description ?? "" + + if let vaultFileResult = mainAppModel.vaultFilesManager?.getVaultFiles(ids: report.reportFiles?.compactMap{ $0.fileId } ?? []) { + self.files = Set(vaultFileResult) + } + + self.objectWillChange.send() + } + } + func saveDraftReport() { self.status = .draft @@ -128,7 +143,7 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { createdDate: Date())} ) - addReport(report: gDriveReport) + reportId == nil ? addReport(report: gDriveReport) : updateReport(report: gDriveReport) } func saveFinalizedReport() { @@ -148,6 +163,10 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { self.failureSavingReport = true } } + + func updateReport(report: GDriveReport) { + //update report logic + } private func getServer() { self.server = mainAppModel.tellaData?.gDriveServers.value.first } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift index 85ef07864..2b8e931ee 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -9,7 +9,12 @@ import Foundation class GDriveViewModel: BaseReportsViewModel { - var draftReports: [GDriveReport] = [] + + @Published var draftReports: [GDriveReport] = [] + @Published var outboxedReports: [GDriveReport] = [] + @Published var submittedReports: [GDriveReport] = [] + + @Published var selectedReport: GDriveReport? var pageViewItems: [PageViewItem] { [ PageViewItem(title: LocalizableReport.draftTitle.localized, @@ -23,9 +28,23 @@ class GDriveViewModel: BaseReportsViewModel { number: 0)] } + var sheetItems : [ListActionSheetItem] { return [ + + ListActionSheetItem(imageName: "view-icon", + content: self.selectedReport?.status?.sheetItemTitle ?? "", + type: self.selectedReport?.status?.reportActionType ?? .viewSubmitted), + ListActionSheetItem(imageName: "delete-icon-white", + content: LocalizableReport.viewModelDelete.localized, + type: ReportActionType.delete) + ]} + override init(mainAppModel: MainAppModel) { super.init(mainAppModel: mainAppModel) self.draftReports = self.mainAppModel.tellaData?.getDraftGDriveReport() ?? [] } + + func deleteReport() { + + } } diff --git a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift index c27a2d0e0..ccb25f28f 100644 --- a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift +++ b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift @@ -14,11 +14,12 @@ struct GDriveDraftView: View { @EnvironmentObject var reportsViewModel : BaseReportsViewModel let gDriveDIContainer: GDriveDIContainer - init(mainAppModel: MainAppModel, gDriveDIContainer: GDriveDIContainer) { + init(mainAppModel: MainAppModel, gDriveDIContainer: GDriveDIContainer, reportId: Int? = nil) { self.gDriveDIContainer = gDriveDIContainer _gDriveDraftVM = StateObject(wrappedValue: GDriveDraftViewModel( mainAppModel: mainAppModel, - repository: gDriveDIContainer.gDriveRepository) + repository: gDriveDIContainer.gDriveRepository, + reportID: reportId) ) } diff --git a/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift b/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift new file mode 100644 index 000000000..f28e68a0a --- /dev/null +++ b/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift @@ -0,0 +1,120 @@ +// +// GDriveCardView.swift +// Tella +// +// Created by gus valbuena on 7/2/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import SwiftUI + +struct GDriveCardView : View { + + @Binding var report : GDriveReport + + @EnvironmentObject var reportsViewModel : GDriveViewModel + @EnvironmentObject private var sheetManager: SheetManager + @EnvironmentObject var mainAppModel : MainAppModel + let gDriveDIContainer = GDriveDIContainer() + + var body : some View { + Button { + reportsViewModel.selectedReport = report + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) { + self.handleActions(type: report.status?.reportActionType) + } + + } label: { + VStack(spacing: 0) { + + HStack { + + ConnectionCardDetail(title: report.title ?? "", subtitle: report.getReportDate) + + Spacer() + + ImageButtonView(imageName: "reports.more", action: { + reportsViewModel.selectedReport = report + showReportActionBottomSheet() + }) + + }.padding(.all, 16) + + } .background(Color.white.opacity(0.08)) + .cornerRadius(15) + .padding(EdgeInsets(top: 6, leading: 0, bottom: 6, trailing: 0)) + } + } + + + private func showReportActionBottomSheet() { + sheetManager.showBottomSheet(modalHeight: 176) { + ActionListBottomSheet(items: reportsViewModel.sheetItems , + headerTitle: reportsViewModel.selectedReport?.title ?? "", + action: { item in + self.handleActions(type : item.type as? ReportActionType) + }) + } + } + + private func showDeleteReportConfirmationView() { + sheetManager.showBottomSheet(modalHeight: 200) { + DeleteReportConfirmationView(title: report.title, + message: deleteMessage) { + reportsViewModel.deleteReport() + sheetManager.hide() + } + } + } + + private func handleActions(type: ReportActionType?) { + + guard let type else { return } + + switch type { + case .editDraft: + self.navigateTo(destination: editDraftReportView) + sheetManager.hide() + case .editOutbox: + navigateTo(destination: outboxDetailsView) + sheetManager.hide() + case .delete: + showDeleteReportConfirmationView() + case .viewSubmitted: + navigateTo(destination: submittedDetailsView) + sheetManager.hide() + } + } + + private var editDraftReportView: some View { + GDriveDraftView(mainAppModel: mainAppModel, + gDriveDIContainer: gDriveDIContainer, + reportId: report.id) + .environmentObject(reportsViewModel as BaseReportsViewModel) + } + + private var submittedDetailsView: some View { + SubmittedDetailsView(appModel: mainAppModel, + reportId: reportsViewModel.selectedReport?.id) + .environmentObject(reportsViewModel as BaseReportsViewModel) + } + + private var outboxDetailsView: some View { + OutboxDetailsView(appModel: mainAppModel, + reportsViewModel: reportsViewModel, + reportId: reportsViewModel.selectedReport?.id) + .environmentObject(reportsViewModel as BaseReportsViewModel) + } + + private var deleteMessage : String { + switch report.status { + case .draft: + return LocalizableReport.deleteDraftReportMessage.localized + case .submitted: + return LocalizableReport.DeleteSubmittedReportMessage.localized + default: + return LocalizableReport.deleteOutboxReportMessage.localized + } + } +} diff --git a/Tella/Scenes/GDrive/Views/GDriveList/GDriveListView.swift b/Tella/Scenes/GDrive/Views/GDriveList/GDriveListView.swift new file mode 100644 index 000000000..a27229cbf --- /dev/null +++ b/Tella/Scenes/GDrive/Views/GDriveList/GDriveListView.swift @@ -0,0 +1,29 @@ +// +// GDriveListView.swift +// Tella +// +// Created by gus valbuena on 6/13/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import SwiftUI + +struct GDriveListView: View { + @Binding var reportArray : [GDriveReport] + var message: String + var body: some View { + ZStack { + if $reportArray.wrappedValue.count > 0 { + ScrollView { + VStack(alignment: .center, spacing: 0) { + ForEach($reportArray, id: \.self) { report in + GDriveCardView(report: report) + } + } + } + } else { + ConnectionEmptyView(message: message, type: .gDrive) + } + } + } +} diff --git a/Tella/Scenes/GDrive/Views/GDriveListView.swift b/Tella/Scenes/GDrive/Views/GDriveListView.swift deleted file mode 100644 index be99dda74..000000000 --- a/Tella/Scenes/GDrive/Views/GDriveListView.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// GDriveListView.swift -// Tella -// -// Created by gus valbuena on 6/13/24. -// Copyright © 2024 HORIZONTAL. All rights reserved. -// - -import SwiftUI - -struct GDriveListView: View { - var message: String - var body: some View { - ConnectionEmptyView(message: message, type: .gDrive) - } -} - -#Preview { - GDriveListView(message: "You have no drafts") -} diff --git a/Tella/Scenes/GDrive/Views/GDriveView.swift b/Tella/Scenes/GDrive/Views/GDriveView.swift index d0ba9f042..cbd370b8d 100644 --- a/Tella/Scenes/GDrive/Views/GDriveView.swift +++ b/Tella/Scenes/GDrive/Views/GDriveView.swift @@ -20,6 +20,7 @@ struct GDriveView: View { var body: some View { contentView .navigationBarTitle(LocalizableSettings.settServerGDrive.localized.capitalized, displayMode: .large) + .environmentObject(gDriveViewModel) } var contentView: some View { @@ -32,11 +33,11 @@ struct GDriveView: View { Spacer() switch self.gDriveViewModel.selectedCell { case .draft: - GDriveListView(message: "You have no draft reports.") + GDriveListView(reportArray: $gDriveViewModel.draftReports, message: "You have no draft reports.") case .outbox: - GDriveListView(message: "You have no outbox reports.") + GDriveListView(reportArray: $gDriveViewModel.outboxedReports, message: "You have no outbox reports.") case .submitted: - GDriveListView(message: "You have no submitted reports.") + GDriveListView(reportArray: $gDriveViewModel.submittedReports, message: "You have no submitted reports.") default: EmptyView() } From 8fc5839d3aefedb7e59c128b57338898b6a13eb4 Mon Sep 17 00:00:00 2001 From: rimKtarii Date: Thu, 4 Jul 2024 11:50:16 +0200 Subject: [PATCH 071/167] Remove accessToken from Webserver --- Tella/Domain/Entity/CommonServer/WebServer.swift | 13 ++++++++----- Tella/Domain/Entity/Report/TellaServer.swift | 6 ++++-- Tella/Domain/Entity/Uwazi/UwaziServer.swift | 5 +++-- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Tella/Domain/Entity/CommonServer/WebServer.swift b/Tella/Domain/Entity/CommonServer/WebServer.swift index e59c99ee4..96b4708bb 100644 --- a/Tella/Domain/Entity/CommonServer/WebServer.swift +++ b/Tella/Domain/Entity/CommonServer/WebServer.swift @@ -13,13 +13,11 @@ class WebServer: Server { var url: String? var username: String? var password: String? - var accessToken: String? enum CodingKeys: String, CodingKey { case url = "c_url" case username = "c_username" case password = "c_password" - case accessToken = "c_access_token" } init(id: Int? = nil, @@ -27,18 +25,23 @@ class WebServer: Server { serverURL: String? = nil, username: String? = nil, password: String? = nil, - accessToken: String? = nil, serverType: ServerConnectionType? = nil) { self.url = serverURL self.username = username self.password = password - self.accessToken = accessToken super.init(id: id, name: name, serverType: serverType) } - + override func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(url, forKey: .url) + try container.encode(username, forKey: .username) + try container.encode(password, forKey: .password) + try super.encode(to: encoder) + } + required init(from decoder: Decoder) throws { try super.init(from: decoder) } diff --git a/Tella/Domain/Entity/Report/TellaServer.swift b/Tella/Domain/Entity/Report/TellaServer.swift index eecc70667..ef3b10c50 100644 --- a/Tella/Domain/Entity/Report/TellaServer.swift +++ b/Tella/Domain/Entity/Report/TellaServer.swift @@ -13,6 +13,8 @@ class TellaServer : WebServer { var slug : String? var autoUpload: Bool? var autoDelete: Bool? + var accessToken: String? + enum CodingKeys: String, CodingKey { case id = "c_server_id" @@ -22,6 +24,7 @@ class TellaServer : WebServer { case slug = "c_slug" case autoUpload = "c_auto_upload" case autoDelete = "c_auto_delete" + case accessToken = "c_access_token" } init(id: Int? = nil, @@ -44,13 +47,12 @@ class TellaServer : WebServer { self.slug = slug self.autoUpload = autoUpload self.autoDelete = autoDelete - + self.accessToken = accessToken super.init(id: id, name: name, serverURL: serverURL, username: username, password: password, - accessToken: accessToken, serverType: serverType) } diff --git a/Tella/Domain/Entity/Uwazi/UwaziServer.swift b/Tella/Domain/Entity/Uwazi/UwaziServer.swift index 4002a4438..87792adcc 100644 --- a/Tella/Domain/Entity/Uwazi/UwaziServer.swift +++ b/Tella/Domain/Entity/Uwazi/UwaziServer.swift @@ -11,7 +11,8 @@ import Foundation class UwaziServer : WebServer { var locale: String? var cookie: String? - + var accessToken: String? + init(id: Int? = nil, name: String? = nil, serverURL: String? = nil, @@ -26,9 +27,9 @@ class UwaziServer : WebServer { serverURL: serverURL, username: username, password: password, - accessToken: accessToken, serverType: serverType) self.locale = locale + self.accessToken = accessToken self.cookie = createCookie() } From e0aa9e21c0ce1536ac505333d6d25d4f77be2ea1 Mon Sep 17 00:00:00 2001 From: Dhekra Rouatbi Date: Thu, 4 Jul 2024 16:09:03 +0100 Subject: [PATCH 072/167] Create reusable report component --- Tella.xcodeproj/project.pbxproj | 87 ++++++++ .../Card/ConnectionCardDetail.swift | 11 +- .../Components/Reports/Draft/DraftView.swift | 15 +- Tella/Data/Database/GDriveDatabase.swift | 2 +- Tella/Data/Database/TellaData.swift | 2 + Tella/Data/Database/TellaDataBase.swift | 9 +- .../Repositories/GDriveRepository.swift | 7 +- .../Upload/BaseUploadOperation.swift | 2 +- Tella/Domain/Entity/Report/Report.swift | 24 ++- Tella/Domain/Entity/Report/ReportStatus.swift | 85 +++++++- Tella/Domain/Entity/Report/ServerType.swift | 4 + Tella/Domain/Entity/Uwazi/EntityStatus.swift | 77 +++++++ .../home.nextcloud.imageset/Contents.json | 12 ++ .../home.nextcloud.pdf | Bin 0 -> 2984 bytes .../ViewModels/CommonCardViewModel.swift | 48 +++++ .../ViewModels/ReportCardViewModel.swift | 38 ++++ .../ViewModels/ReportMainViewModel.swift | 65 ++++++ .../Views/CommonReportListView.swift | 97 +++++++++ .../Views/ReportMainView.swift | 197 ++++++++++++++++++ .../ViewModel/GDriveDraftViewModel.swift | 2 +- .../GDrive/ViewModel/GDriveViewModel.swift | 4 +- .../GDrive/Views/Draft/GDriveDraftView.swift | 8 +- .../Views/GDriveList/GDriveCardView.swift | 4 +- .../Home/Connections/ConnectionsView.swift | 28 ++- .../ViewModels/NextcloudMainViewModel.swift | 61 ++++++ .../Reports/Draft/DraftReportView.swift | 5 +- .../Reports/ReportList/ReportCardView.swift | 4 +- .../Submitted/SubmittedDetailsView.swift | 2 +- .../Reports/View Model/ReportsViewModel.swift | 4 +- .../Uwazi/Models/TemplateActionType.swift | 30 --- .../Uwazi/ViewModel/UwaziCardViewModel.swift | 96 +++------ .../Views/EntityInstances/UwaziListView.swift | 4 +- .../en.lproj/Localizable.strings | 14 +- .../Localizable/LocalizableNextcloud.swift | 14 ++ .../Utils/Localizable/LocalizableReport.swift | 28 ++- 35 files changed, 921 insertions(+), 169 deletions(-) create mode 100644 Tella/NewAssets.xcassets/home.nextcloud.imageset/Contents.json create mode 100644 Tella/NewAssets.xcassets/home.nextcloud.imageset/home.nextcloud.pdf create mode 100644 Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift create mode 100644 Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift create mode 100644 Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift create mode 100644 Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift create mode 100644 Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift create mode 100644 Tella/Scenes/Nextcloud/ViewModels/NextcloudMainViewModel.swift create mode 100644 Tella/Utils/Localizable/LocalizableNextcloud.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 9dec5f443..c62c36afb 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -208,6 +208,9 @@ 126FEE0A2AC4993900B99298 /* ReportPages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126FEE092AC4993900B99298 /* ReportPages.swift */; }; 127092DA2C2EE4E3002030AA /* Server.swift in Sources */ = {isa = PBXBuildFile; fileRef = 127092D92C2EE4E3002030AA /* Server.swift */; }; 127092DC2C2EE7AD002030AA /* WebServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 127092DB2C2EE7AD002030AA /* WebServer.swift */; }; + 127092D42C2D8BA5002030AA /* NextcloudDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 127092D32C2D8BA5002030AA /* NextcloudDatabase.swift */; }; + 127092D72C2DD1A1002030AA /* NextcloudServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 127092D62C2DD1A1002030AA /* NextcloudServer.swift */; }; + 127138382C35EA34004D520B /* CommonCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 127138372C35EA34004D520B /* CommonCardViewModel.swift */; }; 1272F25D27C91ACD0054F2E2 /* ImportFileProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1272F25C27C91ACD0054F2E2 /* ImportFileProgress.swift */; }; 1272F25F27C91BD70054F2E2 /* ImportFilesFromCameraProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1272F25E27C91BD70054F2E2 /* ImportFilesFromCameraProgress.swift */; }; 1272F26127C91CD90054F2E2 /* ImportFilesProgressModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1272F26027C91CD90054F2E2 /* ImportFilesProgressModels.swift */; }; @@ -318,6 +321,12 @@ 12B52580284903AE00B3D1C0 /* AboutAndHelpItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B5257F284903AE00B3D1C0 /* AboutAndHelpItem.swift */; }; 12B6481D28367C1D00CBE541 /* SheetManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B6481C28367C1D00CBE541 /* SheetManager.swift */; }; 12B6AF7D283E4C7200D697F6 /* LocalizableVault.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B6AF7C283E4C7200D697F6 /* LocalizableVault.swift */; }; + 12B84B852C32EF12006363F0 /* LocalizableNextcloud.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B84B842C32EF12006363F0 /* LocalizableNextcloud.swift */; }; + 12B84B902C333DD0006363F0 /* ReportMainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B84B8E2C333DD0006363F0 /* ReportMainViewModel.swift */; }; + 12B84B912C333DD0006363F0 /* ReportMainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B84B8F2C333DD0006363F0 /* ReportMainView.swift */; }; + 12B84B942C333FE3006363F0 /* ReportCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B84B932C333FE3006363F0 /* ReportCardViewModel.swift */; }; + 12B84B962C340025006363F0 /* NextcloudMainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B84B952C340025006363F0 /* NextcloudMainViewModel.swift */; }; + 12B84B982C3413AC006363F0 /* CommonReportListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B84B972C3413AC006363F0 /* CommonReportListView.swift */; }; 12BA188628343BE5002A11D7 /* MoreFileActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BA188528343BE5002A11D7 /* MoreFileActionButton.swift */; }; 12BAFA7728B3B8D300930451 /* UIImageOrientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BAFA7628B3B8D300930451 /* UIImageOrientation.swift */; }; 12C07ECC2B06603A0030AD6E /* EncryptionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C07ECB2B06603A0030AD6E /* EncryptionService.swift */; }; @@ -776,6 +785,7 @@ 1270EAA22A4B4B07000851BA /* my */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = my; path = my.lproj/Localizable.strings; sourceTree = ""; }; 1270EAA72A4DAA79000851BA /* fa-IR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fa-IR"; path = "fa-IR.lproj/Localizable.strings"; sourceTree = ""; }; 1270EAA82A4DB008000851BA /* ta */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ta; path = ta.lproj/Localizable.strings; sourceTree = ""; }; + 127138372C35EA34004D520B /* CommonCardViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonCardViewModel.swift; sourceTree = ""; }; 1272F25C27C91ACD0054F2E2 /* ImportFileProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportFileProgress.swift; sourceTree = ""; }; 1272F25E27C91BD70054F2E2 /* ImportFilesFromCameraProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportFilesFromCameraProgress.swift; sourceTree = ""; }; 1272F26027C91CD90054F2E2 /* ImportFilesProgressModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportFilesProgressModels.swift; sourceTree = ""; }; @@ -883,6 +893,12 @@ 12B5257F284903AE00B3D1C0 /* AboutAndHelpItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutAndHelpItem.swift; sourceTree = ""; }; 12B6481C28367C1D00CBE541 /* SheetManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheetManager.swift; sourceTree = ""; }; 12B6AF7C283E4C7200D697F6 /* LocalizableVault.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizableVault.swift; sourceTree = ""; }; + 12B84B842C32EF12006363F0 /* LocalizableNextcloud.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizableNextcloud.swift; sourceTree = ""; }; + 12B84B8E2C333DD0006363F0 /* ReportMainViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReportMainViewModel.swift; sourceTree = ""; }; + 12B84B8F2C333DD0006363F0 /* ReportMainView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReportMainView.swift; sourceTree = ""; }; + 12B84B932C333FE3006363F0 /* ReportCardViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportCardViewModel.swift; sourceTree = ""; }; + 12B84B952C340025006363F0 /* NextcloudMainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudMainViewModel.swift; sourceTree = ""; }; + 12B84B972C3413AC006363F0 /* CommonReportListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonReportListView.swift; sourceTree = ""; }; 12BA188528343BE5002A11D7 /* MoreFileActionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreFileActionButton.swift; sourceTree = ""; }; 12BAFA7628B3B8D300930451 /* UIImageOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImageOrientation.swift; sourceTree = ""; }; 12C07EC92B0660240030AD6E /* EncryptionOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionOperation.swift; sourceTree = ""; }; @@ -1603,6 +1619,34 @@ path = Upload; sourceTree = ""; }; + 125C789B2C36B36900440014 /* CommonConnectionReport */ = { + isa = PBXGroup; + children = ( + 125C789D2C36B50800440014 /* ViewModels */, + 125C789C2C36B50100440014 /* Views */, + ); + path = CommonConnectionReport; + sourceTree = ""; + }; + 125C789C2C36B50100440014 /* Views */ = { + isa = PBXGroup; + children = ( + 12B84B8F2C333DD0006363F0 /* ReportMainView.swift */, + 12B84B972C3413AC006363F0 /* CommonReportListView.swift */, + ); + path = Views; + sourceTree = ""; + }; + 125C789D2C36B50800440014 /* ViewModels */ = { + isa = PBXGroup; + children = ( + 12B84B8E2C333DD0006363F0 /* ReportMainViewModel.swift */, + 127138372C35EA34004D520B /* CommonCardViewModel.swift */, + 12B84B932C333FE3006363F0 /* ReportCardViewModel.swift */, + ); + path = ViewModels; + sourceTree = ""; + }; 125D231D271F127D00250FBB /* Extensions */ = { isa = PBXGroup; children = ( @@ -2132,6 +2176,39 @@ path = Models; sourceTree = ""; }; + 12B84B832C32E646006363F0 /* Nextcloud */ = { + isa = PBXGroup; + children = ( + 209AC67C2C2D65EB00492356 /* NextcloudAddServerURLView.swift */, + 209AC67E2C2D660600492356 /* NextcloudServerViewModel.swift */, + ); + path = Nextcloud; + sourceTree = ""; + }; + 12B84B8C2C333DD0006363F0 /* Nextcloud */ = { + isa = PBXGroup; + children = ( + 12B84B922C333F86006363F0 /* ViewModels */, + 12B84B8D2C333DD0006363F0 /* Views */, + ); + path = Nextcloud; + sourceTree = ""; + }; + 12B84B8D2C333DD0006363F0 /* Views */ = { + isa = PBXGroup; + children = ( + ); + path = Views; + sourceTree = ""; + }; + 12B84B922C333F86006363F0 /* ViewModels */ = { + isa = PBXGroup; + children = ( + 12B84B952C340025006363F0 /* NextcloudMainViewModel.swift */, + ); + path = ViewModels; + sourceTree = ""; + }; 12BCB2E62816972200889E5A /* Localizable */ = { isa = PBXGroup; children = ( @@ -2146,6 +2223,7 @@ CCE875B22A96699000C576B9 /* LocalizableUwazi.swift */, 12B370382B19109600DDA9E9 /* LocalizableBackgroundActivities.swift */, 1501401C2B71243A00991D69 /* LocalizableResources.swift */, + 12B84B842C32EF12006363F0 /* LocalizableNextcloud.swift */, ); path = Localizable; sourceTree = ""; @@ -2608,6 +2686,8 @@ D53B76DA2601C9E50001CD34 /* Scenes */ = { isa = PBXGroup; children = ( + 125C789B2C36B36900440014 /* CommonConnectionReport */, + 12B84B8C2C333DD0006363F0 /* Nextcloud */, 15B81F332C1A2779007C0E88 /* GDrive */, 15791C182B6AC32B00D67C74 /* Resources */, CC43D9DF2A72F7FB0030192E /* Uwazi */, @@ -3338,6 +3418,7 @@ E108B75729FE79340045CCBE /* UwaziServerViewModel.swift in Sources */, 1293F66A2AD7F29B00F6CFBD /* FeedbackViewModel.swift in Sources */, 1289B98B27C53C2400315FCE /* CameraTypeItemView.swift in Sources */, + 12B84B912C333DD0006363F0 /* ReportMainView.swift in Sources */, 155541B22C0672C20031D3A5 /* GDriveRepository.swift in Sources */, 126AD14A27C6D5EB00081CC9 /* LocalizableCamera.swift in Sources */, 1535A5F12BAA06490009EA42 /* DownloadedResource.swift in Sources */, @@ -3399,6 +3480,7 @@ 128B929927D796E800E92ACF /* FolderListView.swift in Sources */, 1501401D2B71243A00991D69 /* LocalizableResources.swift in Sources */, 126E813B272CAFA300688B64 /* UINavigationControllerExtension.swift in Sources */, + 12B84B852C32EF12006363F0 /* LocalizableNextcloud.swift in Sources */, 15917D752B90FCC3005655AC /* ResourceCardType.swift in Sources */, E1EAA0572AA7501800492078 /* UwaziCheckURL.swift in Sources */, 0E64C6A6265E7625005A7934 /* ActionListBottomSheet.swift in Sources */, @@ -3429,6 +3511,7 @@ 12EC94D128ABB6FA0070E72B /* SecuritySettingsView.swift in Sources */, 0D4BC3CE267668D600DCDC30 /* AddFileYellowButton.swift in Sources */, 126684412B18B67500561650 /* BackgroundActivityModel.swift in Sources */, + 12B84B962C340025006363F0 /* NextcloudMainViewModel.swift in Sources */, CCBC2F6929A93E4900888779 /* SettingCheckboxItem.swift in Sources */, 1293547B294A454900735ED0 /* AppDelegate.swift in Sources */, 127092DC2C2EE7AD002030AA /* WebServer.swift in Sources */, @@ -3535,11 +3618,14 @@ 122DBE012A5C1E0500D6561A /* Toast.swift in Sources */, 1236EE8228E1E1D700973EEA /* DatabaseExtension.swift in Sources */, 15B81F3A2C1A281C007C0E88 /* GDriveViewModel.swift in Sources */, + 12B84B942C333FE3006363F0 /* ReportCardViewModel.swift in Sources */, + 12B84B902C333DD0006363F0 /* ReportMainViewModel.swift in Sources */, 121F87AA2964383D00E6BA0D /* SubmittedReportVM.swift in Sources */, 0DD99E052692D24D009327B3 /* SwipeToDeleteView.swift in Sources */, 121C5D7529422C0800A64123 /* ProjectDetailsResult.swift in Sources */, 15EE30FE2B5073E20033BBBB /* Pages.swift in Sources */, CCC1B4272AC75A380075B819 /* CreateEntityView.swift in Sources */, + 127138382C35EA34004D520B /* CommonCardViewModel.swift in Sources */, CCF47F442ABE18D7000ABBBC /* TemplateActionType.swift in Sources */, 1251C3902BB45616002E9898 /* UwaziListView.swift in Sources */, CC0797BE2A8D46CB00AAE63F /* UnlockView.swift in Sources */, @@ -3559,6 +3645,7 @@ 1289B45A28B64221005DA687 /* UIDeviceOrientationExtension.swift in Sources */, 121C5D7729422D6800A64123 /* DataModel.swift in Sources */, 12EF3D692B136D6F007A2910 /* UpdateQuery.swift in Sources */, + 12B84B982C3413AC006363F0 /* CommonReportListView.swift in Sources */, 125A9E0028CE52C700C0C3C8 /* TellaDataBase.swift in Sources */, 126684432B18B6A400561650 /* BackgroundActivityType.swift in Sources */, 12A2DB03273576D50094B856 /* AddFileView.swift in Sources */, diff --git a/Tella/Components/Connections/Card/ConnectionCardDetail.swift b/Tella/Components/Connections/Card/ConnectionCardDetail.swift index de8726d1e..a4c2c3eb2 100644 --- a/Tella/Components/Connections/Card/ConnectionCardDetail.swift +++ b/Tella/Components/Connections/Card/ConnectionCardDetail.swift @@ -10,7 +10,7 @@ import SwiftUI struct ConnectionCardDetail: View { var title : String - var subtitle: String + var subtitle: String? var body: some View { VStack(alignment: .leading, spacing: 6) { @@ -18,10 +18,11 @@ struct ConnectionCardDetail: View { .font(.custom(Styles.Fonts.semiBoldFontName, size: 14)) .foregroundColor(.white) .lineLimit(1) - - Text(subtitle) - .font(.custom(Styles.Fonts.regularFontName, size: 12)) - .foregroundColor(.white) + if (subtitle != nil) { + Text(subtitle!) + .font(.custom(Styles.Fonts.regularFontName, size: 12)) + .foregroundColor(.white) + } } } } diff --git a/Tella/Components/Reports/Draft/DraftView.swift b/Tella/Components/Reports/Draft/DraftView.swift index 913cdfdec..5ff665eac 100644 --- a/Tella/Components/Reports/Draft/DraftView.swift +++ b/Tella/Components/Reports/Draft/DraftView.swift @@ -16,7 +16,8 @@ struct DraftView: View { @EnvironmentObject var mainAppModel: MainAppModel @EnvironmentObject var sheetManager: SheetManager - @EnvironmentObject var reportsViewModel : BaseReportsViewModel + + var reportsViewModel : ReportMainViewModel @Environment(\.presentationMode) var presentationMode: Binding var body: some View { @@ -122,11 +123,13 @@ struct DraftView: View { } var outboxDetailsView: some View { - OutboxDetailsView(appModel: mainAppModel, - reportsViewModel: reportsViewModel, - reportId: viewModel.reportId, - shouldStartUpload: true) - .environmentObject(reportsViewModel) + Text("") + +// OutboxDetailsView(appModel: mainAppModel, +// reportsViewModel: reportsViewModel, +// reportId: viewModel.reportId, +// shouldStartUpload: true) +// .environmentObject(reportsViewModel) } var photoVideoPickerView: some View { diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index 0eee58502..a0b53de9a 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -93,7 +93,7 @@ extension TellaDataBase { KeyValue(key: D.cDescription, value: report.description), KeyValue(key: D.cCreatedDate, value: Date().getDateDouble()), KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()), - KeyValue(key: D.cStatus, value: report.status?.rawValue), + KeyValue(key: D.cStatus, value: report.status.rawValue), KeyValue(key: D.cServerId, value: report.server?.id)] let reportId = try statementBuilder.insertInto(tableName: D.tGDriveReport, keyValue: reportValuesToAdd) diff --git a/Tella/Data/Database/TellaData.swift b/Tella/Data/Database/TellaData.swift index 998c3d95a..f733f1f22 100644 --- a/Tella/Data/Database/TellaData.swift +++ b/Tella/Data/Database/TellaData.swift @@ -25,6 +25,8 @@ class TellaData : ObservableObject { var shouldReloadUwaziInstances = CurrentValueSubject(false) var shouldReloadUwaziTemplates = CurrentValueSubject(false) + var shouldReloadGDriveReports = CurrentValueSubject(false) + init(database : TellaDataBase, vaultManager: VaultManagerInterface? = nil) throws { self.database = database self.vaultManager = vaultManager diff --git a/Tella/Data/Database/TellaDataBase.swift b/Tella/Data/Database/TellaDataBase.swift index 2a33220d0..4e8eafbe8 100644 --- a/Tella/Data/Database/TellaDataBase.swift +++ b/Tella/Data/Database/TellaDataBase.swift @@ -293,7 +293,7 @@ class TellaDataBase : DataBase { KeyValue(key: D.cDescription, value: report.description), KeyValue(key: D.cCreatedDate, value: Date().getDateDouble()), KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()), - KeyValue(key: D.cStatus, value: report.status?.rawValue), + KeyValue(key: D.cStatus, value: report.status.rawValue), KeyValue(key: D.cServerId, value: report.server?.id), KeyValue(key: D.cCurrentUpload, value:currentUpload )] @@ -335,10 +335,9 @@ class TellaDataBase : DataBase { keyValueArray.append(KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble())) - if let status = report.status { - keyValueArray.append(KeyValue(key: D.cStatus, value: status.rawValue)) - } - + let status = report.status + keyValueArray.append(KeyValue(key: D.cStatus, value: status.rawValue)) + if let serverId = report.server?.id { keyValueArray.append(KeyValue(key: D.cServerId, value: serverId)) } diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 3b60d1b56..872f9da20 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -231,10 +231,15 @@ class GDriveRepository: GDriveRepositoryProtocol { } -struct GDriveDIContainer { +class GDriveDIContainer : DIContainer { + let gDriveRepository: GDriveRepositoryProtocol init(gDriveRepository: GDriveRepositoryProtocol = GDriveRepository()) { self.gDriveRepository = gDriveRepository } } + +class DIContainer { + +} diff --git a/Tella/Data/Networking/Upload/BaseUploadOperation.swift b/Tella/Data/Networking/Upload/BaseUploadOperation.swift index 6a431797d..777082443 100644 --- a/Tella/Data/Networking/Upload/BaseUploadOperation.swift +++ b/Tella/Data/Networking/Upload/BaseUploadOperation.swift @@ -110,7 +110,7 @@ class BaseUploadOperation : Operation { func updateReport(apiID: String? = nil, reportStatus: ReportStatus?) { - self.report?.status = reportStatus + self.report?.status = reportStatus ?? .unknown if apiID != nil { self.report?.apiID = apiID } diff --git a/Tella/Domain/Entity/Report/Report.swift b/Tella/Domain/Entity/Report/Report.swift index 298d421a9..350a22b03 100644 --- a/Tella/Domain/Entity/Report/Report.swift +++ b/Tella/Domain/Entity/Report/Report.swift @@ -11,7 +11,7 @@ protocol BaseReportProtocol: Hashable { var description: String? { get } var createdDate: Date? { get } var updatedDate: Date? { get } - var status: ReportStatus? { get } + var status: ReportStatus { get } var reportFiles: [ReportFile]? { get } var getReportDate: String { get } @@ -24,7 +24,7 @@ class BaseReport : Hashable, Codable, BaseReportProtocol { var description : String? var createdDate : Date? var updatedDate : Date? - var status : ReportStatus? + var status : ReportStatus = .unknown var reportFiles : [ReportFile]? var currentUpload: Bool? @@ -44,7 +44,7 @@ class BaseReport : Hashable, Codable, BaseReportProtocol { description: String? = nil, createdDate: Date? = nil, updatedDate: Date? = nil, - status: ReportStatus? = nil, + status: ReportStatus, vaultFiles: [ReportFile]? = nil, currentUpload: Bool? = nil ) { self.id = id @@ -77,10 +77,8 @@ class BaseReport : Hashable, Codable, BaseReportProtocol { extension BaseReport { var getReportDate: String { - guard let status = self.status else { - return "" - } -// to do + let status = self.status + switch status { case .draft: return self.createdDate?.getDraftReportTime() ?? "" @@ -89,7 +87,7 @@ extension BaseReport { case .submissionInProgress: return "" - + case .submitted: return self.createdDate?.getSubmittedReportTime() ?? "" default: @@ -118,7 +116,13 @@ class Report: BaseReport { currentUpload: Bool? = nil) { self.server = server self.apiID = apiID - super.init(id: id, title: title, description: description, createdDate: createdDate, updatedDate: updatedDate, status: status, vaultFiles: vaultFiles, currentUpload: currentUpload) + super.init(id: id, title: title, + description: description, + createdDate: createdDate, + updatedDate: updatedDate, + status: status ?? .unknown, + vaultFiles: vaultFiles, + currentUpload: currentUpload) } required init(from decoder: any Decoder) throws { @@ -139,7 +143,7 @@ class GDriveReport: BaseReport { description: String? = nil, createdDate: Date? = nil, updatedDate: Date? = nil, - status: ReportStatus? = nil, + status: ReportStatus, server: GDriveServer? = nil, vaultFiles: [ReportFile]? = nil, currentUpload: Bool? = nil) { diff --git a/Tella/Domain/Entity/Report/ReportStatus.swift b/Tella/Domain/Entity/Report/ReportStatus.swift index 65a84c897..245f454c2 100644 --- a/Tella/Domain/Entity/Report/ReportStatus.swift +++ b/Tella/Domain/Entity/Report/ReportStatus.swift @@ -16,37 +16,104 @@ enum ReportStatus : Int, Codable { case submissionInProgress = 8 // Submission launched case submissionAutoPaused = 9 // Submission paused for auto report case submissionScheduled = 10 // Submission scheduled - } extension ReportStatus { var sheetItemTitle : String { switch self { - + case .submitted: return LocalizableReport.viewModelView.localized - + case .draft: return LocalizableReport.viewModelEdit.localized - + default: return LocalizableReport.viewModelOpen.localized } } - + var reportActionType : ReportActionType { switch self { - + case .submitted: return .viewSubmitted - + case .draft: return .editDraft - + default: return .editOutbox - + + } + } + + var listActionSheetItem : [ListActionSheetItem] { + switch self { + + case .submitted: + return [ListActionSheetItem(imageName: "view-icon", + content: LocalizableReport.viewModelView.localized, + type: ReportActionType.viewSubmitted), + ListActionSheetItem(imageName: "delete-icon-white", + content: LocalizableReport.viewModelDelete.localized, + type: UwaziActionType.delete)] + case .draft: + + return [ListActionSheetItem(imageName: "edit-icon", + content: LocalizableReport.viewModelEdit.localized, + type: ReportActionType.editDraft), + ListActionSheetItem(imageName: "delete-icon-white", + content: LocalizableReport.viewModelDelete.localized, + type: UwaziActionType.delete) ] + default: + return [ListActionSheetItem(imageName: "view-icon", + content: LocalizableReport.viewModelView.localized, + type: ReportActionType.editOutbox), + ListActionSheetItem(imageName: "delete-icon-white", + content: LocalizableReport.viewModelDelete.localized, + type: UwaziActionType.delete)] + } + } + + var deleteReportStrings: DeleteReportStrings { + switch self { + case .draft: + DeleteReportStrings(deleteTitle: LocalizableReport.deleteDraftTitle.localized, + deleteMessage: LocalizableReport.deleteDraftReportMessage.localized) + case .submitted: + + DeleteReportStrings(deleteTitle: LocalizableReport.deleteTitle.localized, + deleteMessage: LocalizableReport.deleteSubmittedReportMessage.localized) + default: + DeleteReportStrings(deleteTitle: LocalizableReport.deleteTitle.localized, + deleteMessage: LocalizableReport.deleteOutboxReportMessage.localized) + } + } + + var iconImageName: String? { + + switch self { + case .submitted: + return "submitted" + case .finalized: + return "time.yellow" + case .submissionError, .submissionPending: + return "info-icon" + case .submissionInProgress: + return "progress-circle.green" + default: + return nil } } + +} + + +struct DeleteReportStrings { + var deleteTitle : String + var deleteMessage : String + + } diff --git a/Tella/Domain/Entity/Report/ServerType.swift b/Tella/Domain/Entity/Report/ServerType.swift index 3618bbbdc..73f59abd4 100644 --- a/Tella/Domain/Entity/Report/ServerType.swift +++ b/Tella/Domain/Entity/Report/ServerType.swift @@ -8,6 +8,8 @@ enum ServerConnectionType: Int, Codable { case tella case uwazi case gDrive + case nextcloud + } extension ServerConnectionType { @@ -39,6 +41,8 @@ extension ServerConnectionType { return "uwazi.empty" case.tella: return "reports.report" + case .nextcloud: + return "home.nextcloud" } } } diff --git a/Tella/Domain/Entity/Uwazi/EntityStatus.swift b/Tella/Domain/Entity/Uwazi/EntityStatus.swift index 69672c8b9..a6dae6abd 100644 --- a/Tella/Domain/Entity/Uwazi/EntityStatus.swift +++ b/Tella/Domain/Entity/Uwazi/EntityStatus.swift @@ -22,3 +22,80 @@ enum EntityStatus:Int, Codable { return !(self == .unknown || self == .draft) } } + + +extension EntityStatus { + + + func deleteReportStrings(title:String) -> DeleteReportStrings { + switch self { + case .draft: + + return DeleteReportStrings(deleteTitle: String.init(format: LocalizableUwazi.deleteSheetTitle.localized, "\(title)"), + deleteMessage: LocalizableUwazi.deleteDraftSheetExpl.localized) + + case .submitted: + return DeleteReportStrings(deleteTitle: LocalizableUwazi.submittedDeleteSheetTitle.localized, + deleteMessage :LocalizableUwazi.submittedDeleteSheetExpl.localized) + default: + return DeleteReportStrings(deleteTitle : LocalizableUwazi.submittedDeleteSheetTitle.localized, + deleteMessage : LocalizableUwazi.outboxDeleteSheetExpl.localized) + } + + } + + + var listActionSheetItem: [ListActionSheetItem] { + + switch self { + case .draft: + return [ + ListActionSheetItem(imageName: "edit-icon", + content: LocalizableUwazi.editDraft.localized, + type: UwaziActionType.createEntity), + ListActionSheetItem(imageName: "delete-icon-white", + content: LocalizableUwazi.deleteDraft.localized, + type: UwaziActionType.delete) + ] + case .submitted: + return [ + ListActionSheetItem(imageName: "edit-icon", + content: LocalizableUwazi.viewSheetSelect.localized, + type: UwaziActionType.viewSubmittedEntity), + ListActionSheetItem(imageName: "delete-icon-white", + content: LocalizableUwazi.deleteSheetSelect.localized, + type: UwaziActionType.delete) + ] + default: + return [ + ListActionSheetItem(imageName: "view-icon", + content: LocalizableUwazi.viewSheetSelect.localized, + type: UwaziActionType.viewOutboxEntity), + ListActionSheetItem(imageName: "delete-icon-white", + content: LocalizableUwazi.deleteSheetSelect.localized, + type: UwaziActionType.delete) + ] + } + + + } + + + var iconImageName: String? { + switch self { + case .submitted: + return"submitted" + case .finalized: + return "time.yellow" + case .submissionError, .submissionPending: + return "info-icon" + case .submissionInProgress: + return "progress-circle.green" + default: + return nil + } + + } + + +} diff --git a/Tella/NewAssets.xcassets/home.nextcloud.imageset/Contents.json b/Tella/NewAssets.xcassets/home.nextcloud.imageset/Contents.json new file mode 100644 index 000000000..916bc2f31 --- /dev/null +++ b/Tella/NewAssets.xcassets/home.nextcloud.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "home.nextcloud.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Tella/NewAssets.xcassets/home.nextcloud.imageset/home.nextcloud.pdf b/Tella/NewAssets.xcassets/home.nextcloud.imageset/home.nextcloud.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7c4f73c20f4774a5c9d0f51f83000732f8376155 GIT binary patch literal 2984 zcmY!laBJnxn$y2_BT(x(#vj(b)QUMs#&X`Kk;)|=&4yXuk#)j z-s|qz`XrQ$iI>Wqw0Edn1Ren`@_~%u`=D(fOj6 zS^i>`fZJQ$cx&?`t^TgH7FPQdv@_i{Duk~)A=QWb#-CfvMmifEl&6}$UpjsB%*L2i z>DfMO1Kc&*6f7c2i_Pp4%F|*0pZx zY|%IG3iHG&&11~pt^3D>_r|`6lEQ*Z84MY-rL*;1CVZZ4HrwU7@Ty2-sfFtk?qzSy zf2gDuar+iS>hdEicPDp#cko$RsPL}ME_1JFlA8QerK8-gFFxFvz9{nSPQ}G6Hy0dz z|IDn?d*)Q$d0{^ya}RF57qwf!V9K;D$qHP-b93ZhJ>1-|pfGxWhDheBO)d`Z36~AD zZ)sOcd9G3xU+{FxB8O_l4VFh3136|bUp~+BT=fKwx6H1N=NgrYH<@a+E)(YJym7dp zug!nO6*D8|iP!x?9s8GS1%*CocKhD*;>l%efn5r0Wz$9f^z==+eIom4@7ch-H?0eE zRxz#Hxr*rtN5Iims&ke`EnWF8g9QMjGc@B?9fS=di0F+$pg>5 zHpDK^?8}Wl%iFK7YRUe{<%0g%1yUNb_g=6KQWS}ln9Omr=C+(Q>!+VW0aGWfNOxjf zY%^Ipi9?oaQgz>lV%?X42Pa>S>3YbTaIxzP=d%5RRkBlr9n)T{Hzo##b727t~NJ3)Q{s6ss;XAHqw^&Wk zdG50>T!5qA_lwK6CdVs<3JYsjE%M8I*HR?S_?vO{-Qdzqg*Ui6{6(J?uS#Nh^WR}b zp3_UesrlC$x&i}A(-Nj~vM{^same3%F27|TdwauS?s)fa_HhmAJh>N`+T4Gg%sA;< zyjw=2d#TR6RuN18JB*VhQyx#6;;>8TSlfXQb#{Lb%1!qD)WBWfV$*Z|)6|9YIE(BG zeRdUId&rw_@439a`~% zYt{%u1yHRWgs1>rD@xphOMq22Sl-nTOa=QU7H5N5kR$`*qSUmA3K^B9@2&t!a?mOr zRStuv53I`_a|$vN2^$TouQAL32|&{|+$XqynQ>mOutVVhJg0TEGQCk>r?{mtRt>5DjW#AiNZim=0@1`KG31 zCX(7%0hxqo_kfZGtg+>spI4Ha2ec6s0x-bLZ-kVLs4a9grU*M7*mz8 zIWSmJHJX|L!w^--%m`s)Nl{{EPHGVsD0n?xfPt$~oS&Pjsi2XWq6rCN{h<7OVEBT9 i4;)|m!I@R5ps)Z2ZgELsQ3*J7jLa;Ixl~nM{oMd_WXdrB literal 0 HcmV?d00001 diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift new file mode 100644 index 000000000..9ada2c1e5 --- /dev/null +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift @@ -0,0 +1,48 @@ +// +// CommonCardViewModel.swift +// Tella +// +// Created by Dhekra Rouatbi on 3/7/2024. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +class CommonCardViewModel: Hashable { + + var id : Int + var title: String + var iconImageName: String? + var serverName: String? + var listActionSheetItem: [ListActionSheetItem] + var connectionType: ServerConnectionType + var deleteReportStrings : DeleteReportStrings + var deleteAction: (() -> Void) + + init(id: Int, title: String, + iconImageName: String?, + serverName: String?, + listActionSheetItem: [ListActionSheetItem], + connectionType: ServerConnectionType, + deleteReportStrings: DeleteReportStrings, + deleteAction: @escaping (() -> Void)) { + + self.id = id + self.title = title + self.iconImageName = iconImageName + self.serverName = serverName + self.listActionSheetItem = listActionSheetItem + self.connectionType = connectionType + self.deleteReportStrings = deleteReportStrings + self.deleteAction = deleteAction + } + + static func == (lhs: CommonCardViewModel, rhs: CommonCardViewModel) -> Bool { + lhs.id == rhs.id + } + + func hash(into hasher: inout Hasher) { + hasher.combine(id) + } + +} diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift new file mode 100644 index 000000000..841abb0eb --- /dev/null +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift @@ -0,0 +1,38 @@ +// +// ReportCardViewModel.swift +// Tella +// +// Created by Dhekra Rouatbi on 1/7/2024. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + + +class ReportCardViewModel: CommonCardViewModel { + + var status : ReportStatus = ReportStatus.unknown + + init(report : BaseReport, + serverName : String?, + deleteReport: @escaping (() -> Void)) { + + let title = report.title ?? "" + let serverName = serverName + let iconImageName : String? = report.status.iconImageName + let listActionSheetItem = report.status.listActionSheetItem + let deleteReportStrings = report.status.deleteReportStrings + + super.init(id: Int(UUID().uuidString) ?? 0, + title: title, + iconImageName: iconImageName, + serverName: serverName, + listActionSheetItem: listActionSheetItem, + connectionType: .uwazi, + deleteReportStrings: deleteReportStrings, + deleteAction:deleteReport) + + self.deleteAction = deleteReport + self.status = report.status + } +} diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift new file mode 100644 index 000000000..ffd997d35 --- /dev/null +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift @@ -0,0 +1,65 @@ +// +// ReportMainViewModel.swift +// Tella +// +// Created by Dhekra Rouatbi on 1/7/2024. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation +import Combine + +class ReportMainViewModel: ObservableObject { + + @Published var draftReportsViewModel : [CommonCardViewModel] = [] + @Published var outboxedReportsViewModel : [CommonCardViewModel] = [] + @Published var submittedReportsViewModel : [CommonCardViewModel] = [] + + @Published var selectedCell = Pages.template + + @Published var isLoading: Bool = false + @Published var shouldShowToast : Bool = false + @Published var toastMessage : String = "" + + var pageViewItems : [PageViewItem] { + + [PageViewItem(title: LocalizableUwazi.uwaziPageViewDraft.localized, + page: .draft, + number: draftReportsViewModel.count), + PageViewItem(title: LocalizableUwazi.uwaziPageViewOutbox.localized, + page: .outbox, + number: outboxedReportsViewModel.count), + PageViewItem(title: LocalizableUwazi.uwaziPageViewSubmitted.localized, + page: .submitted, + number: submittedReportsViewModel.count)] + } + + var mainAppModel : MainAppModel + + var tellaData: TellaData? { + return self.mainAppModel.tellaData + } + + var subscribers = Set() + + var connectionType : ServerConnectionType + var title : String + + init(mainAppModel : MainAppModel, connectionType : ServerConnectionType, title:String) { + + self.mainAppModel = mainAppModel + self.connectionType = connectionType + self.title = title + + self.getReports() + self.listenToUpdates() + } + + func getReports() { + } + + func listenToUpdates() { + } +} + + diff --git a/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift b/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift new file mode 100644 index 000000000..057aefe06 --- /dev/null +++ b/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift @@ -0,0 +1,97 @@ +// +// ReportListView.swift +// Tella +// +// Created by Dhekra Rouatbi on 2/7/2024. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +import SwiftUI + +struct CommonReportListView: View { + + var message: String + var emptyMessage: String + + @Binding var cardsViewModel: [CommonCardViewModel] +// @EnvironmentObject var sheetManager: SheetManager + var showDetails: ((CommonCardViewModel) -> Void) + var showBottomSheet: ((CommonCardViewModel) -> Void) + + var body: some View { + + VStack(alignment: .center, spacing: 0) { + + if cardsViewModel.isEmpty { + + ConnectionEmptyView(message: emptyMessage, type: .uwazi) + + } else { + + Text(message) + .font(.custom(Styles.Fonts.regularFontName, size: 14)) + .foregroundColor(.white.opacity(0.64)) + .padding(.all, 15) + + ScrollView { + ForEach($cardsViewModel, id: \.id) { itemViewModel in + + CommonItemView(cardViewModel: itemViewModel , +// showDetails: {showDetailsView(cardViewModel: itemViewModel.wrappedValue)}, + showDetails: {showDetails(itemViewModel.wrappedValue)}, + showBottomSheet: {showBottomSheet(itemViewModel.wrappedValue)}) + } + } + } + } + } + + + + +} + +struct CommonItemView: View { + + @EnvironmentObject var mainAppModel: MainAppModel + + @EnvironmentObject var sheetManager: SheetManager + @Binding var cardViewModel: CommonCardViewModel + + var showDetails: (() -> Void) + var showBottomSheet: (() -> Void) + + var body: some View { + + CardFrameView(padding: EdgeInsets(top: 6, leading: 0, bottom: 0, trailing: 0)) { + + Button(action: showDetails ) { + + HStack { + + if (cardViewModel.iconImageName != nil) { + Image(cardViewModel.iconImageName!) + Spacer() + .frame(width: 12) + } + + ConnectionCardDetail(title: cardViewModel.title, + subtitle: cardViewModel.serverName) + + Spacer() + + ImageButtonView(imageName: "reports.more", + action: showBottomSheet) + + }.padding(.all, 16) + } + } + } + + + +} + + diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift new file mode 100644 index 000000000..bc43f791b --- /dev/null +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -0,0 +1,197 @@ +// +// ReportMainView.swift +// Tella +// +// Created by Dhekra Rouatbi on 1/7/2024. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation +import SwiftUI + +struct ReportMainView: View { + + @State var reportMainViewModel: ReportMainViewModel + @EnvironmentObject var sheetManager: SheetManager + @EnvironmentObject var mainAppModel: MainAppModel + + + let diContainer : DIContainer + + init(reportMainViewModel: ReportMainViewModel, diContainer : DIContainer) { + self.reportMainViewModel = reportMainViewModel + self.diContainer = diContainer + } + + var body: some View { + contentView + .navigationBarTitle(self.reportMainViewModel.title, displayMode: .large) + .environmentObject(reportMainViewModel) + } + + private var contentView :some View { + + ContainerView { + VStack(alignment: .center) { + + PageView(selectedOption: $reportMainViewModel.selectedCell, pageViewItems: reportMainViewModel.pageViewItems) + .frame(maxWidth: .infinity, maxHeight: 40, alignment: .leading) + + VStack (spacing: 0) { + Spacer() + + switch self.reportMainViewModel.selectedCell { + + case .draft: + CommonReportListView(message: LocalizableReport.draftListExpl.localized, + emptyMessage: LocalizableReport.reportsDraftEmpty.localized, + cardsViewModel: $reportMainViewModel.draftReportsViewModel, + showDetails: showDetailsView(cardViewModel: ), + showBottomSheet: showBottomSheet(cardViewModel:)) + + case .outbox: + CommonReportListView(message: LocalizableReport.outboxListExpl.localized, + emptyMessage: LocalizableReport.reportsOutboxEmpty.localized, + cardsViewModel: $reportMainViewModel.outboxedReportsViewModel, + showDetails: showDetailsView(cardViewModel: ), + showBottomSheet: showBottomSheet(cardViewModel:)) + + case .submitted: + CommonReportListView(message: LocalizableReport.submittedListExpl.localized, + emptyMessage: LocalizableReport.reportsSubmitedEmpty.localized, + cardsViewModel: $reportMainViewModel.submittedReportsViewModel, + showDetails: showDetailsView(cardViewModel: ), + showBottomSheet: showBottomSheet(cardViewModel:)) + default: + EmptyView() + } + + Spacer() + } + + TellaButtonView (title: LocalizableReport.reportsCreateNew.localized, + nextButtonAction: .action, + buttonType: .yellow, + isValid: .constant(true)) { + showDraftView() + } .padding(EdgeInsets(top: 30, leading: 0, bottom: 0, trailing: 0)) + + }.background(Styles.Colors.backgroundMain) + .padding(EdgeInsets(top: 15, leading: 20, bottom: 16, trailing: 20)) + } + .navigationBarBackButtonHidden(true) + .navigationBarItems(leading: backButton) + .onReceive(reportMainViewModel.$shouldShowToast) { shouldShowToast in + if shouldShowToast { + Toast.displayToast(message: reportMainViewModel.toastMessage) + } + } + + } + + var backButton : some View { + Button { + self.popToRoot() + } label: { + Image("back") + .flipsForRightToLeftLayoutDirection(true) + .padding(EdgeInsets(top: -3, leading: -8, bottom: 0, trailing: 12)) + } + } + + + private func showBottomSheet(cardViewModel:CommonCardViewModel) { + sheetManager.showBottomSheet(modalHeight: 176) { + + ActionListBottomSheet(items: cardViewModel.listActionSheetItem, + headerTitle: cardViewModel.title, + action: {item in + guard let type = item.type as? ReportActionType else {return} + let id = cardViewModel.id + + switch type { + case .editDraft: + showDraftView(id: id) + + case .editOutbox: + showOutboxView() + + case .viewSubmitted: + showSubmittedEntityView() + sheetManager.hide() + + case .delete: + showDeleteReportConfirmationView(cardViewModel: cardViewModel) + + } + }) + } + } + + private func showDetailsView(cardViewModel:CommonCardViewModel) { + + guard let cardViewModel = cardViewModel as? ReportCardViewModel else { return } + switch cardViewModel.status { + case .unknown, .draft: + showDraftView(id: cardViewModel.id) + sheetManager.hide() + case .submitted: + sheetManager.hide() + default: + sheetManager.hide() + } + } + + private func showDraftView(id:Int? = nil) { + + switch reportMainViewModel.connectionType { + case .tella: + break + case .gDrive: + var destination : any View + let draftViewModel = GDriveDraftViewModel(mainAppModel: mainAppModel, + repository: (diContainer as! GDriveDIContainer).gDriveRepository, + reportID: id) + destination = DraftView(viewModel:draftViewModel, reportsViewModel: reportMainViewModel) + self.navigateTo(destination: destination) + + case .nextcloud: + var destination : any View + let draftViewModel = GDriveDraftViewModel(mainAppModel: mainAppModel, + repository: (diContainer as! GDriveDIContainer).gDriveRepository, + reportID: id) + destination = DraftView(viewModel:draftViewModel, reportsViewModel: reportMainViewModel) + self.navigateTo(destination: destination) + + default: + break + } + sheetManager.hide() + } + + private func showOutboxView() { + sheetManager.hide() + } + + private func showSubmittedEntityView() { + sheetManager.hide() + } + + private func showDeleteReportConfirmationView(cardViewModel:CommonCardViewModel) { + + sheetManager.showBottomSheet(modalHeight: 200) { + return ConfirmBottomSheet(titleText: cardViewModel.deleteReportStrings.deleteTitle, + msgText: cardViewModel.deleteReportStrings.deleteMessage, + cancelText: LocalizableReport.deleteCancel.localized, + actionText: LocalizableReport.deleteConfirm.localized) { + cardViewModel.deleteAction() + } + } + } +} + +struct ReportMainView_Previews: PreviewProvider { + static var previews: some View { + UwaziView() + } +} diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index 7c2368242..cbd07424c 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -135,7 +135,7 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { id: reportId, title: title, description: description, - status: status, + status: status ?? .unknown, server: server, vaultFiles: self.files.compactMap { ReportFile( fileId: $0.id, status: .notSubmitted, diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift index 2b8e931ee..76e8d567a 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -31,8 +31,8 @@ class GDriveViewModel: BaseReportsViewModel { var sheetItems : [ListActionSheetItem] { return [ ListActionSheetItem(imageName: "view-icon", - content: self.selectedReport?.status?.sheetItemTitle ?? "", - type: self.selectedReport?.status?.reportActionType ?? .viewSubmitted), + content: self.selectedReport?.status.sheetItemTitle ?? "", + type: self.selectedReport?.status.reportActionType ?? .viewSubmitted), ListActionSheetItem(imageName: "delete-icon-white", content: LocalizableReport.viewModelDelete.localized, type: ReportActionType.delete) diff --git a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift index ccb25f28f..4a2be01a6 100644 --- a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift +++ b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift @@ -24,9 +24,11 @@ struct GDriveDraftView: View { } var body: some View { - DraftView(viewModel: gDriveDraftVM) - .environmentObject(mainAppModel) - .environmentObject(reportsViewModel) + Text("") + +// DraftView(viewModel: gDriveDraftVM, reportsViewModel: <#ReportMainViewModel#>) +// .environmentObject(mainAppModel) +// .environmentObject(reportsViewModel) } } diff --git a/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift b/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift index f28e68a0a..7abd22625 100644 --- a/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift +++ b/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift @@ -22,7 +22,7 @@ struct GDriveCardView : View { reportsViewModel.selectedReport = report DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) { - self.handleActions(type: report.status?.reportActionType) + self.handleActions(type: report.status.reportActionType) } } label: { @@ -112,7 +112,7 @@ struct GDriveCardView : View { case .draft: return LocalizableReport.deleteDraftReportMessage.localized case .submitted: - return LocalizableReport.DeleteSubmittedReportMessage.localized + return LocalizableReport.deleteSubmittedReportMessage.localized default: return LocalizableReport.deleteOutboxReportMessage.localized } diff --git a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift index 2a4f7ac86..a01954b18 100644 --- a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift +++ b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift @@ -55,14 +55,32 @@ struct ConnectionsView: View { case .gDrive: ConnectionsItemView(title: "Drive", image: "home.drive", - destination: GDriveView(mainAppModel: appModel)) + destination: gDriveMainView) + case .nextcloud: + + ConnectionsItemView(title: LocalizableNextcloud.nextcloudAppBar.localized, + image: "home.nextcloud", + destination:nextcloudMainView) } - } + Spacer() + }.padding(.trailing, 17) - Spacer() - }.padding(.trailing, 17) - + } + } + + var gDriveMainView : some View { + ReportMainView(reportMainViewModel: NextcloudMainViewModel(mainAppModel: appModel, + connectionType: .gDrive, + title: "Drive"), + diContainer: GDriveDIContainer()) + } + + var nextcloudMainView : some View { + ReportMainView(reportMainViewModel: NextcloudMainViewModel(mainAppModel: appModel, + connectionType: .nextcloud, + title: LocalizableNextcloud.nextcloudAppBar.localized), + diContainer: GDriveDIContainer()) } } diff --git a/Tella/Scenes/Nextcloud/ViewModels/NextcloudMainViewModel.swift b/Tella/Scenes/Nextcloud/ViewModels/NextcloudMainViewModel.swift new file mode 100644 index 000000000..48384aff6 --- /dev/null +++ b/Tella/Scenes/Nextcloud/ViewModels/NextcloudMainViewModel.swift @@ -0,0 +1,61 @@ +// +// GDriveMainViewModel.swift +// Tella +// +// Created by Dhekra Rouatbi on 2/7/2024. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation +import Combine + +class NextcloudMainViewModel: ReportMainViewModel { + + override func getReports() { + + let draftReports = tellaData?.database.getDraftGDriveReports() ?? [] + let outboxedReports = tellaData?.database.getDraftGDriveReports() ?? [] + let submittedReports = tellaData?.database.getDraftGDriveReports() ?? [] + + draftReportsViewModel = draftReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: {self.deleteReport(report: report)}) + } + + outboxedReportsViewModel = outboxedReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: {self.deleteReport(report: report)}) + } + + submittedReportsViewModel = submittedReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: {self.deleteReport(report: report)}) + } + } + + override func listenToUpdates() { + self.mainAppModel.tellaData?.shouldReloadGDriveReports + .receive(on: DispatchQueue.main) + .sink { result in + } receiveValue: { draftReports in + self.getReports() + }.store(in: &subscribers) + } + + func deleteReport(report:GDriveReport) { + guard let reportId = report.id else { return } + // let resultDeletion = self.tellaData?.deleteGDriveReport(reportId: reportId) + var message = "" + // if case .success = resultDeletion { + // message = String.init(format: LocalizableUwazi.uwaziDeletedToast.localized, entity.title ?? "") + // } else { + // message = LocalizableCommon.commonError.localized + // } + + self.shouldShowToast = true + self.toastMessage = message + } +} diff --git a/Tella/Scenes/Reports/Draft/DraftReportView.swift b/Tella/Scenes/Reports/Draft/DraftReportView.swift index 0a98b653e..228fa892f 100644 --- a/Tella/Scenes/Reports/Draft/DraftReportView.swift +++ b/Tella/Scenes/Reports/Draft/DraftReportView.swift @@ -22,8 +22,9 @@ struct DraftReportView: View { } var body: some View { - DraftView(viewModel: reportViewModel) - .environmentObject(reportsViewModel) + Text("") +// DraftView(viewModel: reportViewModel, reportsViewModel: <#ReportMainViewModel#>) +// .environmentObject(reportsViewModel) } } diff --git a/Tella/Scenes/Reports/ReportList/ReportCardView.swift b/Tella/Scenes/Reports/ReportList/ReportCardView.swift index 3100b7dcd..4a31f5d45 100644 --- a/Tella/Scenes/Reports/ReportList/ReportCardView.swift +++ b/Tella/Scenes/Reports/ReportList/ReportCardView.swift @@ -18,7 +18,7 @@ struct ReportCardView : View { reportsViewModel.selectedReport = report DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) { - self.handleActions(type: report.status?.reportActionType) + self.handleActions(type: report.status.reportActionType) } } label: { @@ -107,7 +107,7 @@ struct ReportCardView : View { case .draft: return LocalizableReport.deleteDraftReportMessage.localized case .submitted: - return LocalizableReport.DeleteSubmittedReportMessage.localized + return LocalizableReport.deleteSubmittedReportMessage.localized default: return LocalizableReport.deleteOutboxReportMessage.localized } diff --git a/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift b/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift index e58b2eaf0..809eaf42c 100644 --- a/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift +++ b/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift @@ -140,7 +140,7 @@ struct SubmittedDetailsView: View { private func showDeleteReportConfirmationView() { sheetManager.showBottomSheet(modalHeight: 200) { DeleteReportConfirmationView(title: submittedReportVM.title, - message: LocalizableReport.DeleteSubmittedReportMessage.localized) { + message: LocalizableReport.deleteSubmittedReportMessage.localized) { dismissViews() submittedReportVM.deleteReport() sheetManager.hide() diff --git a/Tella/Scenes/Reports/View Model/ReportsViewModel.swift b/Tella/Scenes/Reports/View Model/ReportsViewModel.swift index 6812a0703..7b23baf4f 100644 --- a/Tella/Scenes/Reports/View Model/ReportsViewModel.swift +++ b/Tella/Scenes/Reports/View Model/ReportsViewModel.swift @@ -22,8 +22,8 @@ class ReportsViewModel: BaseReportsViewModel { var sheetItems : [ListActionSheetItem] { return [ ListActionSheetItem(imageName: "view-icon", - content: self.selectedReport?.status?.sheetItemTitle ?? "", - type: self.selectedReport?.status?.reportActionType ?? .viewSubmitted), + content: self.selectedReport?.status.sheetItemTitle ?? "", + type: self.selectedReport?.status.reportActionType ?? .viewSubmitted), ListActionSheetItem(imageName: "delete-icon-white", content: LocalizableReport.viewModelDelete.localized, type: ReportActionType.delete) diff --git a/Tella/Scenes/Uwazi/Models/TemplateActionType.swift b/Tella/Scenes/Uwazi/Models/TemplateActionType.swift index 3ff06edfe..1a47f4a53 100644 --- a/Tella/Scenes/Uwazi/Models/TemplateActionType.swift +++ b/Tella/Scenes/Uwazi/Models/TemplateActionType.swift @@ -35,33 +35,3 @@ var downloadTemplateActionItems : [ListActionSheetItem] { return [ type: UwaziActionType.delete) ] } - -var uwaziDraftActionItems : [ListActionSheetItem] { return [ - ListActionSheetItem(imageName: "edit-icon", - content: LocalizableUwazi.editDraft.localized, - type: UwaziActionType.createEntity), - ListActionSheetItem(imageName: "delete-icon-white", - content: LocalizableUwazi.deleteDraft.localized, - type: UwaziActionType.delete) - ] -} - -var uwaziOutboxActionItems : [ListActionSheetItem] { return [ - ListActionSheetItem(imageName: "edit-icon", - content: LocalizableUwazi.viewSheetSelect.localized, - type: UwaziActionType.viewOutboxEntity), - ListActionSheetItem(imageName: "delete-icon-white", - content: LocalizableUwazi.deleteSheetSelect.localized, - type: UwaziActionType.delete) - ] -} - -var uwaziSubmittedActionItems : [ListActionSheetItem] { return [ - ListActionSheetItem(imageName: "edit-icon", - content: LocalizableUwazi.viewSheetSelect.localized, - type: UwaziActionType.viewSubmittedEntity), - ListActionSheetItem(imageName: "delete-icon-white", - content: LocalizableUwazi.deleteSheetSelect.localized, - type: UwaziActionType.delete) - ] -} diff --git a/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift b/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift index 749f734a9..c9b85029c 100644 --- a/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift +++ b/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift @@ -14,95 +14,59 @@ enum CardType { case entityInstance } -class UwaziCardViewModel: Hashable { - - var id : String +class UwaziCardViewModel: CommonCardViewModel { var templateId : Int? var entityInstanceID : Int? - - var title: String - var deleteAction: (() -> Void) - var serverName: String var serverId: Int? var status : EntityStatus = EntityStatus.unknown - - var deleteTitle: String - var deleteMessage: String - var listActionSheetItem: [ListActionSheetItem] - var type : CardType - - var iconImageName: String? = nil + var type : CardType = .entityInstance init(template : CollectedTemplate, deleteTemplate: @escaping (() -> Void)) { - self.id = UUID().uuidString + + let title = template.entityRow?.translatedName ?? "" + let deleteTitle = String.init(format: LocalizableUwazi.deleteSheetTitle.localized, "\(title)") + let deleteMessage = LocalizableUwazi.uwaziDeleteTemplateExpl.localized + let deleteReportStrings = DeleteReportStrings(deleteTitle: deleteTitle, + deleteMessage: deleteMessage) + super.init(id: Int(UUID().uuidString) ?? 0, + title: title, + iconImageName: nil, + serverName: template.serverName ?? "", + listActionSheetItem: downloadTemplateActionItems, + connectionType: .uwazi, + deleteReportStrings: deleteReportStrings, + deleteAction: deleteTemplate) self.templateId = template.id - self.title = template.entityRow?.translatedName ?? "" - self.deleteAction = deleteTemplate self.serverId = template.serverId - self.serverName = template.serverName ?? "" - - let titleText = String.init(format: LocalizableUwazi.deleteSheetTitle.localized, "\(self.title)") - self.deleteTitle = titleText - self.deleteMessage = LocalizableUwazi.uwaziDeleteTemplateExpl.localized - listActionSheetItem = downloadTemplateActionItems - type = .template } init(instance : UwaziEntityInstance, deleteTemplate: @escaping (() -> Void)) { - self.id = UUID().uuidString + let title = instance.title ?? "" + let serverName = instance.server?.name ?? "" + let iconImageName : String? = instance.status.iconImageName + let listActionSheetItem = instance.status.listActionSheetItem + let deleteReportStrings = instance.status.deleteReportStrings(title: title) + + super.init(id: Int(UUID().uuidString) ?? 0, + title: title, + iconImageName: iconImageName, + serverName: serverName, + listActionSheetItem: listActionSheetItem, + connectionType: .uwazi, + deleteReportStrings: deleteReportStrings, + deleteAction:deleteTemplate) self.entityInstanceID = instance.id self.templateId = instance.templateId - self.title = instance.title ?? "" - self.deleteAction = deleteTemplate - self.serverName = instance.server?.name ?? "" self.status = instance.status - - let titleText = String.init(format: LocalizableUwazi.deleteSheetTitle.localized, "\(self.title)") - - switch instance.status { - case .draft: - self.deleteTitle = titleText - self.deleteMessage = LocalizableUwazi.deleteDraftSheetExpl.localized - listActionSheetItem = uwaziDraftActionItems - case .submitted: - self.deleteTitle = LocalizableUwazi.submittedDeleteSheetTitle.localized - self.deleteMessage = LocalizableUwazi.submittedDeleteSheetExpl.localized - listActionSheetItem = uwaziSubmittedActionItems - default: - self.deleteTitle = LocalizableUwazi.submittedDeleteSheetTitle.localized - self.deleteMessage = LocalizableUwazi.outboxDeleteSheetExpl.localized - listActionSheetItem = uwaziOutboxActionItems - } - - switch instance.status { - case .submitted: - iconImageName = "submitted" - case .finalized: - iconImageName = "time.yellow" - case .submissionError, .submissionPending: - iconImageName = "info-icon" - case .submissionInProgress: - iconImageName = "progress-circle.green" - default: - break - } - type = .entityInstance } - static func == (lhs: UwaziCardViewModel, rhs: UwaziCardViewModel) -> Bool { - lhs.id == rhs.id - } - - func hash(into hasher: inout Hasher) { - hasher.combine(id) - } } diff --git a/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift b/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift index 6ff4a361b..bb2006784 100644 --- a/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift +++ b/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift @@ -136,8 +136,8 @@ struct EntityInstanceItemView: View { private func showDeleteTemplateConfirmationView() { sheetManager.showBottomSheet(modalHeight: 200) { - return ConfirmBottomSheet(titleText: cardViewModel.deleteTitle, - msgText: cardViewModel.deleteMessage, + return ConfirmBottomSheet(titleText: cardViewModel.deleteReportStrings.deleteTitle, + msgText: cardViewModel.deleteReportStrings.deleteMessage, cancelText: LocalizableUwazi.noSheetAction.localized, actionText: LocalizableUwazi.yesSheetAction.localized) { cardViewModel.deleteAction() diff --git a/Tella/Supporting Files/en.lproj/Localizable.strings b/Tella/Supporting Files/en.lproj/Localizable.strings index 33ee9b311..d61548126 100644 --- a/Tella/Supporting Files/en.lproj/Localizable.strings +++ b/Tella/Supporting Files/en.lproj/Localizable.strings @@ -289,6 +289,12 @@ If you want to take a picture or a video, proceed in the following way:\ "Settings_SettAbout_PrivacyPolicy" = "Privacy policy"; "Reports_AppBar" = "Reports"; "Reports_Report_AppBar" = "Report"; + + +"Reports_Draft_DraftList_Expl" = "These are reports you are working on."; +"Reports_Outbox_OutboxList_Expl" = "These reports are ready to be submitted"; +"Reports_Submitted_SubmittedList_Expl" = ""; + "Reports_Draft_EmptyAllFiles_Expl" = "Your Drafts is currently empty. Reports that you have not submitted will appear here."; "Reports_Outbox_EmptyAllFiles_Expl" = "Your Outbox is currently empty. Reports that are ready to be sent will appear here."; "Reports_Submitted_EmptyAllFiles_Expl" = "You have no submitted reports."; @@ -307,7 +313,7 @@ If you want to take a picture or a video, proceed in the following way:\ "Reports_Draft_ExitReport_Save_SheetAction" = "save and exit"; "Reports_Draft_AddFiles" = "Attach files here"; "Reports_DeleteReport_SheetTitle" = "Delete report"; -"Reports_DeleteReport_SheetExpl" = "Are you sure you want to delete this draft?"; +"Reports_DeleteReport_Draft_SheetTitle" = "Delete report"; "Reports_DeleteReport_Cancel_SheetAction" = "CANCEL"; "Reports_DeleteReport_Delete_SheetAction" = "DELETE"; "Reports_PageViewItem_Draft" = "Drafts"; @@ -315,7 +321,7 @@ If you want to take a picture or a video, proceed in the following way:\ "Reports_PageViewItem_Submitted" = "Submitted"; "Reports_ManageReport_Delete_SheetAction" = "Delete"; "Reports_ManageReport_View_SheetAction" = "View"; -"Reports_ManageReport_Edit_SheetAction" = "Edit"; +"Reports_ManageReport_Edit_SheetAction" = "Edit report"; "Reports_ManageReport_Open_SheetAction" = "Open"; "Reports_Draft_Select_SelectProject" = "Select your project"; "Reports_Draft_SelectFiles_TakePhotoVideo_SheetSelect" = "Take photo or video with camera"; @@ -527,3 +533,7 @@ This feedback is anonymous, so make sure to include contact information if you w "Resource_Exit_SheetExpl" = "Your download progress will be lost. You can always come back later to download the resource again."; "Resource_Exit_Confirm_SheetSelect" = "EXIT"; "Resource_Exit_Cancel_SheetSelect" = "KEEP DOWNLOADING"; + + + +"Nextcloud_AppBar" = "Nextcloud"; diff --git a/Tella/Utils/Localizable/LocalizableNextcloud.swift b/Tella/Utils/Localizable/LocalizableNextcloud.swift new file mode 100644 index 000000000..30e781522 --- /dev/null +++ b/Tella/Utils/Localizable/LocalizableNextcloud.swift @@ -0,0 +1,14 @@ +// +// LocalizableNextcloud.swift +// Tella +// +// Created by Dhekra Rouatbi on 1/7/2024. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +enum LocalizableNextcloud : String, LocalizableDelegate { + case nextcloudAppBar = "Nextcloud_AppBar" + +} diff --git a/Tella/Utils/Localizable/LocalizableReport.swift b/Tella/Utils/Localizable/LocalizableReport.swift index ec2590ce7..682b5cf18 100644 --- a/Tella/Utils/Localizable/LocalizableReport.swift +++ b/Tella/Utils/Localizable/LocalizableReport.swift @@ -16,31 +16,33 @@ enum LocalizableReport: String, LocalizableDelegate { case reportsOutboxEmpty = "Reports_Outbox_EmptyAllFiles_Expl" case reportsSubmitedEmpty = "Reports_Submitted_EmptyAllFiles_Expl" case reportsCreateNew = "Reports_Action_NewReport" - + case reportsListTitle = "Reports_Draft_Select_Title" case reportsListDescription = "Reports_Draft_Select_Description" case reportsListMessage = "Reports_Draft_Select_Message" - + case reportsSendTo = "Reports_Draft_SendTo" case audioSavedCorrectly = "Reports_Draft_SuccessMessage" case reportsSubmit = "Reports_Draft_Action_Submit" case reportsSend = "Reports_Draft__Action_Send" case selectFiles = "Reports_Draft_SelectFiles" - + case exitTitle = "Reports_Draft_ExitReport_SheetTitle" case exitMessage = "Reports_Draft_ExitReport_SheetExpl" case exitCancel = "Reports_Draft_ExitReport_Exit_SheetAction" case exitSave = "Reports_Draft_ExitReport_Save_SheetAction" - + case attachFiles = "Reports_Draft_AddFiles" - + case deleteTitle = "Reports_DeleteReport_SheetTitle" + case deleteDraftTitle = "Reports_DeleteReport_Draft_SheetTitle" + case deleteDraftReportMessage = "Reports_DeleteDraftReport_SheetExpl" case deleteOutboxReportMessage = "Reports_DeleteOutboxReport_SheetExpl" - case DeleteSubmittedReportMessage = "Reports_DeleteSubmittedReport_SheetExpl" + case deleteSubmittedReportMessage = "Reports_DeleteSubmittedReport_SheetExpl" case deleteCancel = "Reports_DeleteReport_Cancel_SheetAction" case deleteConfirm = "Reports_DeleteReport_Delete_SheetAction" - + case draftTitle = "Reports_PageViewItem_Draft" case outboxTitle = "Reports_PageViewItem_Outbox" case submittedTitle = "Reports_PageViewItem_Submitted" @@ -49,24 +51,28 @@ enum LocalizableReport: String, LocalizableDelegate { case clearSheetExpl = "Reports_Submitted_ClearAll_SheetExpl" case clearCancel = "Reports_Submitted_ClearAll_Cancel_SheetAction" case clearSubmitted = "Reports_Submitted_ClearAll_ClearSubmitted_SheetAction" - + case viewModelDelete = "Reports_ManageReport_Delete_SheetAction" case viewModelEdit = "Reports_ManageReport_Edit_SheetAction" case viewModelView = "Reports_ManageReport_View_SheetAction" case viewModelOpen = "Reports_ManageReport_Open_SheetAction" case selectProject = "Reports_Draft_Select_SelectProject" - + case cameraFilled = "Reports_Draft_SelectFiles_TakePhotoVideo_SheetSelect" case micFilled = "Reports_Draft_Record_SheetSelect" case galleryFilled = "Reports_Draft_SelectFiles_TellaFiles_SheetSelect" case phoneFilled = "Reports_Draft_SelectFiles_ImportFromDevice_SheetSelect" case waitingConnection = "Reports_Outbox_PercentangeUploaded_Expl" - - + + case draftSavedToast = "Reports_DraftSaved_Toast" case reportDeletedToast = "Reports_ReportDeleted_Toast" case reportSubmittedToast = "Reports_ReportSubmitted_Toast" case outboxSavedToast = "Reports_OutboxSaved_Toast" case allReportDeletedToast = "Reports_AllReportDeleted_Toast" + case draftListExpl = "Reports_Draft_DraftList_Expl" + case outboxListExpl = "Reports_Outbox_OutboxList_Expl" + case submittedListExpl = "Reports_Submitted_SubmittedList_Expl" + } From b8ffc110db07338d00aa8637eae3d512846bd9ff Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 4 Jul 2024 12:17:25 -0300 Subject: [PATCH 073/167] update and delete draft report --- .../Reports/Draft/AddFilesToDraftView.swift | 3 +- .../Draft/DraftViewModelProtocol.swift | 1 + Tella/Data/Database/GDriveData.swift | 20 +++++- Tella/Data/Database/GDriveDatabase.swift | 62 ++++++++++++++++++- Tella/Data/Database/TellaData.swift | 4 ++ .../ViewModel/GDriveDraftViewModel.swift | 14 ++++- .../GDrive/ViewModel/GDriveViewModel.swift | 25 +++++++- .../Reports/Draft/ReportFileGridView.swift | 4 +- 8 files changed, 122 insertions(+), 11 deletions(-) diff --git a/Tella/Components/Reports/Draft/AddFilesToDraftView.swift b/Tella/Components/Reports/Draft/AddFilesToDraftView.swift index 3b38cd0b0..4c8f7c753 100644 --- a/Tella/Components/Reports/Draft/AddFilesToDraftView.swift +++ b/Tella/Components/Reports/Draft/AddFilesToDraftView.swift @@ -41,8 +41,9 @@ struct AddFilesToDraftView: View { var itemsGridView: some View { LazyVGrid(columns: gridLayout, alignment: .center, spacing: 12) { ForEach(draftReportVM.files.sorted{$0.created < $1.created}, id: \.id) { file in - ReportFileGridView(file: file) + ReportFileGridView(file: file) .frame(height: (UIScreen.screenWidth - 64) / 3 ) + .environmentObject(draftReportVM) } } } diff --git a/Tella/Components/Reports/Draft/DraftViewModelProtocol.swift b/Tella/Components/Reports/Draft/DraftViewModelProtocol.swift index 6613aafd9..6c5261801 100644 --- a/Tella/Components/Reports/Draft/DraftViewModelProtocol.swift +++ b/Tella/Components/Reports/Draft/DraftViewModelProtocol.swift @@ -41,4 +41,5 @@ protocol DraftViewModelProtocol: ObservableObject { func submitReport() func saveDraftReport() func saveFinalizedReport() + func deleteFile(fileId: String?) } diff --git a/Tella/Data/Database/GDriveData.swift b/Tella/Data/Database/GDriveData.swift index fe4a6e5e7..916f72706 100644 --- a/Tella/Data/Database/GDriveData.swift +++ b/Tella/Data/Database/GDriveData.swift @@ -12,14 +12,32 @@ extension TellaData { func addGDriveReport(report : GDriveReport) -> Result { let id = database.addGDriveReport(report: report) + getGDriveReports() + return id } + func getGDriveReports() { + DispatchQueue.main.async { + self.gDriveDraftReports.value = self.getDraftGDriveReport() + } + } + func getDraftGDriveReport() -> [GDriveReport] { - self.database.getDraftGDriveReports() + return self.database.getDriveReports(reportStatus: [ReportStatus.draft]) } func getDriveReport(id: Int) -> GDriveReport? { self.database.getGDriveReport(id: id) } + + func updateDriveReport(report: GDriveReport) -> Result { + getGDriveReports() + return self.database.updateDriveReport(report: report) + } + + func deleteDriveReport(reportId: Int?) -> Result { + getGDriveReports() + return self.database.deleteDriveReport(reportId: reportId) + } } diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index 0eee58502..afd434888 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -117,13 +117,13 @@ extension TellaDataBase { } } - func getDraftGDriveReports() -> [GDriveReport] { + func getDriveReports(reportStatus: [ReportStatus]) -> [GDriveReport] { do { - let reportsCondition = [KeyValue(key: D.cStatus, value: ReportStatus.draft.rawValue)] + let statusArray = reportStatus.compactMap{ $0.rawValue } let gDriveReportsDict = try statementBuilder.getSelectQuery(tableName: D.tGDriveReport, - equalCondition: reportsCondition + inCondition: [KeyValues(key:D.cStatus, value: statusArray )] ) let decodedReports = try gDriveReportsDict.compactMap ({ dict in @@ -171,4 +171,60 @@ extension TellaDataBase { return [] } } + + func updateDriveReport(report: GDriveReport) -> Result { + do { + + let valuesToUpdate = [ KeyValue(key: D.cTitle, value: report.title), + KeyValue(key: D.cDescription, value: report.description), + KeyValue(key: D.cStatus, value: report.status?.rawValue), + KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()), + ] + let reportCondition = [KeyValue(key: D.cId, value: report.id)] + + try statementBuilder.update( + tableName: D.tGDriveReport, + valuesToUpdate: valuesToUpdate, + equalCondition: reportCondition + ) + + if let files = report.reportFiles { + let reportFilesCondition = [KeyValue(key: D.cReportInstanceId, value: report.id)] + + try statementBuilder.delete(tableName: D.tGDriveInstanceVaultFile, primarykeyValue: reportFilesCondition) + + try files.forEach( { reportFile in + let reportFilesValuesToAdd = [ + reportFile.id == nil ? nil : KeyValue(key: D.cId, value: reportFile.id), + KeyValue(key: D.cReportInstanceId, value: report.id), + KeyValue(key: D.cVaultFileInstanceId, value: reportFile.fileId), + KeyValue(key: D.cStatus, value: reportFile.status?.rawValue), + KeyValue(key: D.cBytesSent, value: reportFile.bytesSent), + KeyValue(key: D.cCreatedDate, value: reportFile.createdDate), + KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()), + ] + + try statementBuilder.insertInto(tableName: D.tGDriveInstanceVaultFile, keyValue: reportFilesValuesToAdd) + }) + } + return .success(true) + } catch let error { + debugLog(error) + return .failure(error) + } + } + + func deleteDriveReport(reportId: Int?) -> Result { + do { + let reportCondition = [KeyValue(key: D.cId, value: reportId)] + + try statementBuilder.delete(tableName: D.tGDriveReport, primarykeyValue: reportCondition) + + return .success(true) + } catch let error { + debugLog(error) + + return .failure(error) + } + } } diff --git a/Tella/Data/Database/TellaData.swift b/Tella/Data/Database/TellaData.swift index 998c3d95a..8d37ee0f4 100644 --- a/Tella/Data/Database/TellaData.swift +++ b/Tella/Data/Database/TellaData.swift @@ -22,6 +22,9 @@ class TellaData : ObservableObject { var submittedReports = CurrentValueSubject<[Report], Error>([]) var outboxedReports = CurrentValueSubject<[Report], Error>([]) + // GDriveReports + var gDriveDraftReports = CurrentValueSubject<[GDriveReport], Error>([]) + var shouldReloadUwaziInstances = CurrentValueSubject(false) var shouldReloadUwaziTemplates = CurrentValueSubject(false) @@ -31,6 +34,7 @@ class TellaData : ObservableObject { getServers() getReports() + getGDriveReports() } func addServer(server : TellaServer) -> Result { diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index 7c2368242..2e362d430 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -165,7 +165,14 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { } func updateReport(report: GDriveReport) { - //update report logic + let updatedReportResult = self.mainAppModel.tellaData?.updateDriveReport(report: report) + + switch updatedReportResult { + case .success: + self.successSavingReport = true + default: + self.failureSavingReport = true + } } private func getServer() { self.server = mainAppModel.tellaData?.gDriveServers.value.first @@ -185,6 +192,11 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { .eraseToAnyPublisher() } + func deleteFile(fileId: String?) { + guard let index = files.firstIndex(where: { $0.id == fileId}) else {return } + files.remove(at: index) + } + private func bindVaultFileTaken() { $resultFile.sink(receiveValue: { value in guard let value else { return } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift index 2b8e931ee..4abf948b7 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -7,7 +7,7 @@ // import Foundation - +import Combine class GDriveViewModel: BaseReportsViewModel { @Published var draftReports: [GDriveReport] = [] @@ -28,6 +28,9 @@ class GDriveViewModel: BaseReportsViewModel { number: 0)] } + private var subscribers = Set() + private var delayTime = 0.1 + var sheetItems : [ListActionSheetItem] { return [ ListActionSheetItem(imageName: "view-icon", @@ -41,10 +44,26 @@ class GDriveViewModel: BaseReportsViewModel { override init(mainAppModel: MainAppModel) { super.init(mainAppModel: mainAppModel) - self.draftReports = self.mainAppModel.tellaData?.getDraftGDriveReport() ?? [] + self.getReports() + } + + private func getReports() { + getDraftReports() + } + + func getDraftReports() { + self.mainAppModel.tellaData?.gDriveDraftReports + .receive(on: DispatchQueue.main) + .sink { result in + } receiveValue: { draftReports in + self.draftReports = [] + DispatchQueue.main.asyncAfter(deadline: .now() + self.delayTime, execute: { + self.draftReports = draftReports + }) + }.store(in: &subscribers) } func deleteReport() { - + let _ = self.mainAppModel.tellaData?.deleteDriveReport(reportId: selectedReport?.id) } } diff --git a/Tella/Scenes/Reports/Draft/ReportFileGridView.swift b/Tella/Scenes/Reports/Draft/ReportFileGridView.swift index 7fd366e04..c6021c7ac 100644 --- a/Tella/Scenes/Reports/Draft/ReportFileGridView.swift +++ b/Tella/Scenes/Reports/Draft/ReportFileGridView.swift @@ -6,11 +6,11 @@ import SwiftUI -struct ReportFileGridView: View { +struct ReportFileGridView: View { var file: VaultFileDB - @EnvironmentObject var draftReportVM: DraftReportVM + @EnvironmentObject var draftReportVM: VM var body: some View { fileGridView From 8db93c4aaae0cc73256ae9c088e7f6e7bdf9c7d5 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 4 Jul 2024 13:48:48 -0300 Subject: [PATCH 074/167] save outbox and submitted report --- Tella/Data/Database/GDriveData.swift | 10 +++++- Tella/Data/Database/TellaData.swift | 2 ++ .../ViewModel/GDriveDraftViewModel.swift | 22 ++++++++---- .../GDrive/ViewModel/GDriveViewModel.swift | 36 ++++++++++++++++--- 4 files changed, 57 insertions(+), 13 deletions(-) diff --git a/Tella/Data/Database/GDriveData.swift b/Tella/Data/Database/GDriveData.swift index 916f72706..bb6f132a8 100644 --- a/Tella/Data/Database/GDriveData.swift +++ b/Tella/Data/Database/GDriveData.swift @@ -19,7 +19,15 @@ extension TellaData { func getGDriveReports() { DispatchQueue.main.async { - self.gDriveDraftReports.value = self.getDraftGDriveReport() + self.gDriveDraftReports.value = self.database.getDriveReports(reportStatus: [ReportStatus.draft]) + self.gDriveOutboxedReports.value = self.database.getDriveReports(reportStatus: [.finalized, + .submissionError, + .submissionPending, + .submissionPaused, + .submissionInProgress, + .submissionAutoPaused, + .submissionScheduled]) + self.gDriveSubmittedReports.value = self.database.getDriveReports(reportStatus: [ReportStatus.submitted]) } } diff --git a/Tella/Data/Database/TellaData.swift b/Tella/Data/Database/TellaData.swift index 8d37ee0f4..fb2616562 100644 --- a/Tella/Data/Database/TellaData.swift +++ b/Tella/Data/Database/TellaData.swift @@ -24,6 +24,8 @@ class TellaData : ObservableObject { // GDriveReports var gDriveDraftReports = CurrentValueSubject<[GDriveReport], Error>([]) + var gDriveOutboxedReports = CurrentValueSubject<[GDriveReport], Error>([]) + var gDriveSubmittedReports = CurrentValueSubject<[GDriveReport], Error>([]) var shouldReloadUwaziInstances = CurrentValueSubject(false) var shouldReloadUwaziTemplates = CurrentValueSubject(false) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index 2e362d430..4ce79391b 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -103,7 +103,7 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { receiveCompletion: { completion in switch completion { case .finished: - self.saveFinalizedReport() + self.saveSubmittedReport() break case .failure(let error): debugLog(error) @@ -130,7 +130,20 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { func saveDraftReport() { self.status = .draft - + self.saveReport() + } + + func saveFinalizedReport() { + self.status = .finalized + self.saveReport() + } + + func saveSubmittedReport() { + self.status = .submitted + self.saveReport() + } + + func saveReport() { let gDriveReport = GDriveReport( id: reportId, title: title, @@ -146,11 +159,6 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { reportId == nil ? addReport(report: gDriveReport) : updateReport(report: gDriveReport) } - func saveFinalizedReport() { - self.status = .finalized - self.successSavingReport = true - } - func addReport(report: GDriveReport) { let idResult = mainAppModel.tellaData?.addGDriveReport(report: report) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift index 4abf948b7..117fb2fe8 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -19,13 +19,13 @@ class GDriveViewModel: BaseReportsViewModel { [ PageViewItem(title: LocalizableReport.draftTitle.localized, page: .draft, - number: 0), + number: draftReports.count), PageViewItem(title: LocalizableReport.outboxTitle.localized, - page: .outbox, - number: 0), + page: .outbox, + number: outboxedReports.count), PageViewItem(title: LocalizableReport.submittedTitle.localized, - page: .submitted, - number: 0)] + page: .submitted, + number: submittedReports.count)] } private var subscribers = Set() @@ -49,6 +49,8 @@ class GDriveViewModel: BaseReportsViewModel { private func getReports() { getDraftReports() + getOutboxedReports() + getSubmittedReports() } func getDraftReports() { @@ -63,6 +65,30 @@ class GDriveViewModel: BaseReportsViewModel { }.store(in: &subscribers) } + func getOutboxedReports() { + self.mainAppModel.tellaData?.gDriveOutboxedReports + .receive(on: DispatchQueue.main) + .sink { result in + } receiveValue: { outboxedReports in + self.outboxedReports = [] + DispatchQueue.main.asyncAfter(deadline: .now() + self.delayTime, execute: { + self.outboxedReports = outboxedReports + }) + }.store(in: &subscribers) + } + + func getSubmittedReports() { + self.mainAppModel.tellaData?.gDriveSubmittedReports + .receive(on: DispatchQueue.main) + .sink { result in + } receiveValue: { submittedReports in + self.outboxedReports = [] + DispatchQueue.main.asyncAfter(deadline: .now() + self.delayTime, execute: { + self.submittedReports = submittedReports + }) + }.store(in: &subscribers) + } + func deleteReport() { let _ = self.mainAppModel.tellaData?.deleteDriveReport(reportId: selectedReport?.id) } From 628ab6bb5818835d3cbfd91a9bb3c0301b7c0d9c Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 4 Jul 2024 17:08:57 -0300 Subject: [PATCH 075/167] fix UI bug on connection view and merge with latest draft changes --- Tella/Data/Database/GDriveDatabase.swift | 2 +- .../HomeView/Views/Home/Connections/ConnectionsView.swift | 8 +++----- .../Nextcloud/ViewModels/NextcloudMainViewModel.swift | 6 +++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index 73a92bdbd..11abc9da4 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -177,7 +177,7 @@ extension TellaDataBase { let valuesToUpdate = [ KeyValue(key: D.cTitle, value: report.title), KeyValue(key: D.cDescription, value: report.description), - KeyValue(key: D.cStatus, value: report.status?.rawValue), + KeyValue(key: D.cStatus, value: report.status.rawValue), KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()), ] let reportCondition = [KeyValue(key: D.cId, value: report.id)] diff --git a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift index a01954b18..466ad3085 100644 --- a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift +++ b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift @@ -62,11 +62,9 @@ struct ConnectionsView: View { image: "home.nextcloud", destination:nextcloudMainView) } - - Spacer() - }.padding(.trailing, 17) - - } + } + Spacer() + }.padding(.trailing, 17) } var gDriveMainView : some View { diff --git a/Tella/Scenes/Nextcloud/ViewModels/NextcloudMainViewModel.swift b/Tella/Scenes/Nextcloud/ViewModels/NextcloudMainViewModel.swift index 48384aff6..fee4350e3 100644 --- a/Tella/Scenes/Nextcloud/ViewModels/NextcloudMainViewModel.swift +++ b/Tella/Scenes/Nextcloud/ViewModels/NextcloudMainViewModel.swift @@ -13,9 +13,9 @@ class NextcloudMainViewModel: ReportMainViewModel { override func getReports() { - let draftReports = tellaData?.database.getDraftGDriveReports() ?? [] - let outboxedReports = tellaData?.database.getDraftGDriveReports() ?? [] - let submittedReports = tellaData?.database.getDraftGDriveReports() ?? [] + let draftReports = tellaData?.database.getDriveReports(reportStatus: [.draft]) ?? [] + let outboxedReports = tellaData?.database.getDriveReports(reportStatus: [.draft]) ?? [] + let submittedReports = tellaData?.database.getDriveReports(reportStatus: [.draft]) ?? [] draftReportsViewModel = draftReports.compactMap { report in ReportCardViewModel(report: report, From 94aae5dc936a9fcfa55c9a3d9e9c38a66f7defe3 Mon Sep 17 00:00:00 2001 From: Dhekra Rouatbi Date: Fri, 5 Jul 2024 12:00:24 +0100 Subject: [PATCH 076/167] Fix PR comments --- Tella.xcodeproj/project.pbxproj | 55 ++++++---- ...tail.swift => ConnectionCardDetails.swift} | 8 +- ...nType.swift => ConnectionActionType.swift} | 2 +- Tella/Domain/Entity/Report/ReportStatus.swift | 98 ----------------- Tella/Domain/Entity/Uwazi/EntityStatus.swift | 77 -------------- .../ConfirmDeleteConnectionStrings.swift | 14 +++ .../Models/EntityStatusExtension.swift | 76 +++++++++++++ .../Models/ReportStatusExtension.swift | 100 ++++++++++++++++++ .../ViewModels/CommonCardViewModel.swift | 4 +- .../Views/CommonReportListView.swift | 2 +- .../Views/ReportMainView.swift | 2 +- .../GDrive/ViewModel/GDriveViewModel.swift | 2 +- .../Views/GDriveList/GDriveCardView.swift | 6 +- .../Home/Connections/ConnectionsView.swift | 4 +- ...l.swift => NextcloudReportViewModel.swift} | 4 +- .../Reports/ReportList/ReportCardView.swift | 6 +- .../Reports/View Model/ReportsViewModel.swift | 2 +- .../Resources/Views/Common/ResourceCard.swift | 2 +- .../Uwazi/Models/TemplateActionType.swift | 11 +- .../Uwazi/ViewModel/UwaziCardViewModel.swift | 4 +- .../Views/EntityInstances/UwaziListView.swift | 10 +- 21 files changed, 253 insertions(+), 236 deletions(-) rename Tella/Components/Connections/Card/{ConnectionCardDetail.swift => ConnectionCardDetails.swift} (81%) rename Tella/Domain/Entity/Report/{ReportActionType.swift => ConnectionActionType.swift} (80%) create mode 100644 Tella/Scenes/CommonConnectionReport/Models/ConfirmDeleteConnectionStrings.swift create mode 100644 Tella/Scenes/CommonConnectionReport/Models/EntityStatusExtension.swift create mode 100644 Tella/Scenes/CommonConnectionReport/Models/ReportStatusExtension.swift rename Tella/Scenes/Nextcloud/ViewModels/{NextcloudMainViewModel.swift => NextcloudReportViewModel.swift} (96%) diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index c62c36afb..c6931d7c1 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -29,7 +29,7 @@ 0ECC781B267A542300A2ACF2 /* UwaziPages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECC781A267A542300A2ACF2 /* UwaziPages.swift */; }; 1202D9562BEE39A800EAFAB3 /* TrailingImageButtonToolBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1202D9552BEE39A800EAFAB3 /* TrailingImageButtonToolBar.swift */; }; 1202D9582BF4CFF200EAFAB3 /* SelectValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1202D9572BF4CFF200EAFAB3 /* SelectValues.swift */; }; - 1203CDDC298C5B9100D09073 /* ReportActionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1203CDDB298C5B9100D09073 /* ReportActionType.swift */; }; + 1203CDDC298C5B9100D09073 /* ConnectionActionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1203CDDB298C5B9100D09073 /* ConnectionActionType.swift */; }; 1203CDDE298D7C1300D09073 /* FileToUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1203CDDD298D7C1300D09073 /* FileToUpload.swift */; }; 1203CDE02991429200D09073 /* FileStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1203CDDF2991429200D09073 /* FileStatus.swift */; }; 1203CDE129914FA300D09073 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1233007D28E3184D00B8F7BA /* Value.swift */; }; @@ -164,6 +164,9 @@ 125B79F82C205F980061CF84 /* PHAssetExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125B79F72C205F980061CF84 /* PHAssetExtension.swift */; }; 125B79FA2C2213920061CF84 /* AVCaptureMovieFileOutputExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125B79F92C2213920061CF84 /* AVCaptureMovieFileOutputExtension.swift */; }; 125BC1DE2B21F08200A117D0 /* VaultFileDetailsToMerge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BC1DD2B21F08200A117D0 /* VaultFileDetailsToMerge.swift */; }; + 125C789F2C38042700440014 /* ConfirmDeleteConnectionStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125C789E2C38042700440014 /* ConfirmDeleteConnectionStrings.swift */; }; + 125C78A22C38056300440014 /* EntityStatusExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125C78A12C38056300440014 /* EntityStatusExtension.swift */; }; + 125C78A42C3805C600440014 /* ReportStatusExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125C78A32C3805C600440014 /* ReportStatusExtension.swift */; }; 125D231C271F119D00250FBB /* Validator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125D231B271F119D00250FBB /* Validator.swift */; }; 125D231F271F12A000250FBB /* NSRegularExpressionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125D231E271F12A000250FBB /* NSRegularExpressionExtension.swift */; }; 125D2321271F823100250FBB /* UIApplicationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125D2320271F823100250FBB /* UIApplicationExtension.swift */; }; @@ -208,8 +211,6 @@ 126FEE0A2AC4993900B99298 /* ReportPages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126FEE092AC4993900B99298 /* ReportPages.swift */; }; 127092DA2C2EE4E3002030AA /* Server.swift in Sources */ = {isa = PBXBuildFile; fileRef = 127092D92C2EE4E3002030AA /* Server.swift */; }; 127092DC2C2EE7AD002030AA /* WebServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 127092DB2C2EE7AD002030AA /* WebServer.swift */; }; - 127092D42C2D8BA5002030AA /* NextcloudDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 127092D32C2D8BA5002030AA /* NextcloudDatabase.swift */; }; - 127092D72C2DD1A1002030AA /* NextcloudServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 127092D62C2DD1A1002030AA /* NextcloudServer.swift */; }; 127138382C35EA34004D520B /* CommonCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 127138372C35EA34004D520B /* CommonCardViewModel.swift */; }; 1272F25D27C91ACD0054F2E2 /* ImportFileProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1272F25C27C91ACD0054F2E2 /* ImportFileProgress.swift */; }; 1272F25F27C91BD70054F2E2 /* ImportFilesFromCameraProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1272F25E27C91BD70054F2E2 /* ImportFilesFromCameraProgress.swift */; }; @@ -325,7 +326,7 @@ 12B84B902C333DD0006363F0 /* ReportMainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B84B8E2C333DD0006363F0 /* ReportMainViewModel.swift */; }; 12B84B912C333DD0006363F0 /* ReportMainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B84B8F2C333DD0006363F0 /* ReportMainView.swift */; }; 12B84B942C333FE3006363F0 /* ReportCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B84B932C333FE3006363F0 /* ReportCardViewModel.swift */; }; - 12B84B962C340025006363F0 /* NextcloudMainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B84B952C340025006363F0 /* NextcloudMainViewModel.swift */; }; + 12B84B962C340025006363F0 /* NextcloudReportViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B84B952C340025006363F0 /* NextcloudReportViewModel.swift */; }; 12B84B982C3413AC006363F0 /* CommonReportListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B84B972C3413AC006363F0 /* CommonReportListView.swift */; }; 12BA188628343BE5002A11D7 /* MoreFileActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BA188528343BE5002A11D7 /* MoreFileActionButton.swift */; }; 12BAFA7728B3B8D300930451 /* UIImageOrientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BAFA7628B3B8D300930451 /* UIImageOrientation.swift */; }; @@ -452,7 +453,7 @@ CCC1B4392AC75B8D0075B819 /* UwaziEntityParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCC1B4382AC75B8D0075B819 /* UwaziEntityParser.swift */; }; CCC1B43B2AC75BED0075B819 /* UwaziEntityParserProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCC1B43A2AC75BED0075B819 /* UwaziEntityParserProtocol.swift */; }; CCC1B43D2AC75C5D0075B819 /* UwaziConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCC1B43C2AC75C5D0075B819 /* UwaziConstants.swift */; }; - CCD586CD2A7AD94B00014F87 /* ConnectionCardDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCD586CC2A7AD94B00014F87 /* ConnectionCardDetail.swift */; }; + CCD586CD2A7AD94B00014F87 /* ConnectionCardDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCD586CC2A7AD94B00014F87 /* ConnectionCardDetails.swift */; }; CCD586CF2A7AD9E400014F87 /* MoreButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCD586CE2A7AD9E400014F87 /* MoreButtonView.swift */; }; CCD586D12A7C096C00014F87 /* AddTemplatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCD586D02A7C096B00014F87 /* AddTemplatesView.swift */; }; CCD586D42A7C294800014F87 /* TemplateItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCD586D32A7C294800014F87 /* TemplateItemView.swift */; }; @@ -606,7 +607,7 @@ 0F3DC3E42523951C0024B4A0 /* BundleInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleInfo.swift; sourceTree = ""; }; 1202D9552BEE39A800EAFAB3 /* TrailingImageButtonToolBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrailingImageButtonToolBar.swift; sourceTree = ""; }; 1202D9572BF4CFF200EAFAB3 /* SelectValues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectValues.swift; sourceTree = ""; }; - 1203CDDB298C5B9100D09073 /* ReportActionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportActionType.swift; sourceTree = ""; }; + 1203CDDB298C5B9100D09073 /* ConnectionActionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionActionType.swift; sourceTree = ""; }; 1203CDDD298D7C1300D09073 /* FileToUpload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileToUpload.swift; sourceTree = ""; }; 1203CDDF2991429200D09073 /* FileStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileStatus.swift; sourceTree = ""; }; 1203CDE82992C19D00D09073 /* JSONStringEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONStringEncoder.swift; sourceTree = ""; }; @@ -739,6 +740,9 @@ 125B79F72C205F980061CF84 /* PHAssetExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHAssetExtension.swift; sourceTree = ""; }; 125B79F92C2213920061CF84 /* AVCaptureMovieFileOutputExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVCaptureMovieFileOutputExtension.swift; sourceTree = ""; }; 125BC1DD2B21F08200A117D0 /* VaultFileDetailsToMerge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VaultFileDetailsToMerge.swift; sourceTree = ""; }; + 125C789E2C38042700440014 /* ConfirmDeleteConnectionStrings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmDeleteConnectionStrings.swift; sourceTree = ""; }; + 125C78A12C38056300440014 /* EntityStatusExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntityStatusExtension.swift; sourceTree = ""; }; + 125C78A32C3805C600440014 /* ReportStatusExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportStatusExtension.swift; sourceTree = ""; }; 125D231B271F119D00250FBB /* Validator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Validator.swift; sourceTree = ""; }; 125D231E271F12A000250FBB /* NSRegularExpressionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSRegularExpressionExtension.swift; sourceTree = ""; }; 125D2320271F823100250FBB /* UIApplicationExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationExtension.swift; sourceTree = ""; }; @@ -897,7 +901,7 @@ 12B84B8E2C333DD0006363F0 /* ReportMainViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReportMainViewModel.swift; sourceTree = ""; }; 12B84B8F2C333DD0006363F0 /* ReportMainView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReportMainView.swift; sourceTree = ""; }; 12B84B932C333FE3006363F0 /* ReportCardViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportCardViewModel.swift; sourceTree = ""; }; - 12B84B952C340025006363F0 /* NextcloudMainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudMainViewModel.swift; sourceTree = ""; }; + 12B84B952C340025006363F0 /* NextcloudReportViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudReportViewModel.swift; sourceTree = ""; }; 12B84B972C3413AC006363F0 /* CommonReportListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonReportListView.swift; sourceTree = ""; }; 12BA188528343BE5002A11D7 /* MoreFileActionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreFileActionButton.swift; sourceTree = ""; }; 12BAFA7628B3B8D300930451 /* UIImageOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImageOrientation.swift; sourceTree = ""; }; @@ -1030,7 +1034,7 @@ CCC1B4382AC75B8D0075B819 /* UwaziEntityParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziEntityParser.swift; sourceTree = ""; }; CCC1B43A2AC75BED0075B819 /* UwaziEntityParserProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziEntityParserProtocol.swift; sourceTree = ""; }; CCC1B43C2AC75C5D0075B819 /* UwaziConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziConstants.swift; sourceTree = ""; }; - CCD586CC2A7AD94B00014F87 /* ConnectionCardDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionCardDetail.swift; sourceTree = ""; }; + CCD586CC2A7AD94B00014F87 /* ConnectionCardDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionCardDetails.swift; sourceTree = ""; }; CCD586CE2A7AD9E400014F87 /* MoreButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreButtonView.swift; sourceTree = ""; }; CCD586D02A7C096B00014F87 /* AddTemplatesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddTemplatesView.swift; sourceTree = ""; }; CCD586D32A7C294800014F87 /* TemplateItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateItemView.swift; sourceTree = ""; }; @@ -1513,7 +1517,7 @@ 1256A33829490A7A00FE2B5C /* FileInfos.swift */, 1203CDDF2991429200D09073 /* FileStatus.swift */, 1231A45D294C779D0057DA85 /* ReportStatus.swift */, - 1203CDDB298C5B9100D09073 /* ReportActionType.swift */, + 1203CDDB298C5B9100D09073 /* ConnectionActionType.swift */, 12351C1928D2209400F3CB7C /* Report.swift */, 12CCDC5328D8E05300C3BE4E /* TellaServer.swift */, 12A43B4E29941574003EF33E /* ReportFile.swift */, @@ -1622,6 +1626,7 @@ 125C789B2C36B36900440014 /* CommonConnectionReport */ = { isa = PBXGroup; children = ( + 125C78A02C3804AC00440014 /* Models */, 125C789D2C36B50800440014 /* ViewModels */, 125C789C2C36B50100440014 /* Views */, ); @@ -1647,6 +1652,16 @@ path = ViewModels; sourceTree = ""; }; + 125C78A02C3804AC00440014 /* Models */ = { + isa = PBXGroup; + children = ( + 125C789E2C38042700440014 /* ConfirmDeleteConnectionStrings.swift */, + 125C78A12C38056300440014 /* EntityStatusExtension.swift */, + 125C78A32C3805C600440014 /* ReportStatusExtension.swift */, + ); + path = Models; + sourceTree = ""; + }; 125D231D271F127D00250FBB /* Extensions */ = { isa = PBXGroup; children = ( @@ -2176,15 +2191,6 @@ path = Models; sourceTree = ""; }; - 12B84B832C32E646006363F0 /* Nextcloud */ = { - isa = PBXGroup; - children = ( - 209AC67C2C2D65EB00492356 /* NextcloudAddServerURLView.swift */, - 209AC67E2C2D660600492356 /* NextcloudServerViewModel.swift */, - ); - path = Nextcloud; - sourceTree = ""; - }; 12B84B8C2C333DD0006363F0 /* Nextcloud */ = { isa = PBXGroup; children = ( @@ -2204,7 +2210,7 @@ 12B84B922C333F86006363F0 /* ViewModels */ = { isa = PBXGroup; children = ( - 12B84B952C340025006363F0 /* NextcloudMainViewModel.swift */, + 12B84B952C340025006363F0 /* NextcloudReportViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -2630,7 +2636,7 @@ CCD586C92A7AD85400014F87 /* Card */ = { isa = PBXGroup; children = ( - CCD586CC2A7AD94B00014F87 /* ConnectionCardDetail.swift */, + CCD586CC2A7AD94B00014F87 /* ConnectionCardDetails.swift */, CCD586CE2A7AD9E400014F87 /* MoreButtonView.swift */, ); path = Card; @@ -3392,6 +3398,7 @@ D5B823EB262774E00008E04B /* MainView.swift in Sources */, 151308172BF3DBD9000C51D7 /* UwaziRelationshipList.swift in Sources */, 153F96492BFD306F00FE5464 /* CreateDriveFolder.swift in Sources */, + 125C78A22C38056300440014 /* EntityStatusExtension.swift in Sources */, 1220A72E292EB11B000BC24C /* ReportFileGridView.swift in Sources */, 125FA6D6278DE49A004B9D06 /* URLExtension.swift in Sources */, 127369E327B3C4DA00CF7BE5 /* UIDeviceExtension.swift in Sources */, @@ -3405,7 +3412,7 @@ 15BD9CAB2BC740D700C3932B /* EntitySelectorView.swift in Sources */, 122389B7293635790058593B /* SetExtension.swift in Sources */, 155369232B7E9CC100129F2F /* ResourceDatabase.swift in Sources */, - CCD586CD2A7AD94B00014F87 /* ConnectionCardDetail.swift in Sources */, + CCD586CD2A7AD94B00014F87 /* ConnectionCardDetails.swift in Sources */, 12607D5E27904F5300E2B8CC /* PlayerView.swift in Sources */, 125AAD34295348EC002194D6 /* UploadService.swift in Sources */, 1237A71E278F5F8B00D7BC0F /* LanguageManager.swift in Sources */, @@ -3511,7 +3518,7 @@ 12EC94D128ABB6FA0070E72B /* SecuritySettingsView.swift in Sources */, 0D4BC3CE267668D600DCDC30 /* AddFileYellowButton.swift in Sources */, 126684412B18B67500561650 /* BackgroundActivityModel.swift in Sources */, - 12B84B962C340025006363F0 /* NextcloudMainViewModel.swift in Sources */, + 12B84B962C340025006363F0 /* NextcloudReportViewModel.swift in Sources */, CCBC2F6929A93E4900888779 /* SettingCheckboxItem.swift in Sources */, 1293547B294A454900735ED0 /* AppDelegate.swift in Sources */, 127092DC2C2EE7AD002030AA /* WebServer.swift in Sources */, @@ -3660,6 +3667,7 @@ 120A14472B285E1400870157 /* MainViewModel.swift in Sources */, 1293F6662AD7E52800F6CFBD /* FeedbackView.swift in Sources */, 1291A83428BE0D51001A6055 /* SettingsServerItemView.swift in Sources */, + 125C78A42C3805C600440014 /* ReportStatusExtension.swift in Sources */, 12607D5A2790457600E2B8CC /* VideoViewer.swift in Sources */, 125B79FA2C2213920061CF84 /* AVCaptureMovieFileOutputExtension.swift in Sources */, 153AACFB2BE41C010075D5B2 /* UwaziEntityRelationshipItem.swift in Sources */, @@ -3716,7 +3724,7 @@ CC13138C2A5DB79B0057271C /* BottomButtonsView.swift in Sources */, 150913422B841C3F001E782A /* ResourceActionType.swift in Sources */, 129B845128BF6C7800F1B344 /* ServersViewModel.swift in Sources */, - 1203CDDC298C5B9100D09073 /* ReportActionType.swift in Sources */, + 1203CDDC298C5B9100D09073 /* ConnectionActionType.swift in Sources */, E16D20CF2ABEAAB1001708CC /* TemplateItemViewModel.swift in Sources */, 15F64CA42B6D7CA1008A57AA /* AvailableResources.swift in Sources */, 12476E1F2A5B7D2F00069048 /* TrailingButtonToolbar.swift in Sources */, @@ -3778,6 +3786,7 @@ D50727BF2625561400BBC370 /* KeychainManager.swift in Sources */, 1203CDE129914FA300D09073 /* Value.swift in Sources */, 12D7D11F28E36123008121C8 /* ServerRepository.swift in Sources */, + 125C789F2C38042700440014 /* ConfirmDeleteConnectionStrings.swift in Sources */, D7CFC37F254260D300CCB352 /* RecordView.swift in Sources */, 128C23732BEE1A8300539A65 /* SubmittedEntityViewModel.swift in Sources */, D7F55FC825348FA50028739E /* RecordState.swift in Sources */, diff --git a/Tella/Components/Connections/Card/ConnectionCardDetail.swift b/Tella/Components/Connections/Card/ConnectionCardDetails.swift similarity index 81% rename from Tella/Components/Connections/Card/ConnectionCardDetail.swift rename to Tella/Components/Connections/Card/ConnectionCardDetails.swift index a4c2c3eb2..524abbbf8 100644 --- a/Tella/Components/Connections/Card/ConnectionCardDetail.swift +++ b/Tella/Components/Connections/Card/ConnectionCardDetails.swift @@ -8,7 +8,7 @@ import SwiftUI -struct ConnectionCardDetail: View { +struct ConnectionCardDetails: View { var title : String var subtitle: String? var body: some View { @@ -18,8 +18,8 @@ struct ConnectionCardDetail: View { .font(.custom(Styles.Fonts.semiBoldFontName, size: 14)) .foregroundColor(.white) .lineLimit(1) - if (subtitle != nil) { - Text(subtitle!) + if let subtitle { + Text(subtitle) .font(.custom(Styles.Fonts.regularFontName, size: 12)) .foregroundColor(.white) } @@ -29,6 +29,6 @@ struct ConnectionCardDetail: View { struct ReportCardDetail_Previews: PreviewProvider { static var previews: some View { - ConnectionCardDetail(title: "", subtitle: "") + ConnectionCardDetails(title: "", subtitle: "") } } diff --git a/Tella/Domain/Entity/Report/ReportActionType.swift b/Tella/Domain/Entity/Report/ConnectionActionType.swift similarity index 80% rename from Tella/Domain/Entity/Report/ReportActionType.swift rename to Tella/Domain/Entity/Report/ConnectionActionType.swift index ef0c284f3..5c7177e8c 100644 --- a/Tella/Domain/Entity/Report/ReportActionType.swift +++ b/Tella/Domain/Entity/Report/ConnectionActionType.swift @@ -4,7 +4,7 @@ import Foundation -enum ReportActionType: ActionType { +enum ConnectionActionType: ActionType { case editDraft case editOutbox case viewSubmitted diff --git a/Tella/Domain/Entity/Report/ReportStatus.swift b/Tella/Domain/Entity/Report/ReportStatus.swift index 245f454c2..a31e0364d 100644 --- a/Tella/Domain/Entity/Report/ReportStatus.swift +++ b/Tella/Domain/Entity/Report/ReportStatus.swift @@ -18,102 +18,4 @@ enum ReportStatus : Int, Codable { case submissionScheduled = 10 // Submission scheduled } -extension ReportStatus { - - var sheetItemTitle : String { - switch self { - - case .submitted: - return LocalizableReport.viewModelView.localized - - case .draft: - return LocalizableReport.viewModelEdit.localized - - default: - return LocalizableReport.viewModelOpen.localized - } - } - - var reportActionType : ReportActionType { - switch self { - - case .submitted: - return .viewSubmitted - - case .draft: - return .editDraft - - default: - return .editOutbox - - } - } - - var listActionSheetItem : [ListActionSheetItem] { - switch self { - - case .submitted: - return [ListActionSheetItem(imageName: "view-icon", - content: LocalizableReport.viewModelView.localized, - type: ReportActionType.viewSubmitted), - ListActionSheetItem(imageName: "delete-icon-white", - content: LocalizableReport.viewModelDelete.localized, - type: UwaziActionType.delete)] - case .draft: - - return [ListActionSheetItem(imageName: "edit-icon", - content: LocalizableReport.viewModelEdit.localized, - type: ReportActionType.editDraft), - ListActionSheetItem(imageName: "delete-icon-white", - content: LocalizableReport.viewModelDelete.localized, - type: UwaziActionType.delete) ] - default: - return [ListActionSheetItem(imageName: "view-icon", - content: LocalizableReport.viewModelView.localized, - type: ReportActionType.editOutbox), - ListActionSheetItem(imageName: "delete-icon-white", - content: LocalizableReport.viewModelDelete.localized, - type: UwaziActionType.delete)] - } - } - - var deleteReportStrings: DeleteReportStrings { - switch self { - case .draft: - DeleteReportStrings(deleteTitle: LocalizableReport.deleteDraftTitle.localized, - deleteMessage: LocalizableReport.deleteDraftReportMessage.localized) - case .submitted: - - DeleteReportStrings(deleteTitle: LocalizableReport.deleteTitle.localized, - deleteMessage: LocalizableReport.deleteSubmittedReportMessage.localized) - default: - DeleteReportStrings(deleteTitle: LocalizableReport.deleteTitle.localized, - deleteMessage: LocalizableReport.deleteOutboxReportMessage.localized) - } - } - - var iconImageName: String? { - - switch self { - case .submitted: - return "submitted" - case .finalized: - return "time.yellow" - case .submissionError, .submissionPending: - return "info-icon" - case .submissionInProgress: - return "progress-circle.green" - default: - return nil - } - } - -} - -struct DeleteReportStrings { - var deleteTitle : String - var deleteMessage : String - - -} diff --git a/Tella/Domain/Entity/Uwazi/EntityStatus.swift b/Tella/Domain/Entity/Uwazi/EntityStatus.swift index a6dae6abd..69672c8b9 100644 --- a/Tella/Domain/Entity/Uwazi/EntityStatus.swift +++ b/Tella/Domain/Entity/Uwazi/EntityStatus.swift @@ -22,80 +22,3 @@ enum EntityStatus:Int, Codable { return !(self == .unknown || self == .draft) } } - - -extension EntityStatus { - - - func deleteReportStrings(title:String) -> DeleteReportStrings { - switch self { - case .draft: - - return DeleteReportStrings(deleteTitle: String.init(format: LocalizableUwazi.deleteSheetTitle.localized, "\(title)"), - deleteMessage: LocalizableUwazi.deleteDraftSheetExpl.localized) - - case .submitted: - return DeleteReportStrings(deleteTitle: LocalizableUwazi.submittedDeleteSheetTitle.localized, - deleteMessage :LocalizableUwazi.submittedDeleteSheetExpl.localized) - default: - return DeleteReportStrings(deleteTitle : LocalizableUwazi.submittedDeleteSheetTitle.localized, - deleteMessage : LocalizableUwazi.outboxDeleteSheetExpl.localized) - } - - } - - - var listActionSheetItem: [ListActionSheetItem] { - - switch self { - case .draft: - return [ - ListActionSheetItem(imageName: "edit-icon", - content: LocalizableUwazi.editDraft.localized, - type: UwaziActionType.createEntity), - ListActionSheetItem(imageName: "delete-icon-white", - content: LocalizableUwazi.deleteDraft.localized, - type: UwaziActionType.delete) - ] - case .submitted: - return [ - ListActionSheetItem(imageName: "edit-icon", - content: LocalizableUwazi.viewSheetSelect.localized, - type: UwaziActionType.viewSubmittedEntity), - ListActionSheetItem(imageName: "delete-icon-white", - content: LocalizableUwazi.deleteSheetSelect.localized, - type: UwaziActionType.delete) - ] - default: - return [ - ListActionSheetItem(imageName: "view-icon", - content: LocalizableUwazi.viewSheetSelect.localized, - type: UwaziActionType.viewOutboxEntity), - ListActionSheetItem(imageName: "delete-icon-white", - content: LocalizableUwazi.deleteSheetSelect.localized, - type: UwaziActionType.delete) - ] - } - - - } - - - var iconImageName: String? { - switch self { - case .submitted: - return"submitted" - case .finalized: - return "time.yellow" - case .submissionError, .submissionPending: - return "info-icon" - case .submissionInProgress: - return "progress-circle.green" - default: - return nil - } - - } - - -} diff --git a/Tella/Scenes/CommonConnectionReport/Models/ConfirmDeleteConnectionStrings.swift b/Tella/Scenes/CommonConnectionReport/Models/ConfirmDeleteConnectionStrings.swift new file mode 100644 index 000000000..382cabc6f --- /dev/null +++ b/Tella/Scenes/CommonConnectionReport/Models/ConfirmDeleteConnectionStrings.swift @@ -0,0 +1,14 @@ +// +// ConfirmDeleteConnectionStrings.swift +// Tella +// +// Created by Dhekra Rouatbi on 5/7/2024. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +struct ConfirmDeleteConnectionStrings { + var deleteTitle : String + var deleteMessage : String +} diff --git a/Tella/Scenes/CommonConnectionReport/Models/EntityStatusExtension.swift b/Tella/Scenes/CommonConnectionReport/Models/EntityStatusExtension.swift new file mode 100644 index 000000000..bfb3537a3 --- /dev/null +++ b/Tella/Scenes/CommonConnectionReport/Models/EntityStatusExtension.swift @@ -0,0 +1,76 @@ +// +// EntityStatusExtension.swift +// Tella +// +// Created by Dhekra Rouatbi on 5/7/2024. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +extension EntityStatus { + + func deleteReportStrings(title:String) -> ConfirmDeleteConnectionStrings { + switch self { + case .draft: + return ConfirmDeleteConnectionStrings(deleteTitle: String.init(format: LocalizableUwazi.deleteSheetTitle.localized, "\(title)"), + deleteMessage: LocalizableUwazi.deleteDraftSheetExpl.localized) + + case .submitted: + return ConfirmDeleteConnectionStrings(deleteTitle: LocalizableUwazi.submittedDeleteSheetTitle.localized, + deleteMessage :LocalizableUwazi.submittedDeleteSheetExpl.localized) + default: + return ConfirmDeleteConnectionStrings(deleteTitle : LocalizableUwazi.submittedDeleteSheetTitle.localized, + deleteMessage : LocalizableUwazi.outboxDeleteSheetExpl.localized) + } + + } + + var listActionSheetItem: [ListActionSheetItem] { + + switch self { + case .draft: + return [ + ListActionSheetItem(imageName: "edit-icon", + content: LocalizableUwazi.editDraft.localized, + type: ConnectionActionType.editDraft), + ListActionSheetItem(imageName: "delete-icon-white", + content: LocalizableUwazi.deleteDraft.localized, + type: ConnectionActionType.delete) + ] + case .submitted: + return [ + ListActionSheetItem(imageName: "edit-icon", + content: LocalizableUwazi.viewSheetSelect.localized, + type: ConnectionActionType.viewSubmitted), + ListActionSheetItem(imageName: "delete-icon-white", + content: LocalizableUwazi.deleteSheetSelect.localized, + type: ConnectionActionType.delete) + ] + default: + return [ + ListActionSheetItem(imageName: "view-icon", + content: LocalizableUwazi.viewSheetSelect.localized, + type: ConnectionActionType.editOutbox), + ListActionSheetItem(imageName: "delete-icon-white", + content: LocalizableUwazi.deleteSheetSelect.localized, + type: ConnectionActionType.delete) + ] + } + } + + var iconImageName: String? { + switch self { + case .submitted: + return"submitted" + case .finalized: + return "time.yellow" + case .submissionError, .submissionPending: + return "info-icon" + case .submissionInProgress: + return "progress-circle.green" + default: + return nil + } + } +} diff --git a/Tella/Scenes/CommonConnectionReport/Models/ReportStatusExtension.swift b/Tella/Scenes/CommonConnectionReport/Models/ReportStatusExtension.swift new file mode 100644 index 000000000..608e024e7 --- /dev/null +++ b/Tella/Scenes/CommonConnectionReport/Models/ReportStatusExtension.swift @@ -0,0 +1,100 @@ +// +// ReportStatusExtension.swift +// Tella +// +// Created by Dhekra Rouatbi on 5/7/2024. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +extension ReportStatus { + + var sheetItemTitle : String { + switch self { + + case .submitted: + return LocalizableReport.viewModelView.localized + + case .draft: + return LocalizableReport.viewModelEdit.localized + + default: + return LocalizableReport.viewModelOpen.localized + } + } + + var reportActionType : ConnectionActionType { + switch self { + + case .submitted: + return .viewSubmitted + + case .draft: + return .editDraft + + default: + return .editOutbox + + } + } + + var listActionSheetItem : [ListActionSheetItem] { + switch self { + + case .submitted: + return [ListActionSheetItem(imageName: "view-icon", + content: LocalizableReport.viewModelView.localized, + type: ConnectionActionType.viewSubmitted), + ListActionSheetItem(imageName: "delete-icon-white", + content: LocalizableReport.viewModelDelete.localized, + type: ConnectionActionType.delete)] + case .draft: + + return [ListActionSheetItem(imageName: "edit-icon", + content: LocalizableReport.viewModelEdit.localized, + type: ConnectionActionType.editDraft), + ListActionSheetItem(imageName: "delete-icon-white", + content: LocalizableReport.viewModelDelete.localized, + type: ConnectionActionType.delete) ] + default: + return [ListActionSheetItem(imageName: "view-icon", + content: LocalizableReport.viewModelView.localized, + type: ConnectionActionType.editOutbox), + ListActionSheetItem(imageName: "delete-icon-white", + content: LocalizableReport.viewModelDelete.localized, + type: ConnectionActionType.delete)] + } + } + + var deleteReportStrings: ConfirmDeleteConnectionStrings { + switch self { + case .draft: + ConfirmDeleteConnectionStrings(deleteTitle: LocalizableReport.deleteDraftTitle.localized, + deleteMessage: LocalizableReport.deleteDraftReportMessage.localized) + case .submitted: + + ConfirmDeleteConnectionStrings(deleteTitle: LocalizableReport.deleteTitle.localized, + deleteMessage: LocalizableReport.deleteSubmittedReportMessage.localized) + default: + ConfirmDeleteConnectionStrings(deleteTitle: LocalizableReport.deleteTitle.localized, + deleteMessage: LocalizableReport.deleteOutboxReportMessage.localized) + } + } + + var iconImageName: String? { + + switch self { + case .submitted: + return "submitted" + case .finalized: + return "time.yellow" + case .submissionError, .submissionPending: + return "info-icon" + case .submissionInProgress: + return "progress-circle.green" + default: + return nil + } + } +} diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift index 9ada2c1e5..21c22d863 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift @@ -16,7 +16,7 @@ class CommonCardViewModel: Hashable { var serverName: String? var listActionSheetItem: [ListActionSheetItem] var connectionType: ServerConnectionType - var deleteReportStrings : DeleteReportStrings + var deleteReportStrings : ConfirmDeleteConnectionStrings var deleteAction: (() -> Void) init(id: Int, title: String, @@ -24,7 +24,7 @@ class CommonCardViewModel: Hashable { serverName: String?, listActionSheetItem: [ListActionSheetItem], connectionType: ServerConnectionType, - deleteReportStrings: DeleteReportStrings, + deleteReportStrings: ConfirmDeleteConnectionStrings, deleteAction: @escaping (() -> Void)) { self.id = id diff --git a/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift b/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift index 057aefe06..f05b4823c 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift @@ -77,7 +77,7 @@ struct CommonItemView: View { .frame(width: 12) } - ConnectionCardDetail(title: cardViewModel.title, + ConnectionCardDetails(title: cardViewModel.title, subtitle: cardViewModel.serverName) Spacer() diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift index bc43f791b..db570d36c 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -106,7 +106,7 @@ struct ReportMainView: View { ActionListBottomSheet(items: cardViewModel.listActionSheetItem, headerTitle: cardViewModel.title, action: {item in - guard let type = item.type as? ReportActionType else {return} + guard let type = item.type as? ConnectionActionType else {return} let id = cardViewModel.id switch type { diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift index 3d6fce133..85ac95d00 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -38,7 +38,7 @@ class GDriveViewModel: BaseReportsViewModel { type: self.selectedReport?.status.reportActionType ?? .viewSubmitted), ListActionSheetItem(imageName: "delete-icon-white", content: LocalizableReport.viewModelDelete.localized, - type: ReportActionType.delete) + type: ConnectionActionType.delete) ]} override init(mainAppModel: MainAppModel) { diff --git a/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift b/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift index 7abd22625..8191c2dc6 100644 --- a/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift +++ b/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift @@ -30,7 +30,7 @@ struct GDriveCardView : View { HStack { - ConnectionCardDetail(title: report.title ?? "", subtitle: report.getReportDate) + ConnectionCardDetails(title: report.title ?? "", subtitle: report.getReportDate) Spacer() @@ -53,7 +53,7 @@ struct GDriveCardView : View { ActionListBottomSheet(items: reportsViewModel.sheetItems , headerTitle: reportsViewModel.selectedReport?.title ?? "", action: { item in - self.handleActions(type : item.type as? ReportActionType) + self.handleActions(type : item.type as? ConnectionActionType) }) } } @@ -68,7 +68,7 @@ struct GDriveCardView : View { } } - private func handleActions(type: ReportActionType?) { + private func handleActions(type: ConnectionActionType?) { guard let type else { return } diff --git a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift index 466ad3085..abccdcf9a 100644 --- a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift +++ b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift @@ -68,14 +68,14 @@ struct ConnectionsView: View { } var gDriveMainView : some View { - ReportMainView(reportMainViewModel: NextcloudMainViewModel(mainAppModel: appModel, + ReportMainView(reportMainViewModel: NextcloudReportViewModel(mainAppModel: appModel, connectionType: .gDrive, title: "Drive"), diContainer: GDriveDIContainer()) } var nextcloudMainView : some View { - ReportMainView(reportMainViewModel: NextcloudMainViewModel(mainAppModel: appModel, + ReportMainView(reportMainViewModel: NextcloudReportViewModel(mainAppModel: appModel, connectionType: .nextcloud, title: LocalizableNextcloud.nextcloudAppBar.localized), diContainer: GDriveDIContainer()) diff --git a/Tella/Scenes/Nextcloud/ViewModels/NextcloudMainViewModel.swift b/Tella/Scenes/Nextcloud/ViewModels/NextcloudReportViewModel.swift similarity index 96% rename from Tella/Scenes/Nextcloud/ViewModels/NextcloudMainViewModel.swift rename to Tella/Scenes/Nextcloud/ViewModels/NextcloudReportViewModel.swift index fee4350e3..819a22077 100644 --- a/Tella/Scenes/Nextcloud/ViewModels/NextcloudMainViewModel.swift +++ b/Tella/Scenes/Nextcloud/ViewModels/NextcloudReportViewModel.swift @@ -1,5 +1,5 @@ // -// GDriveMainViewModel.swift +// NextcloudReportViewModel.swift // Tella // // Created by Dhekra Rouatbi on 2/7/2024. @@ -9,7 +9,7 @@ import Foundation import Combine -class NextcloudMainViewModel: ReportMainViewModel { +class NextcloudReportViewModel: ReportMainViewModel { override func getReports() { diff --git a/Tella/Scenes/Reports/ReportList/ReportCardView.swift b/Tella/Scenes/Reports/ReportList/ReportCardView.swift index 4a31f5d45..3644d2f6f 100644 --- a/Tella/Scenes/Reports/ReportList/ReportCardView.swift +++ b/Tella/Scenes/Reports/ReportList/ReportCardView.swift @@ -26,7 +26,7 @@ struct ReportCardView : View { HStack { - ConnectionCardDetail(title: report.title ?? "", subtitle: report.getReportDate) + ConnectionCardDetails(title: report.title ?? "", subtitle: report.getReportDate) Spacer() @@ -49,7 +49,7 @@ struct ReportCardView : View { ActionListBottomSheet(items: reportsViewModel.sheetItems , headerTitle: reportsViewModel.selectedReport?.title ?? "", action: { item in - self.handleActions(type : item.type as? ReportActionType) + self.handleActions(type : item.type as? ConnectionActionType) }) } } @@ -64,7 +64,7 @@ struct ReportCardView : View { } } - private func handleActions(type: ReportActionType?) { + private func handleActions(type: ConnectionActionType?) { guard let type else { return } diff --git a/Tella/Scenes/Reports/View Model/ReportsViewModel.swift b/Tella/Scenes/Reports/View Model/ReportsViewModel.swift index 7b23baf4f..9b5aa4cb8 100644 --- a/Tella/Scenes/Reports/View Model/ReportsViewModel.swift +++ b/Tella/Scenes/Reports/View Model/ReportsViewModel.swift @@ -26,7 +26,7 @@ class ReportsViewModel: BaseReportsViewModel { type: self.selectedReport?.status.reportActionType ?? .viewSubmitted), ListActionSheetItem(imageName: "delete-icon-white", content: LocalizableReport.viewModelDelete.localized, - type: ReportActionType.delete) + type: ConnectionActionType.delete) ]} private var subscribers = Set() diff --git a/Tella/Scenes/Resources/Views/Common/ResourceCard.swift b/Tella/Scenes/Resources/Views/Common/ResourceCard.swift index 8d0f6cd8c..56ead6d05 100644 --- a/Tella/Scenes/Resources/Views/Common/ResourceCard.swift +++ b/Tella/Scenes/Resources/Views/Common/ResourceCard.swift @@ -18,7 +18,7 @@ struct ResourceCardView: View { HStack { Image("resources.pdf") .padding() - ConnectionCardDetail(title: resourceCard.title, subtitle: resourceCard.serverName) + ConnectionCardDetails(title: resourceCard.title, subtitle: resourceCard.serverName) Spacer() ZStack { if(!isLoading) { diff --git a/Tella/Scenes/Uwazi/Models/TemplateActionType.swift b/Tella/Scenes/Uwazi/Models/TemplateActionType.swift index 1a47f4a53..ce51c16e1 100644 --- a/Tella/Scenes/Uwazi/Models/TemplateActionType.swift +++ b/Tella/Scenes/Uwazi/Models/TemplateActionType.swift @@ -12,13 +12,6 @@ enum TemplateActionType: ActionType { case delete } -enum UwaziActionType: ActionType { - case delete - case createEntity - case viewOutboxEntity - case viewSubmittedEntity -} - var templateActionItems : [ListActionSheetItem] { return [ ListActionSheetItem(imageName: "delete-icon-white", content: LocalizableUwazi.uwaziDeleteFromDevice.localized, @@ -29,9 +22,9 @@ var templateActionItems : [ListActionSheetItem] { return [ var downloadTemplateActionItems : [ListActionSheetItem] { return [ ListActionSheetItem(imageName: "edit-icon", content: LocalizableUwazi.uwaziCreateEntitySheetExpl.localized, - type: UwaziActionType.createEntity), + type: ConnectionActionType.editDraft), ListActionSheetItem(imageName: "delete-icon-white", content: LocalizableUwazi.uwaziDeleteTemplate.localized, - type: UwaziActionType.delete) + type: ConnectionActionType.delete) ] } diff --git a/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift b/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift index c9b85029c..7c54d7050 100644 --- a/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift +++ b/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift @@ -28,14 +28,14 @@ class UwaziCardViewModel: CommonCardViewModel { let title = template.entityRow?.translatedName ?? "" let deleteTitle = String.init(format: LocalizableUwazi.deleteSheetTitle.localized, "\(title)") let deleteMessage = LocalizableUwazi.uwaziDeleteTemplateExpl.localized - let deleteReportStrings = DeleteReportStrings(deleteTitle: deleteTitle, + let deleteReportStrings = ConfirmDeleteConnectionStrings(deleteTitle: deleteTitle, deleteMessage: deleteMessage) super.init(id: Int(UUID().uuidString) ?? 0, title: title, iconImageName: nil, serverName: template.serverName ?? "", listActionSheetItem: downloadTemplateActionItems, - connectionType: .uwazi, + connectionType: .uwazi, deleteReportStrings: deleteReportStrings, deleteAction: deleteTemplate) diff --git a/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift b/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift index bb2006784..170a678fb 100644 --- a/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift +++ b/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift @@ -66,7 +66,7 @@ struct EntityInstanceItemView: View { .frame(width: 12) } - ConnectionCardDetail(title: cardViewModel.title, + ConnectionCardDetails(title: cardViewModel.title, subtitle: cardViewModel.serverName) Spacer() @@ -84,18 +84,18 @@ struct EntityInstanceItemView: View { ActionListBottomSheet(items: cardViewModel.listActionSheetItem, headerTitle: cardViewModel.title, action: {item in - guard let type = item.type as? UwaziActionType else {return} + guard let type = item.type as? ConnectionActionType else {return} switch type { case .delete: showDeleteTemplateConfirmationView() - case .createEntity: + case .editDraft: showCreateEntityView() sheetManager.hide() - case .viewOutboxEntity: + case .editOutbox: showSummaryEntityView() sheetManager.hide() - case .viewSubmittedEntity: + case .viewSubmitted: showSubmittedEntityView() sheetManager.hide() } From f3d7e23104609397176c58d85125d0a4cdd5d9ae Mon Sep 17 00:00:00 2001 From: Dhekra Rouatbi Date: Fri, 5 Jul 2024 16:14:04 +0100 Subject: [PATCH 077/167] Update report id --- .../ViewModels/CommonCardViewModel.swift | 5 +++-- .../ViewModels/ReportCardViewModel.swift | 2 +- Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift index 21c22d863..714d317da 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift @@ -10,7 +10,7 @@ import Foundation class CommonCardViewModel: Hashable { - var id : Int + var id : Int? var title: String var iconImageName: String? var serverName: String? @@ -19,7 +19,8 @@ class CommonCardViewModel: Hashable { var deleteReportStrings : ConfirmDeleteConnectionStrings var deleteAction: (() -> Void) - init(id: Int, title: String, + init(id: Int?, + title: String, iconImageName: String?, serverName: String?, listActionSheetItem: [ListActionSheetItem], diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift index 841abb0eb..4ea5c9d6d 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift @@ -23,7 +23,7 @@ class ReportCardViewModel: CommonCardViewModel { let listActionSheetItem = report.status.listActionSheetItem let deleteReportStrings = report.status.deleteReportStrings - super.init(id: Int(UUID().uuidString) ?? 0, + super.init(id: report.id, title: title, iconImageName: iconImageName, serverName: serverName, diff --git a/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift b/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift index 7c54d7050..f8761b6d5 100644 --- a/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift +++ b/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift @@ -30,7 +30,7 @@ class UwaziCardViewModel: CommonCardViewModel { let deleteMessage = LocalizableUwazi.uwaziDeleteTemplateExpl.localized let deleteReportStrings = ConfirmDeleteConnectionStrings(deleteTitle: deleteTitle, deleteMessage: deleteMessage) - super.init(id: Int(UUID().uuidString) ?? 0, + super.init(id: Int(UUID().uuidString), title: title, iconImageName: nil, serverName: template.serverName ?? "", @@ -53,7 +53,7 @@ class UwaziCardViewModel: CommonCardViewModel { let listActionSheetItem = instance.status.listActionSheetItem let deleteReportStrings = instance.status.deleteReportStrings(title: title) - super.init(id: Int(UUID().uuidString) ?? 0, + super.init(id: Int(UUID().uuidString) , title: title, iconImageName: iconImageName, serverName: serverName, From 66dbb549cc95924e99a307b5d8dd5f5131bc504b Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 5 Jul 2024 17:11:51 -0300 Subject: [PATCH 078/167] make report to conform with reusable report component --- .../Components/Reports/Draft/DraftView.swift | 12 +- .../ViewModels/ReportCardViewModel.swift | 8 +- .../ViewModels/ReportMainViewModel.swift | 2 +- .../Views/CommonReportListView.swift | 4 - .../Views/ReportMainView.swift | 36 ++- .../Views/GDriveList/GDriveCardView.swift | 9 +- .../Home/Connections/ConnectionsView.swift | 6 +- .../Reports/Draft/DraftReportView.swift | 7 +- .../Reports/Outbox/OutboxDetailsView.swift | 7 +- .../Reports/ReportList/ReportCardView.swift | 8 +- Tella/Scenes/Reports/ReportsView.swift | 244 +++++++++--------- .../Submitted/SubmittedDetailsView.swift | 4 +- .../Reports/View Model/OutboxReportVM.swift | 6 +- .../Reports/View Model/ReportsViewModel.swift | 54 ++-- .../Servers/AddServer/ServerLoginView.swift | 5 +- .../Servers/AddServer/SuccessLoginView.swift | 2 +- 16 files changed, 220 insertions(+), 194 deletions(-) diff --git a/Tella/Components/Reports/Draft/DraftView.swift b/Tella/Components/Reports/Draft/DraftView.swift index 5ff665eac..a4dd6da38 100644 --- a/Tella/Components/Reports/Draft/DraftView.swift +++ b/Tella/Components/Reports/Draft/DraftView.swift @@ -123,13 +123,11 @@ struct DraftView: View { } var outboxDetailsView: some View { - Text("") - -// OutboxDetailsView(appModel: mainAppModel, -// reportsViewModel: reportsViewModel, -// reportId: viewModel.reportId, -// shouldStartUpload: true) -// .environmentObject(reportsViewModel) + OutboxDetailsView(appModel: mainAppModel, + reportsViewModel: reportsViewModel, + reportId: viewModel.reportId, + shouldStartUpload: true) + .environmentObject(reportsViewModel) } var photoVideoPickerView: some View { diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift index 841abb0eb..45ef0dd2b 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift @@ -15,7 +15,9 @@ class ReportCardViewModel: CommonCardViewModel { init(report : BaseReport, serverName : String?, - deleteReport: @escaping (() -> Void)) { + deleteReport: @escaping (() -> Void), + connectionType: ServerConnectionType = .uwazi + ) { let title = report.title ?? "" let serverName = serverName @@ -23,12 +25,12 @@ class ReportCardViewModel: CommonCardViewModel { let listActionSheetItem = report.status.listActionSheetItem let deleteReportStrings = report.status.deleteReportStrings - super.init(id: Int(UUID().uuidString) ?? 0, + super.init(id: report.id ?? 0, title: title, iconImageName: iconImageName, serverName: serverName, listActionSheetItem: listActionSheetItem, - connectionType: .uwazi, + connectionType: connectionType, deleteReportStrings: deleteReportStrings, deleteAction:deleteReport) diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift index ffd997d35..87fbb0a29 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift @@ -15,7 +15,7 @@ class ReportMainViewModel: ObservableObject { @Published var outboxedReportsViewModel : [CommonCardViewModel] = [] @Published var submittedReportsViewModel : [CommonCardViewModel] = [] - @Published var selectedCell = Pages.template + @Published var selectedCell: Pages = .draft @Published var isLoading: Bool = false @Published var shouldShowToast : Bool = false diff --git a/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift b/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift index f05b4823c..b449bde3f 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift @@ -47,10 +47,6 @@ struct CommonReportListView: View { } } } - - - - } struct CommonItemView: View { diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift index db570d36c..0ba481b82 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -34,7 +34,7 @@ struct ReportMainView: View { ContainerView { VStack(alignment: .center) { - PageView(selectedOption: $reportMainViewModel.selectedCell, pageViewItems: reportMainViewModel.pageViewItems) + PageView(selectedOption: self.$reportMainViewModel.selectedCell, pageViewItems: reportMainViewModel.pageViewItems) .frame(maxWidth: .infinity, maxHeight: 40, alignment: .leading) VStack (spacing: 0) { @@ -114,10 +114,10 @@ struct ReportMainView: View { showDraftView(id: id) case .editOutbox: - showOutboxView() + showOutboxView(id: id) case .viewSubmitted: - showSubmittedEntityView() + showSubmittedView(id: id) sheetManager.hide() case .delete: @@ -129,13 +129,17 @@ struct ReportMainView: View { } private func showDetailsView(cardViewModel:CommonCardViewModel) { - guard let cardViewModel = cardViewModel as? ReportCardViewModel else { return } + dump(cardViewModel.status) switch cardViewModel.status { case .unknown, .draft: showDraftView(id: cardViewModel.id) sheetManager.hide() + case .finalized: + showOutboxView(id: cardViewModel.id) + sheetManager.hide() case .submitted: + showSubmittedView(id: cardViewModel.id) sheetManager.hide() default: sheetManager.hide() @@ -146,6 +150,9 @@ struct ReportMainView: View { switch reportMainViewModel.connectionType { case .tella: + var destination: any View + destination = DraftReportView(mainAppModel: mainAppModel, reportId: id).environmentObject(reportMainViewModel) + self.navigateTo(destination: destination) break case .gDrive: var destination : any View @@ -169,11 +176,28 @@ struct ReportMainView: View { sheetManager.hide() } - private func showOutboxView() { + private func showOutboxView(id: Int? = nil) { + switch reportMainViewModel.connectionType { + case .tella: + let destination = OutboxDetailsView(appModel: mainAppModel, reportsViewModel: reportMainViewModel, reportId: id) + .environmentObject(reportMainViewModel) + self.navigateTo(destination: destination) + break + default: + break + } sheetManager.hide() } - private func showSubmittedEntityView() { + private func showSubmittedView(id: Int? = nil) { + switch reportMainViewModel.connectionType { + case .tella: + let destination = SubmittedDetailsView(appModel: mainAppModel, reportId: id).environmentObject(reportMainViewModel) + self.navigateTo(destination: destination) + default: + break + } + sheetManager.hide() } diff --git a/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift b/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift index 8191c2dc6..0d501fe46 100644 --- a/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift +++ b/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift @@ -101,10 +101,11 @@ struct GDriveCardView : View { } private var outboxDetailsView: some View { - OutboxDetailsView(appModel: mainAppModel, - reportsViewModel: reportsViewModel, - reportId: reportsViewModel.selectedReport?.id) - .environmentObject(reportsViewModel as BaseReportsViewModel) +// OutboxDetailsView(appModel: mainAppModel, +// reportsViewModel: reportsViewModel, +// reportId: reportsViewModel.selectedReport?.id) +// .environmentObject(reportsViewModel as BaseReportsViewModel) + Text("") } private var deleteMessage : String { diff --git a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift index abccdcf9a..c920fb467 100644 --- a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift +++ b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift @@ -41,7 +41,7 @@ struct ConnectionsView: View { case .tella: ConnectionsItemView(title: LocalizableReport.reportsTitle.localized, image: "home.report", - destination: ReportsView(mainAppModel: appModel)) + destination: reportsMainView) ConnectionsItemView(title: LocalizableResources.resourcesServerTitle.localized, image: "home.resources", destination: ResourcesView(mainAppModel: appModel), @@ -67,6 +67,10 @@ struct ConnectionsView: View { }.padding(.trailing, 17) } + var reportsMainView: some View { + ReportMainView(reportMainViewModel: ReportsViewModel(mainAppModel: appModel), diContainer: GDriveDIContainer()) + } + var gDriveMainView : some View { ReportMainView(reportMainViewModel: NextcloudReportViewModel(mainAppModel: appModel, connectionType: .gDrive, diff --git a/Tella/Scenes/Reports/Draft/DraftReportView.swift b/Tella/Scenes/Reports/Draft/DraftReportView.swift index 228fa892f..6ed00791e 100644 --- a/Tella/Scenes/Reports/Draft/DraftReportView.swift +++ b/Tella/Scenes/Reports/Draft/DraftReportView.swift @@ -14,7 +14,7 @@ struct DraftReportView: View { @EnvironmentObject var mainAppModel : MainAppModel @EnvironmentObject var sheetManager : SheetManager - @EnvironmentObject var reportsViewModel : BaseReportsViewModel + @EnvironmentObject var reportsViewModel : ReportMainViewModel @Environment(\.presentationMode) var presentationMode: Binding init(mainAppModel: MainAppModel, reportId:Int? = nil) { @@ -22,9 +22,8 @@ struct DraftReportView: View { } var body: some View { - Text("") -// DraftView(viewModel: reportViewModel, reportsViewModel: <#ReportMainViewModel#>) -// .environmentObject(reportsViewModel) + DraftView(viewModel: reportViewModel, reportsViewModel: reportsViewModel) + .environmentObject(reportsViewModel) } } diff --git a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift index e34c8e999..58f532224 100644 --- a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift +++ b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift @@ -7,12 +7,12 @@ import SwiftUI struct OutboxDetailsView: View { @StateObject var outboxReportVM : OutboxReportVM - @EnvironmentObject var reportsViewModel : BaseReportsViewModel + @EnvironmentObject var reportsViewModel : ReportMainViewModel @EnvironmentObject var mainAppModel : MainAppModel @Environment(\.presentationMode) var presentationMode: Binding @EnvironmentObject private var sheetManager: SheetManager - init(appModel: MainAppModel,reportsViewModel: BaseReportsViewModel, reportId : Int?, shouldStartUpload: Bool = false) { + init(appModel: MainAppModel,reportsViewModel: ReportMainViewModel, reportId : Int?, shouldStartUpload: Bool = false) { _outboxReportVM = StateObject(wrappedValue: OutboxReportVM(mainAppModel: appModel, reportsViewModel: reportsViewModel, reportId:reportId, shouldStartUpload: shouldStartUpload)) } @@ -56,6 +56,7 @@ struct OutboxDetailsView: View { HStack(spacing: 0) { Button { + dump("DISMISSS") dismissView() } label: { Image("back") @@ -185,7 +186,7 @@ struct OutboxDetailsView: View { } private func dismissView() { - self.popTo(UIHostingController.self) + self.presentationMode.wrappedValue.dismiss() } private func showDeleteReportConfirmationView() { diff --git a/Tella/Scenes/Reports/ReportList/ReportCardView.swift b/Tella/Scenes/Reports/ReportList/ReportCardView.swift index 3644d2f6f..131da7be8 100644 --- a/Tella/Scenes/Reports/ReportList/ReportCardView.swift +++ b/Tella/Scenes/Reports/ReportList/ReportCardView.swift @@ -58,7 +58,7 @@ struct ReportCardView : View { sheetManager.showBottomSheet(modalHeight: 200) { DeleteReportConfirmationView(title: report.title, message: deleteMessage) { - reportsViewModel.deleteReport() + reportsViewModel.deleteReport(report: report) sheetManager.hide() } } @@ -86,20 +86,20 @@ struct ReportCardView : View { private var editDraftReportView: some View { DraftReportView(mainAppModel: mainAppModel, reportId: reportsViewModel.selectedReport?.id) - .environmentObject(reportsViewModel as BaseReportsViewModel) + .environmentObject(reportsViewModel) } private var submittedDetailsView: some View { SubmittedDetailsView(appModel: mainAppModel, reportId: reportsViewModel.selectedReport?.id) - .environmentObject(reportsViewModel as BaseReportsViewModel) + .environmentObject(reportsViewModel) } private var outboxDetailsView: some View { OutboxDetailsView(appModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: reportsViewModel.selectedReport?.id) - .environmentObject(reportsViewModel as BaseReportsViewModel) + .environmentObject(reportsViewModel) } private var deleteMessage : String { diff --git a/Tella/Scenes/Reports/ReportsView.swift b/Tella/Scenes/Reports/ReportsView.swift index 11d282959..7c6f3082f 100644 --- a/Tella/Scenes/Reports/ReportsView.swift +++ b/Tella/Scenes/Reports/ReportsView.swift @@ -1,124 +1,124 @@ +//// +//// Copyright © 2021 INTERNEWS. All rights reserved. +//// +//import SwiftUI // -// Copyright © 2021 INTERNEWS. All rights reserved. // -import SwiftUI - - -enum ReportPaths { - case reportMain - case draft - case outbox - case submitted -} - -struct ReportsView: View { - - @EnvironmentObject var mainAppModel : MainAppModel - @StateObject private var reportsViewModel : ReportsViewModel - @EnvironmentObject var sheetManager : SheetManager - - init(mainAppModel:MainAppModel) { - _reportsViewModel = StateObject(wrappedValue: ReportsViewModel(mainAppModel: mainAppModel)) - } - - var body: some View { - - contentView - .navigationBarTitle(LocalizableReport.reportsTitle.localized, displayMode: .large) - .environmentObject(reportsViewModel) - } - - private var contentView :some View { - - ContainerView { - - VStack(alignment: .center) { - - PageView(selectedOption: self.$reportsViewModel.selectedCell, pageViewItems: reportsViewModel.pageViewItems) - .frame(maxWidth: .infinity, maxHeight: 40, alignment: .leading) - - VStack (spacing: 0) { - Spacer() - - switch self.reportsViewModel.selectedCell { - - case .draft: - ReportListView(reportArray: $reportsViewModel.draftReports, - message: LocalizableReport.reportsDraftEmpty.localized) - case .outbox: - - ReportListView(reportArray: $reportsViewModel.outboxedReports, - message: LocalizableReport.reportsOutboxEmpty.localized) - - case .submitted: - ReportListView(reportArray: $reportsViewModel.submittedReports, - message: LocalizableReport.reportsSubmitedEmpty.localized) - default: - EmptyView() - } - - Spacer() - } - - TellaButtonView (title: LocalizableReport.reportsCreateNew.localized, - nextButtonAction: .action, - buttonType: .yellow, - isValid: .constant(true)) { - navigateTo(destination: newDraftReportView) - } .padding(EdgeInsets(top: 30, leading: 0, bottom: 0, trailing: 0)) - - }.background(Styles.Colors.backgroundMain) - .padding(EdgeInsets(top: 15, leading: 20, bottom: 16, trailing: 20)) - .navigationBarBackButtonHidden(true) - .navigationBarItems(leading: backButton) - } - - .if(self.reportsViewModel.selectedCell == .submitted && self.reportsViewModel.submittedReports.count > 0, transform: { view in - view.toolbar { - TrailingButtonToolbar(title: LocalizableReport.clearAppBar.localized) { - showDeleteReportConfirmationView() - } - } - }) - } - - private var newDraftReportView: some View { - DraftReportView(mainAppModel: mainAppModel).environmentObject(reportsViewModel as BaseReportsViewModel) - } - - private func showDeleteReportConfirmationView() { - sheetManager.showBottomSheet(modalHeight: 200) { - - - ConfirmBottomSheet(titleText: LocalizableReport.clearSheetTitle.localized, - msgText: LocalizableReport.clearSheetExpl.localized, - cancelText: LocalizableReport.clearCancel.localized, - actionText: LocalizableReport.clearSubmitted.localized, didConfirmAction: { - sheetManager.hide() - reportsViewModel.deleteSubmittedReport() - Toast.displayToast(message: LocalizableReport.allReportDeletedToast.localized) - }) - } - } - - var backButton : some View { - Button { - self.popToRoot() - } label: { - Image("back") - .flipsForRightToLeftLayoutDirection(true) - .padding(EdgeInsets(top: -3, leading: -8, bottom: 0, trailing: 12)) - } - } -} - -struct ReportsView_Previews: PreviewProvider { - - static var previews: some View { - ReportsView(mainAppModel: MainAppModel.stub()) - } -} - -extension Int: Identifiable { - public var id: Int { self } -} +//enum ReportPaths { +// case reportMain +// case draft +// case outbox +// case submitted +//} +// +//struct ReportsView: View { +// +// @EnvironmentObject var mainAppModel : MainAppModel +// @StateObject private var reportsViewModel : ReportsViewModel +// @EnvironmentObject var sheetManager : SheetManager +// +// init(mainAppModel:MainAppModel) { +// _reportsViewModel = StateObject(wrappedValue: ReportsViewModel(mainAppModel: mainAppModel)) +// } +// +// var body: some View { +// +// contentView +// .navigationBarTitle(LocalizableReport.reportsTitle.localized, displayMode: .large) +// .environmentObject(reportsViewModel) +// } +// +// private var contentView :some View { +// +// ContainerView { +// +// VStack(alignment: .center) { +// +// PageView(selectedOption: self.$reportsViewModel.selectedCell, pageViewItems: reportsViewModel.pageViewItems) +// .frame(maxWidth: .infinity, maxHeight: 40, alignment: .leading) +// +// VStack (spacing: 0) { +// Spacer() +// +// switch self.reportsViewModel.selectedCell { +// +// case .draft: +// ReportListView(reportArray: $reportsViewModel.draftReports, +// message: LocalizableReport.reportsDraftEmpty.localized) +// case .outbox: +// +// ReportListView(reportArray: $reportsViewModel.outboxedReports, +// message: LocalizableReport.reportsOutboxEmpty.localized) +// +// case .submitted: +// ReportListView(reportArray: $reportsViewModel.submittedReports, +// message: LocalizableReport.reportsSubmitedEmpty.localized) +// default: +// EmptyView() +// } +// +// Spacer() +// } +// +// TellaButtonView (title: LocalizableReport.reportsCreateNew.localized, +// nextButtonAction: .action, +// buttonType: .yellow, +// isValid: .constant(true)) { +// navigateTo(destination: newDraftReportView) +// } .padding(EdgeInsets(top: 30, leading: 0, bottom: 0, trailing: 0)) +// +// }.background(Styles.Colors.backgroundMain) +// .padding(EdgeInsets(top: 15, leading: 20, bottom: 16, trailing: 20)) +// .navigationBarBackButtonHidden(true) +// .navigationBarItems(leading: backButton) +// } +// +// .if(self.reportsViewModel.selectedCell == .submitted && self.reportsViewModel.submittedReports.count > 0, transform: { view in +// view.toolbar { +// TrailingButtonToolbar(title: LocalizableReport.clearAppBar.localized) { +// showDeleteReportConfirmationView() +// } +// } +// }) +// } +// +// private var newDraftReportView: some View { +// DraftReportView(mainAppModel: mainAppModel).environmentObject(reportsViewModel) +// } +// +// private func showDeleteReportConfirmationView() { +// sheetManager.showBottomSheet(modalHeight: 200) { +// +// +// ConfirmBottomSheet(titleText: LocalizableReport.clearSheetTitle.localized, +// msgText: LocalizableReport.clearSheetExpl.localized, +// cancelText: LocalizableReport.clearCancel.localized, +// actionText: LocalizableReport.clearSubmitted.localized, didConfirmAction: { +// sheetManager.hide() +// reportsViewModel.deleteSubmittedReport() +// Toast.displayToast(message: LocalizableReport.allReportDeletedToast.localized) +// }) +// } +// } +// +// var backButton : some View { +// Button { +// self.popToRoot() +// } label: { +// Image("back") +// .flipsForRightToLeftLayoutDirection(true) +// .padding(EdgeInsets(top: -3, leading: -8, bottom: 0, trailing: 12)) +// } +// } +//} +// +//struct ReportsView_Previews: PreviewProvider { +// +// static var previews: some View { +// ReportsView(mainAppModel: MainAppModel.stub()) +// } +//} +// +//extension Int: Identifiable { +// public var id: Int { self } +//} diff --git a/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift b/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift index 809eaf42c..03f943cb0 100644 --- a/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift +++ b/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift @@ -8,7 +8,7 @@ import SwiftUI struct SubmittedDetailsView: View { @StateObject var submittedReportVM : SubmittedReportVM - @EnvironmentObject var reportsViewModel : BaseReportsViewModel + @EnvironmentObject var reportsViewModel : ReportMainViewModel @EnvironmentObject var mainAppModel : MainAppModel @Environment(\.presentationMode) var presentationMode: Binding @EnvironmentObject private var sheetManager: SheetManager @@ -133,8 +133,8 @@ struct SubmittedDetailsView: View { } private func dismissViews() { - self.popTo(UIHostingController.self) self.reportsViewModel.selectedCell = .submitted + self.popTo(UIHostingController.self) } private func showDeleteReportConfirmationView() { diff --git a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift index 0b64e3475..99c7dcbe5 100644 --- a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift +++ b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift @@ -8,7 +8,7 @@ import Combine class OutboxReportVM: ObservableObject { var mainAppModel : MainAppModel - var reportsViewModel : BaseReportsViewModel + var reportsViewModel : ReportMainViewModel @Published var reportViewModel : ReportViewModel = ReportViewModel() @Published var progressFileItems : [ProgressFileItemViewModel] = [] @@ -53,11 +53,11 @@ class OutboxReportVM: ObservableObject { } - init(mainAppModel: MainAppModel, reportsViewModel : BaseReportsViewModel, reportId : Int?, shouldStartUpload: Bool = false) { + init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, reportId : Int?, shouldStartUpload: Bool = false) { self.mainAppModel = mainAppModel self.reportsViewModel = reportsViewModel - + initVaultFile(reportId: reportId) initializeProgressionInfos() diff --git a/Tella/Scenes/Reports/View Model/ReportsViewModel.swift b/Tella/Scenes/Reports/View Model/ReportsViewModel.swift index 9b5aa4cb8..7d851b295 100644 --- a/Tella/Scenes/Reports/View Model/ReportsViewModel.swift +++ b/Tella/Scenes/Reports/View Model/ReportsViewModel.swift @@ -7,18 +7,9 @@ import Foundation import Combine import SwiftUI -class ReportsViewModel: BaseReportsViewModel { - - @Published var draftReports : [Report] = [] - @Published var outboxedReports : [Report] = [] - @Published var submittedReports : [Report] = [] +class ReportsViewModel: ReportMainViewModel { @Published var selectedReport : Report? - var pageViewItems : [PageViewItem] { - [PageViewItem(title: LocalizableReport.draftTitle.localized, page: .draft, number: draftReports.count), - PageViewItem(title: LocalizableReport.outboxTitle.localized, page: .outbox, number: outboxedReports.count), - PageViewItem(title: LocalizableReport.submittedTitle.localized, page: .submitted, number: submittedReports.count)] } - var sheetItems : [ListActionSheetItem] { return [ ListActionSheetItem(imageName: "view-icon", @@ -29,17 +20,16 @@ class ReportsViewModel: BaseReportsViewModel { type: ConnectionActionType.delete) ]} - private var subscribers = Set() private var delayTime = 0.1 - override init(mainAppModel : MainAppModel) { + init(mainAppModel : MainAppModel) { - super.init(mainAppModel: mainAppModel) + super.init(mainAppModel: mainAppModel, connectionType: .tella, title: LocalizableReport.reportsTitle.localized) self.getReports() } - private func getReports() { + override func getReports() { getDraftReports() getOutboxedReports() getSubmittedReports() @@ -50,10 +40,13 @@ class ReportsViewModel: BaseReportsViewModel { .receive(on: DispatchQueue.main) .sink { result in } receiveValue: { draftReports in - self.draftReports = [] - DispatchQueue.main.asyncAfter(deadline: .now() + self.delayTime, execute: { - self.draftReports = draftReports - }) + self.draftReportsViewModel = draftReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: { self.deleteReport(report: report) }, + connectionType: .tella + ) + } }.store(in: &subscribers) } @@ -62,10 +55,12 @@ class ReportsViewModel: BaseReportsViewModel { .receive(on: DispatchQueue.main) .sink { result in } receiveValue: { outboxedReports in - self.outboxedReports = [] - DispatchQueue.main.asyncAfter(deadline: .now() + self.delayTime, execute: { - self.outboxedReports = outboxedReports - }) + self.outboxedReportsViewModel = outboxedReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: { self.deleteReport(report: report) }, connectionType: .tella + ) + } }.store(in: &subscribers) } @@ -75,15 +70,18 @@ class ReportsViewModel: BaseReportsViewModel { .receive(on: DispatchQueue.main) .sink { result in } receiveValue: { submittedReports in - self.submittedReports = [] - DispatchQueue.main.asyncAfter(deadline: .now() + self.delayTime, execute: { - self.submittedReports = submittedReports - }) + self.submittedReportsViewModel = submittedReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: { self.deleteReport(report: report) }, + connectionType: .tella + ) + } }.store(in: &subscribers) } - func deleteReport() { - mainAppModel.deleteReport(reportId: selectedReport?.id) + func deleteReport(report: Report) { + mainAppModel.deleteReport(reportId: report.id) } func deleteSubmittedReport() { diff --git a/Tella/Scenes/Settings/Views/Servers/AddServer/ServerLoginView.swift b/Tella/Scenes/Settings/Views/Servers/AddServer/ServerLoginView.swift index b9da81412..093dce195 100644 --- a/Tella/Scenes/Settings/Views/Servers/AddServer/ServerLoginView.swift +++ b/Tella/Scenes/Settings/Views/Servers/AddServer/ServerLoginView.swift @@ -87,8 +87,11 @@ struct ServerLoginView: View { private var successLoginView: some View { SuccessLoginView(navigateToAction: { - navigateTo(destination: ReportsView(mainAppModel: mainAppModel)) + navigateTo(destination: reportsMainView) }).environmentObject(serverViewModel) } + var reportsMainView: some View { + ReportMainView(reportMainViewModel: ReportsViewModel(mainAppModel: mainAppModel), diContainer: GDriveDIContainer()) + } } diff --git a/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift b/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift index 49e84cfdb..d1d72d6a1 100644 --- a/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift +++ b/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift @@ -75,7 +75,7 @@ struct SuccessLoginView: View { } private var reportsView: some View { - ReportsView(mainAppModel: mainAppModel) + ReportMainView(reportMainViewModel: ReportsViewModel(mainAppModel: mainAppModel), diContainer: GDriveDIContainer()) } } From 43671785eb4200f417a3d5b316a3b635865b5ca4 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 5 Jul 2024 17:40:25 -0300 Subject: [PATCH 079/167] make gDriveViewModel to conform with reportMainViewModel --- .../GDrive/ViewModel/GDriveViewModel.swift | 58 +++++++++---------- .../Views/GDriveList/GDriveCardView.swift | 6 +- Tella/Scenes/GDrive/Views/GDriveView.swift | 2 +- .../Home/Connections/ConnectionsView.swift | 4 +- 4 files changed, 31 insertions(+), 39 deletions(-) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift index 85ac95d00..1d2cb7292 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -8,27 +8,15 @@ import Foundation import Combine -class GDriveViewModel: BaseReportsViewModel { +class GDriveViewModel: ReportMainViewModel { @Published var draftReports: [GDriveReport] = [] @Published var outboxedReports: [GDriveReport] = [] @Published var submittedReports: [GDriveReport] = [] @Published var selectedReport: GDriveReport? - var pageViewItems: [PageViewItem] { - [ - PageViewItem(title: LocalizableReport.draftTitle.localized, - page: .draft, - number: draftReports.count), - PageViewItem(title: LocalizableReport.outboxTitle.localized, - page: .outbox, - number: outboxedReports.count), - PageViewItem(title: LocalizableReport.submittedTitle.localized, - page: .submitted, - number: submittedReports.count)] - } - - private var subscribers = Set() + + private var delayTime = 0.1 var sheetItems : [ListActionSheetItem] { return [ @@ -41,13 +29,13 @@ class GDriveViewModel: BaseReportsViewModel { type: ConnectionActionType.delete) ]} - override init(mainAppModel: MainAppModel) { - super.init(mainAppModel: mainAppModel) + init(mainAppModel: MainAppModel) { + super.init(mainAppModel: mainAppModel, connectionType: .gDrive, title: "Google Drive") self.getReports() } - private func getReports() { + override func getReports() { getDraftReports() getOutboxedReports() getSubmittedReports() @@ -58,10 +46,12 @@ class GDriveViewModel: BaseReportsViewModel { .receive(on: DispatchQueue.main) .sink { result in } receiveValue: { draftReports in - self.draftReports = [] - DispatchQueue.main.asyncAfter(deadline: .now() + self.delayTime, execute: { - self.draftReports = draftReports - }) + self.draftReportsViewModel = draftReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: { self.deleteReport(report: report) } + ) + } }.store(in: &subscribers) } @@ -70,10 +60,12 @@ class GDriveViewModel: BaseReportsViewModel { .receive(on: DispatchQueue.main) .sink { result in } receiveValue: { outboxedReports in - self.outboxedReports = [] - DispatchQueue.main.asyncAfter(deadline: .now() + self.delayTime, execute: { - self.outboxedReports = outboxedReports - }) + self.outboxedReportsViewModel = outboxedReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: { self.deleteReport(report: report) } + ) + } }.store(in: &subscribers) } @@ -82,14 +74,16 @@ class GDriveViewModel: BaseReportsViewModel { .receive(on: DispatchQueue.main) .sink { result in } receiveValue: { submittedReports in - self.outboxedReports = [] - DispatchQueue.main.asyncAfter(deadline: .now() + self.delayTime, execute: { - self.submittedReports = submittedReports - }) + self.submittedReportsViewModel = submittedReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: { self.deleteReport(report: report) } + ) + } }.store(in: &subscribers) } - func deleteReport() { - let _ = self.mainAppModel.tellaData?.deleteDriveReport(reportId: selectedReport?.id) + func deleteReport(report: GDriveReport) { + let _ = self.mainAppModel.tellaData?.deleteDriveReport(reportId: report.id) } } diff --git a/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift b/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift index 0d501fe46..6ad28a2e6 100644 --- a/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift +++ b/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift @@ -62,7 +62,7 @@ struct GDriveCardView : View { sheetManager.showBottomSheet(modalHeight: 200) { DeleteReportConfirmationView(title: report.title, message: deleteMessage) { - reportsViewModel.deleteReport() + reportsViewModel.deleteReport(report: report) sheetManager.hide() } } @@ -91,13 +91,13 @@ struct GDriveCardView : View { GDriveDraftView(mainAppModel: mainAppModel, gDriveDIContainer: gDriveDIContainer, reportId: report.id) - .environmentObject(reportsViewModel as BaseReportsViewModel) + .environmentObject(reportsViewModel) } private var submittedDetailsView: some View { SubmittedDetailsView(appModel: mainAppModel, reportId: reportsViewModel.selectedReport?.id) - .environmentObject(reportsViewModel as BaseReportsViewModel) + .environmentObject(reportsViewModel) } private var outboxDetailsView: some View { diff --git a/Tella/Scenes/GDrive/Views/GDriveView.swift b/Tella/Scenes/GDrive/Views/GDriveView.swift index cbd370b8d..71f6ba2b9 100644 --- a/Tella/Scenes/GDrive/Views/GDriveView.swift +++ b/Tella/Scenes/GDrive/Views/GDriveView.swift @@ -60,7 +60,7 @@ struct GDriveView: View { private var newGDriveDraftView: some View { GDriveDraftView(mainAppModel: mainAppModel, gDriveDIContainer: gDriveDIContainer) - .environmentObject(gDriveViewModel as BaseReportsViewModel) + .environmentObject(gDriveViewModel) } } diff --git a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift index c920fb467..d4d9c3ecf 100644 --- a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift +++ b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift @@ -72,9 +72,7 @@ struct ConnectionsView: View { } var gDriveMainView : some View { - ReportMainView(reportMainViewModel: NextcloudReportViewModel(mainAppModel: appModel, - connectionType: .gDrive, - title: "Drive"), + ReportMainView(reportMainViewModel: GDriveViewModel(mainAppModel: appModel), diContainer: GDriveDIContainer()) } From cda20decee062787b820527270183a7da2d4237e Mon Sep 17 00:00:00 2001 From: Dhekra Rouatbi Date: Mon, 8 Jul 2024 15:58:49 +0100 Subject: [PATCH 080/167] Remove unused code --- Tella.xcodeproj/project.pbxproj | 20 --- .../Connections/ConnectionEmptyView.swift | 8 +- .../Views/CommonReportListView.swift | 16 +-- .../Views/ReportMainView.swift | 25 ++-- .../GDrive/Views/Draft/GDriveDraftView.swift | 8 +- .../Views/GDriveList/GDriveCardView.swift | 121 ------------------ .../Views/GDriveList/GDriveListView.swift | 29 ----- Tella/Scenes/GDrive/Views/GDriveView.swift | 69 ---------- .../Reports/ReportList/ReportListView.swift | 2 +- .../Views/EntityInstances/UwaziListView.swift | 2 +- .../Views/Template/AddTemplatesView.swift | 2 +- 11 files changed, 28 insertions(+), 274 deletions(-) delete mode 100644 Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift delete mode 100644 Tella/Scenes/GDrive/Views/GDriveList/GDriveListView.swift delete mode 100644 Tella/Scenes/GDrive/Views/GDriveView.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index c6931d7c1..79cf35b60 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -380,12 +380,10 @@ 15791C232B6C2E9100D67C74 /* ResourcesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15791C222B6C2E9100D67C74 /* ResourcesViewModel.swift */; }; 157E4F532BA385B500147345 /* PDFKitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 157E4F522BA385B500147345 /* PDFKitView.swift */; }; 15917D752B90FCC3005655AC /* ResourceCardType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15917D742B90FCC3005655AC /* ResourceCardType.swift */; }; - 159229D92C34A37C003FAC9A /* GDriveCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 159229D82C34A37C003FAC9A /* GDriveCardView.swift */; }; 15994A0C2BFBC6F40017F153 /* SelectDriveConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */; }; 15994A0E2BFBE15F0017F153 /* SelectSharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */; }; 15994A112BFBF0E50017F153 /* SharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A102BFBF0E50017F153 /* SharedDrive.swift */; }; 15A505B32C2F623C0028C7CB /* GDriveData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15A505B22C2F623C0028C7CB /* GDriveData.swift */; }; - 15B81F382C1A2806007C0E88 /* GDriveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B81F372C1A2806007C0E88 /* GDriveView.swift */; }; 15B81F3A2C1A281C007C0E88 /* GDriveViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B81F392C1A281C007C0E88 /* GDriveViewModel.swift */; }; 15BD9CA92BC740B300C3932B /* UwaziRelationshipWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CA82BC740B300C3932B /* UwaziRelationshipWidget.swift */; }; 15BD9CAB2BC740D700C3932B /* EntitySelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CAA2BC740D700C3932B /* EntitySelectorView.swift */; }; @@ -395,7 +393,6 @@ 15C51C442BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C51C432BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift */; }; 15C51C462BFE769500DD9AD0 /* GDriveServerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C51C452BFE769500DD9AD0 /* GDriveServerViewModel.swift */; }; 15CD89102BF297BE00F724F5 /* SelectedEntityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */; }; - 15E3D5032C1B522500B7FECC /* GDriveListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D5022C1B522500B7FECC /* GDriveListView.swift */; }; 15E3D5052C1B531700B7FECC /* ConnectionEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D5042C1B531700B7FECC /* ConnectionEmptyView.swift */; }; 15E3D50A2C1B71E200B7FECC /* GDriveDraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D5092C1B71E200B7FECC /* GDriveDraftView.swift */; }; 15E3D50E2C1B87AC00B7FECC /* GDriveDraftViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D50D2C1B87AC00B7FECC /* GDriveDraftViewModel.swift */; }; @@ -956,12 +953,10 @@ 1589A6202B7672390048C775 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 1589A6212B7672430048C775 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; 15917D742B90FCC3005655AC /* ResourceCardType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceCardType.swift; sourceTree = ""; }; - 159229D82C34A37C003FAC9A /* GDriveCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveCardView.swift; sourceTree = ""; }; 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectDriveConnection.swift; sourceTree = ""; }; 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectSharedDrive.swift; sourceTree = ""; }; 15994A102BFBF0E50017F153 /* SharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedDrive.swift; sourceTree = ""; }; 15A505B22C2F623C0028C7CB /* GDriveData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveData.swift; sourceTree = ""; }; - 15B81F372C1A2806007C0E88 /* GDriveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveView.swift; sourceTree = ""; }; 15B81F392C1A281C007C0E88 /* GDriveViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveViewModel.swift; sourceTree = ""; }; 15BD9CA82BC740B300C3932B /* UwaziRelationshipWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziRelationshipWidget.swift; sourceTree = ""; }; 15BD9CAA2BC740D700C3932B /* EntitySelectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntitySelectorView.swift; sourceTree = ""; }; @@ -971,7 +966,6 @@ 15C51C432BFE6EDE00DD9AD0 /* GDriveAuthViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveAuthViewModel.swift; sourceTree = ""; }; 15C51C452BFE769500DD9AD0 /* GDriveServerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveServerViewModel.swift; sourceTree = ""; }; 15CD890F2BF297BE00F724F5 /* SelectedEntityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedEntityView.swift; sourceTree = ""; }; - 15E3D5022C1B522500B7FECC /* GDriveListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveListView.swift; sourceTree = ""; }; 15E3D5042C1B531700B7FECC /* ConnectionEmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionEmptyView.swift; sourceTree = ""; }; 15E3D5092C1B71E200B7FECC /* GDriveDraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveDraftView.swift; sourceTree = ""; }; 15E3D50D2C1B87AC00B7FECC /* GDriveDraftViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveDraftViewModel.swift; sourceTree = ""; }; @@ -2429,15 +2423,6 @@ path = ViewModel; sourceTree = ""; }; - 159229D72C34A2BF003FAC9A /* GDriveList */ = { - isa = PBXGroup; - children = ( - 15E3D5022C1B522500B7FECC /* GDriveListView.swift */, - 159229D82C34A37C003FAC9A /* GDriveCardView.swift */, - ); - path = GDriveList; - sourceTree = ""; - }; 15994A0A2BFBC6B10017F153 /* GDrive */ = { isa = PBXGroup; children = ( @@ -2478,9 +2463,7 @@ 15E3D5012C1B51D700B7FECC /* Views */ = { isa = PBXGroup; children = ( - 159229D72C34A2BF003FAC9A /* GDriveList */, 15E3D5062C1B712300B7FECC /* Draft */, - 15B81F372C1A2806007C0E88 /* GDriveView.swift */, ); path = Views; sourceTree = ""; @@ -3407,7 +3390,6 @@ D57F5E9026152A4800C1DA47 /* Datable.swift in Sources */, CC1313822A5CB0DB0057271C /* DeleteAfterFailOption.swift in Sources */, 15F924482C17929300C436C5 /* ViewModelState.swift in Sources */, - 15E3D5032C1B522500B7FECC /* GDriveListView.swift in Sources */, 1203CDEB2992C1CB00D09073 /* HTTPCodes.swift in Sources */, 15BD9CAB2BC740D700C3932B /* EntitySelectorView.swift in Sources */, 122389B7293635790058593B /* SetExtension.swift in Sources */, @@ -3510,7 +3492,6 @@ 1237A719278F172E00D7BC0F /* NSUIImage.swift in Sources */, 126818C32A38B69E004606BD /* FileTypeHelper.swift in Sources */, D572EACB263A43C100CE191A /* FileDetailView.swift in Sources */, - 159229D92C34A37C003FAC9A /* GDriveCardView.swift in Sources */, 127B56D5279AC28300F902C9 /* CancelImportView.swift in Sources */, 125D233C2B17344D001EFB8B /* BackgroundActivitiesView.swift in Sources */, 1293F6752AD8853500F6CFBD /* FeedbackRepository.swift in Sources */, @@ -3614,7 +3595,6 @@ 1519BED82B9A5A52006FD290 /* Resource.swift in Sources */, 128BEB202B1E4B3D00420923 /* FeedbackOperation.swift in Sources */, 128EDB92280980DB00747B98 /* SequenceExtension.swift in Sources */, - 15B81F382C1A2806007C0E88 /* GDriveView.swift in Sources */, 1289B98727C5397200315FCE /* ScreenExtension.swift in Sources */, 1227FC8F2922BDBC002FD6FB /* CameraModel.swift in Sources */, E1EEE29629E6796E009FE227 /* ServerSelectionView.swift in Sources */, diff --git a/Tella/Components/Connections/ConnectionEmptyView.swift b/Tella/Components/Connections/ConnectionEmptyView.swift index f8d08a2ab..092c63e5f 100644 --- a/Tella/Components/Connections/ConnectionEmptyView.swift +++ b/Tella/Components/Connections/ConnectionEmptyView.swift @@ -9,11 +9,13 @@ import SwiftUI struct ConnectionEmptyView: View { + var message: String - var type: ServerConnectionType + var iconName: String + var body: some View { VStack(alignment: .center, spacing: 22) { - Image(type.emptyIcon) + Image(iconName) Text(message) .font(.custom(Styles.Fonts.regularFontName, size: 14)) .foregroundColor(.white) @@ -23,5 +25,5 @@ struct ConnectionEmptyView: View { } #Preview { - ConnectionEmptyView(message: "You have no draft reports", type: .tella) + ConnectionEmptyView(message: "You have no draft reports", iconName: "uwazi.empty") } diff --git a/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift b/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift index b449bde3f..12c489a2e 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift @@ -14,20 +14,18 @@ struct CommonReportListView: View { var message: String var emptyMessage: String - + var emptyIcon: String + @Binding var cardsViewModel: [CommonCardViewModel] -// @EnvironmentObject var sheetManager: SheetManager var showDetails: ((CommonCardViewModel) -> Void) var showBottomSheet: ((CommonCardViewModel) -> Void) - + var body: some View { VStack(alignment: .center, spacing: 0) { if cardsViewModel.isEmpty { - - ConnectionEmptyView(message: emptyMessage, type: .uwazi) - + ConnectionEmptyView(message: emptyMessage, iconName: emptyIcon) } else { Text(message) @@ -37,11 +35,9 @@ struct CommonReportListView: View { ScrollView { ForEach($cardsViewModel, id: \.id) { itemViewModel in - CommonItemView(cardViewModel: itemViewModel , -// showDetails: {showDetailsView(cardViewModel: itemViewModel.wrappedValue)}, showDetails: {showDetails(itemViewModel.wrappedValue)}, - showBottomSheet: {showBottomSheet(itemViewModel.wrappedValue)}) + showBottomSheet: {showBottomSheet(itemViewModel.wrappedValue)}) } } } @@ -74,7 +70,7 @@ struct CommonItemView: View { } ConnectionCardDetails(title: cardViewModel.title, - subtitle: cardViewModel.serverName) + subtitle: cardViewModel.serverName) Spacer() diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift index 0ba481b82..3b03aba96 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -45,6 +45,7 @@ struct ReportMainView: View { case .draft: CommonReportListView(message: LocalizableReport.draftListExpl.localized, emptyMessage: LocalizableReport.reportsDraftEmpty.localized, + emptyIcon: reportMainViewModel.connectionType.emptyIcon, cardsViewModel: $reportMainViewModel.draftReportsViewModel, showDetails: showDetailsView(cardViewModel: ), showBottomSheet: showBottomSheet(cardViewModel:)) @@ -52,6 +53,7 @@ struct ReportMainView: View { case .outbox: CommonReportListView(message: LocalizableReport.outboxListExpl.localized, emptyMessage: LocalizableReport.reportsOutboxEmpty.localized, + emptyIcon: reportMainViewModel.connectionType.emptyIcon, cardsViewModel: $reportMainViewModel.outboxedReportsViewModel, showDetails: showDetailsView(cardViewModel: ), showBottomSheet: showBottomSheet(cardViewModel:)) @@ -59,6 +61,7 @@ struct ReportMainView: View { case .submitted: CommonReportListView(message: LocalizableReport.submittedListExpl.localized, emptyMessage: LocalizableReport.reportsSubmitedEmpty.localized, + emptyIcon: reportMainViewModel.connectionType.emptyIcon, cardsViewModel: $reportMainViewModel.submittedReportsViewModel, showDetails: showDetailsView(cardViewModel: ), showBottomSheet: showBottomSheet(cardViewModel:)) @@ -108,7 +111,7 @@ struct ReportMainView: View { action: {item in guard let type = item.type as? ConnectionActionType else {return} let id = cardViewModel.id - + switch type { case .editDraft: showDraftView(id: id) @@ -147,29 +150,25 @@ struct ReportMainView: View { } private func showDraftView(id:Int? = nil) { - + switch reportMainViewModel.connectionType { case .tella: var destination: any View destination = DraftReportView(mainAppModel: mainAppModel, reportId: id).environmentObject(reportMainViewModel) self.navigateTo(destination: destination) - break + case .gDrive: var destination : any View - let draftViewModel = GDriveDraftViewModel(mainAppModel: mainAppModel, - repository: (diContainer as! GDriveDIContainer).gDriveRepository, - reportID: id) - destination = DraftView(viewModel:draftViewModel, reportsViewModel: reportMainViewModel) + destination = GDriveDraftView(mainAppModel: mainAppModel, + gDriveDIContainer: (diContainer as! GDriveDIContainer), + reportId: id) self.navigateTo(destination: destination) - case .nextcloud: var destination : any View - let draftViewModel = GDriveDraftViewModel(mainAppModel: mainAppModel, - repository: (diContainer as! GDriveDIContainer).gDriveRepository, - reportID: id) - destination = DraftView(viewModel:draftViewModel, reportsViewModel: reportMainViewModel) + destination = GDriveDraftView(mainAppModel: mainAppModel, + gDriveDIContainer: (diContainer as! GDriveDIContainer), + reportId: id) self.navigateTo(destination: destination) - default: break } diff --git a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift index 4a2be01a6..e66332b84 100644 --- a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift +++ b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift @@ -11,7 +11,7 @@ import SwiftUI struct GDriveDraftView: View { @StateObject var gDriveDraftVM: GDriveDraftViewModel @EnvironmentObject var mainAppModel : MainAppModel - @EnvironmentObject var reportsViewModel : BaseReportsViewModel + @EnvironmentObject var reportsViewModel : ReportMainViewModel let gDriveDIContainer: GDriveDIContainer init(mainAppModel: MainAppModel, gDriveDIContainer: GDriveDIContainer, reportId: Int? = nil) { @@ -24,11 +24,7 @@ struct GDriveDraftView: View { } var body: some View { - Text("") - -// DraftView(viewModel: gDriveDraftVM, reportsViewModel: <#ReportMainViewModel#>) -// .environmentObject(mainAppModel) -// .environmentObject(reportsViewModel) + DraftView(viewModel: gDriveDraftVM, reportsViewModel: reportsViewModel) } } diff --git a/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift b/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift deleted file mode 100644 index 6ad28a2e6..000000000 --- a/Tella/Scenes/GDrive/Views/GDriveList/GDriveCardView.swift +++ /dev/null @@ -1,121 +0,0 @@ -// -// GDriveCardView.swift -// Tella -// -// Created by gus valbuena on 7/2/24. -// Copyright © 2024 HORIZONTAL. All rights reserved. -// - -import SwiftUI - -struct GDriveCardView : View { - - @Binding var report : GDriveReport - - @EnvironmentObject var reportsViewModel : GDriveViewModel - @EnvironmentObject private var sheetManager: SheetManager - @EnvironmentObject var mainAppModel : MainAppModel - let gDriveDIContainer = GDriveDIContainer() - - var body : some View { - Button { - reportsViewModel.selectedReport = report - - DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) { - self.handleActions(type: report.status.reportActionType) - } - - } label: { - VStack(spacing: 0) { - - HStack { - - ConnectionCardDetails(title: report.title ?? "", subtitle: report.getReportDate) - - Spacer() - - ImageButtonView(imageName: "reports.more", action: { - reportsViewModel.selectedReport = report - showReportActionBottomSheet() - }) - - }.padding(.all, 16) - - } .background(Color.white.opacity(0.08)) - .cornerRadius(15) - .padding(EdgeInsets(top: 6, leading: 0, bottom: 6, trailing: 0)) - } - } - - - private func showReportActionBottomSheet() { - sheetManager.showBottomSheet(modalHeight: 176) { - ActionListBottomSheet(items: reportsViewModel.sheetItems , - headerTitle: reportsViewModel.selectedReport?.title ?? "", - action: { item in - self.handleActions(type : item.type as? ConnectionActionType) - }) - } - } - - private func showDeleteReportConfirmationView() { - sheetManager.showBottomSheet(modalHeight: 200) { - DeleteReportConfirmationView(title: report.title, - message: deleteMessage) { - reportsViewModel.deleteReport(report: report) - sheetManager.hide() - } - } - } - - private func handleActions(type: ConnectionActionType?) { - - guard let type else { return } - - switch type { - case .editDraft: - self.navigateTo(destination: editDraftReportView) - sheetManager.hide() - case .editOutbox: - navigateTo(destination: outboxDetailsView) - sheetManager.hide() - case .delete: - showDeleteReportConfirmationView() - case .viewSubmitted: - navigateTo(destination: submittedDetailsView) - sheetManager.hide() - } - } - - private var editDraftReportView: some View { - GDriveDraftView(mainAppModel: mainAppModel, - gDriveDIContainer: gDriveDIContainer, - reportId: report.id) - .environmentObject(reportsViewModel) - } - - private var submittedDetailsView: some View { - SubmittedDetailsView(appModel: mainAppModel, - reportId: reportsViewModel.selectedReport?.id) - .environmentObject(reportsViewModel) - } - - private var outboxDetailsView: some View { -// OutboxDetailsView(appModel: mainAppModel, -// reportsViewModel: reportsViewModel, -// reportId: reportsViewModel.selectedReport?.id) -// .environmentObject(reportsViewModel as BaseReportsViewModel) - Text("") - } - - private var deleteMessage : String { - switch report.status { - case .draft: - return LocalizableReport.deleteDraftReportMessage.localized - case .submitted: - return LocalizableReport.deleteSubmittedReportMessage.localized - default: - return LocalizableReport.deleteOutboxReportMessage.localized - } - } -} diff --git a/Tella/Scenes/GDrive/Views/GDriveList/GDriveListView.swift b/Tella/Scenes/GDrive/Views/GDriveList/GDriveListView.swift deleted file mode 100644 index a27229cbf..000000000 --- a/Tella/Scenes/GDrive/Views/GDriveList/GDriveListView.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// GDriveListView.swift -// Tella -// -// Created by gus valbuena on 6/13/24. -// Copyright © 2024 HORIZONTAL. All rights reserved. -// - -import SwiftUI - -struct GDriveListView: View { - @Binding var reportArray : [GDriveReport] - var message: String - var body: some View { - ZStack { - if $reportArray.wrappedValue.count > 0 { - ScrollView { - VStack(alignment: .center, spacing: 0) { - ForEach($reportArray, id: \.self) { report in - GDriveCardView(report: report) - } - } - } - } else { - ConnectionEmptyView(message: message, type: .gDrive) - } - } - } -} diff --git a/Tella/Scenes/GDrive/Views/GDriveView.swift b/Tella/Scenes/GDrive/Views/GDriveView.swift deleted file mode 100644 index 71f6ba2b9..000000000 --- a/Tella/Scenes/GDrive/Views/GDriveView.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// GDriveView.swift -// Tella -// -// Created by gus valbuena on 6/12/24. -// Copyright © 2024 HORIZONTAL. All rights reserved. -// - -import SwiftUI - -struct GDriveView: View { - @EnvironmentObject var mainAppModel: MainAppModel - @StateObject var gDriveViewModel: GDriveViewModel - let gDriveDIContainer = GDriveDIContainer() - - init(mainAppModel: MainAppModel) { - _gDriveViewModel = StateObject(wrappedValue: GDriveViewModel(mainAppModel: mainAppModel)) - } - - var body: some View { - contentView - .navigationBarTitle(LocalizableSettings.settServerGDrive.localized.capitalized, displayMode: .large) - .environmentObject(gDriveViewModel) - } - - var contentView: some View { - ContainerView { - VStack(alignment: .center) { - PageView(selectedOption: self.$gDriveViewModel.selectedCell, pageViewItems: gDriveViewModel.pageViewItems) - .frame(maxWidth: .infinity, maxHeight: 40, alignment: .leading) - - VStack { - Spacer() - switch self.gDriveViewModel.selectedCell { - case .draft: - GDriveListView(reportArray: $gDriveViewModel.draftReports, message: "You have no draft reports.") - case .outbox: - GDriveListView(reportArray: $gDriveViewModel.outboxedReports, message: "You have no outbox reports.") - case .submitted: - GDriveListView(reportArray: $gDriveViewModel.submittedReports, message: "You have no submitted reports.") - default: - EmptyView() - } - Spacer() - } - createGDriveReportButton - } - .padding(EdgeInsets(top: 15, leading: 20, bottom: 16, trailing: 20)) - } - } - - var createGDriveReportButton: some View { - TellaButtonView (title: LocalizableReport.reportsCreateNew.localized, - nextButtonAction: .action, - buttonType: .yellow, - isValid: .constant(true)) { - navigateTo(destination: newGDriveDraftView) - } .padding(EdgeInsets(top: 30, leading: 0, bottom: 0, trailing: 0)) - } - - private var newGDriveDraftView: some View { - GDriveDraftView(mainAppModel: mainAppModel, gDriveDIContainer: gDriveDIContainer) - .environmentObject(gDriveViewModel) - } -} - -#Preview { - GDriveView(mainAppModel: MainAppModel.stub()) -} diff --git a/Tella/Scenes/Reports/ReportList/ReportListView.swift b/Tella/Scenes/Reports/ReportList/ReportListView.swift index f01875c7d..c299f38b2 100644 --- a/Tella/Scenes/Reports/ReportList/ReportListView.swift +++ b/Tella/Scenes/Reports/ReportList/ReportListView.swift @@ -24,7 +24,7 @@ struct ReportListView: View { } } } else { - ConnectionEmptyView(message: message, type: .tella) + ConnectionEmptyView(message: message, iconName: "") } } } diff --git a/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift b/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift index 170a678fb..9151665df 100644 --- a/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift +++ b/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift @@ -22,7 +22,7 @@ struct UwaziListView: View { if cardsViewModel.isEmpty { - ConnectionEmptyView(message: emptyMessage, type: .uwazi) + ConnectionEmptyView(message: emptyMessage, iconName: "") } else { diff --git a/Tella/Scenes/Uwazi/Views/Template/AddTemplatesView.swift b/Tella/Scenes/Uwazi/Views/Template/AddTemplatesView.swift index 61a78e56b..923af2d70 100644 --- a/Tella/Scenes/Uwazi/Views/Template/AddTemplatesView.swift +++ b/Tella/Scenes/Uwazi/Views/Template/AddTemplatesView.swift @@ -80,7 +80,7 @@ struct AddTemplatesView: View { } else { Group { Spacer() - ConnectionEmptyView(message: LocalizableUwazi.uwaziAddTemplateEmptydExpl.localized, type: .uwazi) + ConnectionEmptyView(message: LocalizableUwazi.uwaziAddTemplateEmptydExpl.localized, iconName: ServerConnectionType.uwazi.emptyIcon) Spacer() } } From 2041b8f2c9478da9aea9ff940c405c5a5fc91165 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 8 Jul 2024 16:28:49 -0300 Subject: [PATCH 081/167] refactor tellaData and fix navigation between cells --- Tella/Data/Database/GDriveData.swift | 34 ++++----- Tella/Data/Database/TellaData.swift | 56 ++++++--------- .../Views/ReportMainView.swift | 4 +- .../GDrive/ViewModel/GDriveViewModel.swift | 64 ++++++++--------- .../Reports/View Model/ReportsViewModel.swift | 72 +++++++++---------- 5 files changed, 109 insertions(+), 121 deletions(-) diff --git a/Tella/Data/Database/GDriveData.swift b/Tella/Data/Database/GDriveData.swift index bb6f132a8..b49e19c8e 100644 --- a/Tella/Data/Database/GDriveData.swift +++ b/Tella/Data/Database/GDriveData.swift @@ -12,40 +12,40 @@ extension TellaData { func addGDriveReport(report : GDriveReport) -> Result { let id = database.addGDriveReport(report: report) - getGDriveReports() + shouldReloadGDriveReports.send(true) return id } - func getGDriveReports() { - DispatchQueue.main.async { - self.gDriveDraftReports.value = self.database.getDriveReports(reportStatus: [ReportStatus.draft]) - self.gDriveOutboxedReports.value = self.database.getDriveReports(reportStatus: [.finalized, - .submissionError, - .submissionPending, - .submissionPaused, - .submissionInProgress, - .submissionAutoPaused, - .submissionScheduled]) - self.gDriveSubmittedReports.value = self.database.getDriveReports(reportStatus: [ReportStatus.submitted]) - } - } - func getDraftGDriveReport() -> [GDriveReport] { return self.database.getDriveReports(reportStatus: [ReportStatus.draft]) } + func getOutboxedGDriveReport() -> [GDriveReport] { + return self.database.getDriveReports(reportStatus: [.finalized, + .submissionError, + .submissionPending, + .submissionPaused, + .submissionInProgress, + .submissionAutoPaused, + .submissionScheduled]) + } + + func getSubmittedGDriveReport() -> [GDriveReport] { + return self.database.getDriveReports(reportStatus: [ReportStatus.submitted]) + } + func getDriveReport(id: Int) -> GDriveReport? { self.database.getGDriveReport(id: id) } func updateDriveReport(report: GDriveReport) -> Result { - getGDriveReports() + shouldReloadGDriveReports.send(true) return self.database.updateDriveReport(report: report) } func deleteDriveReport(reportId: Int?) -> Result { - getGDriveReports() + shouldReloadGDriveReports.send(true) return self.database.deleteDriveReport(reportId: reportId) } } diff --git a/Tella/Data/Database/TellaData.swift b/Tella/Data/Database/TellaData.swift index d2175c487..1d8298e4e 100644 --- a/Tella/Data/Database/TellaData.swift +++ b/Tella/Data/Database/TellaData.swift @@ -17,16 +17,7 @@ class TellaData : ObservableObject { var uwaziServers = CurrentValueSubject<[UwaziServer], Error>([]) var gDriveServers = CurrentValueSubject<[GDriveServer], Error>([]) - // Reports - var draftReports = CurrentValueSubject<[Report], Error>([]) - var submittedReports = CurrentValueSubject<[Report], Error>([]) - var outboxedReports = CurrentValueSubject<[Report], Error>([]) - - // GDriveReports - var gDriveDraftReports = CurrentValueSubject<[GDriveReport], Error>([]) - var gDriveOutboxedReports = CurrentValueSubject<[GDriveReport], Error>([]) - var gDriveSubmittedReports = CurrentValueSubject<[GDriveReport], Error>([]) - + var shouldReloadTellaReports = CurrentValueSubject(false) var shouldReloadUwaziInstances = CurrentValueSubject(false) var shouldReloadUwaziTemplates = CurrentValueSubject(false) @@ -37,8 +28,6 @@ class TellaData : ObservableObject { self.vaultManager = vaultManager getServers() - getReports() - getGDriveReports() } func addServer(server : TellaServer) -> Result { @@ -78,7 +67,7 @@ class TellaData : ObservableObject { func deleteTellaServer(serverId : Int) -> Result { let deleteServerResult = database.deleteServer(serverId: serverId) getServers() - getReports() + shouldReloadTellaReports.send(true) return deleteServerResult } @@ -109,7 +98,7 @@ class TellaData : ObservableObject { vaultManager?.deleteVaultFile(filesIds: resourcesId) let deleteAllServersResult = database.deleteAllServers() getServers() - getReports() + shouldReloadTellaReports.send(true) return deleteAllServersResult } @@ -159,20 +148,21 @@ class TellaData : ObservableObject { return database.getAutoUploadServer() } - func getReports() { - DispatchQueue.main.async { - - self.draftReports.value = self.database.getReports(reportStatus: [ReportStatus.draft]) - self.outboxedReports.value = self.database.getReports(reportStatus: [.finalized, - .submissionError, - .submissionPending, - .submissionPaused, - .submissionInProgress, - .submissionAutoPaused, - .submissionScheduled]) - - self.submittedReports.value = self.database.getReports(reportStatus: [ReportStatus.submitted]) - } + func getDraftReports() -> [Report] { + return database.getReports(reportStatus: [.draft]) + } + func getOutboxedReports() -> [Report] { + return database.getReports(reportStatus: [.finalized, + .submissionError, + .submissionPending, + .submissionPaused, + .submissionInProgress, + .submissionAutoPaused, + .submissionScheduled]) + } + + func getSubmittedReports() -> [Report] { + return database.getReports(reportStatus: [ReportStatus.submitted]) } func getReport(reportId: Int) -> Report? { @@ -232,7 +222,7 @@ class TellaData : ObservableObject { func addReport(report : Report) -> Result { let id = database.addReport(report: report) - getReports() + shouldReloadTellaReports.send(true) return id } @@ -251,14 +241,14 @@ class TellaData : ObservableObject { @discardableResult func updateReport(report : Report) -> Result { let report = database.updateReport(report: report) - getReports() + shouldReloadTellaReports.send(true) return report } @discardableResult func updateReportStatus(idReport : Int, status: ReportStatus) -> Result { let id = database.updateReportStatus(idReport: idReport, status: status, date: Date()) - getReports() + shouldReloadTellaReports.send(true) return id } @@ -294,14 +284,14 @@ class TellaData : ObservableObject { func deleteReport(reportId : Int?) -> Result { let deleteReportResult = database.deleteReport(reportId: reportId) - getReports() + shouldReloadTellaReports.send(true) return deleteReportResult } @discardableResult func deleteSubmittedReport() -> Result { let deleteSubmittedReportResult = database.deleteSubmittedReport() - getReports() + shouldReloadTellaReports.send(true) return deleteSubmittedReportResult } diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift index 3b03aba96..d24fa2dda 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -11,7 +11,7 @@ import SwiftUI struct ReportMainView: View { - @State var reportMainViewModel: ReportMainViewModel + @ObservedObject var reportMainViewModel: ReportMainViewModel @EnvironmentObject var sheetManager: SheetManager @EnvironmentObject var mainAppModel: MainAppModel @@ -161,7 +161,7 @@ struct ReportMainView: View { var destination : any View destination = GDriveDraftView(mainAppModel: mainAppModel, gDriveDIContainer: (diContainer as! GDriveDIContainer), - reportId: id) + reportId: id).environmentObject(reportMainViewModel) self.navigateTo(destination: destination) case .nextcloud: var destination : any View diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift index 1d2cb7292..cc219020b 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -33,6 +33,7 @@ class GDriveViewModel: ReportMainViewModel { super.init(mainAppModel: mainAppModel, connectionType: .gDrive, title: "Google Drive") self.getReports() + self.listenToUpdates() } override func getReports() { @@ -42,48 +43,45 @@ class GDriveViewModel: ReportMainViewModel { } func getDraftReports() { - self.mainAppModel.tellaData?.gDriveDraftReports - .receive(on: DispatchQueue.main) - .sink { result in - } receiveValue: { draftReports in - self.draftReportsViewModel = draftReports.compactMap { report in - ReportCardViewModel(report: report, - serverName: report.server?.name, - deleteReport: { self.deleteReport(report: report) } - ) - } - }.store(in: &subscribers) + let draftReports = tellaData?.getDraftGDriveReport() ?? [] + self.draftReportsViewModel = draftReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: { self.deleteReport(report: report) } + ) + } } func getOutboxedReports() { - self.mainAppModel.tellaData?.gDriveOutboxedReports - .receive(on: DispatchQueue.main) - .sink { result in - } receiveValue: { outboxedReports in - self.outboxedReportsViewModel = outboxedReports.compactMap { report in - ReportCardViewModel(report: report, - serverName: report.server?.name, - deleteReport: { self.deleteReport(report: report) } - ) - } - }.store(in: &subscribers) + let outboxedReports = tellaData?.getOutboxedGDriveReport() ?? [] + self.outboxedReportsViewModel = outboxedReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: { self.deleteReport(report: report) } + ) + } } func getSubmittedReports() { - self.mainAppModel.tellaData?.gDriveSubmittedReports - .receive(on: DispatchQueue.main) - .sink { result in - } receiveValue: { submittedReports in - self.submittedReportsViewModel = submittedReports.compactMap { report in - ReportCardViewModel(report: report, - serverName: report.server?.name, - deleteReport: { self.deleteReport(report: report) } - ) - } - }.store(in: &subscribers) + let submittedReports = tellaData?.getSubmittedGDriveReport() ?? [] + self.submittedReportsViewModel = submittedReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: { self.deleteReport(report: report) } + ) + } } func deleteReport(report: GDriveReport) { let _ = self.mainAppModel.tellaData?.deleteDriveReport(reportId: report.id) } + + override func listenToUpdates() { + self.mainAppModel.tellaData?.shouldReloadGDriveReports + .receive(on: DispatchQueue.main) + .sink { result in + } receiveValue: { draftReports in + self.getReports() + }.store(in: &subscribers) + } } diff --git a/Tella/Scenes/Reports/View Model/ReportsViewModel.swift b/Tella/Scenes/Reports/View Model/ReportsViewModel.swift index 7d851b295..99186d97d 100644 --- a/Tella/Scenes/Reports/View Model/ReportsViewModel.swift +++ b/Tella/Scenes/Reports/View Model/ReportsViewModel.swift @@ -27,6 +27,7 @@ class ReportsViewModel: ReportMainViewModel { super.init(mainAppModel: mainAppModel, connectionType: .tella, title: LocalizableReport.reportsTitle.localized) self.getReports() + self.listenToUpdates() } override func getReports() { @@ -36,48 +37,38 @@ class ReportsViewModel: ReportMainViewModel { } func getDraftReports() { - self.mainAppModel.tellaData?.draftReports - .receive(on: DispatchQueue.main) - .sink { result in - } receiveValue: { draftReports in - self.draftReportsViewModel = draftReports.compactMap { report in - ReportCardViewModel(report: report, - serverName: report.server?.name, - deleteReport: { self.deleteReport(report: report) }, - connectionType: .tella - ) - } - }.store(in: &subscribers) + let draftReports = tellaData?.getDraftReports() ?? [] + + self.draftReportsViewModel = draftReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: { self.deleteReport(report: report) }, + connectionType: .tella + ) + } } func getOutboxedReports() { - self.mainAppModel.tellaData?.outboxedReports - .receive(on: DispatchQueue.main) - .sink { result in - } receiveValue: { outboxedReports in - self.outboxedReportsViewModel = outboxedReports.compactMap { report in - ReportCardViewModel(report: report, - serverName: report.server?.name, - deleteReport: { self.deleteReport(report: report) }, connectionType: .tella - ) - } - - }.store(in: &subscribers) + let outboxedReports = tellaData?.getOutboxedReports() ?? [] + + self.outboxedReportsViewModel = outboxedReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: { self.deleteReport(report: report) }, connectionType: .tella + ) + } } func getSubmittedReports() { - self.mainAppModel.tellaData?.submittedReports - .receive(on: DispatchQueue.main) - .sink { result in - } receiveValue: { submittedReports in - self.submittedReportsViewModel = submittedReports.compactMap { report in - ReportCardViewModel(report: report, - serverName: report.server?.name, - deleteReport: { self.deleteReport(report: report) }, - connectionType: .tella - ) - } - }.store(in: &subscribers) + let submittedReports = tellaData?.getSubmittedReports() ?? [] + + self.submittedReportsViewModel = submittedReports.compactMap { report in + ReportCardViewModel(report: report, + serverName: report.server?.name, + deleteReport: { self.deleteReport(report: report) }, + connectionType: .tella + ) + } } func deleteReport(report: Report) { @@ -88,4 +79,13 @@ class ReportsViewModel: ReportMainViewModel { mainAppModel.tellaData?.deleteSubmittedReport() } + override func listenToUpdates() { + self.mainAppModel.tellaData?.shouldReloadTellaReports + .receive(on: DispatchQueue.main) + .sink { result in + } receiveValue: { draftReports in + self.getReports() + }.store(in: &subscribers) + } + } From 562bff73a80536ae89e7c785064a4800cca7b31f Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 8 Jul 2024 17:58:02 -0300 Subject: [PATCH 082/167] add DraftMainViewModel --- Tella.xcodeproj/project.pbxproj | 8 +- .../Reports/Draft/AddFilesToDraftView.swift | 6 +- .../Reports/Draft/DraftMainViewModel.swift | 119 ++++++++++++++++++ .../Components/Reports/Draft/DraftView.swift | 6 +- .../Draft/DraftViewModelProtocol.swift | 45 ------- Tella/Domain/Entity/CommonServer/Server.swift | 17 +++ Tella/Domain/Entity/GDrive/GDriveServer.swift | 2 +- Tella/Domain/Entity/Report/TellaServer.swift | 2 +- .../ViewModel/GDriveDraftViewModel.swift | 77 +++--------- .../GDrive/Views/Draft/GDriveDraftView.swift | 2 +- .../Reports/Draft/ReportFileGridView.swift | 4 +- .../Reports/View Model/DraftReportVM.swift | 118 +++-------------- 12 files changed, 185 insertions(+), 221 deletions(-) create mode 100644 Tella/Components/Reports/Draft/DraftMainViewModel.swift delete mode 100644 Tella/Components/Reports/Draft/DraftViewModelProtocol.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 79cf35b60..77f4e695e 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -397,7 +397,7 @@ 15E3D50A2C1B71E200B7FECC /* GDriveDraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D5092C1B71E200B7FECC /* GDriveDraftView.swift */; }; 15E3D50E2C1B87AC00B7FECC /* GDriveDraftViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D50D2C1B87AC00B7FECC /* GDriveDraftViewModel.swift */; }; 15E656AB2C2A147E00BDEC91 /* AddFilesToDraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */; }; - 15E656AD2C2A14F500BDEC91 /* DraftViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E656AC2C2A14F500BDEC91 /* DraftViewModelProtocol.swift */; }; + 15E656AD2C2A14F500BDEC91 /* DraftMainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E656AC2C2A14F500BDEC91 /* DraftMainViewModel.swift */; }; 15EE30FE2B5073E20033BBBB /* Pages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15EE30FD2B5073E20033BBBB /* Pages.swift */; }; 15F1AA542C2E07F50002A7D8 /* BaseReportsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F1AA532C2E07F50002A7D8 /* BaseReportsViewModel.swift */; }; 15F64C9D2B6D7904008A57AA /* DownloadedResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */; }; @@ -970,7 +970,7 @@ 15E3D5092C1B71E200B7FECC /* GDriveDraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveDraftView.swift; sourceTree = ""; }; 15E3D50D2C1B87AC00B7FECC /* GDriveDraftViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveDraftViewModel.swift; sourceTree = ""; }; 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFilesToDraftView.swift; sourceTree = ""; }; - 15E656AC2C2A14F500BDEC91 /* DraftViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftViewModelProtocol.swift; sourceTree = ""; }; + 15E656AC2C2A14F500BDEC91 /* DraftMainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftMainViewModel.swift; sourceTree = ""; }; 15EE30FD2B5073E20033BBBB /* Pages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pages.swift; sourceTree = ""; }; 15F1AA532C2E07F50002A7D8 /* BaseReportsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseReportsViewModel.swift; sourceTree = ""; }; 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResources.swift; sourceTree = ""; }; @@ -2490,7 +2490,7 @@ children = ( 152D38502C2C61DF00323CE7 /* DraftView.swift */, 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */, - 15E656AC2C2A14F500BDEC91 /* DraftViewModelProtocol.swift */, + 15E656AC2C2A14F500BDEC91 /* DraftMainViewModel.swift */, ); path = Draft; sourceTree = ""; @@ -3566,7 +3566,7 @@ 125BC1DE2B21F08200A117D0 /* VaultFileDetailsToMerge.swift in Sources */, 12E0882027AD29E400CEB198 /* SaveAudioConfirmationView.swift in Sources */, 125A895F2A965C33009347C3 /* VaultFileType.swift in Sources */, - 15E656AD2C2A14F500BDEC91 /* DraftViewModelProtocol.swift in Sources */, + 15E656AD2C2A14F500BDEC91 /* DraftMainViewModel.swift in Sources */, 123AE5A129CFAD7F00814CC7 /* OutboxReportVM.swift in Sources */, 12FDEDD5272AFE99005C17AC /* LocalizableHome.swift in Sources */, D572EAC7263A383900CE191A /* RecentFileCell.swift in Sources */, diff --git a/Tella/Components/Reports/Draft/AddFilesToDraftView.swift b/Tella/Components/Reports/Draft/AddFilesToDraftView.swift index 4c8f7c753..cd9fca8fe 100644 --- a/Tella/Components/Reports/Draft/AddFilesToDraftView.swift +++ b/Tella/Components/Reports/Draft/AddFilesToDraftView.swift @@ -8,11 +8,11 @@ import SwiftUI -struct AddFilesToDraftView: View { +struct AddFilesToDraftView: View { @EnvironmentObject var appModel: MainAppModel @EnvironmentObject var sheetManager: SheetManager - @EnvironmentObject var draftReportVM: VM + @EnvironmentObject var draftReportVM: DraftMainViewModel private let gridLayout: [GridItem] = [GridItem(spacing: 12), GridItem(spacing: 12), @@ -41,7 +41,7 @@ struct AddFilesToDraftView: View { var itemsGridView: some View { LazyVGrid(columns: gridLayout, alignment: .center, spacing: 12) { ForEach(draftReportVM.files.sorted{$0.created < $1.created}, id: \.id) { file in - ReportFileGridView(file: file) + ReportFileGridView(file: file) .frame(height: (UIScreen.screenWidth - 64) / 3 ) .environmentObject(draftReportVM) } diff --git a/Tella/Components/Reports/Draft/DraftMainViewModel.swift b/Tella/Components/Reports/Draft/DraftMainViewModel.swift new file mode 100644 index 000000000..5002f1470 --- /dev/null +++ b/Tella/Components/Reports/Draft/DraftMainViewModel.swift @@ -0,0 +1,119 @@ +// +// DraftViewModelProtocol.swift +// Tella +// +// Created by gus valbuena on 6/24/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation +import Combine + +class DraftMainViewModel: ObservableObject { + var mainAppModel : MainAppModel + // Report + @Published var reportId : Int? + @Published var title : String = "" + @Published var description : String = "" + @Published var files : Set = [] + @Published var server : T? + @Published var status : ReportStatus? + @Published var apiID : String? + + // Fields validation + @Published var isValidTitle : Bool = false + @Published var isValidDescription : Bool = false + @Published var shouldShowError : Bool = false + @Published var reportIsValid : Bool = false + @Published var reportIsDraft : Bool = false + + @Published var resultFile : [VaultFileDB]? + + @Published var showingImagePicker : Bool = false + @Published var showingImportDocumentPicker : Bool = false + @Published var showingFileList : Bool = false + @Published var showingRecordView : Bool = false + @Published var showingCamera : Bool = false + + @Published var successSavingReport : Bool = false + @Published var failureSavingReport : Bool = false + + var successSavingReportPublisher: Published.Publisher { $successSavingReport } + var failureSavingReportPublisher: Published.Publisher { $failureSavingReport } + + var serverArray : [T] = [] + + var cancellable : Cancellable? = nil + var subscribers = Set() + var delayTime = 2.0 + + var serverName : String { + guard let serverName = server?.name else { return LocalizableReport.selectProject.localized } + return serverName + } + + var hasMoreServer: Bool { + return serverArray.count > 1 + } + + var isNewDraft: Bool { + return reportId == nil + } + + var addFileToDraftItems : [ListActionSheetItem] { return [ + + ListActionSheetItem(imageName: "report.camera-filled", + content: LocalizableReport.cameraFilled.localized, + type: ManageFileType.camera), + ListActionSheetItem(imageName: "report.mic-filled", + content: LocalizableReport.micFilled.localized, + type: ManageFileType.recorder), + ListActionSheetItem(imageName: "report.gallery", + content: LocalizableReport.galleryFilled.localized, + type: ManageFileType.tellaFile), + ListActionSheetItem(imageName: "report.phone", + content: LocalizableReport.phoneFilled.localized, + type: ManageFileType.fromDevice) + ]} + + init(mainAppModel : MainAppModel, reportId:Int? = nil) { + + self.mainAppModel = mainAppModel + + self.validateReport() + + self.getServers() + + self.initcurrentReportVM(reportId: reportId) + + self.bindVaultFileTaken() + + fillReportVM() + } + + func validateReport() {} + + func getServers() {} + + func initcurrentReportVM(reportId:Int?) { } + + func bindVaultFileTaken() {} + + func publishUpdates() {} + + func fillReportVM() {} + + func saveDraftReport() {} + + func saveFinalizedReport() {} + + func saveReportForSubmission() {} + + func submitReport() {} + + func saveReport() {} + + func deleteFile(fileId: String?) {} + + func deleteReport() {} +} diff --git a/Tella/Components/Reports/Draft/DraftView.swift b/Tella/Components/Reports/Draft/DraftView.swift index a4dd6da38..dcb302b93 100644 --- a/Tella/Components/Reports/Draft/DraftView.swift +++ b/Tella/Components/Reports/Draft/DraftView.swift @@ -8,8 +8,8 @@ import SwiftUI -struct DraftView: View { - @StateObject var viewModel: VM +struct DraftView: View { + @StateObject var viewModel: DraftMainViewModel @State private var menuFrame : CGRect = CGRectZero @State private var shouldShowMenu : Bool = false @@ -86,7 +86,7 @@ struct DraftView: View { Spacer() .frame(height: 24) - AddFilesToDraftView() + AddFilesToDraftView() .environmentObject(viewModel) Spacer() diff --git a/Tella/Components/Reports/Draft/DraftViewModelProtocol.swift b/Tella/Components/Reports/Draft/DraftViewModelProtocol.swift deleted file mode 100644 index 6c5261801..000000000 --- a/Tella/Components/Reports/Draft/DraftViewModelProtocol.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// DraftViewModelProtocol.swift -// Tella -// -// Created by gus valbuena on 6/24/24. -// Copyright © 2024 HORIZONTAL. All rights reserved. -// - -import Foundation -import Combine -protocol DraftViewModelProtocol: ObservableObject { - //report - var reportId: Int? { get set } - var title: String { get set } - var description: String { get set } - var status: ReportStatus? { get set } - - - //validation - var isValidTitle: Bool { get set } - var isValidDescription: Bool { get set } - var shouldShowError: Bool { get set } - var reportIsValid: Bool { get set } - var reportIsDraft: Bool { get set} - var successSavingReport: Bool { get set } - var failureSavingReport: Bool { get set } - var successSavingReportPublisher: Published.Publisher { get } - var failureSavingReportPublisher: Published.Publisher { get } - - //files - var files: Set { get set } - var resultFile: [VaultFileDB]? { get set } - var addFileToDraftItems: [ListActionSheetItem] { get } - var showingImagePicker: Bool { get set } - var showingImportDocumentPicker: Bool { get set } - var showingFileList: Bool { get set } - var showingRecordView: Bool { get set } - var showingCamera: Bool { get set } - - //actions - func submitReport() - func saveDraftReport() - func saveFinalizedReport() - func deleteFile(fileId: String?) -} diff --git a/Tella/Domain/Entity/CommonServer/Server.swift b/Tella/Domain/Entity/CommonServer/Server.swift index 4d2c18d48..fd858ecd8 100644 --- a/Tella/Domain/Entity/CommonServer/Server.swift +++ b/Tella/Domain/Entity/CommonServer/Server.swift @@ -8,6 +8,23 @@ import Foundation +protocol ServerProtocol: Codable, Equatable, Hashable { + var id: Int? { get set } + var name: String? { get set } + var serverType: ServerConnectionType? { get set } + var allowMultiple: Bool? { get set } +} + +extension ServerProtocol { + static func == (lhs: Self, rhs: Self) -> Bool { + return lhs.id == rhs.id + } + + func hash(into hasher: inout Hasher) { + hasher.combine(id.hashValue) + } +} + class Server: Codable, Equatable, Hashable { var id: Int? diff --git a/Tella/Domain/Entity/GDrive/GDriveServer.swift b/Tella/Domain/Entity/GDrive/GDriveServer.swift index 77cb41c3d..cd0529946 100644 --- a/Tella/Domain/Entity/GDrive/GDriveServer.swift +++ b/Tella/Domain/Entity/GDrive/GDriveServer.swift @@ -8,7 +8,7 @@ import Foundation -class GDriveServer: Server { +class GDriveServer: Server, ServerProtocol { var rootFolder: String? enum CodingKeys: String, CodingKey { diff --git a/Tella/Domain/Entity/Report/TellaServer.swift b/Tella/Domain/Entity/Report/TellaServer.swift index ef3b10c50..b1672f9b9 100644 --- a/Tella/Domain/Entity/Report/TellaServer.swift +++ b/Tella/Domain/Entity/Report/TellaServer.swift @@ -5,7 +5,7 @@ import Foundation -class TellaServer : WebServer { +class TellaServer : WebServer, ServerProtocol { var activatedMetadata : Bool? var backgroundUpload : Bool? diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index c456d8117..5f5826c43 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -9,69 +9,20 @@ import Foundation import Combine -class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { - var mainAppModel: MainAppModel +class GDriveDraftViewModel: DraftMainViewModel { private let gDriveRepository: GDriveRepositoryProtocol - private var cancellables = Set() - var server: GDriveServer? - - @Published var reportId : Int? - @Published var title: String = "" - @Published var description: String = "" - - @Published var isValidTitle : Bool = false - @Published var isValidDescription : Bool = false - @Published var shouldShowError : Bool = false - @Published var reportIsValid : Bool = false - @Published var reportIsDraft : Bool = false - - @Published var status: ReportStatus? - @Published var successSavingReport: Bool = false - @Published var failureSavingReport: Bool = false - var successSavingReportPublisher: Published.Publisher { $successSavingReport } - var failureSavingReportPublisher: Published.Publisher { $failureSavingReport } - - // files - @Published var files : Set = [] - @Published var resultFile : [VaultFileDB]? - - @Published var showingImagePicker : Bool = false - @Published var showingImportDocumentPicker : Bool = false - @Published var showingFileList : Bool = false - @Published var showingRecordView : Bool = false - @Published var showingCamera : Bool = false - - private var subscribers = Set() - - var addFileToDraftItems : [ListActionSheetItem] { return [ - - ListActionSheetItem(imageName: "report.camera-filled", - content: LocalizableReport.cameraFilled.localized, - type: ManageFileType.camera), - ListActionSheetItem(imageName: "report.mic-filled", - content: LocalizableReport.micFilled.localized, - type: ManageFileType.recorder), - ListActionSheetItem(imageName: "report.gallery", - content: LocalizableReport.galleryFilled.localized, - type: ManageFileType.tellaFile), - ListActionSheetItem(imageName: "report.phone", - content: LocalizableReport.phoneFilled.localized, - type: ManageFileType.fromDevice) - ]} - - init(mainAppModel: MainAppModel, repository: GDriveRepositoryProtocol, reportID: Int?) { - self.mainAppModel = mainAppModel + init(mainAppModel: MainAppModel, repository: GDriveRepositoryProtocol, reportId reportID: Int?) { self.gDriveRepository = repository - self.validateReport() - self.getServer() + super.init(mainAppModel: mainAppModel, reportId: reportID) + self.getServer() + self.reportId = reportID - self.bindVaultFileTaken() self.fillReportVM() } - private func validateReport() { + override func validateReport() { Publishers.CombineLatest($title, $description) .map { !$0.0.isEmpty && !$0.1.isEmpty } .assign(to: \.reportIsValid, on: self) @@ -83,7 +34,7 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { .store(in: &subscribers) } - func submitReport() { + override func submitReport() { self.status = .submissionScheduled performSubmission() } @@ -112,10 +63,10 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { receiveValue: { result in dump(result) } - ).store(in: &cancellables) + ).store(in: &subscribers) } - func fillReportVM() { + override func fillReportVM() { if let reportId = self.reportId, let report = self.mainAppModel.tellaData?.getDriveReport(id: reportId) { self.title = report.title ?? "" self.description = report.description ?? "" @@ -128,12 +79,12 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { } } - func saveDraftReport() { + override func saveDraftReport() { self.status = .draft self.saveReport() } - func saveFinalizedReport() { + override func saveFinalizedReport() { self.status = .finalized self.saveReport() } @@ -143,7 +94,7 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { self.saveReport() } - func saveReport() { + override func saveReport() { let gDriveReport = GDriveReport( id: reportId, title: title, @@ -200,12 +151,12 @@ class GDriveDraftViewModel: ObservableObject, DraftViewModelProtocol { .eraseToAnyPublisher() } - func deleteFile(fileId: String?) { + override func deleteFile(fileId: String?) { guard let index = files.firstIndex(where: { $0.id == fileId}) else {return } files.remove(at: index) } - private func bindVaultFileTaken() { + override func bindVaultFileTaken() { $resultFile.sink(receiveValue: { value in guard let value else { return } self.files.insert(value) diff --git a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift index e66332b84..b92d0a564 100644 --- a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift +++ b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift @@ -19,7 +19,7 @@ struct GDriveDraftView: View { _gDriveDraftVM = StateObject(wrappedValue: GDriveDraftViewModel( mainAppModel: mainAppModel, repository: gDriveDIContainer.gDriveRepository, - reportID: reportId) + reportId: reportId) ) } diff --git a/Tella/Scenes/Reports/Draft/ReportFileGridView.swift b/Tella/Scenes/Reports/Draft/ReportFileGridView.swift index c6021c7ac..db988bc21 100644 --- a/Tella/Scenes/Reports/Draft/ReportFileGridView.swift +++ b/Tella/Scenes/Reports/Draft/ReportFileGridView.swift @@ -6,11 +6,11 @@ import SwiftUI -struct ReportFileGridView: View { +struct ReportFileGridView: View { var file: VaultFileDB - @EnvironmentObject var draftReportVM: VM + @EnvironmentObject var draftReportVM: DraftMainViewModel var body: some View { fileGridView diff --git a/Tella/Scenes/Reports/View Model/DraftReportVM.swift b/Tella/Scenes/Reports/View Model/DraftReportVM.swift index ad61aed56..615ffafbc 100644 --- a/Tella/Scenes/Reports/View Model/DraftReportVM.swift +++ b/Tella/Scenes/Reports/View Model/DraftReportVM.swift @@ -7,92 +7,12 @@ import Foundation import Combine import SwiftUI -class DraftReportVM: ObservableObject, DraftViewModelProtocol { - - var mainAppModel : MainAppModel - - // Report - @Published var reportId : Int? - @Published var title : String = "" - @Published var description : String = "" - @Published var files : Set = [] - @Published var server : TellaServer? - @Published var status : ReportStatus? - @Published var apiID : String? - - // Fields validation - @Published var isValidTitle : Bool = false - @Published var isValidDescription : Bool = false - @Published var shouldShowError : Bool = false - @Published var reportIsValid : Bool = false - @Published var reportIsDraft : Bool = false - - @Published var resultFile : [VaultFileDB]? - - @Published var showingImagePicker : Bool = false - @Published var showingImportDocumentPicker : Bool = false - @Published var showingFileList : Bool = false - @Published var showingRecordView : Bool = false - @Published var showingCamera : Bool = false - - @Published var successSavingReport : Bool = false - @Published var failureSavingReport : Bool = false - - var successSavingReportPublisher: Published.Publisher { $successSavingReport } - var failureSavingReportPublisher: Published.Publisher { $failureSavingReport } - - - var serverArray : [TellaServer] = [] - - var cancellable : Cancellable? = nil - private var subscribers = Set() - var delayTime = 2.0 - - var serverName : String { - guard let serverName = server?.name else { return LocalizableReport.selectProject.localized } - return serverName - } - - var hasMoreServer: Bool { - return serverArray.count > 1 +class DraftReportVM: DraftMainViewModel { + override init(mainAppModel : MainAppModel, reportId:Int? = nil) { + super.init(mainAppModel: mainAppModel, reportId: reportId) } - var isNewDraft: Bool { - return reportId == nil - } - - var addFileToDraftItems : [ListActionSheetItem] { return [ - - ListActionSheetItem(imageName: "report.camera-filled", - content: LocalizableReport.cameraFilled.localized, - type: ManageFileType.camera), - ListActionSheetItem(imageName: "report.mic-filled", - content: LocalizableReport.micFilled.localized, - type: ManageFileType.recorder), - ListActionSheetItem(imageName: "report.gallery", - content: LocalizableReport.galleryFilled.localized, - type: ManageFileType.tellaFile), - ListActionSheetItem(imageName: "report.phone", - content: LocalizableReport.phoneFilled.localized, - type: ManageFileType.fromDevice) - ]} - - init(mainAppModel : MainAppModel, reportId:Int? = nil) { - - self.mainAppModel = mainAppModel - - self.validateReport() - - self.getServers() - - self.initcurrentReportVM(reportId: reportId) - - self.bindVaultFileTaken() - - fillReportVM() - } - - private func validateReport() { + override func validateReport() { $server.combineLatest( $isValidTitle, $isValidDescription, $files) .sink(receiveValue: { server, isValidTitle, isValidDescription, files in self.reportIsValid = ((server != nil) && isValidTitle && isValidDescription) || ((server != nil) && isValidTitle && !files.isEmpty) @@ -106,18 +26,18 @@ class DraftReportVM: ObservableObject, DraftViewModelProtocol { }).store(in: &subscribers) } - private func getServers() { + override func getServers() { serverArray = mainAppModel.tellaData?.tellaServers.value ?? [] } - private func initcurrentReportVM(reportId:Int?) { + override func initcurrentReportVM(reportId:Int?) { if serverArray.count == 1 { server = serverArray.first } self.reportId = reportId } - private func bindVaultFileTaken() { + override func bindVaultFileTaken() { $resultFile.sink(receiveValue: { value in guard let value else { return } self.files.insert(value) @@ -125,13 +45,13 @@ class DraftReportVM: ObservableObject, DraftViewModelProtocol { }).store(in: &subscribers) } - private func publishUpdates() { + override func publishUpdates() { DispatchQueue.main.async { self.objectWillChange.send() } } - func fillReportVM() { + override func fillReportVM() { if let reportId = self.reportId ,let report = self.mainAppModel.tellaData?.getReport(reportId: reportId) { self.title = report.title ?? "" @@ -153,25 +73,25 @@ class DraftReportVM: ObservableObject, DraftViewModelProtocol { } } - func saveDraftReport() { + override func saveDraftReport() { self.status = .draft self.saveReport() } - func saveFinalizedReport() { + override func saveFinalizedReport() { self.status = .finalized self.saveReport() } - func saveReportForSubmission() { + override func saveReportForSubmission() { self.status = .submissionScheduled self.saveReport() } - func submitReport() { + override func submitReport() { saveReportForSubmission() } - func saveReport() { + override func saveReport() { let report = Report(id: reportId, title: title, @@ -184,10 +104,12 @@ class DraftReportVM: ObservableObject, DraftViewModelProtocol { createdDate: Date())}, apiID: apiID) + dump(report) + !isNewDraft ? updateReport(report: report) : addReport(report: report) } - func updateReport(report:Report) { + private func updateReport(report:Report) { let updateReportResult = mainAppModel.tellaData?.updateReport(report: report) switch updateReportResult { case .success: @@ -197,7 +119,7 @@ class DraftReportVM: ObservableObject, DraftViewModelProtocol { } } - func addReport(report:Report) { + private func addReport(report:Report) { let idResult = mainAppModel.tellaData?.addReport(report: report) switch idResult { case .success(let id ): @@ -208,12 +130,12 @@ class DraftReportVM: ObservableObject, DraftViewModelProtocol { } } - func deleteFile(fileId: String?) { + override func deleteFile(fileId: String?) { guard let index = files.firstIndex(where: { $0.id == fileId}) else {return } files.remove(at: index) } - func deleteReport() { + override func deleteReport() { mainAppModel.deleteReport(reportId: reportId) mainAppModel.deleteReport(reportId: reportId) } From 173ed6dd9f64df5e7f6b8c60ac1b3eb09b385988 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 8 Jul 2024 18:18:08 -0300 Subject: [PATCH 083/167] add server list menu on draft view --- .../Components/Reports/Draft/DraftView.swift | 71 +++++++++++++++++++ .../GDrive/ViewModel/GDriveViewModel.swift | 22 +++--- 2 files changed, 82 insertions(+), 11 deletions(-) diff --git a/Tella/Components/Reports/Draft/DraftView.swift b/Tella/Components/Reports/Draft/DraftView.swift index dcb302b93..391a333d1 100644 --- a/Tella/Components/Reports/Draft/DraftView.swift +++ b/Tella/Components/Reports/Draft/DraftView.swift @@ -25,6 +25,7 @@ struct DraftView: View { ContainerView { contentView .environmentObject(viewModel) + serverListMenuView photoVideoPickerView } .navigationBarHidden(true) @@ -67,6 +68,39 @@ struct DraftView: View { GeometryReader { geometry in ScrollView { VStack(alignment: .leading) { + if viewModel.hasMoreServer { + Text(LocalizableReport.reportsSendTo.localized) + .font(.custom(Styles.Fonts.regularFontName, size: 14)) + .foregroundColor(Color.white) + + Button { + DispatchQueue.main.async { + self.menuFrame = geometry.frame(in: CoordinateSpace.global) + shouldShowMenu = true + } + + } label: { + HStack { + Text(viewModel.serverName) + .font(.custom(Styles.Fonts.regularFontName, size: 14)) + .foregroundColor(Color.white.opacity(0.87)) + .padding() + .frame(maxWidth: .infinity, alignment: .leading) + + Image("reports.arrow-down") + .padding() + + } + }.background(Color.white.opacity(0.08)) + .cornerRadius(12) + + Spacer() + .frame(height: 55) + + } else { + Spacer() + .frame(height: 5) + } TextfieldView(fieldContent: $viewModel.title, isValid: $viewModel.isValidTitle, shouldShowError: $viewModel.shouldShowError, @@ -95,6 +129,43 @@ struct DraftView: View { } } + @ViewBuilder + var serverListMenuView: some View { + + if shouldShowMenu { + VStack { + Spacer() + .frame(height: menuFrame.origin.y + 10) + ScrollView { + + VStack(spacing: 0) { + + ForEach(viewModel.serverArray, id: \.self) { server in + + Button { + shouldShowMenu = false + viewModel.server = server + + } label: { + Text(server.name ?? "") + .font(.custom(Styles.Fonts.regularFontName, size: 14)) + .frame(maxWidth: .infinity, alignment: .leading) + .foregroundColor(.white) + .padding(.all, 14) + }.background(server.id == viewModel.server?.id ? Color.white.opacity(0.16) : Color.white.opacity(0.08)) + } + }.frame(minHeight: 40, maxHeight: 250) + .background(Styles.Colors.backgroundMain) + .cornerRadius(12) + } + Spacer() + } + .padding() + + .background(Color.clear) + } + } + var bottomDraftView: some View { HStack { submitLaterButton diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift index cc219020b..e0a21c268 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -9,13 +9,8 @@ import Foundation import Combine class GDriveViewModel: ReportMainViewModel { - - @Published var draftReports: [GDriveReport] = [] - @Published var outboxedReports: [GDriveReport] = [] - @Published var submittedReports: [GDriveReport] = [] - @Published var selectedReport: GDriveReport? - + @Published var server: GDriveServer? private var delayTime = 0.1 @@ -33,9 +28,14 @@ class GDriveViewModel: ReportMainViewModel { super.init(mainAppModel: mainAppModel, connectionType: .gDrive, title: "Google Drive") self.getReports() + self.getServer() self.listenToUpdates() } + private func getServer() { + self.server = mainAppModel.tellaData?.gDriveServers.value.first + } + override func getReports() { getDraftReports() getOutboxedReports() @@ -45,9 +45,9 @@ class GDriveViewModel: ReportMainViewModel { func getDraftReports() { let draftReports = tellaData?.getDraftGDriveReport() ?? [] self.draftReportsViewModel = draftReports.compactMap { report in - ReportCardViewModel(report: report, - serverName: report.server?.name, - deleteReport: { self.deleteReport(report: report) } + return ReportCardViewModel(report: report, + serverName: server?.name, + deleteReport: { self.deleteReport(report: report) } ) } } @@ -56,7 +56,7 @@ class GDriveViewModel: ReportMainViewModel { let outboxedReports = tellaData?.getOutboxedGDriveReport() ?? [] self.outboxedReportsViewModel = outboxedReports.compactMap { report in ReportCardViewModel(report: report, - serverName: report.server?.name, + serverName: server?.name, deleteReport: { self.deleteReport(report: report) } ) } @@ -66,7 +66,7 @@ class GDriveViewModel: ReportMainViewModel { let submittedReports = tellaData?.getSubmittedGDriveReport() ?? [] self.submittedReportsViewModel = submittedReports.compactMap { report in ReportCardViewModel(report: report, - serverName: report.server?.name, + serverName: server?.name, deleteReport: { self.deleteReport(report: report) } ) } From 2cd583319069c7f2e7dd140a2722c57fbd79fb1f Mon Sep 17 00:00:00 2001 From: Dhekra Rouatbi Date: Tue, 9 Jul 2024 15:29:00 +0100 Subject: [PATCH 084/167] Update Report classes --- Tella.xcodeproj/project.pbxproj | 20 ++- .../Entity/CommonReport/BaseReport.swift | 89 ++++++++++++ Tella/Domain/Entity/GDrive/GDriveReport.swift | 40 +++++ Tella/Domain/Entity/Report/Report.swift | 137 ++---------------- Tella/Domain/Entity/Report/UwaziLocale.swift | 38 ----- .../Resources/Models/DownloadedResource.swift | 1 - 6 files changed, 157 insertions(+), 168 deletions(-) create mode 100644 Tella/Domain/Entity/CommonReport/BaseReport.swift create mode 100644 Tella/Domain/Entity/GDrive/GDriveReport.swift delete mode 100644 Tella/Domain/Entity/Report/UwaziLocale.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 77f4e695e..39097fd2c 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -205,6 +205,8 @@ 1268554027D2994500385E18 /* VaultFileStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1268553F27D2994500385E18 /* VaultFileStatus.swift */; }; 1268554127D2ACB200385E18 /* RecentFilesListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D572EAC4263A383100CE191A /* RecentFilesListView.swift */; }; 126AD14A27C6D5EB00081CC9 /* LocalizableCamera.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126AD14927C6D5EB00081CC9 /* LocalizableCamera.swift */; }; + 126E1AF12C3D7603000AE4CE /* BaseReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126E1AF02C3D7603000AE4CE /* BaseReport.swift */; }; + 126E1AF32C3D7632000AE4CE /* GDriveReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126E1AF22C3D7632000AE4CE /* GDriveReport.swift */; }; 126E813B272CAFA300688B64 /* UINavigationControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126E813A272CAFA300688B64 /* UINavigationControllerExtension.swift */; }; 126ECFEA27C57FA600ED5161 /* CameraState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126ECFE927C57FA600ED5161 /* CameraState.swift */; }; 126FE4D727A427E200AE4188 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126FE4D627A427E200AE4188 /* Constants.swift */; }; @@ -496,7 +498,6 @@ E11968B12A1F409D00BA7B56 /* UwaziLanguageDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11968B02A1F409D00BA7B56 /* UwaziLanguageDTO.swift */; }; E131BA3B2A1B45A30095BC91 /* UwaziServerRepositories.swift in Sources */ = {isa = PBXBuildFile; fileRef = E131BA3A2A1B45A30095BC91 /* UwaziServerRepositories.swift */; }; E14E0CF629FAD68E004FC4CD /* UwaziSuccessView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E14E0CF529FAD68E004FC4CD /* UwaziSuccessView.swift */; }; - E14FD87A2A6AB22200BC7523 /* UwaziLocale.swift in Sources */ = {isa = PBXBuildFile; fileRef = E14FD8792A6AB22200BC7523 /* UwaziLocale.swift */; }; E16D20CF2ABEAAB1001708CC /* TemplateItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16D20CE2ABEAAB1001708CC /* TemplateItemViewModel.swift */; }; E16D20D12ABEB5C7001708CC /* UwaziCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16D20D02ABEB5C7001708CC /* UwaziCardViewModel.swift */; }; E177363C2A83AE4800FE01C0 /* UwaziTemplateDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = E177363B2A83AE4800FE01C0 /* UwaziTemplateDTO.swift */; }; @@ -775,6 +776,8 @@ 126818C22A38B69E004606BD /* FileTypeHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileTypeHelper.swift; sourceTree = ""; }; 1268553F27D2994500385E18 /* VaultFileStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VaultFileStatus.swift; sourceTree = ""; }; 126AD14927C6D5EB00081CC9 /* LocalizableCamera.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizableCamera.swift; sourceTree = ""; }; + 126E1AF02C3D7603000AE4CE /* BaseReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseReport.swift; sourceTree = ""; }; + 126E1AF22C3D7632000AE4CE /* GDriveReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveReport.swift; sourceTree = ""; }; 126E813A272CAFA300688B64 /* UINavigationControllerExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UINavigationControllerExtension.swift; sourceTree = ""; }; 126ECFE927C57FA600ED5161 /* CameraState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraState.swift; sourceTree = ""; }; 126FE4D627A427E200AE4188 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; @@ -1079,7 +1082,6 @@ E11968B02A1F409D00BA7B56 /* UwaziLanguageDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziLanguageDTO.swift; sourceTree = ""; }; E131BA3A2A1B45A30095BC91 /* UwaziServerRepositories.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziServerRepositories.swift; sourceTree = ""; }; E14E0CF529FAD68E004FC4CD /* UwaziSuccessView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziSuccessView.swift; sourceTree = ""; }; - E14FD8792A6AB22200BC7523 /* UwaziLocale.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziLocale.swift; sourceTree = ""; }; E16D20CE2ABEAAB1001708CC /* TemplateItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateItemViewModel.swift; sourceTree = ""; }; E16D20D02ABEB5C7001708CC /* UwaziCardViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziCardViewModel.swift; sourceTree = ""; }; E177363B2A83AE4800FE01C0 /* UwaziTemplateDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziTemplateDTO.swift; sourceTree = ""; }; @@ -1484,6 +1486,7 @@ 1231A45B294C76990057DA85 /* Entity */ = { isa = PBXGroup; children = ( + 126E1AF42C3D77F1000AE4CE /* CommonReport */, 127092D82C2EE4D0002030AA /* CommonServer */, 15994A0F2BFBF0C70017F153 /* GDrive */, 1519BED42B9A5A2B006FD290 /* Resource */, @@ -1520,7 +1523,6 @@ 0DC267A5267AED7C00E55AFA /* VaultFile.swift */, 128FD0B327F774FB00B24915 /* RecentFile.swift */, 12751EA92A13A22100FAD7C6 /* SettingsModel.swift */, - E14FD8792A6AB22200BC7523 /* UwaziLocale.swift */, 125A89592A965BE0009347C3 /* Vault */, ); path = Report; @@ -1749,6 +1751,14 @@ path = FileTypeHelper; sourceTree = ""; }; + 126E1AF42C3D77F1000AE4CE /* CommonReport */ = { + isa = PBXGroup; + children = ( + 126E1AF02C3D7603000AE4CE /* BaseReport.swift */, + ); + path = CommonReport; + sourceTree = ""; + }; 126FEE082AC4992800B99298 /* Models */ = { isa = PBXGroup; children = ( @@ -2438,6 +2448,7 @@ children = ( 15994A102BFBF0E50017F153 /* SharedDrive.swift */, 15587A002C010F1E0071389E /* GDriveServer.swift */, + 126E1AF22C3D7632000AE4CE /* GDriveReport.swift */, ); path = GDrive; sourceTree = ""; @@ -3482,7 +3493,6 @@ 125B79F82C205F980061CF84 /* PHAssetExtension.swift in Sources */, 1216124028DE144200E6D7B6 /* JoinCondition.swift in Sources */, 12AE8D1E278CD4900007C781 /* IntExtension.swift in Sources */, - E14FD87A2A6AB22200BC7523 /* UwaziLocale.swift in Sources */, 12730E67279F11C300DC0135 /* LanguageListView.swift in Sources */, 0ECC7817267A533E00A2ACF2 /* PageViewCell.swift in Sources */, 128B929727D7920300E92ACF /* SelectingFilesHeaderView.swift in Sources */, @@ -3519,6 +3529,7 @@ 1278B66127EB364500C9AC4D /* Utils.swift in Sources */, 125D2321271F823100250FBB /* UIApplicationExtension.swift in Sources */, 12234BE029DAEC4A00D6F981 /* CustomNavigation.swift in Sources */, + 126E1AF12C3D7603000AE4CE /* BaseReport.swift in Sources */, 125D2324271F891500250FBB /* PinView.swift in Sources */, 157E4F532BA385B500147345 /* PDFKitView.swift in Sources */, 125AAD362953607D002194D6 /* UploadReportModels.swift in Sources */, @@ -3551,6 +3562,7 @@ CCEAE5922AE6F6EE0069204A /* EntityCreationResponse.swift in Sources */, 1289B98927C53A9C00315FCE /* CameraType.swift in Sources */, 0E78B3A72656B03600F9BDBC /* DragView.swift in Sources */, + 126E1AF32C3D7632000AE4CE /* GDriveReport.swift in Sources */, 1231A45E294C779D0057DA85 /* ReportStatus.swift in Sources */, 15F64CA82B6D852D008A57AA /* ResourceCard.swift in Sources */, E16D20D12ABEB5C7001708CC /* UwaziCardViewModel.swift in Sources */, diff --git a/Tella/Domain/Entity/CommonReport/BaseReport.swift b/Tella/Domain/Entity/CommonReport/BaseReport.swift new file mode 100644 index 000000000..7f0f2db17 --- /dev/null +++ b/Tella/Domain/Entity/CommonReport/BaseReport.swift @@ -0,0 +1,89 @@ +// +// BaseReport.swift +// Tella +// +// Created by Dhekra Rouatbi on 9/7/2024. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +protocol BaseReportProtocol: Hashable { + var id: Int? { get } + var title: String? { get } + var description: String? { get } + var createdDate: Date? { get } + var updatedDate: Date? { get } + var status: ReportStatus { get } + var reportFiles: [ReportFile]? { get } + + var getReportDate: String { get } +} + +class BaseReport : Hashable, Codable, BaseReportProtocol { + + var id : Int? + var title : String? + var description : String? + var createdDate : Date? + var updatedDate : Date? + var status : ReportStatus = .unknown + var reportFiles : [ReportFile]? + + enum CodingKeys: String, CodingKey { + case id = "c_id" + case title = "c_title" + case description = "c_description" + case createdDate = "c_created_date" + case updatedDate = "c_updated_date" + case status = "c_status" + } + + init(id: Int? = nil, + title: String? = nil, + description: String? = nil, + createdDate: Date? = nil, + updatedDate: Date? = nil, + status: ReportStatus, + vaultFiles: [ReportFile]? = nil) { + + self.id = id + self.title = title + self.description = description + self.createdDate = createdDate + self.updatedDate = updatedDate + self.status = status + self.reportFiles = vaultFiles + + } + + static func == (lhs: BaseReport, rhs: BaseReport) -> Bool { + lhs.id == rhs.id + } + + func hash(into hasher: inout Hasher) { + hasher.combine(id.hashValue) + } +} + +extension BaseReport { + var getReportDate: String { + let status = self.status + + switch status { + case .draft: + return self.createdDate?.getDraftReportTime() ?? "" + case .submissionPaused: + return "Paused" + + case .submissionInProgress: + return "" + + case .submitted: + return self.createdDate?.getSubmittedReportTime() ?? "" + default: + return "" + + } + } +} diff --git a/Tella/Domain/Entity/GDrive/GDriveReport.swift b/Tella/Domain/Entity/GDrive/GDriveReport.swift new file mode 100644 index 000000000..54a2f427f --- /dev/null +++ b/Tella/Domain/Entity/GDrive/GDriveReport.swift @@ -0,0 +1,40 @@ +// +// GDriveReport.swift +// Tella +// +// Created by Dhekra Rouatbi on 9/7/2024. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +class GDriveReport: BaseReport { + + var server: GDriveServer? + + init(id: Int? = nil, + title: String? = nil, + description: String? = nil, + createdDate: Date? = nil, + updatedDate: Date? = nil, + status: ReportStatus, + server: GDriveServer? = nil, + vaultFiles: [ReportFile]? = nil) { + + self.server = server + + super.init(id: id, + title: title, + description: description, + createdDate: createdDate, + updatedDate: updatedDate, + status: status, + vaultFiles: vaultFiles) + } + + required init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try super.init(from: decoder) + } +} + diff --git a/Tella/Domain/Entity/Report/Report.swift b/Tella/Domain/Entity/Report/Report.swift index 350a22b03..1c2876e5b 100644 --- a/Tella/Domain/Entity/Report/Report.swift +++ b/Tella/Domain/Entity/Report/Report.swift @@ -5,105 +5,17 @@ import Foundation -protocol BaseReportProtocol: Hashable { - var id: Int? { get } - var title: String? { get } - var description: String? { get } - var createdDate: Date? { get } - var updatedDate: Date? { get } - var status: ReportStatus { get } - var reportFiles: [ReportFile]? { get } - - var getReportDate: String { get } -} - -class BaseReport : Hashable, Codable, BaseReportProtocol { +class Report: BaseReport { - var id : Int? - var title : String? - var description : String? - var createdDate : Date? - var updatedDate : Date? - var status : ReportStatus = .unknown - var reportFiles : [ReportFile]? + var server: TellaServer? + var apiID: String? var currentUpload: Bool? - + enum CodingKeys: String, CodingKey { - case id = "c_id" - case title = "c_title" - case description = "c_description" - case createdDate = "c_created_date" - case updatedDate = "c_updated_date" - case status = "c_status" - case reportFiles = "c_report_files" + case apiID = "c_api_report_id" case currentUpload = "c_current_upload" } - init(id: Int? = nil, - title: String? = nil, - description: String? = nil, - createdDate: Date? = nil, - updatedDate: Date? = nil, - status: ReportStatus, - vaultFiles: [ReportFile]? = nil, - currentUpload: Bool? = nil ) { - self.id = id - self.title = title - self.description = description - self.createdDate = createdDate - self.updatedDate = updatedDate - self.status = status - self.reportFiles = vaultFiles - self.currentUpload = currentUpload - - } - - static func == (lhs: BaseReport, rhs: BaseReport) -> Bool { - lhs.id == rhs.id - } - - func hash(into hasher: inout Hasher) { - hasher.combine(id.hashValue) - } - -// required init(from decoder: Decoder) throws { -// -// let container = try decoder.container(keyedBy: CodingKeys.self) -// -// self.id = try container.decode(Int.self, forKey: .id) -// self.title = try container.decode(String.self, forKey: .title) -// } -} - -extension BaseReport { - var getReportDate: String { - let status = self.status - - switch status { - case .draft: - return self.createdDate?.getDraftReportTime() ?? "" - case .submissionPaused: - return "Paused" - - case .submissionInProgress: - return "" - - case .submitted: - return self.createdDate?.getSubmittedReportTime() ?? "" - default: - return "" - - } - } -} - - -// Report - -class Report: BaseReport { - var server: TellaServer? - var apiID: String? - init(id: Int? = nil, title: String? = nil, description: String? = nil, @@ -114,48 +26,23 @@ class Report: BaseReport { vaultFiles: [ReportFile]? = nil, apiID: String? = nil, currentUpload: Bool? = nil) { + self.server = server self.apiID = apiID - super.init(id: id, title: title, + self.currentUpload = currentUpload + + super.init(id: id, title: title, description: description, createdDate: createdDate, updatedDate: updatedDate, status: status ?? .unknown, - vaultFiles: vaultFiles, - currentUpload: currentUpload) - } - - required init(from decoder: any Decoder) throws { - try super.init(from: decoder) - } -} - -// GDriveReport -class GDriveReport: BaseReport { - var server: GDriveServer? - - enum CodingKeys: String, CodingKey { - case server = "c_server" - } - // Keep the existing initializer - init(id: Int? = nil, - title: String? = nil, - description: String? = nil, - createdDate: Date? = nil, - updatedDate: Date? = nil, - status: ReportStatus, - server: GDriveServer? = nil, - vaultFiles: [ReportFile]? = nil, - currentUpload: Bool? = nil) { - self.server = server - super.init(id: id, title: title, description: description, createdDate: createdDate, updatedDate: updatedDate, status: status, vaultFiles: vaultFiles, currentUpload: currentUpload) + vaultFiles: vaultFiles) } required init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - self.server = try container.decodeIfPresent(GDriveServer.self, forKey: .server) - + self.apiID = try container.decode(String?.self, forKey: .apiID) + self.currentUpload = try container.decode(Bool?.self, forKey: .currentUpload) try super.init(from: decoder) } } - diff --git a/Tella/Domain/Entity/Report/UwaziLocale.swift b/Tella/Domain/Entity/Report/UwaziLocale.swift deleted file mode 100644 index 76abb3511..000000000 --- a/Tella/Domain/Entity/Report/UwaziLocale.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// UwaziLocale.swift -// Tella -// -// Created by Robert Shrestha on 7/21/23. -// Copyright © 2023 HORIZONTAL. All rights reserved. -// - -import Foundation - -class UwaziLocale : Hashable, Codable { - - var id : Int? - var locale : String? - var serverId : Int? - - init(id: Int? = nil, - locale: String? = nil, - serverId: Int? = nil - ) { - self.id = id - self.locale = locale - self.serverId = serverId - } - enum CodingKeys: String, CodingKey { - case id = "c_locale_id" - case locale = "c_locale" - case serverId = "c_server_id" - } - - static func == (lhs: UwaziLocale, rhs: UwaziLocale) -> Bool { - lhs.id == rhs.id - } - - func hash(into hasher: inout Hasher) { - hasher.combine(id.hashValue) - } -} diff --git a/Tella/Scenes/Resources/Models/DownloadedResource.swift b/Tella/Scenes/Resources/Models/DownloadedResource.swift index dc2639877..3032124dc 100644 --- a/Tella/Scenes/Resources/Models/DownloadedResource.swift +++ b/Tella/Scenes/Resources/Models/DownloadedResource.swift @@ -20,6 +20,5 @@ struct DownloadedResource: Codable, Identifiable { case externalId = "c_external_id" case title = "c_title" case fileName = "c_filename" - case server } } From 18a0678eb71b9a927868add9691713cafc3c658b Mon Sep 17 00:00:00 2001 From: Dhekra Rouatbi Date: Tue, 9 Jul 2024 17:16:23 +0100 Subject: [PATCH 085/167] Add serverId to BaseReport --- Tella/Domain/Entity/CommonReport/BaseReport.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tella/Domain/Entity/CommonReport/BaseReport.swift b/Tella/Domain/Entity/CommonReport/BaseReport.swift index 7f0f2db17..a178ebd5a 100644 --- a/Tella/Domain/Entity/CommonReport/BaseReport.swift +++ b/Tella/Domain/Entity/CommonReport/BaseReport.swift @@ -29,7 +29,8 @@ class BaseReport : Hashable, Codable, BaseReportProtocol { var updatedDate : Date? var status : ReportStatus = .unknown var reportFiles : [ReportFile]? - + var serverId: Int? + enum CodingKeys: String, CodingKey { case id = "c_id" case title = "c_title" @@ -37,6 +38,7 @@ class BaseReport : Hashable, Codable, BaseReportProtocol { case createdDate = "c_created_date" case updatedDate = "c_updated_date" case status = "c_status" + case serverId = "c_server_id" } init(id: Int? = nil, From 7ab5ac48f617538ed365b51dddedd153e18cbf35 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 10 Jul 2024 15:37:10 -0300 Subject: [PATCH 086/167] create OutboxMainVM --- Tella.xcodeproj/project.pbxproj | 28 ++-- .../Components/Reports/Draft/DraftView.swift | 15 ++- .../Reports/Outbox/OutboxMainViewModel.swift | 98 ++++++++++++++ .../Views/ReportMainView.swift | 3 +- .../Reports/Outbox/OutboxDetailsView.swift | 7 +- .../Reports/ReportList/ReportCardView.swift | 126 ------------------ .../Reports/ReportList/ReportListView.swift | 45 ------- .../Reports/View Model/OutboxReportVM.swift | 75 ++--------- 8 files changed, 136 insertions(+), 261 deletions(-) create mode 100644 Tella/Components/Reports/Outbox/OutboxMainViewModel.swift delete mode 100644 Tella/Scenes/Reports/ReportList/ReportCardView.swift delete mode 100644 Tella/Scenes/Reports/ReportList/ReportListView.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 39097fd2c..c7a373af7 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -123,8 +123,6 @@ 123AE5A329CFB7F000814CC7 /* UploadReportOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123AE5A229CFB7F000814CC7 /* UploadReportOperation.swift */; }; 123CE54F272028D1005BF386 /* Roboto-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 123CE54E272028D1005BF386 /* Roboto-Light.ttf */; }; 123CE84429126B52003C251F /* ServerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123CE84329126B52003C251F /* ServerViewModel.swift */; }; - 1240E6B02907E14400692232 /* ReportCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1240E6AF2907E14400692232 /* ReportCardView.swift */; }; - 1240E6B22908123900692232 /* ReportListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1240E6B12908123900692232 /* ReportListView.swift */; }; 124190442A42F3A700E177F3 /* SQLStatementBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 124190432A42F3A700E177F3 /* SQLStatementBuilder.swift */; }; 124190462A43230000E177F3 /* SQLiteStatementBuilderExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 124190452A43230000E177F3 /* SQLiteStatementBuilderExtension.swift */; }; 1242135529B774A40002402D /* DeleteReportConfirmationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1242135429B774A40002402D /* DeleteReportConfirmationView.swift */; }; @@ -363,6 +361,7 @@ 1503C87E2C07A080000F2209 /* ServerConnectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1503C87D2C07A080000F2209 /* ServerConnectionHeaderView.swift */; }; 150913422B841C3F001E782A /* ResourceActionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 150913412B841C3F001E782A /* ResourceActionType.swift */; }; 151308172BF3DBD9000C51D7 /* UwaziRelationshipList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 151308162BF3DBD9000C51D7 /* UwaziRelationshipList.swift */; }; + 1517A9AA2C3F011D00CB8EBF /* OutboxMainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1517A9A92C3F011D00CB8EBF /* OutboxMainViewModel.swift */; }; 1519BED82B9A5A52006FD290 /* Resource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1519BED72B9A5A52006FD290 /* Resource.swift */; }; 152D38512C2C61DF00323CE7 /* DraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152D38502C2C61DF00323CE7 /* DraftView.swift */; }; 1535A5F12BAA06490009EA42 /* DownloadedResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1535A5F02BAA06490009EA42 /* DownloadedResource.swift */; }; @@ -697,8 +696,6 @@ 123AE5A229CFB7F000814CC7 /* UploadReportOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadReportOperation.swift; sourceTree = ""; }; 123CE54E272028D1005BF386 /* Roboto-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Light.ttf"; sourceTree = ""; }; 123CE84329126B52003C251F /* ServerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerViewModel.swift; sourceTree = ""; }; - 1240E6AF2907E14400692232 /* ReportCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportCardView.swift; sourceTree = ""; }; - 1240E6B12908123900692232 /* ReportListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportListView.swift; sourceTree = ""; }; 124190432A42F3A700E177F3 /* SQLStatementBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SQLStatementBuilder.swift; sourceTree = ""; }; 124190452A43230000E177F3 /* SQLiteStatementBuilderExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SQLiteStatementBuilderExtension.swift; sourceTree = ""; }; 1242135429B774A40002402D /* DeleteReportConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteReportConfirmationView.swift; sourceTree = ""; }; @@ -935,6 +932,7 @@ 1503C87D2C07A080000F2209 /* ServerConnectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConnectionHeaderView.swift; sourceTree = ""; }; 150913412B841C3F001E782A /* ResourceActionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceActionType.swift; sourceTree = ""; }; 151308162BF3DBD9000C51D7 /* UwaziRelationshipList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziRelationshipList.swift; sourceTree = ""; }; + 1517A9A92C3F011D00CB8EBF /* OutboxMainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutboxMainViewModel.swift; sourceTree = ""; }; 1519BED72B9A5A52006FD290 /* Resource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Resource.swift; sourceTree = ""; }; 152D38502C2C61DF00323CE7 /* DraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftView.swift; sourceTree = ""; }; 1535A5F02BAA06490009EA42 /* DownloadedResource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResource.swift; sourceTree = ""; }; @@ -1172,7 +1170,6 @@ children = ( 0D4BC3C1267577F900DCDC30 /* ReportsView.swift */, 126FEE082AC4992800B99298 /* Models */, - 12794E70294CB4E000B13BBF /* ReportList */, 121C945C28FF3D6900570EB4 /* Draft */, 12199C322940936B0041BD38 /* Outbox */, 123048D3295F954E0015CD96 /* Submitted */, @@ -1854,15 +1851,6 @@ path = Utils; sourceTree = ""; }; - 12794E70294CB4E000B13BBF /* ReportList */ = { - isa = PBXGroup; - children = ( - 1240E6B12908123900692232 /* ReportListView.swift */, - 1240E6AF2907E14400692232 /* ReportCardView.swift */, - ); - path = ReportList; - sourceTree = ""; - }; 127964B327CFA8AF003DD7DF /* Add files */ = { isa = PBXGroup; children = ( @@ -2395,6 +2383,14 @@ path = Common; sourceTree = ""; }; + 1517A9A82C3F010D00CB8EBF /* Outbox */ = { + isa = PBXGroup; + children = ( + 1517A9A92C3F011D00CB8EBF /* OutboxMainViewModel.swift */, + ); + path = Outbox; + sourceTree = ""; + }; 1519BED42B9A5A2B006FD290 /* Resource */ = { isa = PBXGroup; children = ( @@ -2490,6 +2486,7 @@ 15E656A92C2A142300BDEC91 /* Reports */ = { isa = PBXGroup; children = ( + 1517A9A82C3F010D00CB8EBF /* Outbox */, 15E656AE2C2A14FA00BDEC91 /* Draft */, 15F1AA532C2E07F50002A7D8 /* BaseReportsViewModel.swift */, ); @@ -3354,7 +3351,6 @@ files = ( CC13138A2A5DB68E0057271C /* BottomSheetTitleView.swift in Sources */, E1E7C5842AAB70A500DDB07E /* UwaziDictionaryRow.swift in Sources */, - 1240E6B02907E14400692232 /* ReportCardView.swift in Sources */, 15E656AB2C2A147E00BDEC91 /* AddFilesToDraftView.swift in Sources */, 12A1489A2720B53800A1ADDC /* ConfirmPasswordErrorView.swift in Sources */, 128B15CB27DA30C800E1C1E0 /* OnboardingEndView.swift in Sources */, @@ -3390,6 +3386,7 @@ 12E6772F27A9719F00DC1E1C /* UIImageExtension.swift in Sources */, 15994A0E2BFBE15F0017F153 /* SelectSharedDrive.swift in Sources */, D5B823EB262774E00008E04B /* MainView.swift in Sources */, + 1517A9AA2C3F011D00CB8EBF /* OutboxMainViewModel.swift in Sources */, 151308172BF3DBD9000C51D7 /* UwaziRelationshipList.swift in Sources */, 153F96492BFD306F00FE5464 /* CreateDriveFolder.swift in Sources */, 125C78A22C38056300440014 /* EntityStatusExtension.swift in Sources */, @@ -3800,7 +3797,6 @@ 126684452B18B78200561650 /* BackgroundActivityStatus.swift in Sources */, 12EC94CF28AA566C0070E72B /* GeneralView.swift in Sources */, CCD586CF2A7AD9E400014F87 /* MoreButtonView.swift in Sources */, - 1240E6B22908123900692232 /* ReportListView.swift in Sources */, 1218E86528E48AEC00FE2E68 /* LoginResult.swift in Sources */, 1204F64327D928C9006E40EE /* FileTypeExtension.swift in Sources */, 0DA213C72680286F00526995 /* FileListItem.swift in Sources */, diff --git a/Tella/Components/Reports/Draft/DraftView.swift b/Tella/Components/Reports/Draft/DraftView.swift index 391a333d1..fae93dfef 100644 --- a/Tella/Components/Reports/Draft/DraftView.swift +++ b/Tella/Components/Reports/Draft/DraftView.swift @@ -21,7 +21,6 @@ struct DraftView: View { @Environment(\.presentationMode) var presentationMode: Binding var body: some View { - // TO DO: INCLUDE SERVER SELECTION VIEW!!!!!! ContainerView { contentView .environmentObject(viewModel) @@ -194,11 +193,15 @@ struct DraftView: View { } var outboxDetailsView: some View { - OutboxDetailsView(appModel: mainAppModel, - reportsViewModel: reportsViewModel, - reportId: viewModel.reportId, - shouldStartUpload: true) - .environmentObject(reportsViewModel) + Group { + switch reportsViewModel.connectionType { + case .tella: + let outboxVM = OutboxReportVM(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: viewModel.reportId, shouldStartUpload: true) + OutboxDetailsView(outboxReportVM: outboxVM).environmentObject(reportsViewModel) + default: + Text("") + } + } } var photoVideoPickerView: some View { diff --git a/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift b/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift new file mode 100644 index 000000000..03430df1e --- /dev/null +++ b/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift @@ -0,0 +1,98 @@ +// +// OutboxMainViewModel.swift +// Tella +// +// Created by gus valbuena on 7/10/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation +import Combine + +class OutboxMainViewModel: ObservableObject { + + var mainAppModel : MainAppModel + var reportsViewModel : ReportMainViewModel + + @Published var reportViewModel : ReportViewModel = ReportViewModel() + @Published var progressFileItems : [ProgressFileItemViewModel] = [] + @Published var percentUploaded : Float = 0.0 + @Published var percentUploadedInfo : String = LocalizableReport.waitingConnection.localized + @Published var uploadedFiles : String = "" + + @Published var isLoading : Bool = false + var isSubmissionInProgress: Bool { + return reportViewModel.status == .submissionInProgress + + } + @Published var shouldShowSubmittedReportView : Bool = false + @Published var shouldShowMainView : Bool = false + + var subscribers = Set() + var filesToUpload : [FileToUpload] = [] + var reportRepository = ReportRepository() + + var uploadButtonTitle: String { + + switch reportViewModel.status { + case .finalized: + return "Submit" + case .submissionInProgress: + return "Pause" + default: + return "Resume" + } + } + + var reportHasFile: Bool { + return !reportViewModel.files.isEmpty + } + + var reportHasDescription: Bool { + return !reportViewModel.description.isEmpty + } + + var reportIsNotAutoDelete: Bool { + return !(reportViewModel.server?.autoDelete ?? true) + } + + + init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, reportId : Int?, shouldStartUpload: Bool = false) { + self.mainAppModel = mainAppModel + self.reportsViewModel = reportsViewModel + + initVaultFile(reportId: reportId) + + initializeProgressionInfos() + + if shouldStartUpload { + self.submitReport() + } else { + treat(uploadResponse:reportRepository.checkUploadReportOperation(reportId: self.reportViewModel.id)) + } + } + + func treat(uploadResponse: CurrentValueSubject?) { + + } + + func initVaultFile(reportId: Int?) {} + + func initializeProgressionInfos() {} + + func pauseSubmission() {} + + func submitReport() {} + + func showSubmittedReport() {} + + func showMainView() {} + + func updateProgressInfos(uploadProgressInfo : UploadProgressInfo) {} + + // MARK: Update Local database + + func updateReportStatus(reportStatus:ReportStatus) {} + + func deleteReport() {} +} diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift index d24fa2dda..a91d1b467 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -178,7 +178,8 @@ struct ReportMainView: View { private func showOutboxView(id: Int? = nil) { switch reportMainViewModel.connectionType { case .tella: - let destination = OutboxDetailsView(appModel: mainAppModel, reportsViewModel: reportMainViewModel, reportId: id) + var outboxViewModel = OutboxReportVM(mainAppModel: mainAppModel, reportsViewModel: reportMainViewModel, reportId: id) + let destination = OutboxDetailsView(outboxReportVM: outboxViewModel) .environmentObject(reportMainViewModel) self.navigateTo(destination: destination) break diff --git a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift index 58f532224..64c09ecf0 100644 --- a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift +++ b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift @@ -6,16 +6,12 @@ import SwiftUI struct OutboxDetailsView: View { - @StateObject var outboxReportVM : OutboxReportVM + @StateObject var outboxReportVM : OutboxMainViewModel @EnvironmentObject var reportsViewModel : ReportMainViewModel @EnvironmentObject var mainAppModel : MainAppModel @Environment(\.presentationMode) var presentationMode: Binding @EnvironmentObject private var sheetManager: SheetManager - init(appModel: MainAppModel,reportsViewModel: ReportMainViewModel, reportId : Int?, shouldStartUpload: Bool = false) { - _outboxReportVM = StateObject(wrappedValue: OutboxReportVM(mainAppModel: appModel, reportsViewModel: reportsViewModel, reportId:reportId, shouldStartUpload: shouldStartUpload)) - } - var body: some View { ContainerView { @@ -56,7 +52,6 @@ struct OutboxDetailsView: View { HStack(spacing: 0) { Button { - dump("DISMISSS") dismissView() } label: { Image("back") diff --git a/Tella/Scenes/Reports/ReportList/ReportCardView.swift b/Tella/Scenes/Reports/ReportList/ReportCardView.swift deleted file mode 100644 index 131da7be8..000000000 --- a/Tella/Scenes/Reports/ReportList/ReportCardView.swift +++ /dev/null @@ -1,126 +0,0 @@ -// Tella -// -// Copyright © 2022 INTERNEWS. All rights reserved. -// - -import SwiftUI - -struct ReportCardView : View { - - @Binding var report : Report - - @EnvironmentObject var reportsViewModel : ReportsViewModel - @EnvironmentObject private var sheetManager: SheetManager - @EnvironmentObject var mainAppModel : MainAppModel - - var body : some View { - Button { - reportsViewModel.selectedReport = report - - DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) { - self.handleActions(type: report.status.reportActionType) - } - - } label: { - VStack(spacing: 0) { - - HStack { - - ConnectionCardDetails(title: report.title ?? "", subtitle: report.getReportDate) - - Spacer() - - ImageButtonView(imageName: "reports.more", action: { - reportsViewModel.selectedReport = report - showReportActionBottomSheet() - }) - - }.padding(.all, 16) - - } .background(Color.white.opacity(0.08)) - .cornerRadius(15) - .padding(EdgeInsets(top: 6, leading: 0, bottom: 6, trailing: 0)) - } - } - - - private func showReportActionBottomSheet() { - sheetManager.showBottomSheet(modalHeight: 176) { - ActionListBottomSheet(items: reportsViewModel.sheetItems , - headerTitle: reportsViewModel.selectedReport?.title ?? "", - action: { item in - self.handleActions(type : item.type as? ConnectionActionType) - }) - } - } - - private func showDeleteReportConfirmationView() { - sheetManager.showBottomSheet(modalHeight: 200) { - DeleteReportConfirmationView(title: report.title, - message: deleteMessage) { - reportsViewModel.deleteReport(report: report) - sheetManager.hide() - } - } - } - - private func handleActions(type: ConnectionActionType?) { - - guard let type else { return } - - switch type { - case .editDraft: - self.navigateTo(destination: editDraftReportView) - sheetManager.hide() - case .editOutbox: - navigateTo(destination: outboxDetailsView) - sheetManager.hide() - case .delete: - showDeleteReportConfirmationView() - case .viewSubmitted: - navigateTo(destination: submittedDetailsView) - sheetManager.hide() - } - } - - private var editDraftReportView: some View { - DraftReportView(mainAppModel: mainAppModel, - reportId: reportsViewModel.selectedReport?.id) - .environmentObject(reportsViewModel) - } - - private var submittedDetailsView: some View { - SubmittedDetailsView(appModel: mainAppModel, - reportId: reportsViewModel.selectedReport?.id) - .environmentObject(reportsViewModel) - } - - private var outboxDetailsView: some View { - OutboxDetailsView(appModel: mainAppModel, - reportsViewModel: reportsViewModel, - reportId: reportsViewModel.selectedReport?.id) - .environmentObject(reportsViewModel) - } - - private var deleteMessage : String { - switch report.status { - case .draft: - return LocalizableReport.deleteDraftReportMessage.localized - case .submitted: - return LocalizableReport.deleteSubmittedReportMessage.localized - default: - return LocalizableReport.deleteOutboxReportMessage.localized - } - } -} - -struct ReportCardView_Previews: PreviewProvider { - static var previews: some View { - ContainerView { - ReportCardView(report: .constant(Report(title: LocalizableReport.reportsListTitle.localized, - description: LocalizableReport.reportsListDescription.localized, - status: .draft, - server: TellaServer(autoUpload: false, autoDelete: true), vaultFiles: []))) - } - } -} diff --git a/Tella/Scenes/Reports/ReportList/ReportListView.swift b/Tella/Scenes/Reports/ReportList/ReportListView.swift deleted file mode 100644 index c299f38b2..000000000 --- a/Tella/Scenes/Reports/ReportList/ReportListView.swift +++ /dev/null @@ -1,45 +0,0 @@ -// Tella -// -// Copyright © 2022 INTERNEWS. All rights reserved. -// - -import SwiftUI - -struct ReportListView: View { - - @Binding var reportArray : [Report] - var message : String - - var body: some View { - ZStack { - if $reportArray.wrappedValue.count > 0 { - - ScrollView { - - VStack(alignment: .center, spacing: 0) { - - ForEach($reportArray, id: \.self) { report in - ReportCardView(report: report) - } - } - } - } else { - ConnectionEmptyView(message: message, iconName: "") - } - } - } -} - -struct ReportListView_Previews: PreviewProvider { - static var previews: some View { - ContainerView { - ReportListView(reportArray: .constant([Report(title: LocalizableReport.reportsListTitle.localized, - description: LocalizableReport.reportsListDescription.localized, - status: ReportStatus.draft, - server: TellaServer(autoUpload: false, autoDelete: true), vaultFiles: [])]), - message: LocalizableReport.reportsListMessage.localized) - } - } -} - - diff --git a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift index 99c7dcbe5..e9ecc2005 100644 --- a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift +++ b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift @@ -5,58 +5,11 @@ import SwiftUI import Combine -class OutboxReportVM: ObservableObject { +class OutboxReportVM: OutboxMainViewModel { - var mainAppModel : MainAppModel - var reportsViewModel : ReportMainViewModel - - @Published var reportViewModel : ReportViewModel = ReportViewModel() - @Published var progressFileItems : [ProgressFileItemViewModel] = [] - @Published var percentUploaded : Float = 0.0 - @Published var percentUploadedInfo : String = LocalizableReport.waitingConnection.localized - @Published var uploadedFiles : String = "" - - @Published var isLoading : Bool = false - var isSubmissionInProgress: Bool { - return reportViewModel.status == .submissionInProgress - - } - @Published var shouldShowSubmittedReportView : Bool = false - @Published var shouldShowMainView : Bool = false - - private var subscribers = Set() - private var filesToUpload : [FileToUpload] = [] - private var reportRepository = ReportRepository() - - var uploadButtonTitle: String { - - switch reportViewModel.status { - case .finalized: - return "Submit" - case .submissionInProgress: - return "Pause" - default: - return "Resume" - } - } - - var reportHasFile: Bool { - return !reportViewModel.files.isEmpty - } - - var reportHasDescription: Bool { - return !reportViewModel.description.isEmpty - } - - var reportIsNotAutoDelete: Bool { - return !(reportViewModel.server?.autoDelete ?? true) - } - - - init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, reportId : Int?, shouldStartUpload: Bool = false) { - - self.mainAppModel = mainAppModel - self.reportsViewModel = reportsViewModel + override init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, reportId : Int?, shouldStartUpload: Bool = false) { + + super.init(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: reportId) initVaultFile(reportId: reportId) @@ -69,7 +22,7 @@ class OutboxReportVM: ObservableObject { } } - func treat(uploadResponse: CurrentValueSubject?) { + override func treat(uploadResponse: CurrentValueSubject?) { uploadResponse? .sink { result in @@ -125,7 +78,7 @@ class OutboxReportVM: ObservableObject { .store(in: &subscribers) } - func initVaultFile(reportId: Int?) { + override func initVaultFile(reportId: Int?) { if let reportId, let report = self.mainAppModel.tellaData?.getReport(reportId: reportId) { @@ -151,7 +104,7 @@ class OutboxReportVM: ObservableObject { } } - func initializeProgressionInfos() { + override func initializeProgressionInfos() { let totalSize = self.reportViewModel.files.reduce(0) { $0 + ($1.size) } let bytesSent = self.reportViewModel.files.reduce(0) { $0 + ($1.bytesSent)} @@ -179,7 +132,7 @@ class OutboxReportVM: ObservableObject { } } - func pauseSubmission() { + override func pauseSubmission() { if isSubmissionInProgress { self.updateReportStatus(reportStatus: .submissionPaused) self.reportRepository.pause(reportId: self.reportViewModel.id) @@ -187,7 +140,7 @@ class OutboxReportVM: ObservableObject { } - func submitReport() { + override func submitReport() { let report = Report(id: reportViewModel.id, title: reportViewModel.title, @@ -208,19 +161,19 @@ class OutboxReportVM: ObservableObject { } } - func showSubmittedReport() { + override func showSubmittedReport() { DispatchQueue.main.async { self.shouldShowSubmittedReportView = true } } - func showMainView() { + override func showMainView() { DispatchQueue.main.async { self.shouldShowMainView = true } } - private func updateProgressInfos(uploadProgressInfo : UploadProgressInfo) { + override func updateProgressInfos(uploadProgressInfo : UploadProgressInfo) { _ = self.reportViewModel.files.compactMap { _ in let currentFile = self.reportViewModel.files.first(where: {$0.id == uploadProgressInfo.fileId}) @@ -268,7 +221,7 @@ class OutboxReportVM: ObservableObject { // MARK: Update Local database - func updateReportStatus(reportStatus:ReportStatus) { + override func updateReportStatus(reportStatus:ReportStatus) { self.reportViewModel.status = reportStatus @@ -277,7 +230,7 @@ class OutboxReportVM: ObservableObject { mainAppModel.tellaData?.updateReportStatus(idReport: id, status: reportStatus) } - func deleteReport() { + override func deleteReport() { mainAppModel.deleteReport(reportId: reportViewModel.id) mainAppModel.deleteReport(reportId: reportViewModel.id) } From 18cf3f06865b66556eb6cbf1caceb1ecf583b90d Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 10 Jul 2024 19:28:50 -0300 Subject: [PATCH 087/167] add GDriveOutboxVM --- Tella.xcodeproj/project.pbxproj | 4 + .../Components/Reports/Draft/DraftView.swift | 3 + .../Reports/Outbox/OutboxMainViewModel.swift | 51 ++++---- Tella/Data/Database/GDriveData.swift | 7 ++ Tella/Data/Database/GDriveDatabase.swift | 17 +++ .../Views/ReportMainView.swift | 6 +- .../ViewModel/GDriveDraftViewModel.swift | 53 +-------- .../ViewModel/GDriveOutboxViewModel.swift | 111 ++++++++++++++++++ .../Reports/Outbox/OutboxDetailsView.swift | 4 +- .../Reports/View Model/OutboxReportVM.swift | 37 ++---- .../Reports/View Model/ReportViewModel.swift | 6 +- 11 files changed, 193 insertions(+), 106 deletions(-) create mode 100644 Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index c7a373af7..f2b02e2d6 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -362,6 +362,7 @@ 150913422B841C3F001E782A /* ResourceActionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 150913412B841C3F001E782A /* ResourceActionType.swift */; }; 151308172BF3DBD9000C51D7 /* UwaziRelationshipList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 151308162BF3DBD9000C51D7 /* UwaziRelationshipList.swift */; }; 1517A9AA2C3F011D00CB8EBF /* OutboxMainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1517A9A92C3F011D00CB8EBF /* OutboxMainViewModel.swift */; }; + 1517A9AF2C3F0D7A00CB8EBF /* GDriveOutboxViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1517A9AE2C3F0D7A00CB8EBF /* GDriveOutboxViewModel.swift */; }; 1519BED82B9A5A52006FD290 /* Resource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1519BED72B9A5A52006FD290 /* Resource.swift */; }; 152D38512C2C61DF00323CE7 /* DraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152D38502C2C61DF00323CE7 /* DraftView.swift */; }; 1535A5F12BAA06490009EA42 /* DownloadedResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1535A5F02BAA06490009EA42 /* DownloadedResource.swift */; }; @@ -933,6 +934,7 @@ 150913412B841C3F001E782A /* ResourceActionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceActionType.swift; sourceTree = ""; }; 151308162BF3DBD9000C51D7 /* UwaziRelationshipList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziRelationshipList.swift; sourceTree = ""; }; 1517A9A92C3F011D00CB8EBF /* OutboxMainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutboxMainViewModel.swift; sourceTree = ""; }; + 1517A9AE2C3F0D7A00CB8EBF /* GDriveOutboxViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveOutboxViewModel.swift; sourceTree = ""; }; 1519BED72B9A5A52006FD290 /* Resource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Resource.swift; sourceTree = ""; }; 152D38502C2C61DF00323CE7 /* DraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftView.swift; sourceTree = ""; }; 1535A5F02BAA06490009EA42 /* DownloadedResource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResource.swift; sourceTree = ""; }; @@ -2463,6 +2465,7 @@ children = ( 15B81F392C1A281C007C0E88 /* GDriveViewModel.swift */, 15E3D50D2C1B87AC00B7FECC /* GDriveDraftViewModel.swift */, + 1517A9AE2C3F0D7A00CB8EBF /* GDriveOutboxViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -3689,6 +3692,7 @@ 1E67B39223FC9067001F3D64 /* ImagePickerSheet.swift in Sources */, 12B3AD8A28C0DD0200AC9AF9 /* ServerLoginView.swift in Sources */, 1285BF402A3C5D63005D5D23 /* OpenXmlFormats.swift in Sources */, + 1517A9AF2C3F0D7A00CB8EBF /* GDriveOutboxViewModel.swift in Sources */, CC4864E92AF94AF300293F62 /* SummaryEntityView.swift in Sources */, 1252F7052BDAB1C30076DF4B /* EntityInstanceToSend.swift in Sources */, 15E3D50A2C1B71E200B7FECC /* GDriveDraftView.swift in Sources */, diff --git a/Tella/Components/Reports/Draft/DraftView.swift b/Tella/Components/Reports/Draft/DraftView.swift index fae93dfef..f17e3571a 100644 --- a/Tella/Components/Reports/Draft/DraftView.swift +++ b/Tella/Components/Reports/Draft/DraftView.swift @@ -198,6 +198,9 @@ struct DraftView: View { case .tella: let outboxVM = OutboxReportVM(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: viewModel.reportId, shouldStartUpload: true) OutboxDetailsView(outboxReportVM: outboxVM).environmentObject(reportsViewModel) + case .gDrive: + let outboxVM = GDriveOutboxViewModel(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: viewModel.reportId, repository: GDriveRepository(), shouldStartUpload: true) + OutboxDetailsView(outboxReportVM: outboxVM).environmentObject(reportsViewModel) default: Text("") } diff --git a/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift b/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift index 03430df1e..38b0a95ff 100644 --- a/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift +++ b/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift @@ -9,12 +9,12 @@ import Foundation import Combine -class OutboxMainViewModel: ObservableObject { +class OutboxMainViewModel: ObservableObject { var mainAppModel : MainAppModel var reportsViewModel : ReportMainViewModel - @Published var reportViewModel : ReportViewModel = ReportViewModel() + @Published var reportViewModel : ReportViewModel = ReportViewModel() @Published var progressFileItems : [ProgressFileItemViewModel] = [] @Published var percentUploaded : Float = 0.0 @Published var percentUploadedInfo : String = LocalizableReport.waitingConnection.localized @@ -30,7 +30,6 @@ class OutboxMainViewModel: ObservableObject { var subscribers = Set() var filesToUpload : [FileToUpload] = [] - var reportRepository = ReportRepository() var uploadButtonTitle: String { @@ -52,33 +51,41 @@ class OutboxMainViewModel: ObservableObject { return !reportViewModel.description.isEmpty } - var reportIsNotAutoDelete: Bool { - return !(reportViewModel.server?.autoDelete ?? true) - } - init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, reportId : Int?, shouldStartUpload: Bool = false) { self.mainAppModel = mainAppModel self.reportsViewModel = reportsViewModel - - initVaultFile(reportId: reportId) - - initializeProgressionInfos() - - if shouldStartUpload { - self.submitReport() - } else { - treat(uploadResponse:reportRepository.checkUploadReportOperation(reportId: self.reportViewModel.id)) - } - } - - func treat(uploadResponse: CurrentValueSubject?) { - } func initVaultFile(reportId: Int?) {} - func initializeProgressionInfos() {} + func initializeProgressionInfos() { + + let totalSize = self.reportViewModel.files.reduce(0) { $0 + ($1.size) } + let bytesSent = self.reportViewModel.files.reduce(0) { $0 + ($1.bytesSent)} + + if totalSize > 0 { + + // All Files + let percentUploaded = Float(bytesSent) / Float(totalSize) + + let formattedPercentUploaded = percentUploaded >= 1.0 ? 1.0 : Float(percentUploaded) + + let formattedTotalUploaded = bytesSent.getFormattedFileSize().getFileSizeWithoutUnit() + let formattedTotalSize = totalSize.getFormattedFileSize() + DispatchQueue.main.async { + + self.percentUploadedInfo = "\(Int(formattedPercentUploaded * 100))% uploaded" + self.percentUploaded = Float(percentUploaded) + self.uploadedFiles = " \(self.reportViewModel.files.count) files, \(formattedTotalUploaded)/\(formattedTotalSize) uploaded" + + self.progressFileItems = self.reportViewModel.files.compactMap{ProgressFileItemViewModel(file: $0, progression: ($0.bytesSent.getFormattedFileSize()) + "/" + ($0.size.getFormattedFileSize()))} + + self.objectWillChange.send() + + } + } + } func pauseSubmission() {} diff --git a/Tella/Data/Database/GDriveData.swift b/Tella/Data/Database/GDriveData.swift index b49e19c8e..640afd31c 100644 --- a/Tella/Data/Database/GDriveData.swift +++ b/Tella/Data/Database/GDriveData.swift @@ -48,4 +48,11 @@ extension TellaData { shouldReloadGDriveReports.send(true) return self.database.deleteDriveReport(reportId: reportId) } + + @discardableResult + func updateDriveReportStatus(idReport: Int, status: ReportStatus) -> Result { + shouldReloadGDriveReports.send(true) + + return self.database.updateDriveReportStatus(idReport: idReport, status: status) + } } diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index 11abc9da4..0c50115fb 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -227,4 +227,21 @@ extension TellaDataBase { return .failure(error) } } + + func updateDriveReportStatus(idReport: Int, status: ReportStatus) -> Result { + do { + let valuesToUpdate = [KeyValue(key: D.cStatus, value: status.rawValue), + KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()) + ] + + let reportCondition = [KeyValue(key: D.cId, value: idReport)] + + try statementBuilder.update(tableName: D.tGDriveReport, valuesToUpdate: valuesToUpdate, equalCondition: reportCondition) + + return .success(true) + } catch let error { + debugLog(error) + return .failure(error) + } + } } diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift index a91d1b467..3acd63a86 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -178,11 +178,15 @@ struct ReportMainView: View { private func showOutboxView(id: Int? = nil) { switch reportMainViewModel.connectionType { case .tella: - var outboxViewModel = OutboxReportVM(mainAppModel: mainAppModel, reportsViewModel: reportMainViewModel, reportId: id) + let outboxViewModel = OutboxReportVM(mainAppModel: mainAppModel, reportsViewModel: reportMainViewModel, reportId: id) let destination = OutboxDetailsView(outboxReportVM: outboxViewModel) .environmentObject(reportMainViewModel) self.navigateTo(destination: destination) break + case .gDrive: + let outboxViewModel = GDriveOutboxViewModel(mainAppModel: mainAppModel, reportsViewModel: reportMainViewModel, reportId: id, repository: GDriveRepository()) + let destination = OutboxDetailsView(outboxReportVM: outboxViewModel) + self.navigateTo(destination: destination) default: break } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index 5f5826c43..e9da4a410 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -34,38 +34,6 @@ class GDriveDraftViewModel: DraftMainViewModel { .store(in: &subscribers) } - override func submitReport() { - self.status = .submissionScheduled - performSubmission() - } - - - func performSubmission() { - gDriveRepository.createDriveFolder( - folderName: self.title, - parentId: server?.rootFolder, - description: self.description - ) - .receive(on: DispatchQueue.main) - .flatMap { folderId in - self.uploadFiles(to: folderId) - } - .sink( - receiveCompletion: { completion in - switch completion { - case .finished: - self.saveSubmittedReport() - break - case .failure(let error): - debugLog(error) - } - }, - receiveValue: { result in - dump(result) - } - ).store(in: &subscribers) - } - override func fillReportVM() { if let reportId = self.reportId, let report = self.mainAppModel.tellaData?.getDriveReport(id: reportId) { self.title = report.title ?? "" @@ -88,9 +56,12 @@ class GDriveDraftViewModel: DraftMainViewModel { self.status = .finalized self.saveReport() } + override func submitReport() { + saveReportForSubmission() + } - func saveSubmittedReport() { - self.status = .submitted + override func saveReportForSubmission() { + self.status = .submissionScheduled self.saveReport() } @@ -137,20 +108,6 @@ class GDriveDraftViewModel: DraftMainViewModel { self.server = mainAppModel.tellaData?.gDriveServers.value.first } - private func uploadFiles(to folderId: String) -> AnyPublisher { - let uploadPublishers = files.map { file -> AnyPublisher in - guard let fileUrl = self.mainAppModel.vaultManager.loadVaultFileToURL(file: file) else { - return Fail(error: APIError.unexpectedResponse).eraseToAnyPublisher() - } - return gDriveRepository.uploadFile(fileURL: fileUrl, mimeType: file.mimeType ?? "", folderId: folderId) - } - - return Publishers.MergeMany(uploadPublishers) - .collect() - .map { _ in () } - .eraseToAnyPublisher() - } - override func deleteFile(fileId: String?) { guard let index = files.firstIndex(where: { $0.id == fileId}) else {return } files.remove(at: index) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift new file mode 100644 index 000000000..265255b5f --- /dev/null +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -0,0 +1,111 @@ +// +// GDriveOutboxViewModel.swift +// Tella +// +// Created by gus valbuena on 7/10/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation +import Combine + +class GDriveOutboxViewModel: OutboxMainViewModel { + private let gDriveRepository: GDriveRepositoryProtocol + + init(mainAppModel: MainAppModel, + reportsViewModel : ReportMainViewModel, + reportId : Int?, + repository: GDriveRepository, + shouldStartUpload: Bool = false + ) { + self.gDriveRepository = repository + super.init(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: reportId) + + initVaultFile(reportId: reportId) + + initializeProgressionInfos() + + if shouldStartUpload { + self.submitReport() + } else { + // treat + } + } + + + override func initVaultFile(reportId: Int?) { + if let reportId, let report = self.mainAppModel.tellaData?.getDriveReport(id: reportId) { + let vaultFileResult = mainAppModel.vaultFilesManager?.getVaultFiles(ids: report.reportFiles?.compactMap{$0.fileId} ?? []) + + var files: [ReportVaultFile] = [] + + report.reportFiles?.forEach({ reportFile in + if let vaultFile = vaultFileResult?.first(where: {reportFile.fileId == $0.id}) { + let reportVaultFile = ReportVaultFile(reportFile: reportFile, vaultFile: vaultFile) + files.append(reportVaultFile) + } + }) + + self.reportViewModel = ReportViewModel(id: report.id, + title: report.title ?? "", + description: report.description ?? "", + files: files, + reportFiles: report.reportFiles ?? [], + server: report.server, + status: report.status, + apiID: nil) + } + } + + override func submitReport() { + performSubmission() + } + + func performSubmission() { + gDriveRepository.createDriveFolder( + folderName: reportViewModel.title, + parentId: reportViewModel.server?.rootFolder, + description: reportViewModel.description + ) + .receive(on: DispatchQueue.main) + .flatMap { folderId in + self.uploadFiles(to: folderId) + } + .sink( + receiveCompletion: { completion in + switch completion { + case .finished: + self.updateReportStatus(reportStatus: .submitted) + break + case .failure(let error): + debugLog(error) + } + }, + receiveValue: { result in + dump(result) + } + ).store(in: &subscribers) + } + + private func uploadFiles(to folderId: String) -> AnyPublisher { + let uploadPublishers = reportViewModel.files.map { file -> AnyPublisher in + guard let fileUrl = self.mainAppModel.vaultManager.loadVaultFileToURL(file: file) else { + return Fail(error: APIError.unexpectedResponse).eraseToAnyPublisher() + } + return gDriveRepository.uploadFile(fileURL: fileUrl, mimeType: file.mimeType ?? "", folderId: folderId) + } + + return Publishers.MergeMany(uploadPublishers) + .collect() + .map { _ in () } + .eraseToAnyPublisher() + } + + override func updateReportStatus(reportStatus: ReportStatus) { + self.reportViewModel.status = reportStatus + + guard let id = reportViewModel.id else { return } + + mainAppModel.tellaData?.updateDriveReportStatus(idReport: id, status: reportStatus) + } +} diff --git a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift index 64c09ecf0..9f3a4fa3a 100644 --- a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift +++ b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift @@ -4,9 +4,9 @@ import SwiftUI -struct OutboxDetailsView: View { +struct OutboxDetailsView: View { - @StateObject var outboxReportVM : OutboxMainViewModel + @StateObject var outboxReportVM : OutboxMainViewModel @EnvironmentObject var reportsViewModel : ReportMainViewModel @EnvironmentObject var mainAppModel : MainAppModel @Environment(\.presentationMode) var presentationMode: Binding diff --git a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift index e9ecc2005..d281df111 100644 --- a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift +++ b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift @@ -5,8 +5,13 @@ import SwiftUI import Combine -class OutboxReportVM: OutboxMainViewModel { +class OutboxReportVM: OutboxMainViewModel { + var reportRepository = ReportRepository() + var reportIsNotAutoDelete: Bool { + return !(reportViewModel.server?.autoDelete ?? true) + } + override init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, reportId : Int?, shouldStartUpload: Bool = false) { super.init(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: reportId) @@ -22,7 +27,7 @@ class OutboxReportVM: OutboxMainViewModel { } } - override func treat(uploadResponse: CurrentValueSubject?) { + private func treat(uploadResponse: CurrentValueSubject?) { uploadResponse? .sink { result in @@ -104,34 +109,6 @@ class OutboxReportVM: OutboxMainViewModel { } } - override func initializeProgressionInfos() { - - let totalSize = self.reportViewModel.files.reduce(0) { $0 + ($1.size) } - let bytesSent = self.reportViewModel.files.reduce(0) { $0 + ($1.bytesSent)} - - if totalSize > 0 { - - // All Files - let percentUploaded = Float(bytesSent) / Float(totalSize) - - let formattedPercentUploaded = percentUploaded >= 1.0 ? 1.0 : Float(percentUploaded) - - let formattedTotalUploaded = bytesSent.getFormattedFileSize().getFileSizeWithoutUnit() - let formattedTotalSize = totalSize.getFormattedFileSize() - DispatchQueue.main.async { - - self.percentUploadedInfo = "\(Int(formattedPercentUploaded * 100))% uploaded" - self.percentUploaded = Float(percentUploaded) - self.uploadedFiles = " \(self.reportViewModel.files.count) files, \(formattedTotalUploaded)/\(formattedTotalSize) uploaded" - - self.progressFileItems = self.reportViewModel.files.compactMap{ProgressFileItemViewModel(file: $0, progression: ($0.bytesSent.getFormattedFileSize()) + "/" + ($0.size.getFormattedFileSize()))} - - self.objectWillChange.send() - - } - } - } - override func pauseSubmission() { if isSubmissionInProgress { self.updateReportStatus(reportStatus: .submissionPaused) diff --git a/Tella/Scenes/Reports/View Model/ReportViewModel.swift b/Tella/Scenes/Reports/View Model/ReportViewModel.swift index 8c3a1be34..1877513fd 100644 --- a/Tella/Scenes/Reports/View Model/ReportViewModel.swift +++ b/Tella/Scenes/Reports/View Model/ReportViewModel.swift @@ -4,13 +4,13 @@ import Foundation -class ReportViewModel { +class ReportViewModel { @Published var id : Int? @Published var title : String = "" @Published var description : String = "" @Published var files : [ReportVaultFile] = [] @Published var reportFiles : [ReportFile] = [] - @Published var server : TellaServer? + @Published var server : T? @Published var status : ReportStatus? @Published var apiID : String? @@ -18,7 +18,7 @@ class ReportViewModel { } - init(id: Int?, title: String, description: String, files: [ReportVaultFile], reportFiles : [ReportFile], server: TellaServer?, status: ReportStatus?, apiID: String?) { + init(id: Int?, title: String, description: String, files: [ReportVaultFile], reportFiles : [ReportFile], server: T?, status: ReportStatus?, apiID: String?) { self.id = id self.title = title self.description = description From 21b3365a9b074f58c13741791687252e1ac65c10 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 11 Jul 2024 15:45:41 -0300 Subject: [PATCH 088/167] add submitMainViewModel and implement it on tella reports and drive reports --- Tella.xcodeproj/project.pbxproj | 16 +++++++ .../Reports/Outbox/OutboxMainViewModel.swift | 14 ++++-- .../Submitted/SubmittedMainViewModel.swift | 41 ++++++++++++++++++ .../Views/ReportMainView.swift | 7 ++- .../ViewModel/GDriveOutboxViewModel.swift | 1 + .../ViewModel/GDriveSubmittedViewModel.swift | 43 +++++++++++++++++++ .../Reports/Outbox/OutboxDetailsView.swift | 15 +++++-- .../Submitted/SubmittedDetailsView.swift | 6 +-- .../Reports/View Model/OutboxReportVM.swift | 12 ------ .../View Model/SubmittedReportVM.swift | 32 +++----------- 10 files changed, 137 insertions(+), 50 deletions(-) create mode 100644 Tella/Components/Reports/Submitted/SubmittedMainViewModel.swift create mode 100644 Tella/Scenes/GDrive/ViewModel/GDriveSubmittedViewModel.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index f2b02e2d6..967460730 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -363,6 +363,8 @@ 151308172BF3DBD9000C51D7 /* UwaziRelationshipList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 151308162BF3DBD9000C51D7 /* UwaziRelationshipList.swift */; }; 1517A9AA2C3F011D00CB8EBF /* OutboxMainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1517A9A92C3F011D00CB8EBF /* OutboxMainViewModel.swift */; }; 1517A9AF2C3F0D7A00CB8EBF /* GDriveOutboxViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1517A9AE2C3F0D7A00CB8EBF /* GDriveOutboxViewModel.swift */; }; + 1517A9B22C404F4000CB8EBF /* SubmittedMainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1517A9B12C404F4000CB8EBF /* SubmittedMainViewModel.swift */; }; + 1517A9B42C4050D500CB8EBF /* GDriveSubmittedViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1517A9B32C4050D500CB8EBF /* GDriveSubmittedViewModel.swift */; }; 1519BED82B9A5A52006FD290 /* Resource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1519BED72B9A5A52006FD290 /* Resource.swift */; }; 152D38512C2C61DF00323CE7 /* DraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152D38502C2C61DF00323CE7 /* DraftView.swift */; }; 1535A5F12BAA06490009EA42 /* DownloadedResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1535A5F02BAA06490009EA42 /* DownloadedResource.swift */; }; @@ -935,6 +937,8 @@ 151308162BF3DBD9000C51D7 /* UwaziRelationshipList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziRelationshipList.swift; sourceTree = ""; }; 1517A9A92C3F011D00CB8EBF /* OutboxMainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutboxMainViewModel.swift; sourceTree = ""; }; 1517A9AE2C3F0D7A00CB8EBF /* GDriveOutboxViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveOutboxViewModel.swift; sourceTree = ""; }; + 1517A9B12C404F4000CB8EBF /* SubmittedMainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubmittedMainViewModel.swift; sourceTree = ""; }; + 1517A9B32C4050D500CB8EBF /* GDriveSubmittedViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveSubmittedViewModel.swift; sourceTree = ""; }; 1519BED72B9A5A52006FD290 /* Resource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Resource.swift; sourceTree = ""; }; 152D38502C2C61DF00323CE7 /* DraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftView.swift; sourceTree = ""; }; 1535A5F02BAA06490009EA42 /* DownloadedResource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResource.swift; sourceTree = ""; }; @@ -2393,6 +2397,14 @@ path = Outbox; sourceTree = ""; }; + 1517A9B02C404F1100CB8EBF /* Submitted */ = { + isa = PBXGroup; + children = ( + 1517A9B12C404F4000CB8EBF /* SubmittedMainViewModel.swift */, + ); + path = Submitted; + sourceTree = ""; + }; 1519BED42B9A5A2B006FD290 /* Resource */ = { isa = PBXGroup; children = ( @@ -2466,6 +2478,7 @@ 15B81F392C1A281C007C0E88 /* GDriveViewModel.swift */, 15E3D50D2C1B87AC00B7FECC /* GDriveDraftViewModel.swift */, 1517A9AE2C3F0D7A00CB8EBF /* GDriveOutboxViewModel.swift */, + 1517A9B32C4050D500CB8EBF /* GDriveSubmittedViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -2489,6 +2502,7 @@ 15E656A92C2A142300BDEC91 /* Reports */ = { isa = PBXGroup; children = ( + 1517A9B02C404F1100CB8EBF /* Submitted */, 1517A9A82C3F010D00CB8EBF /* Outbox */, 15E656AE2C2A14FA00BDEC91 /* Draft */, 15F1AA532C2E07F50002A7D8 /* BaseReportsViewModel.swift */, @@ -3559,6 +3573,7 @@ 1249B3832AD43AA7009A7023 /* VaultFilesManagerInterface.swift in Sources */, 15F64CA62B6D80F7008A57AA /* ResourceCardViewModel.swift in Sources */, 0DA213CB268028A200526995 /* FileSortOptions.swift in Sources */, + 1517A9B22C404F4000CB8EBF /* SubmittedMainViewModel.swift in Sources */, CCEAE5922AE6F6EE0069204A /* EntityCreationResponse.swift in Sources */, 1289B98927C53A9C00315FCE /* CameraType.swift in Sources */, 0E78B3A72656B03600F9BDBC /* DragView.swift in Sources */, @@ -3568,6 +3583,7 @@ E16D20D12ABEB5C7001708CC /* UwaziCardViewModel.swift in Sources */, 12607D562790416400E2B8CC /* PlayerViewModel.swift in Sources */, 128B929B27D798E200E92ACF /* ManageFileView.swift in Sources */, + 1517A9B42C4050D500CB8EBF /* GDriveSubmittedViewModel.swift in Sources */, E1E7C57D2AAB553500DDB07E /* UwaziProperty.swift in Sources */, 12F2C65C2B86567F008457EB /* FileDetailsViewModel.swift in Sources */, 1237A71A278F18C000D7BC0F /* WebView.swift in Sources */, diff --git a/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift b/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift index 38b0a95ff..354d754ac 100644 --- a/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift +++ b/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift @@ -91,9 +91,17 @@ class OutboxMainViewModel: ObservableObject { func submitReport() {} - func showSubmittedReport() {} - - func showMainView() {} + func showSubmittedReport() { + DispatchQueue.main.async { + self.shouldShowSubmittedReportView = true + } + } + + func showMainView() { + DispatchQueue.main.async { + self.shouldShowMainView = true + } + } func updateProgressInfos(uploadProgressInfo : UploadProgressInfo) {} diff --git a/Tella/Components/Reports/Submitted/SubmittedMainViewModel.swift b/Tella/Components/Reports/Submitted/SubmittedMainViewModel.swift new file mode 100644 index 000000000..ee18e8e4e --- /dev/null +++ b/Tella/Components/Reports/Submitted/SubmittedMainViewModel.swift @@ -0,0 +1,41 @@ +// +// SubmittedMainViewModel.swift +// Tella +// +// Created by gus valbuena on 7/11/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +class SubmittedMainViewModel: ObservableObject { + + var mainAppModel : MainAppModel + + // Report + @Published var id : Int? + @Published var title : String = "" + @Published var description : String = "" + @Published var files : [VaultFileDB] = [] + + @Published var progressFileItems : [ProgressFileItemViewModel] = [] + @Published var uploadedDate : String = "" + @Published var uploadedFiles : String = "" + + var reportHasFile: Bool { + return !files.isEmpty + } + + var reportHasDescription: Bool { + return !description.isEmpty + } + + init(mainAppModel: MainAppModel, shouldStartUpload: Bool = false, reportId: Int?) { + self.mainAppModel = mainAppModel + fillReportVM(reportId: reportId) + } + + func fillReportVM(reportId:Int?) {} + + func deleteReport() {} +} diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift index 3acd63a86..04be084a8 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -196,7 +196,12 @@ struct ReportMainView: View { private func showSubmittedView(id: Int? = nil) { switch reportMainViewModel.connectionType { case .tella: - let destination = SubmittedDetailsView(appModel: mainAppModel, reportId: id).environmentObject(reportMainViewModel) + let vm = SubmittedReportVM(mainAppModel: mainAppModel, reportId: id) + let destination = SubmittedDetailsView(submittedReportVM: vm).environmentObject(reportMainViewModel) + self.navigateTo(destination: destination) + case .gDrive: + let vm = GDriveSubmittedViewModel(mainAppModel: mainAppModel, reportId: id) + let destination = SubmittedDetailsView(submittedReportVM: vm).environmentObject(reportMainViewModel) self.navigateTo(destination: destination) default: break diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 265255b5f..a603c8058 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -76,6 +76,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { switch completion { case .finished: self.updateReportStatus(reportStatus: .submitted) + self.showSubmittedReport() break case .failure(let error): debugLog(error) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveSubmittedViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveSubmittedViewModel.swift new file mode 100644 index 000000000..6109179c4 --- /dev/null +++ b/Tella/Scenes/GDrive/ViewModel/GDriveSubmittedViewModel.swift @@ -0,0 +1,43 @@ +// +// GDriveSubmittedViewModel.swift +// Tella +// +// Created by gus valbuena on 7/11/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +class GDriveSubmittedViewModel: SubmittedMainViewModel { + override init(mainAppModel: MainAppModel, shouldStartUpload: Bool = false, reportId: Int?) { + super.init(mainAppModel: mainAppModel, shouldStartUpload: shouldStartUpload, reportId: reportId) + fillReportVM(reportId: reportId) + } + + override func fillReportVM(reportId: Int?) { + if let reportId, let report = self.mainAppModel.tellaData?.getDriveReport(id: reportId) { + self.id = report.id + self.title = report.title ?? "" + self.description = report.description ?? "" + + let vaultFileResult = mainAppModel.vaultFilesManager?.getVaultFiles(ids: report.reportFiles?.compactMap{$0.fileId} ?? []) ?? [] + self.files = Array(vaultFileResult) + + // todo -> progress bar + progressFileItems = self.files.compactMap{ProgressFileItemViewModel(file: $0, progression:$0.size.getFormattedFileSize() + "/" + $0.size.getFormattedFileSize())} + let totalSize = self.files.reduce(0) { $0 + $1.size } + + if let date = report.createdDate { + self.uploadedDate = "Uploaded on \(date.getFormattedDateString(format: DateFormat.submittedReport.rawValue))" + } + + let fileNumber = self.files.count + let fileString = fileNumber == 1 ? "file" : "files" + self.uploadedFiles = "\(fileNumber) \(fileString), \(totalSize.getFormattedFileSize())" + } + } + + override func deleteReport() { + let _ = mainAppModel.tellaData?.deleteDriveReport(reportId: id) + } +} diff --git a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift index 9f3a4fa3a..b0e2281c8 100644 --- a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift +++ b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift @@ -175,9 +175,18 @@ struct OutboxDetailsView: View { } private var submittedDetailsView: some View { - SubmittedDetailsView(appModel: mainAppModel, - reportId: outboxReportVM.reportViewModel.id) - .environmentObject(reportsViewModel) + Group { + switch reportsViewModel.connectionType { + case .tella: + let vm = SubmittedReportVM(mainAppModel: mainAppModel, shouldStartUpload: true, reportId: outboxReportVM.reportViewModel.id) + SubmittedDetailsView(submittedReportVM: vm).environmentObject(reportsViewModel) + case .gDrive: + let vm = GDriveSubmittedViewModel(mainAppModel: mainAppModel, shouldStartUpload: true, reportId: outboxReportVM.reportViewModel.id) + SubmittedDetailsView(submittedReportVM: vm).environmentObject(reportsViewModel) + default: + Text("") + } + } } private func dismissView() { diff --git a/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift b/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift index 03f943cb0..bfdaf7232 100644 --- a/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift +++ b/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift @@ -7,16 +7,12 @@ import SwiftUI struct SubmittedDetailsView: View { - @StateObject var submittedReportVM : SubmittedReportVM + @StateObject var submittedReportVM : SubmittedMainViewModel @EnvironmentObject var reportsViewModel : ReportMainViewModel @EnvironmentObject var mainAppModel : MainAppModel @Environment(\.presentationMode) var presentationMode: Binding @EnvironmentObject private var sheetManager: SheetManager - init(appModel: MainAppModel, reportId : Int?) { - _submittedReportVM = StateObject(wrappedValue: SubmittedReportVM(mainAppModel: appModel, reportId: reportId)) - } - var body: some View { ContainerView { diff --git a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift index d281df111..fefda01be 100644 --- a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift +++ b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift @@ -138,18 +138,6 @@ class OutboxReportVM: OutboxMainViewModel { } } - override func showSubmittedReport() { - DispatchQueue.main.async { - self.shouldShowSubmittedReportView = true - } - } - - override func showMainView() { - DispatchQueue.main.async { - self.shouldShowMainView = true - } - } - override func updateProgressInfos(uploadProgressInfo : UploadProgressInfo) { _ = self.reportViewModel.files.compactMap { _ in diff --git a/Tella/Scenes/Reports/View Model/SubmittedReportVM.swift b/Tella/Scenes/Reports/View Model/SubmittedReportVM.swift index ce0541f06..416aba5e2 100644 --- a/Tella/Scenes/Reports/View Model/SubmittedReportVM.swift +++ b/Tella/Scenes/Reports/View Model/SubmittedReportVM.swift @@ -5,34 +5,14 @@ import Foundation import Combine -class SubmittedReportVM: ObservableObject { - - var mainAppModel : MainAppModel - - // Report - @Published var id : Int? - @Published var title : String = "" - @Published var description : String = "" - @Published var files : [VaultFileDB] = [] - - @Published var progressFileItems : [ProgressFileItemViewModel] = [] - @Published var uploadedDate : String = "" - @Published var uploadedFiles : String = "" - - var reportHasFile: Bool { - return !files.isEmpty - } - - var reportHasDescription: Bool { - return !description.isEmpty - } - - init(mainAppModel: MainAppModel, shouldStartUpload: Bool = false, reportId: Int?) { - self.mainAppModel = mainAppModel +class SubmittedReportVM: SubmittedMainViewModel { + + override init(mainAppModel: MainAppModel, shouldStartUpload: Bool = false, reportId: Int?) { + super.init(mainAppModel: mainAppModel, shouldStartUpload: shouldStartUpload, reportId: reportId) fillReportVM(reportId: reportId) } - func fillReportVM(reportId:Int?) { + override func fillReportVM(reportId:Int?) { if let reportId ,let report = self.mainAppModel.tellaData?.getReport(reportId: reportId) { @@ -63,7 +43,7 @@ class SubmittedReportVM: ObservableObject { } } - func deleteReport() { + override func deleteReport() { mainAppModel.deleteReport(reportId: id) } } From 56ec7234de03d4283de5d9b9cc09f15a4884efda Mon Sep 17 00:00:00 2001 From: Dhekra Rouatbi Date: Thu, 11 Jul 2024 20:31:32 +0100 Subject: [PATCH 089/167] Update ReportFile class, Move redundant functions to DraftMainViewModel --- .../Reports/Draft/DraftMainViewModel.swift | 59 ++++++++++++------- Tella/Domain/Entity/Report/ReportFile.swift | 46 +++++++++++++-- .../ViewModel/GDriveDraftViewModel.swift | 22 +------ .../Reports/View Model/DraftReportVM.swift | 26 +------- 4 files changed, 81 insertions(+), 72 deletions(-) diff --git a/Tella/Components/Reports/Draft/DraftMainViewModel.swift b/Tella/Components/Reports/Draft/DraftMainViewModel.swift index 5002f1470..f22c4415e 100644 --- a/Tella/Components/Reports/Draft/DraftMainViewModel.swift +++ b/Tella/Components/Reports/Draft/DraftMainViewModel.swift @@ -42,7 +42,7 @@ class DraftMainViewModel: ObservableObject { var failureSavingReportPublisher: Published.Publisher { $failureSavingReport } var serverArray : [T] = [] - + var cancellable : Cancellable? = nil var subscribers = Set() var delayTime = 2.0 @@ -51,15 +51,15 @@ class DraftMainViewModel: ObservableObject { guard let serverName = server?.name else { return LocalizableReport.selectProject.localized } return serverName } - + var hasMoreServer: Bool { return serverArray.count > 1 } - + var isNewDraft: Bool { return reportId == nil } - + var addFileToDraftItems : [ListActionSheetItem] { return [ ListActionSheetItem(imageName: "report.camera-filled", @@ -92,28 +92,45 @@ class DraftMainViewModel: ObservableObject { } func validateReport() {} - + func getServers() {} - - func initcurrentReportVM(reportId:Int?) { } - + func bindVaultFileTaken() {} - + func publishUpdates() {} - - func fillReportVM() {} - - func saveDraftReport() {} - - func saveFinalizedReport() {} - - func saveReportForSubmission() {} - - func submitReport() {} + func fillReportVM() {} + func saveReport() {} - + func deleteFile(fileId: String?) {} - + func deleteReport() {} + + func initcurrentReportVM(reportId:Int?) { + if serverArray.count == 1 { + server = serverArray.first + } + self.reportId = reportId + } + + func saveDraftReport() { + self.status = .draft + self.saveReport() + } + + func saveFinalizedReport() { + self.status = .finalized + self.saveReport() + } + + func saveSubmittedReport() { + self.status = .submitted + self.saveReport() + } + func submitReport() { + self.status = .submissionScheduled + self.saveReport() + } + } diff --git a/Tella/Domain/Entity/Report/ReportFile.swift b/Tella/Domain/Entity/Report/ReportFile.swift index a4f94660a..971fb4592 100644 --- a/Tella/Domain/Entity/Report/ReportFile.swift +++ b/Tella/Domain/Entity/Report/ReportFile.swift @@ -5,14 +5,15 @@ import Foundation class ReportFile : Hashable, Codable { - + var id : Int? var fileId : String? var status : FileStatus? var bytesSent : Int? var createdDate : Date? var updatedDate : Date? - + var reportInstanceId : Int? + enum CodingKeys: String, CodingKey { case id = "c_id" case fileId = "c_vault_file_instance_id" @@ -20,6 +21,7 @@ class ReportFile : Hashable, Codable { case bytesSent = "c_bytes_Sent" case createdDate = "c_created_date" case updatedDate = "c_updated_date" + case reportInstanceId = "c_report_instance_id" } init(id: Int? = nil, @@ -27,15 +29,17 @@ class ReportFile : Hashable, Codable { status: FileStatus? = nil, bytesSent: Int? = 0, createdDate: Date? = nil, - updatedDate: Date? = Date()) { + updatedDate: Date? = Date(), + reportInstanceId: Int? = nil) { self.id = id self.fileId = fileId self.status = status self.bytesSent = bytesSent self.createdDate = createdDate self.updatedDate = updatedDate + self.reportInstanceId = reportInstanceId } - + static func == (lhs: ReportFile, rhs: ReportFile) -> Bool { lhs.id == rhs.id } @@ -43,5 +47,37 @@ class ReportFile : Hashable, Codable { func hash(into hasher: inout Hasher) { hasher.combine(id.hashValue) } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try container.encode(fileId, forKey: .fileId) + try container.encode(status, forKey: .status) + try container.encode(bytesSent, forKey: .bytesSent) + let createdDate = createdDate?.getDateDouble() + try container.encode(createdDate, forKey: .createdDate) + let updatedDate = Date().getDateDouble() + try container.encode(updatedDate, forKey: .updatedDate) + try container.encode(reportInstanceId, forKey: .reportInstanceId) + } + + required init(from decoder: Decoder) throws { + + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.id = try container.decode(Int.self, forKey: .id) + + self.fileId = try container.decode(String.self, forKey: .fileId) + + let status = try container.decode(Int.self, forKey: .status) + self.status = FileStatus(rawValue: status) ?? FileStatus.unknown + + let createdDate = try container.decode(Double.self, forKey: .createdDate) + self.createdDate = createdDate.getDate() + + let updatedDate = try container.decode(Double.self, forKey: .updatedDate) + self.updatedDate = updatedDate.getDate() + + self.reportInstanceId = try container.decode(Int.self, forKey: .reportInstanceId) + } } - diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index e9da4a410..ac0408ace 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -17,8 +17,6 @@ class GDriveDraftViewModel: DraftMainViewModel { super.init(mainAppModel: mainAppModel, reportId: reportID) self.getServer() - - self.reportId = reportID self.fillReportVM() } @@ -46,25 +44,7 @@ class GDriveDraftViewModel: DraftMainViewModel { self.objectWillChange.send() } } - - override func saveDraftReport() { - self.status = .draft - self.saveReport() - } - - override func saveFinalizedReport() { - self.status = .finalized - self.saveReport() - } - override func submitReport() { - saveReportForSubmission() - } - - override func saveReportForSubmission() { - self.status = .submissionScheduled - self.saveReport() - } - + override func saveReport() { let gDriveReport = GDriveReport( id: reportId, diff --git a/Tella/Scenes/Reports/View Model/DraftReportVM.swift b/Tella/Scenes/Reports/View Model/DraftReportVM.swift index 615ffafbc..6d2709ccb 100644 --- a/Tella/Scenes/Reports/View Model/DraftReportVM.swift +++ b/Tella/Scenes/Reports/View Model/DraftReportVM.swift @@ -30,12 +30,6 @@ class DraftReportVM: DraftMainViewModel { serverArray = mainAppModel.tellaData?.tellaServers.value ?? [] } - override func initcurrentReportVM(reportId:Int?) { - if serverArray.count == 1 { - server = serverArray.first - } - self.reportId = reportId - } override func bindVaultFileTaken() { $resultFile.sink(receiveValue: { value in @@ -72,25 +66,7 @@ class DraftReportVM: DraftMainViewModel { self.objectWillChange.send() } } - - override func saveDraftReport() { - self.status = .draft - self.saveReport() - } - - override func saveFinalizedReport() { - self.status = .finalized - self.saveReport() - } - - override func saveReportForSubmission() { - self.status = .submissionScheduled - self.saveReport() - } - - override func submitReport() { - saveReportForSubmission() - } + override func saveReport() { let report = Report(id: reportId, From f7e88f341e4a2aac809ca2a6956e246d0580007a Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 12 Jul 2024 16:31:34 -0300 Subject: [PATCH 090/167] track progress update on gDrive --- .../Repositories/GDriveRepository.swift | 63 ++++++++++++++++--- .../Views/ReportMainView.swift | 1 + .../ViewModel/GDriveOutboxViewModel.swift | 55 +++++++++++++--- 3 files changed, 100 insertions(+), 19 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 872f9da20..6638b26e1 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -17,7 +17,7 @@ protocol GDriveRepositoryProtocol { func handleUrl(url: URL) func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> func createDriveFolder(folderName: String, parentId: String?, description: String?) -> AnyPublisher - func uploadFile(fileURL: URL, mimeType: String, folderId: String) -> AnyPublisher + func uploadFile(fileURL: URL, fileId: String, mimeType: String, folderId: String) -> AnyPublisher func signOut() -> Void } @@ -184,13 +184,17 @@ class GDriveRepository: GDriveRepositoryProtocol { func uploadFile( fileURL: URL, + fileId: String, mimeType: String, folderId: String - ) -> AnyPublisher { - Deferred { - Future { [weak self] promise in - guard let user = self?.googleUser else { - return promise(.failure(APIError.noToken)) + ) -> AnyPublisher { + let progressSubject = PassthroughSubject() + + return Deferred { + Future { [weak self] promise in + guard let self = self, let user = self.googleUser else { + promise(.failure(APIError.noToken)) + return } let driveService = GTLRDriveService() @@ -207,22 +211,57 @@ class GDriveRepository: GDriveRepositoryProtocol { let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: uploadParameters) query.supportsAllDrives = true + let totalSize = UInt64((try? Data(contentsOf: fileURL).count) ?? 0) + var totalBytesSent: UInt64 = 0 + let uploadProgressInfo = UploadProgressInfo(fileId: fileId, status: .notSubmitted, total: Int(totalSize)) + + let timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in + if totalBytesSent < totalSize { + totalBytesSent += UInt64(1024 * 1024) // Simulate progress in bytes (1 MB chunks) + totalBytesSent = min(totalBytesSent, totalSize) + let progress = Double(totalBytesSent) / Double(totalSize) + uploadProgressInfo.bytesSent = Int(totalBytesSent) + uploadProgressInfo.current = Int(totalBytesSent) + uploadProgressInfo.status = .partialSubmitted + uploadProgressInfo.reportStatus = .submissionInProgress + progressSubject.send(uploadProgressInfo) + } else { + timer.invalidate() + } + } + driveService.executeQuery(query) { (ticket, file, error) in + timer.invalidate() + if let error = error { print("Error uploading file: \(error.localizedDescription)") + uploadProgressInfo.error = APIError.unexpectedResponse + uploadProgressInfo.status = .submissionError + progressSubject.send(completion: .failure(error)) promise(.failure(error)) return } guard let uploadedFile = file as? GTLRDrive_File else { - promise(.failure(APIError.unexpectedResponse)) + let apiError = APIError.unexpectedResponse + uploadProgressInfo.error = apiError + uploadProgressInfo.status = .submissionError + progressSubject.send(completion: .failure(apiError)) + promise(.failure(apiError)) return } - promise(.success(uploadedFile.identifier ?? "")) + totalBytesSent = totalSize + uploadProgressInfo.bytesSent = Int(totalBytesSent) + uploadProgressInfo.current = Int(totalBytesSent) + uploadProgressInfo.status = .uploaded + progressSubject.send(uploadProgressInfo) + progressSubject.send(completion: .finished) + promise(.success(uploadProgressInfo)) } } - }.eraseToAnyPublisher() + } + .eraseToAnyPublisher() } func signOut() { @@ -243,3 +282,9 @@ class GDriveDIContainer : DIContainer { class DIContainer { } + + +struct UploadProgressWithFolderId { + let folderId: String + let progressInfo: UploadProgressInfo +} diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift index 04be084a8..6446d963b 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -186,6 +186,7 @@ struct ReportMainView: View { case .gDrive: let outboxViewModel = GDriveOutboxViewModel(mainAppModel: mainAppModel, reportsViewModel: reportMainViewModel, reportId: id, repository: GDriveRepository()) let destination = OutboxDetailsView(outboxReportVM: outboxViewModel) + .environmentObject(reportMainViewModel) self.navigateTo(destination: destination) default: break diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index a603c8058..254bc6c79 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -27,8 +27,6 @@ class GDriveOutboxViewModel: OutboxMainViewModel { if shouldStartUpload { self.submitReport() - } else { - // treat } } @@ -68,7 +66,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { description: reportViewModel.description ) .receive(on: DispatchQueue.main) - .flatMap { folderId in + .flatMap { folderId -> AnyPublisher in self.uploadFiles(to: folderId) } .sink( @@ -82,26 +80,63 @@ class GDriveOutboxViewModel: OutboxMainViewModel { debugLog(error) } }, - receiveValue: { result in - dump(result) + receiveValue: { uploadProgressWithFolderId in + self.updateProgressInfos(uploadProgressInfo: uploadProgressWithFolderId.progressInfo) } ).store(in: &subscribers) } - private func uploadFiles(to folderId: String) -> AnyPublisher { - let uploadPublishers = reportViewModel.files.map { file -> AnyPublisher in + private func uploadFiles(to folderId: String) -> AnyPublisher { + let uploadPublishers = reportViewModel.files.map { file -> AnyPublisher in guard let fileUrl = self.mainAppModel.vaultManager.loadVaultFileToURL(file: file) else { return Fail(error: APIError.unexpectedResponse).eraseToAnyPublisher() } - return gDriveRepository.uploadFile(fileURL: fileUrl, mimeType: file.mimeType ?? "", folderId: folderId) + + return gDriveRepository.uploadFile(fileURL: fileUrl, fileId: file.id ?? "", mimeType: file.mimeType ?? "", folderId: folderId) + .map { progressInfo in + UploadProgressWithFolderId(folderId: folderId, progressInfo: progressInfo) + } + .eraseToAnyPublisher() } return Publishers.MergeMany(uploadPublishers) - .collect() - .map { _ in () } .eraseToAnyPublisher() } + override func updateProgressInfos(uploadProgressInfo: UploadProgressInfo) { + if let currentFile = self.reportViewModel.files.first(where: { $0.id == uploadProgressInfo.fileId }) { + currentFile.current = uploadProgressInfo.current ?? 0 + currentFile.bytesSent = uploadProgressInfo.bytesSent ?? 0 + currentFile.status = uploadProgressInfo.status + } + + // All Files + let totalBytesSent = self.reportViewModel.files.reduce(0) { $0 + ($1.bytesSent) } + let totalSize = self.reportViewModel.files.reduce(0) { $0 + ($1.size) } + + if totalSize > 0 { + let percentUploaded = Float(totalBytesSent) / Float(totalSize) + let formattedPercentUploaded = percentUploaded >= 1.0 ? 1.0 : percentUploaded + let formattedTotalUploaded = totalBytesSent.getFormattedFileSize().getFileSizeWithoutUnit() + let formattedTotalSize = totalSize.getFormattedFileSize() + + DispatchQueue.main.async { + + self.percentUploadedInfo = "\(Int(formattedPercentUploaded * 100))% uploaded" + self.percentUploaded = formattedPercentUploaded + self.uploadedFiles = " \(self.reportViewModel.files.count) files, \(formattedTotalUploaded)/\(formattedTotalSize) uploaded" + + if let currentItem = self.progressFileItems.first(where: { $0.file.id == uploadProgressInfo.fileId }) { + let size = currentItem.file.size.getFormattedFileSize() + let currentFileTotalBytesSent = uploadProgressInfo.bytesSent?.getFormattedFileSize().getFileSizeWithoutUnit() ?? "0" + + currentItem.progression = "\(currentFileTotalBytesSent)/\(size)" + } + self.objectWillChange.send() + } + } + } + override func updateReportStatus(reportStatus: ReportStatus) { self.reportViewModel.status = reportStatus From 4e03fe8c32afe61b42ae88dfda40c9967a7aafda Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 12 Jul 2024 18:15:53 -0300 Subject: [PATCH 091/167] show proper status of uploading --- .../Repositories/GDriveRepository.swift | 35 +++++++------------ 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 6638b26e1..e6f39b332 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -211,28 +211,10 @@ class GDriveRepository: GDriveRepositoryProtocol { let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: uploadParameters) query.supportsAllDrives = true - let totalSize = UInt64((try? Data(contentsOf: fileURL).count) ?? 0) - var totalBytesSent: UInt64 = 0 + let totalSize = UInt64((try? fileURL.resourceValues(forKeys: [.fileSizeKey]).fileSize) ?? 0) let uploadProgressInfo = UploadProgressInfo(fileId: fileId, status: .notSubmitted, total: Int(totalSize)) - let timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in - if totalBytesSent < totalSize { - totalBytesSent += UInt64(1024 * 1024) // Simulate progress in bytes (1 MB chunks) - totalBytesSent = min(totalBytesSent, totalSize) - let progress = Double(totalBytesSent) / Double(totalSize) - uploadProgressInfo.bytesSent = Int(totalBytesSent) - uploadProgressInfo.current = Int(totalBytesSent) - uploadProgressInfo.status = .partialSubmitted - uploadProgressInfo.reportStatus = .submissionInProgress - progressSubject.send(uploadProgressInfo) - } else { - timer.invalidate() - } - } - - driveService.executeQuery(query) { (ticket, file, error) in - timer.invalidate() - + let ticket = driveService.executeQuery(query) { (ticket, file, error) in if let error = error { print("Error uploading file: \(error.localizedDescription)") uploadProgressInfo.error = APIError.unexpectedResponse @@ -251,14 +233,21 @@ class GDriveRepository: GDriveRepositoryProtocol { return } - totalBytesSent = totalSize - uploadProgressInfo.bytesSent = Int(totalBytesSent) - uploadProgressInfo.current = Int(totalBytesSent) + uploadProgressInfo.bytesSent = Int(totalSize) + uploadProgressInfo.current = Int(totalSize) uploadProgressInfo.status = .uploaded progressSubject.send(uploadProgressInfo) progressSubject.send(completion: .finished) promise(.success(uploadProgressInfo)) } + + ticket.objectFetcher?.sendProgressBlock = { bytesSent, totalBytesSent, totalBytesExpectedToSend in + uploadProgressInfo.bytesSent = Int(totalBytesSent) + uploadProgressInfo.current = Int(totalBytesSent) + uploadProgressInfo.status = .partialSubmitted + uploadProgressInfo.reportStatus = .submissionInProgress + progressSubject.send(uploadProgressInfo) + } } } .eraseToAnyPublisher() From e048eef9e49fc6a04a2dc956664d55079414ce11 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 16 Jul 2024 15:23:27 -0300 Subject: [PATCH 092/167] add folderId to gDriveReport --- .../Database/Common/DatabaseConstants.swift | 1 + Tella/Data/Database/GDriveData.swift | 7 ++++ Tella/Data/Database/GDriveDatabase.swift | 31 ++++++++++++--- Tella/Domain/Entity/GDrive/GDriveReport.swift | 8 +++- .../ViewModel/GDriveOutboxViewModel.swift | 39 ++++++++++++++----- .../Reports/View Model/ReportViewModel.swift | 4 +- 6 files changed, 73 insertions(+), 17 deletions(-) diff --git a/Tella/Data/Database/Common/DatabaseConstants.swift b/Tella/Data/Database/Common/DatabaseConstants.swift index 28aa56db4..95c9d6e6b 100644 --- a/Tella/Data/Database/Common/DatabaseConstants.swift +++ b/Tella/Data/Database/Common/DatabaseConstants.swift @@ -96,6 +96,7 @@ struct D { //gDrive static let cRootFolder = "c_root_folder" + static let cFolderId = "c_folder_id" } diff --git a/Tella/Data/Database/GDriveData.swift b/Tella/Data/Database/GDriveData.swift index 640afd31c..311b65b7d 100644 --- a/Tella/Data/Database/GDriveData.swift +++ b/Tella/Data/Database/GDriveData.swift @@ -55,4 +55,11 @@ extension TellaData { return self.database.updateDriveReportStatus(idReport: idReport, status: status) } + + @discardableResult + func updateDriveFolderId(idReport: Int, folderId: String) -> Result { + shouldReloadGDriveReports.send(true) + + return self.database.updateDriveReportFolderId(idReport: idReport, folderId: folderId) + } } diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index 0c50115fb..78cd94d2e 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -66,6 +66,7 @@ extension TellaDataBase { cddl(D.cCreatedDate, D.float), cddl(D.cUpdatedDate, D.float), cddl(D.cStatus, D.integer), + cddl(D.cFolderId, D.text), cddl(D.cServerId, D.integer, tableName: D.tGDriveServer, referenceKey: D.cId) ] @@ -90,11 +91,12 @@ extension TellaDataBase { func addGDriveReport(report: GDriveReport) -> Result { do { let reportValuesToAdd = [KeyValue(key: D.cTitle, value: report.title), - KeyValue(key: D.cDescription, value: report.description), - KeyValue(key: D.cCreatedDate, value: Date().getDateDouble()), - KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()), - KeyValue(key: D.cStatus, value: report.status.rawValue), - KeyValue(key: D.cServerId, value: report.server?.id)] + KeyValue(key: D.cDescription, value: report.description), + KeyValue(key: D.cCreatedDate, value: Date().getDateDouble()), + KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()), + KeyValue(key: D.cStatus, value: report.status.rawValue), + KeyValue(key: D.cFolderId, value: report.folderId), + KeyValue(key: D.cServerId, value: report.server?.id)] let reportId = try statementBuilder.insertInto(tableName: D.tGDriveReport, keyValue: reportValuesToAdd) @@ -125,7 +127,7 @@ extension TellaDataBase { let gDriveReportsDict = try statementBuilder.getSelectQuery(tableName: D.tGDriveReport, inCondition: [KeyValues(key:D.cStatus, value: statusArray )] ) - + let decodedReports = try gDriveReportsDict.compactMap ({ dict in return try dict.decode(GDriveReport.self) }) @@ -244,4 +246,21 @@ extension TellaDataBase { return .failure(error) } } + + func updateDriveReportFolderId(idReport: Int, folderId: String) -> Result { + do { + let valuesToUpdate = [KeyValue(key: D.cFolderId, value: folderId), + KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()) + ] + + let reportCondition = [KeyValue(key: D.cId, value: idReport)] + + try statementBuilder.update(tableName: D.tGDriveReport, valuesToUpdate: valuesToUpdate, equalCondition: reportCondition) + + return .success(true) + } catch let error { + debugLog(error) + return .failure(error) + } + } } diff --git a/Tella/Domain/Entity/GDrive/GDriveReport.swift b/Tella/Domain/Entity/GDrive/GDriveReport.swift index 54a2f427f..8d1651e4e 100644 --- a/Tella/Domain/Entity/GDrive/GDriveReport.swift +++ b/Tella/Domain/Entity/GDrive/GDriveReport.swift @@ -11,7 +11,10 @@ import Foundation class GDriveReport: BaseReport { var server: GDriveServer? - + var folderId: String? + enum CodingKeys: String, CodingKey { + case folderId = "c_folder_id" + } init(id: Int? = nil, title: String? = nil, description: String? = nil, @@ -19,9 +22,11 @@ class GDriveReport: BaseReport { updatedDate: Date? = nil, status: ReportStatus, server: GDriveServer? = nil, + folderId: String? = nil, vaultFiles: [ReportFile]? = nil) { self.server = server + self.folderId = folderId super.init(id: id, title: title, @@ -34,6 +39,7 @@ class GDriveReport: BaseReport { required init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) + self.folderId = try container.decodeIfPresent(String.self, forKey: .folderId) try super.init(from: decoder) } } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 254bc6c79..582aa9748 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -45,18 +45,26 @@ class GDriveOutboxViewModel: OutboxMainViewModel { }) self.reportViewModel = ReportViewModel(id: report.id, - title: report.title ?? "", - description: report.description ?? "", - files: files, - reportFiles: report.reportFiles ?? [], - server: report.server, - status: report.status, - apiID: nil) + title: report.title ?? "", + description: report.description ?? "", + files: files, + reportFiles: report.reportFiles ?? [], + server: report.server, + status: report.status, + apiID: nil, + folderId: report.folderId) } } override func submitReport() { - performSubmission() + if isSubmissionInProgress == false { + self.updateReportStatus(reportStatus: .submissionInProgress) + } + guard let folderId = reportViewModel.folderId else { + return performSubmission() + } + + let _ = self.uploadFiles(to: folderId) } func performSubmission() { @@ -67,7 +75,9 @@ class GDriveOutboxViewModel: OutboxMainViewModel { ) .receive(on: DispatchQueue.main) .flatMap { folderId -> AnyPublisher in - self.uploadFiles(to: folderId) + self.reportViewModel.folderId = folderId + self.updateReportFolderId(folderId: folderId) + return self.uploadFiles(to: folderId) } .sink( receiveCompletion: { completion in @@ -137,6 +147,11 @@ class GDriveOutboxViewModel: OutboxMainViewModel { } } + override func pauseSubmission() { + if isSubmissionInProgress { + updateReportStatus(reportStatus: .submissionPaused) + } + } override func updateReportStatus(reportStatus: ReportStatus) { self.reportViewModel.status = reportStatus @@ -144,4 +159,10 @@ class GDriveOutboxViewModel: OutboxMainViewModel { mainAppModel.tellaData?.updateDriveReportStatus(idReport: id, status: reportStatus) } + + private func updateReportFolderId(folderId: String) { + guard let id = reportViewModel.id else { return } + + mainAppModel.tellaData?.updateDriveFolderId(idReport: id, folderId: folderId) + } } diff --git a/Tella/Scenes/Reports/View Model/ReportViewModel.swift b/Tella/Scenes/Reports/View Model/ReportViewModel.swift index 1877513fd..9eac065fc 100644 --- a/Tella/Scenes/Reports/View Model/ReportViewModel.swift +++ b/Tella/Scenes/Reports/View Model/ReportViewModel.swift @@ -13,12 +13,13 @@ class ReportViewModel { @Published var server : T? @Published var status : ReportStatus? @Published var apiID : String? + @Published var folderId: String? init() { } - init(id: Int?, title: String, description: String, files: [ReportVaultFile], reportFiles : [ReportFile], server: T?, status: ReportStatus?, apiID: String?) { + init(id: Int?, title: String, description: String, files: [ReportVaultFile], reportFiles : [ReportFile], server: T?, status: ReportStatus?, apiID: String?, folderId: String? = nil) { self.id = id self.title = title self.description = description @@ -27,6 +28,7 @@ class ReportViewModel { self.server = server self.status = status self.apiID = apiID + self.folderId = folderId } } From 89c1414d9e32ce5e19301e07532892643002972e Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 17 Jul 2024 16:03:03 -0300 Subject: [PATCH 093/167] implement pause and resume --- .../Repositories/GDriveRepository.swift | 162 ++++++++++++------ .../ViewModel/GDriveOutboxViewModel.swift | 25 ++- 2 files changed, 131 insertions(+), 56 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index e6f39b332..a2b4ca519 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -18,11 +18,17 @@ protocol GDriveRepositoryProtocol { func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> func createDriveFolder(folderName: String, parentId: String?, description: String?) -> AnyPublisher func uploadFile(fileURL: URL, fileId: String, mimeType: String, folderId: String) -> AnyPublisher + func pauseAllUploads() + func resumeAllUploads() func signOut() -> Void } class GDriveRepository: GDriveRepositoryProtocol { private var googleUser: GIDGoogleUser? + private var uploadTasks: [String: GTLRServiceTicket] = [:] + private let uploadQueue = DispatchQueue(label: "com.tella.gdriveupload", attributes: .concurrent) + private let uploadLock = NSLock() + private(set) var isUploading = false private var rootViewController: UIViewController? { return UIApplication.shared.windows.first?.rootViewController @@ -183,74 +189,122 @@ class GDriveRepository: GDriveRepositoryProtocol { } func uploadFile( - fileURL: URL, - fileId: String, - mimeType: String, - folderId: String + fileURL: URL, + fileId: String, + mimeType: String, + folderId: String ) -> AnyPublisher { - let progressSubject = PassthroughSubject() - return Deferred { Future { [weak self] promise in - guard let self = self, let user = self.googleUser else { - promise(.failure(APIError.noToken)) + guard let self = self else { + promise(.failure(APIError.unexpectedResponse)) return } - let driveService = GTLRDriveService() - driveService.authorizer = user.fetcherAuthorizer - - let file = GTLRDrive_File() - file.name = fileURL.lastPathComponent - file.mimeType = mimeType - file.parents = [folderId] - - let uploadParameters = GTLRUploadParameters(fileURL: fileURL, mimeType: mimeType) - uploadParameters.shouldUploadWithSingleRequest = false - - let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: uploadParameters) - query.supportsAllDrives = true - - let totalSize = UInt64((try? fileURL.resourceValues(forKeys: [.fileSizeKey]).fileSize) ?? 0) - let uploadProgressInfo = UploadProgressInfo(fileId: fileId, status: .notSubmitted, total: Int(totalSize)) - - let ticket = driveService.executeQuery(query) { (ticket, file, error) in - if let error = error { - print("Error uploading file: \(error.localizedDescription)") - uploadProgressInfo.error = APIError.unexpectedResponse - uploadProgressInfo.status = .submissionError - progressSubject.send(completion: .failure(error)) - promise(.failure(error)) + self.uploadQueue.async { + self.uploadLock.lock() + defer { self.uploadLock.unlock() } + + guard self.isUploading else { + promise(.failure(APIError.unexpectedResponse)) return } - guard let uploadedFile = file as? GTLRDrive_File else { - let apiError = APIError.unexpectedResponse - uploadProgressInfo.error = apiError - uploadProgressInfo.status = .submissionError - progressSubject.send(completion: .failure(apiError)) - promise(.failure(apiError)) + guard let user = self.googleUser else { + promise(.failure(APIError.noToken)) return } - uploadProgressInfo.bytesSent = Int(totalSize) - uploadProgressInfo.current = Int(totalSize) - uploadProgressInfo.status = .uploaded - progressSubject.send(uploadProgressInfo) - progressSubject.send(completion: .finished) - promise(.success(uploadProgressInfo)) - } - - ticket.objectFetcher?.sendProgressBlock = { bytesSent, totalBytesSent, totalBytesExpectedToSend in - uploadProgressInfo.bytesSent = Int(totalBytesSent) - uploadProgressInfo.current = Int(totalBytesSent) - uploadProgressInfo.status = .partialSubmitted - uploadProgressInfo.reportStatus = .submissionInProgress - progressSubject.send(uploadProgressInfo) + let driveService = GTLRDriveService() + driveService.authorizer = user.fetcherAuthorizer + + let file = GTLRDrive_File() + file.name = fileURL.lastPathComponent + file.mimeType = mimeType + file.parents = [folderId] + + let uploadParameters = GTLRUploadParameters(fileURL: fileURL, mimeType: mimeType) + uploadParameters.shouldUploadWithSingleRequest = false + + let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: uploadParameters) + query.supportsAllDrives = true + + let totalSize = UInt64((try? fileURL.resourceValues(forKeys: [.fileSizeKey]).fileSize) ?? 0) + var uploadProgressInfo = UploadProgressInfo(fileId: fileId, status: .notSubmitted, total: Int(totalSize)) + + let ticket = driveService.executeQuery(query) { [weak self] (ticket, file, error) in + guard let self = self else { return } + + self.uploadLock.lock() + defer { + self.uploadLock.unlock() + self.uploadTasks.removeValue(forKey: fileId) + } + + if !self.isUploading { + uploadProgressInfo.status = .notSubmitted + promise(.success(uploadProgressInfo)) + return + } + + if let error = error { + uploadProgressInfo.error = APIError.unexpectedResponse + uploadProgressInfo.status = .submissionError + promise(.failure(error)) + return + } + + guard let uploadedFile = file as? GTLRDrive_File else { + let error = APIError.unexpectedResponse + uploadProgressInfo.error = error + uploadProgressInfo.status = .submissionError + promise(.failure(error)) + return + } + + uploadProgressInfo.bytesSent = Int(totalSize) + uploadProgressInfo.current = Int(totalSize) + uploadProgressInfo.status = .uploaded + promise(.success(uploadProgressInfo)) + } + + ticket.objectFetcher?.sendProgressBlock = { [weak self] bytesSent, totalBytesSent, totalBytesExpectedToSend in + guard let self = self else { return } + + self.uploadLock.lock() + defer { self.uploadLock.unlock() } + + if !self.isUploading { + return + } + + uploadProgressInfo.bytesSent = Int(totalBytesSent) + uploadProgressInfo.current = Int(totalBytesSent) + uploadProgressInfo.status = .partialSubmitted + uploadProgressInfo.reportStatus = .submissionInProgress + promise(.success(uploadProgressInfo)) + } + + self.uploadTasks[fileId] = ticket } } - } - .eraseToAnyPublisher() + }.eraseToAnyPublisher() + } + + func pauseAllUploads() { + uploadLock.lock() + defer { uploadLock.unlock() } + + isUploading = false + uploadTasks.forEach { $0.value.cancel() } + uploadTasks.removeAll() + } + + func resumeAllUploads() { + uploadLock.lock() + defer { uploadLock.unlock() } + + isUploading = true } func signOut() { diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 582aa9748..61a3a5e27 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -11,6 +11,7 @@ import Combine class GDriveOutboxViewModel: OutboxMainViewModel { private let gDriveRepository: GDriveRepositoryProtocol + private var currentUploadCancellables: Set = [] init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, @@ -60,11 +61,17 @@ class GDriveOutboxViewModel: OutboxMainViewModel { if isSubmissionInProgress == false { self.updateReportStatus(reportStatus: .submissionInProgress) } + gDriveRepository.resumeAllUploads() guard let folderId = reportViewModel.folderId else { return performSubmission() } - let _ = self.uploadFiles(to: folderId) + uploadFiles(to: folderId) + .sink( + receiveCompletion: { _ in }, + receiveValue: { _ in } + ) + .store(in: ¤tUploadCancellables) } func performSubmission() { @@ -97,7 +104,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { } private func uploadFiles(to folderId: String) -> AnyPublisher { - let uploadPublishers = reportViewModel.files.map { file -> AnyPublisher in + let uploadPublishers = reportViewModel.files.filter { $0.status != .uploaded }.map { file -> AnyPublisher in guard let fileUrl = self.mainAppModel.vaultManager.loadVaultFileToURL(file: file) else { return Fail(error: APIError.unexpectedResponse).eraseToAnyPublisher() } @@ -110,6 +117,18 @@ class GDriveOutboxViewModel: OutboxMainViewModel { } return Publishers.MergeMany(uploadPublishers) + .receive(on: DispatchQueue.main) + .handleEvents(receiveOutput: { [weak self] uploadProgressWithFolderId in + self?.updateProgressInfos(uploadProgressInfo: uploadProgressWithFolderId.progressInfo) + }, receiveCompletion: { [weak self] completion in + switch completion { + case .finished: + self?.updateReportStatus(reportStatus: .submitted) + self?.showSubmittedReport() + case .failure(let error): + debugLog(error) + } + }) .eraseToAnyPublisher() } @@ -150,6 +169,8 @@ class GDriveOutboxViewModel: OutboxMainViewModel { override func pauseSubmission() { if isSubmissionInProgress { updateReportStatus(reportStatus: .submissionPaused) + gDriveRepository.pauseAllUploads() + currentUploadCancellables.removeAll() } } override func updateReportStatus(reportStatus: ReportStatus) { From 448caf499c3756ac49ed2effccf4c210ca04fef7 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 18 Jul 2024 10:24:45 -0300 Subject: [PATCH 094/167] add queue to send files sequentially --- .../Repositories/GDriveRepository.swift | 16 ---- .../ViewModel/GDriveOutboxViewModel.swift | 85 ++++++++++--------- 2 files changed, 46 insertions(+), 55 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index a2b4ca519..0974c5355 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -268,22 +268,6 @@ class GDriveRepository: GDriveRepositoryProtocol { promise(.success(uploadProgressInfo)) } - ticket.objectFetcher?.sendProgressBlock = { [weak self] bytesSent, totalBytesSent, totalBytesExpectedToSend in - guard let self = self else { return } - - self.uploadLock.lock() - defer { self.uploadLock.unlock() } - - if !self.isUploading { - return - } - - uploadProgressInfo.bytesSent = Int(totalBytesSent) - uploadProgressInfo.current = Int(totalBytesSent) - uploadProgressInfo.status = .partialSubmitted - uploadProgressInfo.reportStatus = .submissionInProgress - promise(.success(uploadProgressInfo)) - } self.uploadTasks[fileId] = ticket } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 61a3a5e27..dd6ecc124 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -11,7 +11,8 @@ import Combine class GDriveOutboxViewModel: OutboxMainViewModel { private let gDriveRepository: GDriveRepositoryProtocol - private var currentUploadCancellables: Set = [] + private var currentUploadCancellable: AnyCancellable? + private var uploadQueue: [ReportVaultFile] = [] init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, @@ -67,11 +68,6 @@ class GDriveOutboxViewModel: OutboxMainViewModel { } uploadFiles(to: folderId) - .sink( - receiveCompletion: { _ in }, - receiveValue: { _ in } - ) - .store(in: ¤tUploadCancellables) } func performSubmission() { @@ -81,55 +77,64 @@ class GDriveOutboxViewModel: OutboxMainViewModel { description: reportViewModel.description ) .receive(on: DispatchQueue.main) - .flatMap { folderId -> AnyPublisher in - self.reportViewModel.folderId = folderId - self.updateReportFolderId(folderId: folderId) - return self.uploadFiles(to: folderId) - } .sink( receiveCompletion: { completion in switch completion { case .finished: - self.updateReportStatus(reportStatus: .submitted) - self.showSubmittedReport() break case .failure(let error): debugLog(error) + self.updateReportStatus(reportStatus: .submissionError) } }, - receiveValue: { uploadProgressWithFolderId in - self.updateProgressInfos(uploadProgressInfo: uploadProgressWithFolderId.progressInfo) + receiveValue: { [weak self] folderId in + guard let self = self else { return } + self.reportViewModel.folderId = folderId + self.updateReportFolderId(folderId: folderId) + self.uploadFiles(to: folderId) } ).store(in: &subscribers) } - private func uploadFiles(to folderId: String) -> AnyPublisher { - let uploadPublishers = reportViewModel.files.filter { $0.status != .uploaded }.map { file -> AnyPublisher in - guard let fileUrl = self.mainAppModel.vaultManager.loadVaultFileToURL(file: file) else { - return Fail(error: APIError.unexpectedResponse).eraseToAnyPublisher() - } - - return gDriveRepository.uploadFile(fileURL: fileUrl, fileId: file.id ?? "", mimeType: file.mimeType ?? "", folderId: folderId) - .map { progressInfo in - UploadProgressWithFolderId(folderId: folderId, progressInfo: progressInfo) - } - .eraseToAnyPublisher() + private func uploadFiles(to folderId: String) { + uploadQueue = reportViewModel.files.filter { $0.status != .uploaded } + uploadNextFile(folderId: folderId) + } + + private func uploadNextFile(folderId: String) { + guard let fileToUpload = uploadQueue.first else { + // All files have been uploaded + self.updateReportStatus(reportStatus: .submitted) + self.showSubmittedReport() + return + } + + guard let fileUrl = self.mainAppModel.vaultManager.loadVaultFileToURL(file: fileToUpload) else { + // Handle error: unable to load file + uploadQueue.removeFirst() + uploadNextFile(folderId: folderId) + return } - return Publishers.MergeMany(uploadPublishers) + currentUploadCancellable = gDriveRepository.uploadFile(fileURL: fileUrl, fileId: fileToUpload.id ?? "", mimeType: fileToUpload.mimeType ?? "", folderId: folderId) .receive(on: DispatchQueue.main) - .handleEvents(receiveOutput: { [weak self] uploadProgressWithFolderId in - self?.updateProgressInfos(uploadProgressInfo: uploadProgressWithFolderId.progressInfo) - }, receiveCompletion: { [weak self] completion in - switch completion { - case .finished: - self?.updateReportStatus(reportStatus: .submitted) - self?.showSubmittedReport() - case .failure(let error): - debugLog(error) + .sink( + receiveCompletion: { [weak self] completion in + guard let self = self else { return } + switch completion { + case .finished: + // File upload completed successfully + self.uploadQueue.removeFirst() + self.uploadNextFile(folderId: folderId) + case .failure(let error): + debugLog(error) + self.updateReportStatus(reportStatus: .submissionError) + } + }, + receiveValue: { [weak self] progressInfo in + self?.updateProgressInfos(uploadProgressInfo: progressInfo) } - }) - .eraseToAnyPublisher() + ) } override func updateProgressInfos(uploadProgressInfo: UploadProgressInfo) { @@ -170,9 +175,11 @@ class GDriveOutboxViewModel: OutboxMainViewModel { if isSubmissionInProgress { updateReportStatus(reportStatus: .submissionPaused) gDriveRepository.pauseAllUploads() - currentUploadCancellables.removeAll() + currentUploadCancellable?.cancel() + currentUploadCancellable = nil } } + override func updateReportStatus(reportStatus: ReportStatus) { self.reportViewModel.status = reportStatus From 154ccf5b3f2c536064ae06d43aaf89639c37fa79 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 18 Jul 2024 14:46:41 -0300 Subject: [PATCH 095/167] persist outbox files progress --- Tella/Data/Database/GDriveDatabase.swift | 2 +- .../Repositories/GDriveRepository.swift | 180 +++++++++++------- Tella/Domain/Entity/Report/ReportFile.swift | 1 + .../Views/ReportMainView.swift | 1 - .../ViewModel/GDriveDraftViewModel.swift | 1 - .../ViewModel/GDriveOutboxViewModel.swift | 104 ++++++---- .../Reports/View Model/DraftReportVM.swift | 2 - 7 files changed, 177 insertions(+), 114 deletions(-) diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index 78cd94d2e..d3707639d 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -202,7 +202,7 @@ extension TellaDataBase { KeyValue(key: D.cVaultFileInstanceId, value: reportFile.fileId), KeyValue(key: D.cStatus, value: reportFile.status?.rawValue), KeyValue(key: D.cBytesSent, value: reportFile.bytesSent), - KeyValue(key: D.cCreatedDate, value: reportFile.createdDate), + KeyValue(key: D.cCreatedDate, value: reportFile.createdDate?.getDateDouble()), KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()), ] diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 0974c5355..ea0d37f88 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -195,84 +195,118 @@ class GDriveRepository: GDriveRepositoryProtocol { folderId: String ) -> AnyPublisher { return Deferred { - Future { [weak self] promise in - guard let self = self else { - promise(.failure(APIError.unexpectedResponse)) + Future { promise in + Task { + do { + try await self.ensureSignedIn() + self.performUploadFile( + fileURL: fileURL, + fileId: fileId, + mimeType: mimeType, + folderId: folderId, + promise: promise + ) + } catch { + promise(.failure(error)) + } + } + } + }.eraseToAnyPublisher() + } + + private func performUploadFile( + fileURL: URL, + fileId: String, + mimeType: String, + folderId: String, + promise: @escaping (Result) -> Void + ) { + self.uploadQueue.async { + self.uploadLock.lock() + defer { self.uploadLock.unlock() } + + guard self.isUploading else { + promise(.failure(APIError.unexpectedResponse)) + return + } + + guard let user = self.googleUser else { + promise(.failure(APIError.noToken)) + return + } + + let driveService = GTLRDriveService() + driveService.authorizer = user.fetcherAuthorizer + + let file = GTLRDrive_File() + file.name = fileURL.lastPathComponent + file.mimeType = mimeType + file.parents = [folderId] + + let uploadParameters = GTLRUploadParameters(fileURL: fileURL, mimeType: mimeType) + uploadParameters.shouldUploadWithSingleRequest = false + + let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: uploadParameters) + query.supportsAllDrives = true + + let totalSize = UInt64((try? fileURL.resourceValues(forKeys: [.fileSizeKey]).fileSize) ?? 0) + var uploadProgressInfo = UploadProgressInfo(fileId: fileId, status: .notSubmitted, total: Int(totalSize)) + + let ticket = driveService.executeQuery(query) { [weak self] (ticket, file, error) in + guard let self = self else { return } + + self.uploadLock.lock() + defer { + self.uploadLock.unlock() + self.uploadTasks.removeValue(forKey: fileId) + } + + if !self.isUploading { + uploadProgressInfo.status = .notSubmitted + promise(.success(uploadProgressInfo)) return } - self.uploadQueue.async { - self.uploadLock.lock() - defer { self.uploadLock.unlock() } - - guard self.isUploading else { - promise(.failure(APIError.unexpectedResponse)) - return - } - - guard let user = self.googleUser else { - promise(.failure(APIError.noToken)) - return - } - - let driveService = GTLRDriveService() - driveService.authorizer = user.fetcherAuthorizer - - let file = GTLRDrive_File() - file.name = fileURL.lastPathComponent - file.mimeType = mimeType - file.parents = [folderId] - - let uploadParameters = GTLRUploadParameters(fileURL: fileURL, mimeType: mimeType) - uploadParameters.shouldUploadWithSingleRequest = false - - let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: uploadParameters) - query.supportsAllDrives = true - - let totalSize = UInt64((try? fileURL.resourceValues(forKeys: [.fileSizeKey]).fileSize) ?? 0) - var uploadProgressInfo = UploadProgressInfo(fileId: fileId, status: .notSubmitted, total: Int(totalSize)) - - let ticket = driveService.executeQuery(query) { [weak self] (ticket, file, error) in - guard let self = self else { return } - - self.uploadLock.lock() - defer { - self.uploadLock.unlock() - self.uploadTasks.removeValue(forKey: fileId) - } - - if !self.isUploading { - uploadProgressInfo.status = .notSubmitted - promise(.success(uploadProgressInfo)) - return - } - - if let error = error { - uploadProgressInfo.error = APIError.unexpectedResponse - uploadProgressInfo.status = .submissionError - promise(.failure(error)) - return - } - - guard let uploadedFile = file as? GTLRDrive_File else { - let error = APIError.unexpectedResponse - uploadProgressInfo.error = error - uploadProgressInfo.status = .submissionError - promise(.failure(error)) - return - } - - uploadProgressInfo.bytesSent = Int(totalSize) - uploadProgressInfo.current = Int(totalSize) - uploadProgressInfo.status = .uploaded - promise(.success(uploadProgressInfo)) - } - - - self.uploadTasks[fileId] = ticket + if let error = error { + uploadProgressInfo.error = APIError.unexpectedResponse + uploadProgressInfo.status = .submissionError + promise(.failure(error)) + return + } + + guard let uploadedFile = file as? GTLRDrive_File else { + let error = APIError.unexpectedResponse + uploadProgressInfo.error = error + uploadProgressInfo.status = .submissionError + promise(.failure(error)) + return } + + uploadProgressInfo.bytesSent = Int(totalSize) + uploadProgressInfo.current = Int(totalSize) + uploadProgressInfo.status = .uploaded + promise(.success(uploadProgressInfo)) } - }.eraseToAnyPublisher() + + ticket.objectFetcher?.sendProgressBlock = { [weak self] bytesSent, totalBytesSent, totalBytesExpectedToSend in + guard let self = self else { return } + + self.uploadLock.lock() + defer { self.uploadLock.unlock() } + + if !self.isUploading { + return + } + + uploadProgressInfo.bytesSent = Int(totalBytesSent) + uploadProgressInfo.current = Int(totalBytesSent) + uploadProgressInfo.status = .partialSubmitted + uploadProgressInfo.reportStatus = .submissionInProgress + promise(.success(uploadProgressInfo)) + } + + self.uploadTasks[fileId] = ticket + } } func pauseAllUploads() { diff --git a/Tella/Domain/Entity/Report/ReportFile.swift b/Tella/Domain/Entity/Report/ReportFile.swift index 971fb4592..31d2c3211 100644 --- a/Tella/Domain/Entity/Report/ReportFile.swift +++ b/Tella/Domain/Entity/Report/ReportFile.swift @@ -72,6 +72,7 @@ class ReportFile : Hashable, Codable { let status = try container.decode(Int.self, forKey: .status) self.status = FileStatus(rawValue: status) ?? FileStatus.unknown + self.bytesSent = try container.decode(Int.self, forKey: .bytesSent) let createdDate = try container.decode(Double.self, forKey: .createdDate) self.createdDate = createdDate.getDate() diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift index 6446d963b..8a24efb06 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -133,7 +133,6 @@ struct ReportMainView: View { private func showDetailsView(cardViewModel:CommonCardViewModel) { guard let cardViewModel = cardViewModel as? ReportCardViewModel else { return } - dump(cardViewModel.status) switch cardViewModel.status { case .unknown, .draft: showDraftView(id: cardViewModel.id) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index ac0408ace..a50f8602d 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -66,7 +66,6 @@ class GDriveDraftViewModel: DraftMainViewModel { switch idResult { case .success(let id ): - dump(id) self.reportId = id self.successSavingReport = true default: diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index dd6ecc124..b67c2913b 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -58,19 +58,57 @@ class GDriveOutboxViewModel: OutboxMainViewModel { } } + //tracking progress + override func updateProgressInfos(uploadProgressInfo: UploadProgressInfo) { + if let currentFile = self.reportViewModel.files.first(where: { $0.id == uploadProgressInfo.fileId }) { + currentFile.current = uploadProgressInfo.current ?? 0 + currentFile.bytesSent = uploadProgressInfo.bytesSent ?? 0 + currentFile.status = uploadProgressInfo.status + updateFileProgress(fileId: uploadProgressInfo.fileId ?? "", bytesSent: uploadProgressInfo.bytesSent ?? 0, status: uploadProgressInfo.status) + } + + // All Files + let totalBytesSent = self.reportViewModel.files.reduce(0) { $0 + ($1.bytesSent) } + let totalSize = self.reportViewModel.files.reduce(0) { $0 + ($1.size) } + + if totalSize > 0 { + let percentUploaded = Float(totalBytesSent) / Float(totalSize) + let formattedPercentUploaded = percentUploaded >= 1.0 ? 1.0 : percentUploaded + let formattedTotalUploaded = totalBytesSent.getFormattedFileSize().getFileSizeWithoutUnit() + let formattedTotalSize = totalSize.getFormattedFileSize() + + DispatchQueue.main.async { + + self.percentUploadedInfo = "\(Int(formattedPercentUploaded * 100))% uploaded" + self.percentUploaded = formattedPercentUploaded + self.uploadedFiles = " \(self.reportViewModel.files.count) files, \(formattedTotalUploaded)/\(formattedTotalSize) uploaded" + + if let currentItem = self.progressFileItems.first(where: { $0.file.id == uploadProgressInfo.fileId }) { + let size = currentItem.file.size.getFormattedFileSize() + let currentFileTotalBytesSent = uploadProgressInfo.bytesSent?.getFormattedFileSize().getFileSizeWithoutUnit() ?? "0" + + currentItem.progression = "\(currentFileTotalBytesSent)/\(size)" + } + self.objectWillChange.send() + } + } + } + + //submit report + override func submitReport() { if isSubmissionInProgress == false { self.updateReportStatus(reportStatus: .submissionInProgress) } gDriveRepository.resumeAllUploads() guard let folderId = reportViewModel.folderId else { - return performSubmission() + return createDriveFolder() } uploadFiles(to: folderId) } - func performSubmission() { + func createDriveFolder() { gDriveRepository.createDriveFolder( folderName: reportViewModel.title, parentId: reportViewModel.server?.rootFolder, @@ -137,40 +175,6 @@ class GDriveOutboxViewModel: OutboxMainViewModel { ) } - override func updateProgressInfos(uploadProgressInfo: UploadProgressInfo) { - if let currentFile = self.reportViewModel.files.first(where: { $0.id == uploadProgressInfo.fileId }) { - currentFile.current = uploadProgressInfo.current ?? 0 - currentFile.bytesSent = uploadProgressInfo.bytesSent ?? 0 - currentFile.status = uploadProgressInfo.status - } - - // All Files - let totalBytesSent = self.reportViewModel.files.reduce(0) { $0 + ($1.bytesSent) } - let totalSize = self.reportViewModel.files.reduce(0) { $0 + ($1.size) } - - if totalSize > 0 { - let percentUploaded = Float(totalBytesSent) / Float(totalSize) - let formattedPercentUploaded = percentUploaded >= 1.0 ? 1.0 : percentUploaded - let formattedTotalUploaded = totalBytesSent.getFormattedFileSize().getFileSizeWithoutUnit() - let formattedTotalSize = totalSize.getFormattedFileSize() - - DispatchQueue.main.async { - - self.percentUploadedInfo = "\(Int(formattedPercentUploaded * 100))% uploaded" - self.percentUploaded = formattedPercentUploaded - self.uploadedFiles = " \(self.reportViewModel.files.count) files, \(formattedTotalUploaded)/\(formattedTotalSize) uploaded" - - if let currentItem = self.progressFileItems.first(where: { $0.file.id == uploadProgressInfo.fileId }) { - let size = currentItem.file.size.getFormattedFileSize() - let currentFileTotalBytesSent = uploadProgressInfo.bytesSent?.getFormattedFileSize().getFileSizeWithoutUnit() ?? "0" - - currentItem.progression = "\(currentFileTotalBytesSent)/\(size)" - } - self.objectWillChange.send() - } - } - } - override func pauseSubmission() { if isSubmissionInProgress { updateReportStatus(reportStatus: .submissionPaused) @@ -193,4 +197,32 @@ class GDriveOutboxViewModel: OutboxMainViewModel { mainAppModel.tellaData?.updateDriveFolderId(idReport: id, folderId: folderId) } + + private func updateFileProgress(fileId: String, bytesSent: Int, status: FileStatus) { + if let index = reportViewModel.files.firstIndex(where: { $0.id == fileId }) { + reportViewModel.files[index].bytesSent = bytesSent + reportViewModel.files[index].status = status + + let reportFiles = reportViewModel.files.map { file in + return ReportFile( + id: file.instanceId, + fileId: file.id, + status: file.status, + bytesSent: file.bytesSent, + createdDate: file.createdDate + ) + } + + let updatedReport = GDriveReport( + id: reportViewModel.id, + title: reportViewModel.title, + description: reportViewModel.description, + status: reportViewModel.status ?? .submissionInProgress, + vaultFiles: reportFiles + ) + + let _ = mainAppModel.tellaData?.updateDriveReport(report: updatedReport) + + } + } } diff --git a/Tella/Scenes/Reports/View Model/DraftReportVM.swift b/Tella/Scenes/Reports/View Model/DraftReportVM.swift index 6d2709ccb..e66565793 100644 --- a/Tella/Scenes/Reports/View Model/DraftReportVM.swift +++ b/Tella/Scenes/Reports/View Model/DraftReportVM.swift @@ -80,8 +80,6 @@ class DraftReportVM: DraftMainViewModel { createdDate: Date())}, apiID: apiID) - dump(report) - !isNewDraft ? updateReport(report: report) : addReport(report: report) } From 3e46adf76c187af9a97a0a75206d459572c38a0c Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 18 Jul 2024 17:09:27 -0300 Subject: [PATCH 096/167] prevent duplicated files --- .../Repositories/GDriveRepository.swift | 180 +++++++++++------- .../Views/ReportMainView.swift | 8 +- 2 files changed, 113 insertions(+), 75 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index ea0d37f88..88117c887 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -215,97 +215,129 @@ class GDriveRepository: GDriveRepositoryProtocol { } private func performUploadFile( - fileURL: URL, - fileId: String, - mimeType: String, - folderId: String, - promise: @escaping (Result) -> Void + fileURL: URL, + fileId: String, + mimeType: String, + folderId: String, + promise: @escaping (Result) -> Void ) { - self.uploadQueue.async { - self.uploadLock.lock() - defer { self.uploadLock.unlock() } - - guard self.isUploading else { - promise(.failure(APIError.unexpectedResponse)) - return - } - - guard let user = self.googleUser else { - promise(.failure(APIError.noToken)) - return - } - - let driveService = GTLRDriveService() - driveService.authorizer = user.fetcherAuthorizer - - let file = GTLRDrive_File() - file.name = fileURL.lastPathComponent - file.mimeType = mimeType - file.parents = [folderId] - - let uploadParameters = GTLRUploadParameters(fileURL: fileURL, mimeType: mimeType) - uploadParameters.shouldUploadWithSingleRequest = false - - let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: uploadParameters) - query.supportsAllDrives = true - - let totalSize = UInt64((try? fileURL.resourceValues(forKeys: [.fileSizeKey]).fileSize) ?? 0) - var uploadProgressInfo = UploadProgressInfo(fileId: fileId, status: .notSubmitted, total: Int(totalSize)) - - let ticket = driveService.executeQuery(query) { [weak self] (ticket, file, error) in - guard let self = self else { return } - + Task { + do { self.uploadLock.lock() - defer { - self.uploadLock.unlock() - self.uploadTasks.removeValue(forKey: fileId) - } + defer { self.uploadLock.unlock() } - if !self.isUploading { - uploadProgressInfo.status = .notSubmitted - promise(.success(uploadProgressInfo)) + guard self.isUploading else { + promise(.failure(APIError.unexpectedResponse)) return } - if let error = error { - uploadProgressInfo.error = APIError.unexpectedResponse - uploadProgressInfo.status = .submissionError - promise(.failure(error)) + guard let user = self.googleUser else { + promise(.failure(APIError.noToken)) return } - guard let uploadedFile = file as? GTLRDrive_File else { - let error = APIError.unexpectedResponse - uploadProgressInfo.error = error - uploadProgressInfo.status = .submissionError - promise(.failure(error)) - return - } + let driveService = GTLRDriveService() + driveService.authorizer = user.fetcherAuthorizer - uploadProgressInfo.bytesSent = Int(totalSize) - uploadProgressInfo.current = Int(totalSize) - uploadProgressInfo.status = .uploaded + let fileName = fileURL.lastPathComponent + let totalSize = UInt64((try? fileURL.resourceValues(forKeys: [.fileSizeKey]).fileSize) ?? 0) + var uploadProgressInfo = UploadProgressInfo(fileId: fileId, status: .notSubmitted, total: Int(totalSize)) + + let fileExists = try await checkFileExists(fileName: fileName, folderId: folderId, driveService: driveService) + + if fileExists { + // File already exists, mark as uploaded + uploadProgressInfo.bytesSent = Int(totalSize) + uploadProgressInfo.current = Int(totalSize) + uploadProgressInfo.status = .uploaded + promise(.success(uploadProgressInfo)) + } else { + // File doesn't exist, proceed with upload + self.uploadNewFile(fileURL: fileURL, fileId: fileId, mimeType: mimeType, folderId: folderId, driveService: driveService, uploadProgressInfo: uploadProgressInfo, promise: promise) + } + } catch { + promise(.failure(error)) + } + } + } + + private func uploadNewFile( + fileURL: URL, + fileId: String, + mimeType: String, + folderId: String, + driveService: GTLRDriveService, + uploadProgressInfo: UploadProgressInfo, + promise: @escaping (Result) -> Void + ) { + let file = GTLRDrive_File() + file.name = fileURL.lastPathComponent + file.mimeType = mimeType + file.parents = [folderId] + + let uploadParameters = GTLRUploadParameters(fileURL: fileURL, mimeType: mimeType) + uploadParameters.shouldUploadWithSingleRequest = false + + let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: uploadParameters) + query.supportsAllDrives = true + + let ticket = driveService.executeQuery(query) { [weak self] (ticket, file, error) in + guard let self = self else { return } + + self.uploadLock.lock() + defer { + self.uploadLock.unlock() + self.uploadTasks.removeValue(forKey: fileId) + } + + if !self.isUploading { + uploadProgressInfo.status = .notSubmitted promise(.success(uploadProgressInfo)) + return } - ticket.objectFetcher?.sendProgressBlock = { [weak self] bytesSent, totalBytesSent, totalBytesExpectedToSend in - guard let self = self else { return } - - self.uploadLock.lock() - defer { self.uploadLock.unlock() } - - if !self.isUploading { + if let error = error { + uploadProgressInfo.error = APIError.unexpectedResponse + uploadProgressInfo.status = .submissionError + promise(.failure(error)) + return + } + + guard let uploadedFile = file as? GTLRDrive_File else { + let error = APIError.unexpectedResponse + uploadProgressInfo.error = error + uploadProgressInfo.status = .submissionError + promise(.failure(error)) + return + } + + uploadProgressInfo.bytesSent = Int(uploadProgressInfo.total!) + uploadProgressInfo.current = Int(uploadProgressInfo.total!) + uploadProgressInfo.status = .uploaded + promise(.success(uploadProgressInfo)) + } + + self.uploadTasks[fileId] = ticket + } + + private func checkFileExists(fileName: String, folderId: String, driveService: GTLRDriveService) async throws -> Bool { + return try await withCheckedThrowingContinuation { continuation in + let query = GTLRDriveQuery_FilesList.query() + query.q = "name = '\(fileName)' and '\(folderId)' in parents and trashed = false" + query.fields = "files(id, name)" + + driveService.executeQuery(query) { (_, response, error) in + if let error = error { + continuation.resume(throwing: error) return } - uploadProgressInfo.bytesSent = Int(totalBytesSent) - uploadProgressInfo.current = Int(totalBytesSent) - uploadProgressInfo.status = .partialSubmitted - uploadProgressInfo.reportStatus = .submissionInProgress - promise(.success(uploadProgressInfo)) + if let fileList = response as? GTLRDrive_FileList, let files = fileList.files, !files.isEmpty { + continuation.resume(returning: true) + } else { + continuation.resume(returning: false) + } } - - self.uploadTasks[fileId] = ticket } } diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift index 8a24efb06..57ab1fed5 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -137,7 +137,13 @@ struct ReportMainView: View { case .unknown, .draft: showDraftView(id: cardViewModel.id) sheetManager.hide() - case .finalized: + case .finalized, + .submissionError, + .submissionPending, + .submissionPaused, + .submissionInProgress, + .submissionAutoPaused, + .submissionScheduled: showOutboxView(id: cardViewModel.id) sheetManager.hide() case .submitted: From 245f4548f3de101435573e8e880495f7d67610e9 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 18 Jul 2024 17:45:24 -0300 Subject: [PATCH 097/167] fix no root folder error --- .../GDrive/ViewModel/GDriveOutboxViewModel.swift | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index b67c2913b..75429bb30 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -13,6 +13,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { private let gDriveRepository: GDriveRepositoryProtocol private var currentUploadCancellable: AnyCancellable? private var uploadQueue: [ReportVaultFile] = [] + var server: GDriveServer? init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, @@ -23,15 +24,22 @@ class GDriveOutboxViewModel: OutboxMainViewModel { self.gDriveRepository = repository super.init(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: reportId) + getServer() initVaultFile(reportId: reportId) - initializeProgressionInfos() if shouldStartUpload { self.submitReport() + } else { + updateReportStatus(reportStatus: .submissionPaused) } } + private func getServer() { + self.server = mainAppModel.tellaData?.gDriveServers.value.first + dump(server?.rootFolder) + } + override func initVaultFile(reportId: Int?) { if let reportId, let report = self.mainAppModel.tellaData?.getDriveReport(id: reportId) { @@ -51,7 +59,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { description: report.description ?? "", files: files, reportFiles: report.reportFiles ?? [], - server: report.server, + server: server, status: report.status, apiID: nil, folderId: report.folderId) @@ -109,6 +117,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { } func createDriveFolder() { + dump(reportViewModel.server?.rootFolder) gDriveRepository.createDriveFolder( folderName: reportViewModel.title, parentId: reportViewModel.server?.rootFolder, From a7bb1a94d07d1163ff37e508ec31fc85e4c72636 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 22 Jul 2024 15:16:06 -0300 Subject: [PATCH 098/167] show offline error when is not connected to internet --- .../Repositories/GDriveRepository.swift | 110 ++++++++++++++---- .../ViewModel/GDriveOutboxViewModel.swift | 46 +++++--- 2 files changed, 118 insertions(+), 38 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 88117c887..6afaa08f3 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -16,8 +16,8 @@ protocol GDriveRepositoryProtocol { func restorePreviousSignIn() async throws func handleUrl(url: URL) func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> - func createDriveFolder(folderName: String, parentId: String?, description: String?) -> AnyPublisher - func uploadFile(fileURL: URL, fileId: String, mimeType: String, folderId: String) -> AnyPublisher + func createDriveFolder(folderName: String, parentId: String?, description: String?) -> AnyPublisher + func uploadFile(fileURL: URL, fileId: String, mimeType: String, folderId: String) -> AnyPublisher func pauseAllUploads() func resumeAllUploads() func signOut() -> Void @@ -26,10 +26,26 @@ protocol GDriveRepositoryProtocol { class GDriveRepository: GDriveRepositoryProtocol { private var googleUser: GIDGoogleUser? private var uploadTasks: [String: GTLRServiceTicket] = [:] - private let uploadQueue = DispatchQueue(label: "com.tella.gdriveupload", attributes: .concurrent) private let uploadLock = NSLock() private(set) var isUploading = false + private let networkMonitor: NetworkMonitor + var subscribers : Set = [] + private let networkStatusSubject = PassthroughSubject() + init(networkMonitor: NetworkMonitor = .shared) { + self.networkMonitor = networkMonitor + + setupNetworkMonitor() + } + + private func setupNetworkMonitor() { + networkMonitor.connectionDidChange.sink(receiveValue: { isConnected in + self.networkStatusSubject.send(isConnected) + if(!isConnected) { + self.pauseAllUploads() + } + }).store(in: &subscribers) + } private var rootViewController: UIViewController? { return UIApplication.shared.windows.first?.rootViewController } @@ -124,9 +140,13 @@ class GDriveRepository: GDriveRepositoryProtocol { folderName: String, parentId: String? = nil, description: String? - ) -> AnyPublisher { + ) -> AnyPublisher { Deferred { Future { promise in + guard self.networkMonitor.isConnected else { + promise(.failure(.noInternetConnection)) + return + } Task { do { try await self.ensureSignedIn() @@ -136,7 +156,7 @@ class GDriveRepository: GDriveRepositoryProtocol { description: description, promise: promise) } catch { - promise(.failure(error)) + promise(.failure(self.mapToAPIError(error))) } } } @@ -147,7 +167,7 @@ class GDriveRepository: GDriveRepositoryProtocol { folderName: String, parentId: String?, description: String?, - promise: @escaping (Result) -> Void + promise: @escaping (Result) -> Void ) { guard let user = googleUser else { promise(.failure(APIError.noToken)) @@ -175,7 +195,7 @@ class GDriveRepository: GDriveRepositoryProtocol { driveService.executeQuery(query) { (ticket, file, error) in if let error = error { print("Error creating folder: \(error.localizedDescription)") - promise(.failure(error)) + promise(.failure(self.mapToAPIError(error))) return } @@ -193,9 +213,13 @@ class GDriveRepository: GDriveRepositoryProtocol { fileId: String, mimeType: String, folderId: String - ) -> AnyPublisher { + ) -> AnyPublisher { return Deferred { Future { promise in + guard self.networkMonitor.isConnected else { + promise(.failure(.noInternetConnection)) + return + } Task { do { try await self.ensureSignedIn() @@ -206,8 +230,16 @@ class GDriveRepository: GDriveRepositoryProtocol { folderId: folderId, promise: promise ) + + self.networkStatusSubject + .filter { !$0 } + .first() + .sink { _ in + promise(.failure(.noInternetConnection)) + } + .store(in: &self.subscribers) } catch { - promise(.failure(error)) + promise(.failure(self.mapToAPIError(error))) } } } @@ -219,13 +251,18 @@ class GDriveRepository: GDriveRepositoryProtocol { fileId: String, mimeType: String, folderId: String, - promise: @escaping (Result) -> Void + promise: @escaping (Result) -> Void ) { Task { do { self.uploadLock.lock() defer { self.uploadLock.unlock() } + guard self.networkMonitor.isConnected else { + promise(.failure(.noInternetConnection)) + return + } + guard self.isUploading else { promise(.failure(APIError.unexpectedResponse)) return @@ -241,7 +278,7 @@ class GDriveRepository: GDriveRepositoryProtocol { let fileName = fileURL.lastPathComponent let totalSize = UInt64((try? fileURL.resourceValues(forKeys: [.fileSizeKey]).fileSize) ?? 0) - var uploadProgressInfo = UploadProgressInfo(fileId: fileId, status: .notSubmitted, total: Int(totalSize)) + let uploadProgressInfo = UploadProgressInfo(fileId: fileId, status: .notSubmitted, total: Int(totalSize)) let fileExists = try await checkFileExists(fileName: fileName, folderId: folderId, driveService: driveService) @@ -256,7 +293,7 @@ class GDriveRepository: GDriveRepositoryProtocol { self.uploadNewFile(fileURL: fileURL, fileId: fileId, mimeType: mimeType, folderId: folderId, driveService: driveService, uploadProgressInfo: uploadProgressInfo, promise: promise) } } catch { - promise(.failure(error)) + promise(.failure(self.mapToAPIError(error))) } } } @@ -268,7 +305,7 @@ class GDriveRepository: GDriveRepositoryProtocol { folderId: String, driveService: GTLRDriveService, uploadProgressInfo: UploadProgressInfo, - promise: @escaping (Result) -> Void + promise: @escaping (Result) -> Void ) { let file = GTLRDrive_File() file.name = fileURL.lastPathComponent @@ -296,18 +333,13 @@ class GDriveRepository: GDriveRepositoryProtocol { return } - if let error = error { - uploadProgressInfo.error = APIError.unexpectedResponse - uploadProgressInfo.status = .submissionError - promise(.failure(error)) + if error != nil { + handleSubmissionError(uploadProgressInfo: uploadProgressInfo, promise: promise) return } - guard let uploadedFile = file as? GTLRDrive_File else { - let error = APIError.unexpectedResponse - uploadProgressInfo.error = error - uploadProgressInfo.status = .submissionError - promise(.failure(error)) + guard file is GTLRDrive_File else { + handleSubmissionError(uploadProgressInfo: uploadProgressInfo, promise: promise) return } @@ -360,6 +392,40 @@ class GDriveRepository: GDriveRepositoryProtocol { func signOut() { GIDSignIn.sharedInstance.signOut() } + + private func handleSubmissionError(uploadProgressInfo: UploadProgressInfo, promise: @escaping (Result) -> Void) { + uploadProgressInfo.status = .submissionError + if !networkMonitor.isConnected { + uploadProgressInfo.error = APIError.noInternetConnection + promise(.failure(.noInternetConnection)) + return + } + uploadProgressInfo.error = APIError.unexpectedResponse + promise(.failure(.unexpectedResponse)) + } + + private func mapToAPIError(_ error: Error) -> APIError { + if let apiError = error as? APIError { + return apiError + } + + // Map other error types to APIError + if let nsError = error as NSError? { + switch nsError.code { + case NSURLErrorNotConnectedToInternet, + NSURLErrorNetworkConnectionLost, + NSURLErrorCannotConnectToHost, + NSURLErrorCannotFindHost: + return .noInternetConnection + case NSURLErrorTimedOut: + return networkMonitor.isConnected ? .unexpectedResponse : .noInternetConnection + default: + return .unexpectedResponse + } + } + + return .unexpectedResponse + } } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 75429bb30..b12d64570 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -126,13 +126,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { .receive(on: DispatchQueue.main) .sink( receiveCompletion: { completion in - switch completion { - case .finished: - break - case .failure(let error): - debugLog(error) - self.updateReportStatus(reportStatus: .submissionError) - } + self.handleCompletionForCreateFolder(completion) }, receiveValue: { [weak self] folderId in guard let self = self else { return } @@ -168,15 +162,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { .sink( receiveCompletion: { [weak self] completion in guard let self = self else { return } - switch completion { - case .finished: - // File upload completed successfully - self.uploadQueue.removeFirst() - self.uploadNextFile(folderId: folderId) - case .failure(let error): - debugLog(error) - self.updateReportStatus(reportStatus: .submissionError) - } + handleCompletionForUploadFile(completion, folderId: folderId) }, receiveValue: { [weak self] progressInfo in self?.updateProgressInfos(uploadProgressInfo: progressInfo) @@ -184,6 +170,34 @@ class GDriveOutboxViewModel: OutboxMainViewModel { ) } + private func handleCompletionForUploadFile(_ completion: Subscribers.Completion, folderId: String) { + switch completion { + case .finished: + // File upload completed successfully + self.uploadQueue.removeFirst() + self.uploadNextFile(folderId: folderId) + case .failure( let error): + switch error { + default: + Toast.displayToast(message: error.errorDescription ?? error.localizedDescription) + updateReportStatus(reportStatus: .submissionError) + } + } + } + + private func handleCompletionForCreateFolder(_ completion: Subscribers.Completion) { + switch completion { + case .finished: + break + case .failure( let error): + switch error { + default: + Toast.displayToast(message: error.errorDescription ?? error.localizedDescription) + updateReportStatus(reportStatus: .submissionError) + } + } + } + override func pauseSubmission() { if isSubmissionInProgress { updateReportStatus(reportStatus: .submissionPaused) From e3e9b09e0163858937627d352dab8a7d83b29806 Mon Sep 17 00:00:00 2001 From: Dhekra Rouatbi Date: Tue, 23 Jul 2024 16:34:28 +0100 Subject: [PATCH 099/167] Centralise updateProgressInfos in OutboxMainViewModel --- .../Reports/Outbox/OutboxMainViewModel.swift | 56 +++++++++++- .../Upload/BaseUploadOperation.swift | 9 +- .../ViewModel/GDriveOutboxViewModel.swift | 91 +++++-------------- .../Reports/View Model/OutboxReportVM.swift | 48 +--------- 4 files changed, 86 insertions(+), 118 deletions(-) diff --git a/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift b/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift index 354d754ac..758837e9d 100644 --- a/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift +++ b/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift @@ -10,7 +10,7 @@ import Foundation import Combine class OutboxMainViewModel: ObservableObject { - + var mainAppModel : MainAppModel var reportsViewModel : ReportMainViewModel @@ -96,17 +96,67 @@ class OutboxMainViewModel: ObservableObject { self.shouldShowSubmittedReportView = true } } - + func showMainView() { DispatchQueue.main.async { self.shouldShowMainView = true } } - func updateProgressInfos(uploadProgressInfo : UploadProgressInfo) {} + func updateProgressInfos(uploadProgressInfo : UploadProgressInfo) { + + guard let _ = self.reportViewModel.files.first(where: {$0.id == uploadProgressInfo.fileId}) else { return} + + _ = self.reportViewModel.files.compactMap { _ in + let currentFile = self.reportViewModel.files.first(where: {$0.id == uploadProgressInfo.fileId}) + currentFile?.bytesSent = uploadProgressInfo.bytesSent ?? 0 + currentFile?.status = uploadProgressInfo.status + return currentFile + } + + self.updateFileProgress(progressInfo: uploadProgressInfo) + + // All Files + let totalBytesSent = self.reportViewModel.files.reduce(0) { $0 + ($1.bytesSent)} + let totalSize = self.reportViewModel.files.reduce(0) { $0 + ($1.size)} + + // current file + + guard let currentFileTotalBytesSent = uploadProgressInfo.bytesSent else {return} + + if totalSize > 0 { + + // All Files + let percentUploaded = Float(totalBytesSent) / Float(totalSize) + let formattedPercentUploaded = percentUploaded >= 1.0 ? 1.0 : Float(percentUploaded) + let formattedTotalUploaded = totalBytesSent.getFormattedFileSize().getFileSizeWithoutUnit() + let formattedTotalSize = totalSize.getFormattedFileSize() + + DispatchQueue.main.async { + // Progress Files + self.percentUploadedInfo = "\(Int(formattedPercentUploaded * 100))% uploaded" + self.percentUploaded = Float(formattedPercentUploaded) + self.uploadedFiles = " \(self.reportViewModel.files.count) files, \(formattedTotalUploaded)/\(formattedTotalSize) uploaded" + + //Progress File Item + if let currentItem = self.progressFileItems.first(where: {$0.file.id == uploadProgressInfo.fileId}) { + + let size = currentItem.file.size.getFormattedFileSize() + let currentFileTotalBytesSent = currentFileTotalBytesSent.getFormattedFileSize().getFileSizeWithoutUnit() + + currentItem.progression = "\(currentFileTotalBytesSent)/\(size )" + } + self.objectWillChange.send() + } + } + + } // MARK: Update Local database + func updateFileProgress(progressInfo:UploadProgressInfo) { + + } func updateReportStatus(reportStatus:ReportStatus) {} func deleteReport() {} diff --git a/Tella/Data/Networking/Upload/BaseUploadOperation.swift b/Tella/Data/Networking/Upload/BaseUploadOperation.swift index 777082443..c2c65b5cd 100644 --- a/Tella/Data/Networking/Upload/BaseUploadOperation.swift +++ b/Tella/Data/Networking/Upload/BaseUploadOperation.swift @@ -80,13 +80,18 @@ class BaseUploadOperation : Operation { let file = self.reportVaultFiles?.first(where: {$0.id == progressInfo.fileId}) let instanceId = file?.instanceId - let totalByteSent = self.updateReportFile(fileStatus: progressInfo.status, id: instanceId, bytesSent: progressInfo.bytesSent,current: progressInfo.current) + let totalByteSent = self.updateReportFile(fileStatus: progressInfo.status, id: instanceId, + bytesSent: progressInfo.bytesSent, + current: progressInfo.current) if let _ = progressInfo.error { self.updateReport(reportStatus: .submissionError) } - self.response.send(UploadResponse.progress(progressInfo: UploadProgressInfo(fileId: progressInfo.fileId, status: progressInfo.status, total: totalByteSent, reportStatus: self.report?.status))) + self.response.send(UploadResponse.progress(progressInfo: UploadProgressInfo(bytesSent:totalByteSent, + fileId: progressInfo.fileId, + status: progressInfo.status, + reportStatus: self.report?.status))) if progressInfo.status == .submitted { self.checkAllFilesAreUploaded() diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index b12d64570..40867075e 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -66,44 +66,8 @@ class GDriveOutboxViewModel: OutboxMainViewModel { } } - //tracking progress - override func updateProgressInfos(uploadProgressInfo: UploadProgressInfo) { - if let currentFile = self.reportViewModel.files.first(where: { $0.id == uploadProgressInfo.fileId }) { - currentFile.current = uploadProgressInfo.current ?? 0 - currentFile.bytesSent = uploadProgressInfo.bytesSent ?? 0 - currentFile.status = uploadProgressInfo.status - updateFileProgress(fileId: uploadProgressInfo.fileId ?? "", bytesSent: uploadProgressInfo.bytesSent ?? 0, status: uploadProgressInfo.status) - } - - // All Files - let totalBytesSent = self.reportViewModel.files.reduce(0) { $0 + ($1.bytesSent) } - let totalSize = self.reportViewModel.files.reduce(0) { $0 + ($1.size) } - - if totalSize > 0 { - let percentUploaded = Float(totalBytesSent) / Float(totalSize) - let formattedPercentUploaded = percentUploaded >= 1.0 ? 1.0 : percentUploaded - let formattedTotalUploaded = totalBytesSent.getFormattedFileSize().getFileSizeWithoutUnit() - let formattedTotalSize = totalSize.getFormattedFileSize() - - DispatchQueue.main.async { - - self.percentUploadedInfo = "\(Int(formattedPercentUploaded * 100))% uploaded" - self.percentUploaded = formattedPercentUploaded - self.uploadedFiles = " \(self.reportViewModel.files.count) files, \(formattedTotalUploaded)/\(formattedTotalSize) uploaded" - - if let currentItem = self.progressFileItems.first(where: { $0.file.id == uploadProgressInfo.fileId }) { - let size = currentItem.file.size.getFormattedFileSize() - let currentFileTotalBytesSent = uploadProgressInfo.bytesSent?.getFormattedFileSize().getFileSizeWithoutUnit() ?? "0" - - currentItem.progression = "\(currentFileTotalBytesSent)/\(size)" - } - self.objectWillChange.send() - } - } - } - //submit report - + override func submitReport() { if isSubmissionInProgress == false { self.updateReportStatus(reportStatus: .submissionInProgress) @@ -138,10 +102,10 @@ class GDriveOutboxViewModel: OutboxMainViewModel { } private func uploadFiles(to folderId: String) { - uploadQueue = reportViewModel.files.filter { $0.status != .uploaded } - uploadNextFile(folderId: folderId) - } - + uploadQueue = reportViewModel.files.filter { $0.status != .uploaded } + uploadNextFile(folderId: folderId) + } + private func uploadNextFile(folderId: String) { guard let fileToUpload = uploadQueue.first else { // All files have been uploaded @@ -211,7 +175,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { self.reportViewModel.status = reportStatus guard let id = reportViewModel.id else { return } - + mainAppModel.tellaData?.updateDriveReportStatus(idReport: id, status: reportStatus) } @@ -221,31 +185,26 @@ class GDriveOutboxViewModel: OutboxMainViewModel { mainAppModel.tellaData?.updateDriveFolderId(idReport: id, folderId: folderId) } - private func updateFileProgress(fileId: String, bytesSent: Int, status: FileStatus) { - if let index = reportViewModel.files.firstIndex(where: { $0.id == fileId }) { - reportViewModel.files[index].bytesSent = bytesSent - reportViewModel.files[index].status = status - - let reportFiles = reportViewModel.files.map { file in - return ReportFile( - id: file.instanceId, - fileId: file.id, - status: file.status, - bytesSent: file.bytesSent, - createdDate: file.createdDate - ) - } - - let updatedReport = GDriveReport( - id: reportViewModel.id, - title: reportViewModel.title, - description: reportViewModel.description, - status: reportViewModel.status ?? .submissionInProgress, - vaultFiles: reportFiles + override func updateFileProgress(progressInfo:UploadProgressInfo) { + + let reportFiles = reportViewModel.files.map { file in + return ReportFile( + id: file.instanceId, + fileId: file.id, + status: file.status, + bytesSent: file.bytesSent, + createdDate: file.createdDate ) - - let _ = mainAppModel.tellaData?.updateDriveReport(report: updatedReport) - } + + let updatedReport = GDriveReport( + id: reportViewModel.id, + title: reportViewModel.title, + description: reportViewModel.description, + status: reportViewModel.status ?? .submissionInProgress, + vaultFiles: reportFiles + ) + + let _ = mainAppModel.tellaData?.updateDriveReport(report: updatedReport) } } diff --git a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift index fefda01be..b49e1474a 100644 --- a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift +++ b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift @@ -137,53 +137,7 @@ class OutboxReportVM: OutboxMainViewModel { treat(uploadResponse: self.reportRepository.sendReport(report: report, mainAppModel: mainAppModel)) } } - - override func updateProgressInfos(uploadProgressInfo : UploadProgressInfo) { - - _ = self.reportViewModel.files.compactMap { _ in - let currentFile = self.reportViewModel.files.first(where: {$0.id == uploadProgressInfo.fileId}) - currentFile?.current = uploadProgressInfo.current ?? 0 - return currentFile - } - - guard let _ = self.reportViewModel.files.first(where: {$0.id == uploadProgressInfo.fileId}) else { return} - - // All Files - let totalBytesSent = self.reportViewModel.files.reduce(0) { $0 + ($1.bytesSent)} - let totalSize = self.reportViewModel.files.reduce(0) { $0 + ($1.size)} - - // current file - - if let currentFileTotalBytesSent = uploadProgressInfo.total { - - if totalSize > 0 { - - // All Files - let percentUploaded = Float(totalBytesSent) / Float(totalSize) - let formattedPercentUploaded = percentUploaded >= 1.0 ? 1.0 : Float(percentUploaded) - let formattedTotalUploaded = totalBytesSent.getFormattedFileSize().getFileSizeWithoutUnit() - let formattedTotalSize = totalSize.getFormattedFileSize() - - DispatchQueue.main.async { - // Progress Files - self.percentUploadedInfo = "\(Int(formattedPercentUploaded * 100))% uploaded" - self.percentUploaded = Float(formattedPercentUploaded) - self.uploadedFiles = " \(self.reportViewModel.files.count) files, \(formattedTotalUploaded)/\(formattedTotalSize) uploaded" - - //Progress File Item - if let currentItem = self.progressFileItems.first(where: {$0.file.id == uploadProgressInfo.fileId}) { - - let size = currentItem.file.size.getFormattedFileSize() - let currentFileTotalBytesSent = currentFileTotalBytesSent.getFormattedFileSize().getFileSizeWithoutUnit() - - currentItem.progression = "\(currentFileTotalBytesSent)/\(size )" - } - self.objectWillChange.send() - } - } - } - } - + // MARK: Update Local database override func updateReportStatus(reportStatus:ReportStatus) { From a795694968df4d838eb61e19fe1921e02ac3fd2a Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 23 Jul 2024 13:38:29 -0300 Subject: [PATCH 100/167] fix drive encoding when adding and updating drive reports --- Tella/Data/Database/GDriveDatabase.swift | 105 +++++++----------- .../Entity/CommonReport/BaseReport.swift | 11 ++ Tella/Domain/Entity/GDrive/GDriveReport.swift | 6 + .../ViewModel/GDriveDraftViewModel.swift | 4 +- .../ViewModel/GDriveOutboxViewModel.swift | 6 +- 5 files changed, 65 insertions(+), 67 deletions(-) diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index d3707639d..41d4f509c 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -90,25 +90,16 @@ extension TellaDataBase { func addGDriveReport(report: GDriveReport) -> Result { do { - let reportValuesToAdd = [KeyValue(key: D.cTitle, value: report.title), - KeyValue(key: D.cDescription, value: report.description), - KeyValue(key: D.cCreatedDate, value: Date().getDateDouble()), - KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()), - KeyValue(key: D.cStatus, value: report.status.rawValue), - KeyValue(key: D.cFolderId, value: report.folderId), - KeyValue(key: D.cServerId, value: report.server?.id)] - - let reportId = try statementBuilder.insertInto(tableName: D.tGDriveReport, keyValue: reportValuesToAdd) - - try report.reportFiles?.forEach( { reportFile in - let reportFileValuesToAdd = [KeyValue(key: D.cReportInstanceId, value: reportId), - KeyValue(key: D.cVaultFileInstanceId, value: reportFile.fileId), - KeyValue(key: D.cStatus, value: reportFile.status?.rawValue), - KeyValue(key: D.cBytesSent, value: 0), - KeyValue(key: D.cCreatedDate, value: Date().getDateDouble()), - KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble())] + let reportDict = report.dictionary + let valuesToAdd = reportDict.compactMap({ KeyValue(key: $0.key, value: $0.value) }) + let reportId = try statementBuilder.insertInto(tableName: D.tGDriveReport, keyValue: valuesToAdd) + + _ = report.reportFiles?.compactMap({ $0.reportInstanceId = reportId }) + try report.reportFiles?.forEach( { reportFiles in + let reportFilesDictionary = reportFiles.dictionary + let reportFilesValuesToAdd = reportFilesDictionary.compactMap({KeyValue(key: $0.key, value: $0.value)}) - try statementBuilder.insertInto(tableName: D.tGDriveInstanceVaultFile, keyValue: reportFileValuesToAdd) + try statementBuilder.insertInto(tableName: D.tGDriveInstanceVaultFile, keyValue: reportFilesValuesToAdd) }) return .success(reportId) @@ -119,6 +110,38 @@ extension TellaDataBase { } } + func updateDriveReport(report: GDriveReport) -> Result { + do { + + let reportDict = report.dictionary + let valuesToUpdate = reportDict.compactMap({ KeyValue(key: $0.key, value: $0.value) }) + let reportCondition = [KeyValue(key: D.cId, value: report.id)] + + try statementBuilder.update( + tableName: D.tGDriveReport, + valuesToUpdate: valuesToUpdate, + equalCondition: reportCondition + ) + + if let files = report.reportFiles { + let reportFilesCondition = [KeyValue(key: D.cReportInstanceId, value: report.id)] + + try statementBuilder.delete(tableName: D.tGDriveInstanceVaultFile, primarykeyValue: reportFilesCondition) + + try files.forEach( { reportFiles in + let reportFilesDict = reportFiles.dictionary + let reportFilesValuesToAdd = reportFilesDict.compactMap({ KeyValue( key: $0.key, value: $0.value) }) + + try statementBuilder.insertInto(tableName: D.tGDriveInstanceVaultFile, keyValue: reportFilesValuesToAdd) + }) + } + return .success(true) + } catch let error { + debugLog(error) + return .failure(error) + } + } + func getDriveReports(reportStatus: [ReportStatus]) -> [GDriveReport] { do { @@ -131,7 +154,7 @@ extension TellaDataBase { let decodedReports = try gDriveReportsDict.compactMap ({ dict in return try dict.decode(GDriveReport.self) }) - + return decodedReports } catch let error { @@ -146,7 +169,6 @@ extension TellaDataBase { let gDriveReportsDict = try statementBuilder.getSelectQuery(tableName: D.tGDriveReport, equalCondition: reportsCondition ) - let decodedReports = try gDriveReportsDict.first?.decode(GDriveReport.self) let reportFiles = getDriveVaultFiles(reportId: decodedReports?.id) decodedReports?.reportFiles = reportFiles @@ -174,48 +196,6 @@ extension TellaDataBase { } } - func updateDriveReport(report: GDriveReport) -> Result { - do { - - let valuesToUpdate = [ KeyValue(key: D.cTitle, value: report.title), - KeyValue(key: D.cDescription, value: report.description), - KeyValue(key: D.cStatus, value: report.status.rawValue), - KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()), - ] - let reportCondition = [KeyValue(key: D.cId, value: report.id)] - - try statementBuilder.update( - tableName: D.tGDriveReport, - valuesToUpdate: valuesToUpdate, - equalCondition: reportCondition - ) - - if let files = report.reportFiles { - let reportFilesCondition = [KeyValue(key: D.cReportInstanceId, value: report.id)] - - try statementBuilder.delete(tableName: D.tGDriveInstanceVaultFile, primarykeyValue: reportFilesCondition) - - try files.forEach( { reportFile in - let reportFilesValuesToAdd = [ - reportFile.id == nil ? nil : KeyValue(key: D.cId, value: reportFile.id), - KeyValue(key: D.cReportInstanceId, value: report.id), - KeyValue(key: D.cVaultFileInstanceId, value: reportFile.fileId), - KeyValue(key: D.cStatus, value: reportFile.status?.rawValue), - KeyValue(key: D.cBytesSent, value: reportFile.bytesSent), - KeyValue(key: D.cCreatedDate, value: reportFile.createdDate?.getDateDouble()), - KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()), - ] - - try statementBuilder.insertInto(tableName: D.tGDriveInstanceVaultFile, keyValue: reportFilesValuesToAdd) - }) - } - return .success(true) - } catch let error { - debugLog(error) - return .failure(error) - } - } - func deleteDriveReport(reportId: Int?) -> Result { do { let reportCondition = [KeyValue(key: D.cId, value: reportId)] @@ -252,7 +232,6 @@ extension TellaDataBase { let valuesToUpdate = [KeyValue(key: D.cFolderId, value: folderId), KeyValue(key: D.cUpdatedDate, value: Date().getDateDouble()) ] - let reportCondition = [KeyValue(key: D.cId, value: idReport)] try statementBuilder.update(tableName: D.tGDriveReport, valuesToUpdate: valuesToUpdate, equalCondition: reportCondition) diff --git a/Tella/Domain/Entity/CommonReport/BaseReport.swift b/Tella/Domain/Entity/CommonReport/BaseReport.swift index a178ebd5a..ac18f3d56 100644 --- a/Tella/Domain/Entity/CommonReport/BaseReport.swift +++ b/Tella/Domain/Entity/CommonReport/BaseReport.swift @@ -59,6 +59,17 @@ class BaseReport : Hashable, Codable, BaseReportProtocol { } + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try container.encode(title, forKey: .title) + try container.encode(description, forKey: .description) + try container.encode(createdDate?.getDateDouble() ?? Date().getDateDouble(), forKey: .createdDate) + try container.encode(updatedDate?.getDateDouble() ?? Date().getDateDouble(), forKey: .updatedDate) + try container.encode(status.rawValue, forKey: .status) + try container.encode(serverId, forKey: .serverId) + } + static func == (lhs: BaseReport, rhs: BaseReport) -> Bool { lhs.id == rhs.id } diff --git a/Tella/Domain/Entity/GDrive/GDriveReport.swift b/Tella/Domain/Entity/GDrive/GDriveReport.swift index 8d1651e4e..ead32f4f6 100644 --- a/Tella/Domain/Entity/GDrive/GDriveReport.swift +++ b/Tella/Domain/Entity/GDrive/GDriveReport.swift @@ -37,6 +37,12 @@ class GDriveReport: BaseReport { vaultFiles: vaultFiles) } + override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(folderId, forKey: .folderId) + } + required init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.folderId = try container.decodeIfPresent(String.self, forKey: .folderId) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index a50f8602d..86bd512bf 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -52,10 +52,12 @@ class GDriveDraftViewModel: DraftMainViewModel { description: description, status: status ?? .unknown, server: server, + folderId: nil, vaultFiles: self.files.compactMap { ReportFile( fileId: $0.id, status: .notSubmitted, bytesSent: 0, - createdDate: Date())} + createdDate: Date(), + reportInstanceId: reportId)} ) reportId == nil ? addReport(report: gDriveReport) : updateReport(report: gDriveReport) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index b12d64570..25350ab83 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -37,7 +37,6 @@ class GDriveOutboxViewModel: OutboxMainViewModel { private func getServer() { self.server = mainAppModel.tellaData?.gDriveServers.value.first - dump(server?.rootFolder) } @@ -117,7 +116,6 @@ class GDriveOutboxViewModel: OutboxMainViewModel { } func createDriveFolder() { - dump(reportViewModel.server?.rootFolder) gDriveRepository.createDriveFolder( folderName: reportViewModel.title, parentId: reportViewModel.server?.rootFolder, @@ -232,7 +230,8 @@ class GDriveOutboxViewModel: OutboxMainViewModel { fileId: file.id, status: file.status, bytesSent: file.bytesSent, - createdDate: file.createdDate + createdDate: file.createdDate, + reportInstanceId: reportViewModel.id ) } @@ -241,6 +240,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { title: reportViewModel.title, description: reportViewModel.description, status: reportViewModel.status ?? .submissionInProgress, + folderId: reportViewModel.folderId, vaultFiles: reportFiles ) From b1f63ba879126dd18157122ad45cd0c3ec63d25e Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 23 Jul 2024 17:11:24 -0300 Subject: [PATCH 101/167] only update files when tracking progress --- Tella/Data/Database/GDriveData.swift | 15 +++++--- Tella/Data/Database/GDriveDatabase.swift | 34 +++++++++++++------ .../ViewModel/GDriveOutboxViewModel.swift | 18 ++++------ 3 files changed, 40 insertions(+), 27 deletions(-) diff --git a/Tella/Data/Database/GDriveData.swift b/Tella/Data/Database/GDriveData.swift index 311b65b7d..cb3037edf 100644 --- a/Tella/Data/Database/GDriveData.swift +++ b/Tella/Data/Database/GDriveData.swift @@ -50,16 +50,23 @@ extension TellaData { } @discardableResult - func updateDriveReportStatus(idReport: Int, status: ReportStatus) -> Result { + func updateDriveReportStatus(reportId: Int, status: ReportStatus) -> Result { shouldReloadGDriveReports.send(true) - return self.database.updateDriveReportStatus(idReport: idReport, status: status) + return self.database.updateDriveReportStatus(idReport: reportId, status: status) } @discardableResult - func updateDriveFolderId(idReport: Int, folderId: String) -> Result { + func updateDriveFolderId(reportId: Int, folderId: String) -> Result { shouldReloadGDriveReports.send(true) - return self.database.updateDriveReportFolderId(idReport: idReport, folderId: folderId) + return self.database.updateDriveReportFolderId(idReport: reportId, folderId: folderId) + } + + @discardableResult + func updateDriveFiles(reportId: Int, files: [ReportFile]) -> Result { + shouldReloadGDriveReports.send(true) + + return self.database.updateDriveReportFiles(files: files, reportId: reportId) } } diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index 41d4f509c..fc5dd7b64 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -123,17 +123,8 @@ extension TellaDataBase { equalCondition: reportCondition ) - if let files = report.reportFiles { - let reportFilesCondition = [KeyValue(key: D.cReportInstanceId, value: report.id)] - - try statementBuilder.delete(tableName: D.tGDriveInstanceVaultFile, primarykeyValue: reportFilesCondition) - - try files.forEach( { reportFiles in - let reportFilesDict = reportFiles.dictionary - let reportFilesValuesToAdd = reportFilesDict.compactMap({ KeyValue( key: $0.key, value: $0.value) }) - - try statementBuilder.insertInto(tableName: D.tGDriveInstanceVaultFile, keyValue: reportFilesValuesToAdd) - }) + if let files = report.reportFiles, let reportId = report.id { + let _ = try updateDriveReportFiles(files: files, reportId: reportId) } return .success(true) } catch let error { @@ -142,6 +133,27 @@ extension TellaDataBase { } } + func updateDriveReportFiles(files: [ReportFile], reportId: Int) -> Result { + dump("update") + do { + let reportFilesCondition = [KeyValue(key: D.cReportInstanceId, value: reportId)] + + try statementBuilder.delete(tableName: D.tGDriveInstanceVaultFile, primarykeyValue: reportFilesCondition) + + try files.forEach( { reportFiles in + let reportFilesDict = reportFiles.dictionary + let reportFilesValuesToAdd = reportFilesDict.compactMap({ KeyValue( key: $0.key, value: $0.value) }) + + try statementBuilder.insertInto(tableName: D.tGDriveInstanceVaultFile, keyValue: reportFilesValuesToAdd) + }) + + return .success(true) + } catch let error { + debugLog(error) + return .failure(error) + } + } + func getDriveReports(reportStatus: [ReportStatus]) -> [GDriveReport] { do { diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index fff8fbc2a..d5bb55404 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -174,16 +174,17 @@ class GDriveOutboxViewModel: OutboxMainViewModel { guard let id = reportViewModel.id else { return } - mainAppModel.tellaData?.updateDriveReportStatus(idReport: id, status: reportStatus) + mainAppModel.tellaData?.updateDriveReportStatus(reportId: id, status: reportStatus) } private func updateReportFolderId(folderId: String) { guard let id = reportViewModel.id else { return } - mainAppModel.tellaData?.updateDriveFolderId(idReport: id, folderId: folderId) + mainAppModel.tellaData?.updateDriveFolderId(reportId: id, folderId: folderId) } override func updateFileProgress(progressInfo:UploadProgressInfo) { + guard let reportId = reportViewModel.id else { return } let reportFiles = reportViewModel.files.map { file in return ReportFile( @@ -191,18 +192,11 @@ class GDriveOutboxViewModel: OutboxMainViewModel { fileId: file.id, status: file.status, bytesSent: file.bytesSent, - createdDate: file.createdDate + createdDate: file.createdDate, + reportInstanceId: reportViewModel.id ) } - let updatedReport = GDriveReport( - id: reportViewModel.id, - title: reportViewModel.title, - description: reportViewModel.description, - status: reportViewModel.status ?? .submissionInProgress, - vaultFiles: reportFiles - ) - - let _ = mainAppModel.tellaData?.updateDriveReport(report: updatedReport) + let _ = mainAppModel.tellaData?.updateDriveFiles(reportId: reportId, files: reportFiles) } } From 2065762b9820835dbd13cf21cb2978a6df5a110e Mon Sep 17 00:00:00 2001 From: Dhekra Rouatbi Date: Wed, 24 Jul 2024 11:54:18 +0100 Subject: [PATCH 102/167] Remove unused code --- .../Components/Reports/Submitted/SubmittedMainViewModel.swift | 2 +- Tella/Scenes/GDrive/ViewModel/GDriveSubmittedViewModel.swift | 4 ++-- Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift | 4 ++-- Tella/Scenes/Reports/View Model/SubmittedReportVM.swift | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Tella/Components/Reports/Submitted/SubmittedMainViewModel.swift b/Tella/Components/Reports/Submitted/SubmittedMainViewModel.swift index ee18e8e4e..54ed85a22 100644 --- a/Tella/Components/Reports/Submitted/SubmittedMainViewModel.swift +++ b/Tella/Components/Reports/Submitted/SubmittedMainViewModel.swift @@ -30,7 +30,7 @@ class SubmittedMainViewModel: ObservableObject { return !description.isEmpty } - init(mainAppModel: MainAppModel, shouldStartUpload: Bool = false, reportId: Int?) { + init(mainAppModel: MainAppModel, reportId: Int?) { self.mainAppModel = mainAppModel fillReportVM(reportId: reportId) } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveSubmittedViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveSubmittedViewModel.swift index 6109179c4..bbde984e6 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveSubmittedViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveSubmittedViewModel.swift @@ -9,8 +9,8 @@ import Foundation class GDriveSubmittedViewModel: SubmittedMainViewModel { - override init(mainAppModel: MainAppModel, shouldStartUpload: Bool = false, reportId: Int?) { - super.init(mainAppModel: mainAppModel, shouldStartUpload: shouldStartUpload, reportId: reportId) + override init(mainAppModel: MainAppModel, reportId: Int?) { + super.init(mainAppModel: mainAppModel, reportId: reportId) fillReportVM(reportId: reportId) } diff --git a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift index b0e2281c8..f50879856 100644 --- a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift +++ b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift @@ -178,10 +178,10 @@ struct OutboxDetailsView: View { Group { switch reportsViewModel.connectionType { case .tella: - let vm = SubmittedReportVM(mainAppModel: mainAppModel, shouldStartUpload: true, reportId: outboxReportVM.reportViewModel.id) + let vm = SubmittedReportVM(mainAppModel: mainAppModel, reportId: outboxReportVM.reportViewModel.id) SubmittedDetailsView(submittedReportVM: vm).environmentObject(reportsViewModel) case .gDrive: - let vm = GDriveSubmittedViewModel(mainAppModel: mainAppModel, shouldStartUpload: true, reportId: outboxReportVM.reportViewModel.id) + let vm = GDriveSubmittedViewModel(mainAppModel: mainAppModel, reportId: outboxReportVM.reportViewModel.id) SubmittedDetailsView(submittedReportVM: vm).environmentObject(reportsViewModel) default: Text("") diff --git a/Tella/Scenes/Reports/View Model/SubmittedReportVM.swift b/Tella/Scenes/Reports/View Model/SubmittedReportVM.swift index 416aba5e2..9c27ae994 100644 --- a/Tella/Scenes/Reports/View Model/SubmittedReportVM.swift +++ b/Tella/Scenes/Reports/View Model/SubmittedReportVM.swift @@ -7,8 +7,8 @@ import Combine class SubmittedReportVM: SubmittedMainViewModel { - override init(mainAppModel: MainAppModel, shouldStartUpload: Bool = false, reportId: Int?) { - super.init(mainAppModel: mainAppModel, shouldStartUpload: shouldStartUpload, reportId: reportId) + override init(mainAppModel: MainAppModel, reportId: Int?) { + super.init(mainAppModel: mainAppModel, reportId: reportId) fillReportVM(reportId: reportId) } From ab3b04154200ada0bc7114e27ca7852de24e346a Mon Sep 17 00:00:00 2001 From: Dhekra Rouatbi Date: Wed, 24 Jul 2024 13:24:57 +0100 Subject: [PATCH 103/167] Centralise fillReportVM function in SubmittedMainViewModel class --- .../Submitted/SubmittedMainViewModel.swift | 35 +++++++++++++++++-- Tella/Data/Database/GDriveData.swift | 5 +-- Tella/Data/Database/TellaData.swift | 3 +- .../ViewModel/GDriveSubmittedViewModel.swift | 26 +++----------- .../View Model/SubmittedReportVM.swift | 33 ++--------------- 5 files changed, 44 insertions(+), 58 deletions(-) diff --git a/Tella/Components/Reports/Submitted/SubmittedMainViewModel.swift b/Tella/Components/Reports/Submitted/SubmittedMainViewModel.swift index 54ed85a22..9d6629732 100644 --- a/Tella/Components/Reports/Submitted/SubmittedMainViewModel.swift +++ b/Tella/Components/Reports/Submitted/SubmittedMainViewModel.swift @@ -12,6 +12,9 @@ class SubmittedMainViewModel: ObservableObject { var mainAppModel : MainAppModel + var report: BaseReport? { + return nil + } // Report @Published var id : Int? @Published var title : String = "" @@ -34,8 +37,34 @@ class SubmittedMainViewModel: ObservableObject { self.mainAppModel = mainAppModel fillReportVM(reportId: reportId) } - - func fillReportVM(reportId:Int?) {} - + + func fillReportVM(reportId: Int?) { + + guard let reportId else {return} + self.id = reportId + + guard let report else {return} + + self.id = report.id + self.title = report.title ?? "" + self.description = report.description ?? "" + + let vaultFileResult = mainAppModel.vaultFilesManager?.getVaultFiles(ids: report.reportFiles?.compactMap{$0.fileId} ?? []) ?? [] + self.files = Array(vaultFileResult) + + // todo -> progress bar + progressFileItems = self.files.compactMap{ProgressFileItemViewModel(file: $0, progression:$0.size.getFormattedFileSize() + "/" + $0.size.getFormattedFileSize())} + let totalSize = self.files.reduce(0) { $0 + $1.size } + + if let date = report.createdDate { + self.uploadedDate = "Uploaded on \(date.getFormattedDateString(format: DateFormat.submittedReport.rawValue))" + } + + let fileNumber = self.files.count + let fileString = fileNumber == 1 ? "file" : "files" + self.uploadedFiles = "\(fileNumber) \(fileString), \(totalSize.getFormattedFileSize())" + + } + func deleteReport() {} } diff --git a/Tella/Data/Database/GDriveData.swift b/Tella/Data/Database/GDriveData.swift index cb3037edf..0d897d847 100644 --- a/Tella/Data/Database/GDriveData.swift +++ b/Tella/Data/Database/GDriveData.swift @@ -35,8 +35,9 @@ extension TellaData { return self.database.getDriveReports(reportStatus: [ReportStatus.submitted]) } - func getDriveReport(id: Int) -> GDriveReport? { - self.database.getGDriveReport(id: id) + func getDriveReport(id: Int?) -> GDriveReport? { + guard let id else { return nil } + return self.database.getGDriveReport(id: id) } func updateDriveReport(report: GDriveReport) -> Result { diff --git a/Tella/Data/Database/TellaData.swift b/Tella/Data/Database/TellaData.swift index 1d8298e4e..286382e71 100644 --- a/Tella/Data/Database/TellaData.swift +++ b/Tella/Data/Database/TellaData.swift @@ -165,7 +165,8 @@ class TellaData : ObservableObject { return database.getReports(reportStatus: [ReportStatus.submitted]) } - func getReport(reportId: Int) -> Report? { + func getReport(reportId: Int?) -> Report? { + guard let reportId else { return nil } return database.getReport(reportId: reportId) } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveSubmittedViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveSubmittedViewModel.swift index bbde984e6..b71253ee5 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveSubmittedViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveSubmittedViewModel.swift @@ -9,34 +9,16 @@ import Foundation class GDriveSubmittedViewModel: SubmittedMainViewModel { + override init(mainAppModel: MainAppModel, reportId: Int?) { super.init(mainAppModel: mainAppModel, reportId: reportId) fillReportVM(reportId: reportId) } - override func fillReportVM(reportId: Int?) { - if let reportId, let report = self.mainAppModel.tellaData?.getDriveReport(id: reportId) { - self.id = report.id - self.title = report.title ?? "" - self.description = report.description ?? "" - - let vaultFileResult = mainAppModel.vaultFilesManager?.getVaultFiles(ids: report.reportFiles?.compactMap{$0.fileId} ?? []) ?? [] - self.files = Array(vaultFileResult) - - // todo -> progress bar - progressFileItems = self.files.compactMap{ProgressFileItemViewModel(file: $0, progression:$0.size.getFormattedFileSize() + "/" + $0.size.getFormattedFileSize())} - let totalSize = self.files.reduce(0) { $0 + $1.size } - - if let date = report.createdDate { - self.uploadedDate = "Uploaded on \(date.getFormattedDateString(format: DateFormat.submittedReport.rawValue))" - } - - let fileNumber = self.files.count - let fileString = fileNumber == 1 ? "file" : "files" - self.uploadedFiles = "\(fileNumber) \(fileString), \(totalSize.getFormattedFileSize())" - } + override var report: BaseReport? { + self.mainAppModel.tellaData?.getDriveReport(id: self.id) } - + override func deleteReport() { let _ = mainAppModel.tellaData?.deleteDriveReport(reportId: id) } diff --git a/Tella/Scenes/Reports/View Model/SubmittedReportVM.swift b/Tella/Scenes/Reports/View Model/SubmittedReportVM.swift index 9c27ae994..72193e608 100644 --- a/Tella/Scenes/Reports/View Model/SubmittedReportVM.swift +++ b/Tella/Scenes/Reports/View Model/SubmittedReportVM.swift @@ -6,41 +6,14 @@ import Foundation import Combine class SubmittedReportVM: SubmittedMainViewModel { - + override init(mainAppModel: MainAppModel, reportId: Int?) { super.init(mainAppModel: mainAppModel, reportId: reportId) fillReportVM(reportId: reportId) } - override func fillReportVM(reportId:Int?) { - - if let reportId ,let report = self.mainAppModel.tellaData?.getReport(reportId: reportId) { - - // Init file -// var vaultFileResult : Set = [] - - self.id = report.id - self.title = report.title ?? "" - self.description = report.description ?? "" - - let vaultFileResult = mainAppModel.vaultFilesManager?.getVaultFiles(ids: report.reportFiles?.compactMap{$0.fileId} ?? []) ?? [] - - self.files = Array(vaultFileResult) - - // Initialize progression Infos - progressFileItems = self.files.compactMap{ProgressFileItemViewModel(file: $0, progression:$0.size.getFormattedFileSize() + "/" + $0.size.getFormattedFileSize())} - let totalSize = self.files.reduce(0) { $0 + $1.size} - - // Display "Uploaded on 12.10.2021, 3:45 AM" - if let date = report.createdDate { - self.uploadedDate = "Uploaded on \(date.getFormattedDateString(format: DateFormat.submittedReport.rawValue))" - } - - // Display 11 files, 89MB - let fileNumber = self.files.count - let fileString = fileNumber == 1 ? "file" : "files" - self.uploadedFiles = "\(fileNumber) \(fileString), \(totalSize.getFormattedFileSize())" - } + override var report: BaseReport? { + self.mainAppModel.tellaData?.getReport(reportId: self.id) } override func deleteReport() { From a29d4d5ae7a605e4f968fc14b41323797d9254dc Mon Sep 17 00:00:00 2001 From: Dhekra Rouatbi Date: Wed, 24 Jul 2024 14:47:02 +0100 Subject: [PATCH 104/167] Refactor code to start uploading report from draft --- Tella/Components/Reports/Draft/DraftView.swift | 4 ++-- .../Reports/Outbox/OutboxMainViewModel.swift | 7 ++++++- .../GDrive/ViewModel/GDriveOutboxViewModel.swift | 13 ++++--------- .../Scenes/Reports/View Model/OutboxReportVM.swift | 8 ++------ 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/Tella/Components/Reports/Draft/DraftView.swift b/Tella/Components/Reports/Draft/DraftView.swift index f17e3571a..676c00399 100644 --- a/Tella/Components/Reports/Draft/DraftView.swift +++ b/Tella/Components/Reports/Draft/DraftView.swift @@ -196,10 +196,10 @@ struct DraftView: View { Group { switch reportsViewModel.connectionType { case .tella: - let outboxVM = OutboxReportVM(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: viewModel.reportId, shouldStartUpload: true) + let outboxVM = OutboxReportVM(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: viewModel.reportId) OutboxDetailsView(outboxReportVM: outboxVM).environmentObject(reportsViewModel) case .gDrive: - let outboxVM = GDriveOutboxViewModel(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: viewModel.reportId, repository: GDriveRepository(), shouldStartUpload: true) + let outboxVM = GDriveOutboxViewModel(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: viewModel.reportId, repository: GDriveRepository()) OutboxDetailsView(outboxReportVM: outboxVM).environmentObject(reportsViewModel) default: Text("") diff --git a/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift b/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift index 758837e9d..d0953a435 100644 --- a/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift +++ b/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift @@ -52,9 +52,14 @@ class OutboxMainViewModel: ObservableObject { } - init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, reportId : Int?, shouldStartUpload: Bool = false) { + init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, reportId : Int?) { self.mainAppModel = mainAppModel self.reportsViewModel = reportsViewModel + + initVaultFile(reportId: reportId) + + initializeProgressionInfos() + } func initVaultFile(reportId: Int?) {} diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index d5bb55404..69c6cdbd4 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -18,20 +18,15 @@ class GDriveOutboxViewModel: OutboxMainViewModel { init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, reportId : Int?, - repository: GDriveRepository, - shouldStartUpload: Bool = false - ) { + repository: GDriveRepository) { + self.gDriveRepository = repository super.init(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: reportId) getServer() - initVaultFile(reportId: reportId) - initializeProgressionInfos() - - if shouldStartUpload { + + if reportViewModel.status == .submissionScheduled { self.submitReport() - } else { - updateReportStatus(reportStatus: .submissionPaused) } } diff --git a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift index b49e1474a..04713cdf6 100644 --- a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift +++ b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift @@ -12,15 +12,11 @@ class OutboxReportVM: OutboxMainViewModel { return !(reportViewModel.server?.autoDelete ?? true) } - override init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, reportId : Int?, shouldStartUpload: Bool = false) { + override init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, reportId : Int?) { super.init(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: reportId) - initVaultFile(reportId: reportId) - - initializeProgressionInfos() - - if shouldStartUpload { + if reportViewModel.status == .submissionScheduled { self.submitReport() } else { treat(uploadResponse:reportRepository.checkUploadReportOperation(reportId: self.reportViewModel.id)) From ee6952722952b3dc74251bc6ce1e9836ce08f58f Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 25 Jul 2024 17:40:36 -0300 Subject: [PATCH 105/167] fix duplicated files issue in shared drive and fix some bugs --- Tella/Data/Database/GDriveDatabase.swift | 1 - Tella/Data/Networking/Repositories/GDriveRepository.swift | 2 ++ Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift | 5 ++--- .../Settings/Views/Servers/GDrive/SelectSharedDrive.swift | 7 ++++++- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index fc5dd7b64..ee2ef1d19 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -134,7 +134,6 @@ extension TellaDataBase { } func updateDriveReportFiles(files: [ReportFile], reportId: Int) -> Result { - dump("update") do { let reportFilesCondition = [KeyValue(key: D.cReportInstanceId, value: reportId)] diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 6afaa08f3..1e1849d98 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -357,6 +357,8 @@ class GDriveRepository: GDriveRepositoryProtocol { let query = GTLRDriveQuery_FilesList.query() query.q = "name = '\(fileName)' and '\(folderId)' in parents and trashed = false" query.fields = "files(id, name)" + query.includeItemsFromAllDrives = true + query.supportsAllDrives = true driveService.executeQuery(query) { (_, response, error) in if let error = error { diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 69c6cdbd4..2dd169f94 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -22,8 +22,6 @@ class GDriveOutboxViewModel: OutboxMainViewModel { self.gDriveRepository = repository super.init(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: reportId) - - getServer() if reportViewModel.status == .submissionScheduled { self.submitReport() @@ -34,8 +32,9 @@ class GDriveOutboxViewModel: OutboxMainViewModel { self.server = mainAppModel.tellaData?.gDriveServers.value.first } - override func initVaultFile(reportId: Int?) { + getServer() + if let reportId, let report = self.mainAppModel.tellaData?.getDriveReport(id: reportId) { let vaultFileResult = mainAppModel.vaultFilesManager?.getVaultFiles(ids: report.reportFiles?.compactMap{$0.fileId} ?? []) diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index edd978268..c925a3e95 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -11,6 +11,7 @@ import GoogleAPIClientForREST struct SelectSharedDrive: View { @EnvironmentObject var gDriveServerViewModel: GDriveServerViewModel + @Environment(\.presentationMode) var presentationMode: Binding var body: some View { ContainerView { VStack(alignment: .leading){ @@ -59,7 +60,11 @@ struct SelectSharedDrive: View { } func backButtonAction() -> Void { - gDriveServerViewModel.addServer(rootFolder: gDriveServerViewModel.selectedDrive?.id ?? "") { + guard let selectedDrive = gDriveServerViewModel.selectedDrive else { + presentationMode.wrappedValue.dismiss() + return + } + gDriveServerViewModel.addServer(rootFolder: selectedDrive.id) { navigateTo(destination: SuccessLoginView(navigateToAction: {self.popToRoot()}, type: .gDrive)) } } From cf04bee55d4a0581a3aeb4cdeabe845a1655bb76 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 25 Jul 2024 17:57:51 -0300 Subject: [PATCH 106/167] remove everything related to drive server after deleting the connection --- Tella/Data/Database/GDriveDatabase.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index ee2ef1d19..5221134dc 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -49,6 +49,7 @@ extension TellaDataBase { do { try statementBuilder.delete(tableName: D.tGDriveServer, primarykeyValue: [KeyValue(key: D.cId, value: serverId)]) + try statementBuilder.deleteAll(tableNames: [D.tGDriveReport, D.tGDriveInstanceVaultFile]) } catch let error { debugLog(error) } From bcf2792d052fd69f4a79b3b07c342db5296faafc Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 26 Jul 2024 16:56:03 -0300 Subject: [PATCH 107/167] fix UI errors --- Tella.xcodeproj/project.pbxproj | 4 - .../ViewModels/CommonCardViewModel.swift | 14 ++ .../ViewModels/ReportCardViewModel.swift | 1 + .../Views/CommonReportListView.swift | 2 +- .../ViewModel/GDriveOutboxViewModel.swift | 3 - Tella/Scenes/Reports/ReportsView.swift | 124 ------------------ .../Views/EntityInstances/UwaziListView.swift | 2 +- 7 files changed, 17 insertions(+), 133 deletions(-) delete mode 100644 Tella/Scenes/Reports/ReportsView.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 967460730..c22c658ac 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 0807BE8AD7991EBCC67BBF58 /* libPods-Tella-TellaUITests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83BA47B1A745C8D086B482FE /* libPods-Tella-TellaUITests.a */; }; - 0D4BC3C5267577F900DCDC30 /* ReportsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D4BC3C1267577F900DCDC30 /* ReportsView.swift */; }; 0D4BC3CE267668D600DCDC30 /* AddFileYellowButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D4BC3CD267668D600DCDC30 /* AddFileYellowButton.swift */; }; 0D4D7518266470A700D7A635 /* SettingToggleItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D4D7517266470A700D7A635 /* SettingToggleItem.swift */; }; 0DA213C72680286F00526995 /* FileListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DA213C62680286F00526995 /* FileListItem.swift */; }; @@ -580,7 +579,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 0D4BC3C1267577F900DCDC30 /* ReportsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReportsView.swift; sourceTree = ""; }; 0D4BC3CB26765B8C00DCDC30 /* ModelStubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelStubs.swift; sourceTree = ""; }; 0D4BC3CD267668D600DCDC30 /* AddFileYellowButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFileYellowButton.swift; sourceTree = ""; }; 0D4D7517266470A700D7A635 /* SettingToggleItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingToggleItem.swift; sourceTree = ""; }; @@ -1174,7 +1172,6 @@ 0D4BC3BE2675737F00DCDC30 /* Reports */ = { isa = PBXGroup; children = ( - 0D4BC3C1267577F900DCDC30 /* ReportsView.swift */, 126FEE082AC4992800B99298 /* Models */, 121C945C28FF3D6900570EB4 /* Draft */, 12199C322940936B0041BD38 /* Outbox */, @@ -3602,7 +3599,6 @@ 1202D9582BF4CFF200EAFAB3 /* SelectValues.swift in Sources */, 1268554027D2994500385E18 /* VaultFileStatus.swift in Sources */, 155541B02C066F990031D3A5 /* ServerConnectionButton.swift in Sources */, - 0D4BC3C5267577F900DCDC30 /* ReportsView.swift in Sources */, 12776A9027BA742700CDC5DC /* CameraControlsView.swift in Sources */, 128D6E1A28045C090082AB18 /* ManageFileType.swift in Sources */, CC5DF8782B02B06A0068F622 /* UwaziServer.swift in Sources */, diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift index 714d317da..bee20bba8 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/CommonCardViewModel.swift @@ -14,6 +14,7 @@ class CommonCardViewModel: Hashable { var title: String var iconImageName: String? var serverName: String? + var updatedAt: String? var listActionSheetItem: [ListActionSheetItem] var connectionType: ServerConnectionType var deleteReportStrings : ConfirmDeleteConnectionStrings @@ -23,6 +24,7 @@ class CommonCardViewModel: Hashable { title: String, iconImageName: String?, serverName: String?, + updatedAt: String? = nil, listActionSheetItem: [ListActionSheetItem], connectionType: ServerConnectionType, deleteReportStrings: ConfirmDeleteConnectionStrings, @@ -32,6 +34,7 @@ class CommonCardViewModel: Hashable { self.title = title self.iconImageName = iconImageName self.serverName = serverName + self.updatedAt = updatedAt self.listActionSheetItem = listActionSheetItem self.connectionType = connectionType self.deleteReportStrings = deleteReportStrings @@ -47,3 +50,14 @@ class CommonCardViewModel: Hashable { } } + +extension CommonCardViewModel { + var subtitle: String { + switch connectionType { + case .uwazi: + return self.serverName ?? "" + default: + return self.updatedAt ?? "" + } + } +} diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift index 537743ab1..99cb3a72f 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportCardViewModel.swift @@ -29,6 +29,7 @@ class ReportCardViewModel: CommonCardViewModel { title: title, iconImageName: iconImageName, serverName: serverName, + updatedAt: report.updatedDate?.getDraftReportTime(), listActionSheetItem: listActionSheetItem, connectionType: connectionType, deleteReportStrings: deleteReportStrings, diff --git a/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift b/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift index 12c489a2e..e1621db39 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift @@ -70,7 +70,7 @@ struct CommonItemView: View { } ConnectionCardDetails(title: cardViewModel.title, - subtitle: cardViewModel.serverName) + subtitle: cardViewModel.subtitle) Spacer() diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 2dd169f94..4880939cc 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -100,14 +100,12 @@ class GDriveOutboxViewModel: OutboxMainViewModel { private func uploadNextFile(folderId: String) { guard let fileToUpload = uploadQueue.first else { - // All files have been uploaded self.updateReportStatus(reportStatus: .submitted) self.showSubmittedReport() return } guard let fileUrl = self.mainAppModel.vaultManager.loadVaultFileToURL(file: fileToUpload) else { - // Handle error: unable to load file uploadQueue.removeFirst() uploadNextFile(folderId: folderId) return @@ -129,7 +127,6 @@ class GDriveOutboxViewModel: OutboxMainViewModel { private func handleCompletionForUploadFile(_ completion: Subscribers.Completion, folderId: String) { switch completion { case .finished: - // File upload completed successfully self.uploadQueue.removeFirst() self.uploadNextFile(folderId: folderId) case .failure( let error): diff --git a/Tella/Scenes/Reports/ReportsView.swift b/Tella/Scenes/Reports/ReportsView.swift deleted file mode 100644 index 7c6f3082f..000000000 --- a/Tella/Scenes/Reports/ReportsView.swift +++ /dev/null @@ -1,124 +0,0 @@ -//// -//// Copyright © 2021 INTERNEWS. All rights reserved. -//// -//import SwiftUI -// -// -//enum ReportPaths { -// case reportMain -// case draft -// case outbox -// case submitted -//} -// -//struct ReportsView: View { -// -// @EnvironmentObject var mainAppModel : MainAppModel -// @StateObject private var reportsViewModel : ReportsViewModel -// @EnvironmentObject var sheetManager : SheetManager -// -// init(mainAppModel:MainAppModel) { -// _reportsViewModel = StateObject(wrappedValue: ReportsViewModel(mainAppModel: mainAppModel)) -// } -// -// var body: some View { -// -// contentView -// .navigationBarTitle(LocalizableReport.reportsTitle.localized, displayMode: .large) -// .environmentObject(reportsViewModel) -// } -// -// private var contentView :some View { -// -// ContainerView { -// -// VStack(alignment: .center) { -// -// PageView(selectedOption: self.$reportsViewModel.selectedCell, pageViewItems: reportsViewModel.pageViewItems) -// .frame(maxWidth: .infinity, maxHeight: 40, alignment: .leading) -// -// VStack (spacing: 0) { -// Spacer() -// -// switch self.reportsViewModel.selectedCell { -// -// case .draft: -// ReportListView(reportArray: $reportsViewModel.draftReports, -// message: LocalizableReport.reportsDraftEmpty.localized) -// case .outbox: -// -// ReportListView(reportArray: $reportsViewModel.outboxedReports, -// message: LocalizableReport.reportsOutboxEmpty.localized) -// -// case .submitted: -// ReportListView(reportArray: $reportsViewModel.submittedReports, -// message: LocalizableReport.reportsSubmitedEmpty.localized) -// default: -// EmptyView() -// } -// -// Spacer() -// } -// -// TellaButtonView (title: LocalizableReport.reportsCreateNew.localized, -// nextButtonAction: .action, -// buttonType: .yellow, -// isValid: .constant(true)) { -// navigateTo(destination: newDraftReportView) -// } .padding(EdgeInsets(top: 30, leading: 0, bottom: 0, trailing: 0)) -// -// }.background(Styles.Colors.backgroundMain) -// .padding(EdgeInsets(top: 15, leading: 20, bottom: 16, trailing: 20)) -// .navigationBarBackButtonHidden(true) -// .navigationBarItems(leading: backButton) -// } -// -// .if(self.reportsViewModel.selectedCell == .submitted && self.reportsViewModel.submittedReports.count > 0, transform: { view in -// view.toolbar { -// TrailingButtonToolbar(title: LocalizableReport.clearAppBar.localized) { -// showDeleteReportConfirmationView() -// } -// } -// }) -// } -// -// private var newDraftReportView: some View { -// DraftReportView(mainAppModel: mainAppModel).environmentObject(reportsViewModel) -// } -// -// private func showDeleteReportConfirmationView() { -// sheetManager.showBottomSheet(modalHeight: 200) { -// -// -// ConfirmBottomSheet(titleText: LocalizableReport.clearSheetTitle.localized, -// msgText: LocalizableReport.clearSheetExpl.localized, -// cancelText: LocalizableReport.clearCancel.localized, -// actionText: LocalizableReport.clearSubmitted.localized, didConfirmAction: { -// sheetManager.hide() -// reportsViewModel.deleteSubmittedReport() -// Toast.displayToast(message: LocalizableReport.allReportDeletedToast.localized) -// }) -// } -// } -// -// var backButton : some View { -// Button { -// self.popToRoot() -// } label: { -// Image("back") -// .flipsForRightToLeftLayoutDirection(true) -// .padding(EdgeInsets(top: -3, leading: -8, bottom: 0, trailing: 12)) -// } -// } -//} -// -//struct ReportsView_Previews: PreviewProvider { -// -// static var previews: some View { -// ReportsView(mainAppModel: MainAppModel.stub()) -// } -//} -// -//extension Int: Identifiable { -// public var id: Int { self } -//} diff --git a/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift b/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift index 9151665df..6918629c3 100644 --- a/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift +++ b/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift @@ -22,7 +22,7 @@ struct UwaziListView: View { if cardsViewModel.isEmpty { - ConnectionEmptyView(message: emptyMessage, iconName: "") + ConnectionEmptyView(message: emptyMessage, iconName: ServerConnectionType.uwazi.emptyIcon) } else { From 2f976ba2d7d1a3ef66ef9c676f7f3b15c5267fbd Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 29 Jul 2024 14:27:25 -0300 Subject: [PATCH 108/167] change client id and add navigation fix --- .../Reports/Outbox/OutboxDetailsView.swift | 2 +- Tella/Supporting Files/Info.plist | 202 +++++++++--------- 2 files changed, 102 insertions(+), 102 deletions(-) diff --git a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift index f50879856..d4cd67878 100644 --- a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift +++ b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift @@ -190,7 +190,7 @@ struct OutboxDetailsView: View { } private func dismissView() { - self.presentationMode.wrappedValue.dismiss() + self.popTo(UIHostingController.self) } private func showDeleteReportConfirmationView() { diff --git a/Tella/Supporting Files/Info.plist b/Tella/Supporting Files/Info.plist index d4d55ea53..d8d53371b 100644 --- a/Tella/Supporting Files/Info.plist +++ b/Tella/Supporting Files/Info.plist @@ -2,106 +2,106 @@ - - - BGTaskSchedulerPermittedIdentifiers - - $(PRODUCT_BUNDLE_IDENTIFIER) - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Tella - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleURLTypes - - - CFBundleTypeRole - Editor - CFBundleURLName - googleDrive - CFBundleURLSchemes - - com.googleusercontent.apps.428441678272-3qafj3vp7njl6r3ohgi65m87lqe6mcc3 - - - - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - GIDClientID - 428441678272-3qafj3vp7njl6r3ohgi65m87lqe6mcc3.apps.googleusercontent.com - ITSAppUsesNonExemptEncryption - - LSApplicationCategoryType - - LSRequiresIPhoneOS - - NSCameraUsageDescription - Tella requires access to the camera to to take photos and videos inside the app. - NSMicrophoneUsageDescription - Tella requires access to your microphone to record audio inside the app. - NSPhotoLibraryUsageDescription - Tella requires access to your photo library to add or delete photos. - UIAppFonts - - OpenSans-Italic.ttf - OpenSans-Regular.ttf - OpenSans-Bold.ttf - OpenSans-Light.ttf - Roboto-Light.ttf - OpenSans-Semibold.ttf - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - - - - - UIBackgroundModes - - fetch - processing - - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UIStatusBarStyle - UIStatusBarStyleLightContent - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - NSLocationWhenInUseUsageDescription - Tella requires access to the location to capture photos with location information. + + + BGTaskSchedulerPermittedIdentifiers + + $(PRODUCT_BUNDLE_IDENTIFIER) + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Tella + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + googleDrive + CFBundleURLSchemes + + com.googleusercontent.apps.299748721134-oqrpkd21ko4rfgqtp976cs8gndc868gv + + + + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + GIDClientID + 299748721134-oqrpkd21ko4rfgqtp976cs8gndc868gv.apps.googleusercontent.com + ITSAppUsesNonExemptEncryption + + LSApplicationCategoryType + + LSRequiresIPhoneOS + + NSCameraUsageDescription + Tella requires access to the camera to to take photos and videos inside the app. + NSMicrophoneUsageDescription + Tella requires access to your microphone to record audio inside the app. + NSPhotoLibraryUsageDescription + Tella requires access to your photo library to add or delete photos. + UIAppFonts + + OpenSans-Italic.ttf + OpenSans-Regular.ttf + OpenSans-Bold.ttf + OpenSans-Light.ttf + Roboto-Light.ttf + OpenSans-Semibold.ttf + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + + + + + UIBackgroundModes + + fetch + processing + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarStyle + UIStatusBarStyleLightContent + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + NSLocationWhenInUseUsageDescription + Tella requires access to the location to capture photos with location information. From 2f5d61a122c1ab87958102cfb65bb074bb65717c Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 29 Jul 2024 16:22:21 -0300 Subject: [PATCH 109/167] organize files and folder structure --- Tella.xcodeproj/project.pbxproj | 60 +++++++------------ .../ViewModels}/DraftMainViewModel.swift | 0 .../ViewModels}/OutboxMainViewModel.swift | 0 .../ProgressFileItemViewModel.swift | 0 .../ViewModels}/ReportViewModel.swift | 0 .../ViewModels}/SubmittedMainViewModel.swift | 0 .../Views}/DeleteReportConfirmationView.swift | 0 .../Views}/Draft/AddFilesToDraftView.swift | 0 .../Views}/Draft/DraftView.swift | 0 .../Views}/Draft/ReportFileGridView.swift | 0 10 files changed, 23 insertions(+), 37 deletions(-) rename Tella/{Components/Reports/Draft => Scenes/CommonConnectionReport/ViewModels}/DraftMainViewModel.swift (100%) rename Tella/{Components/Reports/Outbox => Scenes/CommonConnectionReport/ViewModels}/OutboxMainViewModel.swift (100%) rename Tella/Scenes/{Reports/View Model => CommonConnectionReport/ViewModels}/ProgressFileItemViewModel.swift (100%) rename Tella/Scenes/{Reports/View Model => CommonConnectionReport/ViewModels}/ReportViewModel.swift (100%) rename Tella/{Components/Reports/Submitted => Scenes/CommonConnectionReport/ViewModels}/SubmittedMainViewModel.swift (100%) rename Tella/Scenes/{Reports => CommonConnectionReport/Views}/DeleteReportConfirmationView.swift (100%) rename Tella/{Components/Reports => Scenes/CommonConnectionReport/Views}/Draft/AddFilesToDraftView.swift (100%) rename Tella/{Components/Reports => Scenes/CommonConnectionReport/Views}/Draft/DraftView.swift (100%) rename Tella/Scenes/{Reports => CommonConnectionReport/Views}/Draft/ReportFileGridView.swift (100%) diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index c22c658ac..9f8be2a3d 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -1174,9 +1174,6 @@ children = ( 126FEE082AC4992800B99298 /* Models */, 121C945C28FF3D6900570EB4 /* Draft */, - 12199C322940936B0041BD38 /* Outbox */, - 123048D3295F954E0015CD96 /* Submitted */, - 1242135429B774A40002402D /* DeleteReportConfirmationView.swift */, 1232EE9A2918F8470094EE3A /* View Model */, ); path = Reports; @@ -1385,7 +1382,8 @@ 12199C33294094430041BD38 /* OutboxDetailsView.swift */, 12199C392941260D0041BD38 /* OutboxDetailsItemView.swift */, ); - path = Outbox; + name = Outbox; + path = ../../Reports/Outbox; sourceTree = ""; }; 121C945B28FF026200570EB4 /* AddServer */ = { @@ -1407,7 +1405,6 @@ isa = PBXGroup; children = ( 1236644E28FFECEF00FA839B /* DraftReportView.swift */, - 1220A72D292EB11B000BC24C /* ReportFileGridView.swift */, ); path = Draft; sourceTree = ""; @@ -1458,7 +1455,8 @@ 123048D4295F95A40015CD96 /* SubmittedDetailsView.swift */, 123048D6295F95BB0015CD96 /* SubmittedDetailsItemView.swift */, ); - path = Submitted; + name = Submitted; + path = ../../Reports/Submitted; sourceTree = ""; }; 1231A459294C76040057DA85 /* Domain */ = { @@ -1535,8 +1533,6 @@ 1221E05B2906CA6A00BC05F5 /* DraftReportVM.swift */, 123AE5A029CFAD7F00814CC7 /* OutboxReportVM.swift */, 121F87A92964383D00E6BA0D /* SubmittedReportVM.swift */, - 123048D1295F84BD0015CD96 /* ProgressFileItemViewModel.swift */, - 122E6A5229A3812A00BDACAD /* ReportViewModel.swift */, ); path = "View Model"; sourceTree = ""; @@ -1632,6 +1628,10 @@ 125C789C2C36B50100440014 /* Views */ = { isa = PBXGroup; children = ( + 1242135429B774A40002402D /* DeleteReportConfirmationView.swift */, + 123048D3295F954E0015CD96 /* Submitted */, + 12199C322940936B0041BD38 /* Outbox */, + 15CA1B882C582168002333A8 /* Draft */, 12B84B8F2C333DD0006363F0 /* ReportMainView.swift */, 12B84B972C3413AC006363F0 /* CommonReportListView.swift */, ); @@ -1641,6 +1641,11 @@ 125C789D2C36B50800440014 /* ViewModels */ = { isa = PBXGroup; children = ( + 122E6A5229A3812A00BDACAD /* ReportViewModel.swift */, + 123048D1295F84BD0015CD96 /* ProgressFileItemViewModel.swift */, + 1517A9B12C404F4000CB8EBF /* SubmittedMainViewModel.swift */, + 15E656AC2C2A14F500BDEC91 /* DraftMainViewModel.swift */, + 1517A9A92C3F011D00CB8EBF /* OutboxMainViewModel.swift */, 12B84B8E2C333DD0006363F0 /* ReportMainViewModel.swift */, 127138372C35EA34004D520B /* CommonCardViewModel.swift */, 12B84B932C333FE3006363F0 /* ReportCardViewModel.swift */, @@ -2386,22 +2391,6 @@ path = Common; sourceTree = ""; }; - 1517A9A82C3F010D00CB8EBF /* Outbox */ = { - isa = PBXGroup; - children = ( - 1517A9A92C3F011D00CB8EBF /* OutboxMainViewModel.swift */, - ); - path = Outbox; - sourceTree = ""; - }; - 1517A9B02C404F1100CB8EBF /* Submitted */ = { - isa = PBXGroup; - children = ( - 1517A9B12C404F4000CB8EBF /* SubmittedMainViewModel.swift */, - ); - path = Submitted; - sourceTree = ""; - }; 1519BED42B9A5A2B006FD290 /* Resource */ = { isa = PBXGroup; children = ( @@ -2480,6 +2469,16 @@ path = ViewModel; sourceTree = ""; }; + 15CA1B882C582168002333A8 /* Draft */ = { + isa = PBXGroup; + children = ( + 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */, + 1220A72D292EB11B000BC24C /* ReportFileGridView.swift */, + 152D38502C2C61DF00323CE7 /* DraftView.swift */, + ); + path = Draft; + sourceTree = ""; + }; 15E3D5012C1B51D700B7FECC /* Views */ = { isa = PBXGroup; children = ( @@ -2499,24 +2498,11 @@ 15E656A92C2A142300BDEC91 /* Reports */ = { isa = PBXGroup; children = ( - 1517A9B02C404F1100CB8EBF /* Submitted */, - 1517A9A82C3F010D00CB8EBF /* Outbox */, - 15E656AE2C2A14FA00BDEC91 /* Draft */, 15F1AA532C2E07F50002A7D8 /* BaseReportsViewModel.swift */, ); path = Reports; sourceTree = ""; }; - 15E656AE2C2A14FA00BDEC91 /* Draft */ = { - isa = PBXGroup; - children = ( - 152D38502C2C61DF00323CE7 /* DraftView.swift */, - 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */, - 15E656AC2C2A14F500BDEC91 /* DraftMainViewModel.swift */, - ); - path = Draft; - sourceTree = ""; - }; 15F64C9B2B6D78D8008A57AA /* Views */ = { isa = PBXGroup; children = ( diff --git a/Tella/Components/Reports/Draft/DraftMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/DraftMainViewModel.swift similarity index 100% rename from Tella/Components/Reports/Draft/DraftMainViewModel.swift rename to Tella/Scenes/CommonConnectionReport/ViewModels/DraftMainViewModel.swift diff --git a/Tella/Components/Reports/Outbox/OutboxMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift similarity index 100% rename from Tella/Components/Reports/Outbox/OutboxMainViewModel.swift rename to Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift diff --git a/Tella/Scenes/Reports/View Model/ProgressFileItemViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/ProgressFileItemViewModel.swift similarity index 100% rename from Tella/Scenes/Reports/View Model/ProgressFileItemViewModel.swift rename to Tella/Scenes/CommonConnectionReport/ViewModels/ProgressFileItemViewModel.swift diff --git a/Tella/Scenes/Reports/View Model/ReportViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportViewModel.swift similarity index 100% rename from Tella/Scenes/Reports/View Model/ReportViewModel.swift rename to Tella/Scenes/CommonConnectionReport/ViewModels/ReportViewModel.swift diff --git a/Tella/Components/Reports/Submitted/SubmittedMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/SubmittedMainViewModel.swift similarity index 100% rename from Tella/Components/Reports/Submitted/SubmittedMainViewModel.swift rename to Tella/Scenes/CommonConnectionReport/ViewModels/SubmittedMainViewModel.swift diff --git a/Tella/Scenes/Reports/DeleteReportConfirmationView.swift b/Tella/Scenes/CommonConnectionReport/Views/DeleteReportConfirmationView.swift similarity index 100% rename from Tella/Scenes/Reports/DeleteReportConfirmationView.swift rename to Tella/Scenes/CommonConnectionReport/Views/DeleteReportConfirmationView.swift diff --git a/Tella/Components/Reports/Draft/AddFilesToDraftView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/AddFilesToDraftView.swift similarity index 100% rename from Tella/Components/Reports/Draft/AddFilesToDraftView.swift rename to Tella/Scenes/CommonConnectionReport/Views/Draft/AddFilesToDraftView.swift diff --git a/Tella/Components/Reports/Draft/DraftView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift similarity index 100% rename from Tella/Components/Reports/Draft/DraftView.swift rename to Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift diff --git a/Tella/Scenes/Reports/Draft/ReportFileGridView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/ReportFileGridView.swift similarity index 100% rename from Tella/Scenes/Reports/Draft/ReportFileGridView.swift rename to Tella/Scenes/CommonConnectionReport/Views/Draft/ReportFileGridView.swift From d6acf98bdc039e0980a3701733055a55eea6756b Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 29 Jul 2024 16:41:05 -0300 Subject: [PATCH 110/167] add remaining localizable strings --- Tella.xcodeproj/project.pbxproj | 4 ++++ .../Scenes/GDrive/ViewModel/GDriveViewModel.swift | 2 +- .../Views/Home/Connections/ConnectionsView.swift | 2 +- .../Supporting Files/en.lproj/Localizable.strings | 1 + Tella/Utils/Localizable/LocalizableGDrive.swift | 14 ++++++++++++++ 5 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 Tella/Utils/Localizable/LocalizableGDrive.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 9f8be2a3d..f5eb0666f 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -399,6 +399,7 @@ 15E3D5052C1B531700B7FECC /* ConnectionEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D5042C1B531700B7FECC /* ConnectionEmptyView.swift */; }; 15E3D50A2C1B71E200B7FECC /* GDriveDraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D5092C1B71E200B7FECC /* GDriveDraftView.swift */; }; 15E3D50E2C1B87AC00B7FECC /* GDriveDraftViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E3D50D2C1B87AC00B7FECC /* GDriveDraftViewModel.swift */; }; + 15E54AB92C5824DA00290DE8 /* LocalizableGDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E54AB82C5824DA00290DE8 /* LocalizableGDrive.swift */; }; 15E656AB2C2A147E00BDEC91 /* AddFilesToDraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */; }; 15E656AD2C2A14F500BDEC91 /* DraftMainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E656AC2C2A14F500BDEC91 /* DraftMainViewModel.swift */; }; 15EE30FE2B5073E20033BBBB /* Pages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15EE30FD2B5073E20033BBBB /* Pages.swift */; }; @@ -974,6 +975,7 @@ 15E3D5042C1B531700B7FECC /* ConnectionEmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionEmptyView.swift; sourceTree = ""; }; 15E3D5092C1B71E200B7FECC /* GDriveDraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveDraftView.swift; sourceTree = ""; }; 15E3D50D2C1B87AC00B7FECC /* GDriveDraftViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveDraftViewModel.swift; sourceTree = ""; }; + 15E54AB82C5824DA00290DE8 /* LocalizableGDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizableGDrive.swift; sourceTree = ""; }; 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFilesToDraftView.swift; sourceTree = ""; }; 15E656AC2C2A14F500BDEC91 /* DraftMainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftMainViewModel.swift; sourceTree = ""; }; 15EE30FD2B5073E20033BBBB /* Pages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pages.swift; sourceTree = ""; }; @@ -2230,6 +2232,7 @@ 12B370382B19109600DDA9E9 /* LocalizableBackgroundActivities.swift */, 1501401C2B71243A00991D69 /* LocalizableResources.swift */, 12B84B842C32EF12006363F0 /* LocalizableNextcloud.swift */, + 15E54AB82C5824DA00290DE8 /* LocalizableGDrive.swift */, ); path = Localizable; sourceTree = ""; @@ -3666,6 +3669,7 @@ 1242135529B774A40002402D /* DeleteReportConfirmationView.swift in Sources */, 12B5257E2849037E00B3D1C0 /* LockTimeoutOptionsStatus.swift in Sources */, 12E8129A27A1570A007DDDC0 /* LocalizableSettings.swift in Sources */, + 15E54AB92C5824DA00290DE8 /* LocalizableGDrive.swift in Sources */, 129B845328BFB7AC00F1B344 /* AddServerAccessChoiceView.swift in Sources */, 1293F6772AD88A0400F6CFBD /* FeedbackDTO.swift in Sources */, 12C07F052B0748D50030AD6E /* TopSheetView.swift in Sources */, diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift index e0a21c268..b17b56b4f 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -25,7 +25,7 @@ class GDriveViewModel: ReportMainViewModel { ]} init(mainAppModel: MainAppModel) { - super.init(mainAppModel: mainAppModel, connectionType: .gDrive, title: "Google Drive") + super.init(mainAppModel: mainAppModel, connectionType: .gDrive, title: LocalizableGDrive.gDriveAppBar.localized) self.getReports() self.getServer() diff --git a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift index d4d9c3ecf..eb9287045 100644 --- a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift +++ b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift @@ -53,7 +53,7 @@ struct ConnectionsView: View { image: "home.uwazi", destination: UwaziView().environmentObject(UwaziViewModel(mainAppModel: appModel, server: server.servers.first))) case .gDrive: - ConnectionsItemView(title: "Drive", + ConnectionsItemView(title: LocalizableGDrive.gDriveAppBar.localized, image: "home.drive", destination: gDriveMainView) case .nextcloud: diff --git a/Tella/Supporting Files/en.lproj/Localizable.strings b/Tella/Supporting Files/en.lproj/Localizable.strings index d61548126..1b58ed7cb 100644 --- a/Tella/Supporting Files/en.lproj/Localizable.strings +++ b/Tella/Supporting Files/en.lproj/Localizable.strings @@ -537,3 +537,4 @@ This feedback is anonymous, so make sure to include contact information if you w "Nextcloud_AppBar" = "Nextcloud"; +"GDrive_AppBar" = "Google Drive"; diff --git a/Tella/Utils/Localizable/LocalizableGDrive.swift b/Tella/Utils/Localizable/LocalizableGDrive.swift new file mode 100644 index 000000000..4b18d0f4e --- /dev/null +++ b/Tella/Utils/Localizable/LocalizableGDrive.swift @@ -0,0 +1,14 @@ +// +// LocalizableGDrive.swift +// Tella +// +// Created by gus valbuena on 7/29/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +enum LocalizableGDrive : String, LocalizableDelegate { + case gDriveAppBar = "GDrive_AppBar" + +} From 44bfdecce232b5e6527a67e7d9543bf244516612 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 29 Jul 2024 17:01:25 -0300 Subject: [PATCH 111/167] pause submission when app enter bg mode or user exit the app --- .../GDrive/ViewModel/GDriveOutboxViewModel.swift | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 4880939cc..c381f6f86 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -8,6 +8,7 @@ import Foundation import Combine +import UIKit class GDriveOutboxViewModel: OutboxMainViewModel { private let gDriveRepository: GDriveRepositoryProtocol @@ -25,6 +26,21 @@ class GDriveOutboxViewModel: OutboxMainViewModel { if reportViewModel.status == .submissionScheduled { self.submitReport() + } else { + self.pauseSubmission() + } + + NotificationCenter.default.addObserver(self, selector: #selector(handleAppWillResignActive), name: UIApplication.willResignActiveNotification, object: nil) + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + @objc private func handleAppWillResignActive() { + if isSubmissionInProgress { + pauseSubmission() + updateReportStatus(reportStatus: .submissionPaused) } } From d4223732f3440f314390fcae9a5b72257fc0b6d5 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 31 Jul 2024 13:12:42 -0300 Subject: [PATCH 112/167] fix localizable issues --- .../Card/ConnectionCardDetails.swift | 4 ++-- .../Views/CommonReportListView.swift | 2 +- .../Resources/Views/Common/ResourceCard.swift | 2 +- .../Settings/Models/DeleteServerTexts.swift | 18 ++++++++---------- .../Views/EntityInstances/UwaziListView.swift | 2 +- .../en.lproj/Localizable.strings | 7 ++++++- .../Localizable/LocalizableSettings.swift | 6 ++++++ 7 files changed, 25 insertions(+), 16 deletions(-) diff --git a/Tella/Components/Connections/Card/ConnectionCardDetails.swift b/Tella/Components/Connections/Card/ConnectionCardDetails.swift index 524abbbf8..3cad27172 100644 --- a/Tella/Components/Connections/Card/ConnectionCardDetails.swift +++ b/Tella/Components/Connections/Card/ConnectionCardDetails.swift @@ -8,7 +8,7 @@ import SwiftUI -struct ConnectionCardDetails: View { +struct ConnectionCardDetailsView: View { var title : String var subtitle: String? var body: some View { @@ -29,6 +29,6 @@ struct ConnectionCardDetails: View { struct ReportCardDetail_Previews: PreviewProvider { static var previews: some View { - ConnectionCardDetails(title: "", subtitle: "") + ConnectionCardDetailsView(title: "", subtitle: "") } } diff --git a/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift b/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift index e1621db39..d580953bc 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/CommonReportListView.swift @@ -69,7 +69,7 @@ struct CommonItemView: View { .frame(width: 12) } - ConnectionCardDetails(title: cardViewModel.title, + ConnectionCardDetailsView(title: cardViewModel.title, subtitle: cardViewModel.subtitle) Spacer() diff --git a/Tella/Scenes/Resources/Views/Common/ResourceCard.swift b/Tella/Scenes/Resources/Views/Common/ResourceCard.swift index 56ead6d05..8467794a6 100644 --- a/Tella/Scenes/Resources/Views/Common/ResourceCard.swift +++ b/Tella/Scenes/Resources/Views/Common/ResourceCard.swift @@ -18,7 +18,7 @@ struct ResourceCardView: View { HStack { Image("resources.pdf") .padding() - ConnectionCardDetails(title: resourceCard.title, subtitle: resourceCard.serverName) + ConnectionCardDetailsView(title: resourceCard.title, subtitle: resourceCard.serverName) Spacer() ZStack { if(!isLoading) { diff --git a/Tella/Scenes/Settings/Models/DeleteServerTexts.swift b/Tella/Scenes/Settings/Models/DeleteServerTexts.swift index 390c1146f..d886bbbee 100644 --- a/Tella/Scenes/Settings/Models/DeleteServerTexts.swift +++ b/Tella/Scenes/Settings/Models/DeleteServerTexts.swift @@ -18,11 +18,11 @@ enum DeleteServerTexts { var titleText: String { switch self { case .tella(let name): - return "Delete \(name) server?" + return String(format: LocalizableSettings.settServerDeleteTellaConnectionTitle.localized, name) case .uwazi(let name): - return "Delete \"\(name)\" connection?" + return String(format: LocalizableSettings.settServerDeleteConnectionTitle.localized, name) case .gDrive(let name): - return "Delete \"\(name)\" connection?" + return String(format: LocalizableSettings.settServerDeleteConnectionTitle.localized, name) case .unknown: return "" } @@ -30,23 +30,21 @@ enum DeleteServerTexts { var messageText: String { switch self { - case .tella: - return "if you delete this server, all draft and submitted forms will be deleted from your device." case .uwazi: - return "If you delete this server, all draft and submitted entities will be deleted from your device. Delete anyway?" - case .gDrive: - return "If you delete this server, all draft and submitted reports will be deleted from your device." + return LocalizableSettings.settServerDeleteUwaziConnectionMessage.localized case .unknown: return "" + default: + return LocalizableSettings.settServerDeleteConnectionMessage.localized } } var cancelText: String { - return "CANCEL" + return LocalizableSettings.settServerCancelSheetAction.localized } var actionText: String { - return "Delete" + return LocalizableSettings.settServerDeleteSheetAction.localized } } diff --git a/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift b/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift index 6918629c3..cd4c62c74 100644 --- a/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift +++ b/Tella/Scenes/Uwazi/Views/EntityInstances/UwaziListView.swift @@ -66,7 +66,7 @@ struct EntityInstanceItemView: View { .frame(width: 12) } - ConnectionCardDetails(title: cardViewModel.title, + ConnectionCardDetailsView(title: cardViewModel.title, subtitle: cardViewModel.serverName) Spacer() diff --git a/Tella/Supporting Files/en.lproj/Localizable.strings b/Tella/Supporting Files/en.lproj/Localizable.strings index 1b58ed7cb..d3b6518a0 100644 --- a/Tella/Supporting Files/en.lproj/Localizable.strings +++ b/Tella/Supporting Files/en.lproj/Localizable.strings @@ -246,7 +246,12 @@ If you want to take a picture or a video, proceed in the following way:\ "Setting_SettServer_UnavailableConnections_Title" = "Unavailable connections"; "Setting_SettServer_UnavailableConnections_Description" = "For the following categories, only one connection can be enabled at a time. To add a new connection, please delete the current one by going to Connections Settings."; "Setting_SettServer_No_Token" = "No token present, please connect again"; - +"Settings_SettServer_DeleteTellaConnection_Title" = "Delete %@ server?"; +"Settings_SettServre_DeleteConnection_Title" = "Delete \"%@\" connection?"; +"Settings_SettServer_DeleteConnection_Message" = "if you delete this server, all draft and submitted forms will be deleted from your device."; +"Settings_SettServer_DeleteUwaziConnection_Message" = "If you delete this server, all draft and submitted entities will be deleted from your device. Delete anyway?"; +"Settings_SettServer_Cancel_SheetAction" = "CANCEL"; +"Settings_SettServer_Delete_SheetAction" = "DELETE"; "Home_RecentFiles_Subhead" = "Recent files"; diff --git a/Tella/Utils/Localizable/LocalizableSettings.swift b/Tella/Utils/Localizable/LocalizableSettings.swift index 289ac6bf3..8dad9c433 100644 --- a/Tella/Utils/Localizable/LocalizableSettings.swift +++ b/Tella/Utils/Localizable/LocalizableSettings.swift @@ -94,6 +94,12 @@ enum LocalizableSettings: String, LocalizableDelegate { case settServerUnavailableConnectionsTitle = "Setting_SettServer_UnavailableConnections_Title" case settServerUnavailableConnectionsDesc = "Setting_SettServer_UnavailableConnections_Description" case settServerNoTokenPresent = "Setting_SettServer_No_Token" + case settServerDeleteConnectionTitle = "Settings_SettServre_DeleteConnection_Title" + case settServerDeleteTellaConnectionTitle = "Settings_SettServer_DeleteTellaConnection_Title" + case settServerDeleteConnectionMessage = "Settings_SettServer_DeleteConnection_Message" + case settServerDeleteUwaziConnectionMessage = "Settings_SettServer_DeleteUwaziConnection_Message" + case settServerDeleteSheetAction = "Settings_SettServer_Delete_SheetAction" + case settServerCancelSheetAction = "Settings_SettServer_Cancel_SheetAction" // Uwazi case UwaziServerURL = "Setting_Server_Uwazi_Server_URL" From 85428f0d4386abf91431385ac7d7b2219489460a Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 31 Jul 2024 15:27:14 -0300 Subject: [PATCH 113/167] improve sign in state on GDriveAuthVM --- Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift index e91a2bb8d..56362c5ee 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -12,7 +12,7 @@ import Combine class GDriveAuthViewModel: ObservableObject { private let gDriveRepository: GDriveRepositoryProtocol private var cancellables = Set() - @Published var signInState: ViewModelState = .loaded("") + @Published var signInState: ViewModelState = .loaded(nil) init(repository: GDriveRepositoryProtocol) { self.gDriveRepository = repository } @@ -23,11 +23,13 @@ class GDriveAuthViewModel: ObservableObject { do { try await gDriveRepository.handleSignIn() DispatchQueue.main.async { - self.signInState = .loaded("") + self.signInState = .loaded(nil) completion() } } catch let error { - self.signInState = .error(error.localizedDescription) + DispatchQueue.main.async { + self.signInState = .error(error.localizedDescription) + } } } } From 839c286b2e09860f3eed4f23bd8781c5f1d961f6 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 2 Aug 2024 14:06:56 -0300 Subject: [PATCH 114/167] remove environmentObjects for mainAppModel --- .../Views/Draft/DraftView.swift | 11 +++++------ .../Views/ReportMainView.swift | 16 +++++++--------- .../GDrive/ViewModel/GDriveViewModel.swift | 9 ++++++--- Tella/Scenes/Reports/Draft/DraftReportView.swift | 1 - 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift index 676c00399..41537fdfa 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift @@ -14,7 +14,6 @@ struct DraftView: View { @State private var menuFrame : CGRect = CGRectZero @State private var shouldShowMenu : Bool = false - @EnvironmentObject var mainAppModel: MainAppModel @EnvironmentObject var sheetManager: SheetManager var reportsViewModel : ReportMainViewModel @@ -196,10 +195,10 @@ struct DraftView: View { Group { switch reportsViewModel.connectionType { case .tella: - let outboxVM = OutboxReportVM(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: viewModel.reportId) + let outboxVM = OutboxReportVM(mainAppModel: viewModel.mainAppModel, reportsViewModel: reportsViewModel, reportId: viewModel.reportId) OutboxDetailsView(outboxReportVM: outboxVM).environmentObject(reportsViewModel) case .gDrive: - let outboxVM = GDriveOutboxViewModel(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: viewModel.reportId, repository: GDriveRepository()) + let outboxVM = GDriveOutboxViewModel(mainAppModel: viewModel.mainAppModel, reportsViewModel: reportsViewModel, reportId: viewModel.reportId, repository: GDriveRepository()) OutboxDetailsView(outboxReportVM: outboxVM).environmentObject(reportsViewModel) default: Text("") @@ -210,14 +209,14 @@ struct DraftView: View { var photoVideoPickerView: some View { PhotoVideoPickerView(showingImagePicker: $viewModel.showingImagePicker, showingImportDocumentPicker: $viewModel.showingImportDocumentPicker, - appModel: mainAppModel, + appModel: viewModel.mainAppModel, resultFile: $viewModel.resultFile, shouldReloadVaultFiles: .constant(false)) } var recordView: some View { viewModel.showingRecordView ? - RecordView(appModel: mainAppModel, + RecordView(appModel: viewModel.mainAppModel, sourceView: .addReportFile, showingRecoredrView: $viewModel.showingRecordView, resultFile: $viewModel.resultFile) : nil @@ -228,7 +227,7 @@ struct DraftView: View { CameraView(sourceView: SourceView.addReportFile, showingCameraView: $viewModel.showingCamera, resultFile: $viewModel.resultFile, - mainAppModel: mainAppModel) : nil + mainAppModel: viewModel.mainAppModel) : nil } private func showSaveReportConfirmationView() { diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift index 57ab1fed5..79827dca2 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -13,8 +13,6 @@ struct ReportMainView: View { @ObservedObject var reportMainViewModel: ReportMainViewModel @EnvironmentObject var sheetManager: SheetManager - @EnvironmentObject var mainAppModel: MainAppModel - let diContainer : DIContainer @@ -159,18 +157,18 @@ struct ReportMainView: View { switch reportMainViewModel.connectionType { case .tella: var destination: any View - destination = DraftReportView(mainAppModel: mainAppModel, reportId: id).environmentObject(reportMainViewModel) + destination = DraftReportView(mainAppModel: reportMainViewModel.mainAppModel, reportId: id).environmentObject(reportMainViewModel) self.navigateTo(destination: destination) case .gDrive: var destination : any View - destination = GDriveDraftView(mainAppModel: mainAppModel, + destination = GDriveDraftView(mainAppModel: reportMainViewModel.mainAppModel, gDriveDIContainer: (diContainer as! GDriveDIContainer), reportId: id).environmentObject(reportMainViewModel) self.navigateTo(destination: destination) case .nextcloud: var destination : any View - destination = GDriveDraftView(mainAppModel: mainAppModel, + destination = GDriveDraftView(mainAppModel: reportMainViewModel.mainAppModel, gDriveDIContainer: (diContainer as! GDriveDIContainer), reportId: id) self.navigateTo(destination: destination) @@ -183,13 +181,13 @@ struct ReportMainView: View { private func showOutboxView(id: Int? = nil) { switch reportMainViewModel.connectionType { case .tella: - let outboxViewModel = OutboxReportVM(mainAppModel: mainAppModel, reportsViewModel: reportMainViewModel, reportId: id) + let outboxViewModel = OutboxReportVM(mainAppModel: reportMainViewModel.mainAppModel, reportsViewModel: reportMainViewModel, reportId: id) let destination = OutboxDetailsView(outboxReportVM: outboxViewModel) .environmentObject(reportMainViewModel) self.navigateTo(destination: destination) break case .gDrive: - let outboxViewModel = GDriveOutboxViewModel(mainAppModel: mainAppModel, reportsViewModel: reportMainViewModel, reportId: id, repository: GDriveRepository()) + let outboxViewModel = GDriveOutboxViewModel(mainAppModel: reportMainViewModel.mainAppModel, reportsViewModel: reportMainViewModel, reportId: id, repository: GDriveRepository()) let destination = OutboxDetailsView(outboxReportVM: outboxViewModel) .environmentObject(reportMainViewModel) self.navigateTo(destination: destination) @@ -202,11 +200,11 @@ struct ReportMainView: View { private func showSubmittedView(id: Int? = nil) { switch reportMainViewModel.connectionType { case .tella: - let vm = SubmittedReportVM(mainAppModel: mainAppModel, reportId: id) + let vm = SubmittedReportVM(mainAppModel: reportMainViewModel.mainAppModel, reportId: id) let destination = SubmittedDetailsView(submittedReportVM: vm).environmentObject(reportMainViewModel) self.navigateTo(destination: destination) case .gDrive: - let vm = GDriveSubmittedViewModel(mainAppModel: mainAppModel, reportId: id) + let vm = GDriveSubmittedViewModel(mainAppModel: reportMainViewModel.mainAppModel, reportId: id) let destination = SubmittedDetailsView(submittedReportVM: vm).environmentObject(reportMainViewModel) self.navigateTo(destination: destination) default: diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift index b17b56b4f..427c80613 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -47,7 +47,8 @@ class GDriveViewModel: ReportMainViewModel { self.draftReportsViewModel = draftReports.compactMap { report in return ReportCardViewModel(report: report, serverName: server?.name, - deleteReport: { self.deleteReport(report: report) } + deleteReport: { self.deleteReport(report: report) }, + connectionType: .gDrive ) } } @@ -57,7 +58,8 @@ class GDriveViewModel: ReportMainViewModel { self.outboxedReportsViewModel = outboxedReports.compactMap { report in ReportCardViewModel(report: report, serverName: server?.name, - deleteReport: { self.deleteReport(report: report) } + deleteReport: { self.deleteReport(report: report) }, + connectionType: .gDrive ) } } @@ -67,7 +69,8 @@ class GDriveViewModel: ReportMainViewModel { self.submittedReportsViewModel = submittedReports.compactMap { report in ReportCardViewModel(report: report, serverName: server?.name, - deleteReport: { self.deleteReport(report: report) } + deleteReport: { self.deleteReport(report: report) }, + connectionType: .gDrive ) } } diff --git a/Tella/Scenes/Reports/Draft/DraftReportView.swift b/Tella/Scenes/Reports/Draft/DraftReportView.swift index 6ed00791e..0f8f1f04e 100644 --- a/Tella/Scenes/Reports/Draft/DraftReportView.swift +++ b/Tella/Scenes/Reports/Draft/DraftReportView.swift @@ -23,7 +23,6 @@ struct DraftReportView: View { var body: some View { DraftView(viewModel: reportViewModel, reportsViewModel: reportsViewModel) - .environmentObject(reportsViewModel) } } From e1c7c79c58af43958a2cb9c97ca508be2c68200a Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 2 Aug 2024 15:54:15 -0300 Subject: [PATCH 115/167] fix wording for page component --- Tella/Components/Reports/BaseReportsViewModel.swift | 4 ++-- Tella/Components/Tabs/PageView.swift | 6 +++--- Tella/Components/Tabs/PageViewCell.swift | 4 ++-- Tella/Components/Tabs/Pages.swift | 2 +- .../ViewModels/ReportMainViewModel.swift | 2 +- .../CommonConnectionReport/Views/Draft/DraftView.swift | 4 ++-- .../CommonConnectionReport/Views/ReportMainView.swift | 4 ++-- Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift | 2 +- Tella/Scenes/Uwazi/ViewModel/UwaziViewModel.swift | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Tella/Components/Reports/BaseReportsViewModel.swift b/Tella/Components/Reports/BaseReportsViewModel.swift index bd299578e..173b9322e 100644 --- a/Tella/Components/Reports/BaseReportsViewModel.swift +++ b/Tella/Components/Reports/BaseReportsViewModel.swift @@ -9,13 +9,13 @@ import Foundation protocol ReportsViewModelProtocol: ObservableObject { - var selectedCell: Pages { get set } + var selectedCell: Page { get set } } class BaseReportsViewModel: ObservableObject, ReportsViewModelProtocol { var mainAppModel: MainAppModel - @Published var selectedCell: Pages = .draft + @Published var selectedCell: Page = .draft init(mainAppModel: MainAppModel) { self.mainAppModel = mainAppModel diff --git a/Tella/Components/Tabs/PageView.swift b/Tella/Components/Tabs/PageView.swift index 6b3966f46..2c0cb3832 100644 --- a/Tella/Components/Tabs/PageView.swift +++ b/Tella/Components/Tabs/PageView.swift @@ -7,10 +7,10 @@ import SwiftUI class PageViewItem { var title : String - var page : Pages + var page : Page var number : Int - init(title: String, page: Pages, number: Int) { + init(title: String, page: Page, number: Int) { self.title = title self.page = page self.number = number @@ -19,7 +19,7 @@ class PageViewItem { public struct PageView: View { - @Binding var selectedOption: Pages + @Binding var selectedOption: Page var pageViewItems : [PageViewItem] public var body: some View { diff --git a/Tella/Components/Tabs/PageViewCell.swift b/Tella/Components/Tabs/PageViewCell.swift index 9a0026d3d..11ca136f7 100644 --- a/Tella/Components/Tabs/PageViewCell.swift +++ b/Tella/Components/Tabs/PageViewCell.swift @@ -9,9 +9,9 @@ struct PageViewCell: View { let title: String let number: Int - let page: Pages + let page: Page - @Binding var selectedOption: Pages + @Binding var selectedOption: Page public var body: some View { diff --git a/Tella/Components/Tabs/Pages.swift b/Tella/Components/Tabs/Pages.swift index 2fb03428b..130f708b7 100644 --- a/Tella/Components/Tabs/Pages.swift +++ b/Tella/Components/Tabs/Pages.swift @@ -8,7 +8,7 @@ import Foundation -public enum Pages: Hashable { +public enum Page: Hashable { case draft case outbox diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift index 87fbb0a29..de4e06e99 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift @@ -15,7 +15,7 @@ class ReportMainViewModel: ObservableObject { @Published var outboxedReportsViewModel : [CommonCardViewModel] = [] @Published var submittedReportsViewModel : [CommonCardViewModel] = [] - @Published var selectedCell: Pages = .draft + @Published var selectedPage: Page = .draft @Published var isLoading: Bool = false @Published var shouldShowToast : Bool = false diff --git a/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift index 41537fdfa..cffb37821 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift @@ -262,13 +262,13 @@ struct DraftView: View { } private func handleSuccessSavingDraft() { - reportsViewModel.selectedCell = .draft + reportsViewModel.selectedPage = .draft dismissViews() Toast.displayToast(message: LocalizableReport.draftSavedToast.localized) } private func handleSuccessSavingOutbox() { - reportsViewModel.selectedCell = .outbox + reportsViewModel.selectedPage = .outbox dismissViews() Toast.displayToast(message: LocalizableReport.outboxSavedToast.localized) } diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift index 79827dca2..7dee34a9e 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -32,13 +32,13 @@ struct ReportMainView: View { ContainerView { VStack(alignment: .center) { - PageView(selectedOption: self.$reportMainViewModel.selectedCell, pageViewItems: reportMainViewModel.pageViewItems) + PageView(selectedOption: self.$reportMainViewModel.selectedPage, pageViewItems: reportMainViewModel.pageViewItems) .frame(maxWidth: .infinity, maxHeight: 40, alignment: .leading) VStack (spacing: 0) { Spacer() - switch self.reportMainViewModel.selectedCell { + switch self.reportMainViewModel.selectedPage { case .draft: CommonReportListView(message: LocalizableReport.draftListExpl.localized, diff --git a/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift b/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift index bfdaf7232..b83f5a156 100644 --- a/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift +++ b/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift @@ -129,7 +129,7 @@ struct SubmittedDetailsView: View { } private func dismissViews() { - self.reportsViewModel.selectedCell = .submitted + self.reportsViewModel.selectedPage = .submitted self.popTo(UIHostingController.self) } diff --git a/Tella/Scenes/Uwazi/ViewModel/UwaziViewModel.swift b/Tella/Scenes/Uwazi/ViewModel/UwaziViewModel.swift index 049929544..0bfa6be1a 100644 --- a/Tella/Scenes/Uwazi/ViewModel/UwaziViewModel.swift +++ b/Tella/Scenes/Uwazi/ViewModel/UwaziViewModel.swift @@ -22,7 +22,7 @@ class UwaziViewModel: ObservableObject { @Published var outboxedEntitiesViewModel : [UwaziCardViewModel] = [] @Published var submittedEntitiesViewModel : [UwaziCardViewModel] = [] - @Published var selectedCell = Pages.template + @Published var selectedCell = Page.template @Published var isLoading: Bool = false @Published var serverName : String = "" From abb0fd24b5c5a9d9a04bc0c6e81f56d7be3ffab3 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 5 Aug 2024 11:55:06 -0300 Subject: [PATCH 116/167] remove BaseReportsVM --- Tella.xcodeproj/project.pbxproj | 4 ---- .../Reports/BaseReportsViewModel.swift | 23 ------------------- .../Reports/Draft/DraftReportView.swift | 1 - 3 files changed, 28 deletions(-) delete mode 100644 Tella/Components/Reports/BaseReportsViewModel.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index f5eb0666f..fb8500122 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -403,7 +403,6 @@ 15E656AB2C2A147E00BDEC91 /* AddFilesToDraftView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */; }; 15E656AD2C2A14F500BDEC91 /* DraftMainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15E656AC2C2A14F500BDEC91 /* DraftMainViewModel.swift */; }; 15EE30FE2B5073E20033BBBB /* Pages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15EE30FD2B5073E20033BBBB /* Pages.swift */; }; - 15F1AA542C2E07F50002A7D8 /* BaseReportsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F1AA532C2E07F50002A7D8 /* BaseReportsViewModel.swift */; }; 15F64C9D2B6D7904008A57AA /* DownloadedResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */; }; 15F64CA02B6D794B008A57AA /* SectionTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */; }; 15F64CA22B6D797C008A57AA /* SectionMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F64CA12B6D797C008A57AA /* SectionMessage.swift */; }; @@ -979,7 +978,6 @@ 15E656AA2C2A147E00BDEC91 /* AddFilesToDraftView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFilesToDraftView.swift; sourceTree = ""; }; 15E656AC2C2A14F500BDEC91 /* DraftMainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftMainViewModel.swift; sourceTree = ""; }; 15EE30FD2B5073E20033BBBB /* Pages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pages.swift; sourceTree = ""; }; - 15F1AA532C2E07F50002A7D8 /* BaseReportsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseReportsViewModel.swift; sourceTree = ""; }; 15F64C9C2B6D7904008A57AA /* DownloadedResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedResources.swift; sourceTree = ""; }; 15F64C9F2B6D794B008A57AA /* SectionTitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionTitle.swift; sourceTree = ""; }; 15F64CA12B6D797C008A57AA /* SectionMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionMessage.swift; sourceTree = ""; }; @@ -2501,7 +2499,6 @@ 15E656A92C2A142300BDEC91 /* Reports */ = { isa = PBXGroup; children = ( - 15F1AA532C2E07F50002A7D8 /* BaseReportsViewModel.swift */, ); path = Reports; sourceTree = ""; @@ -3714,7 +3711,6 @@ 1289B45828B63187005DA687 /* RotationViewModifier.swift in Sources */, 126818BF2A376A0E004606BD /* OOXMLContentTypeParser.swift in Sources */, 125D2326271F896400250FBB /* CustomPinView.swift in Sources */, - 15F1AA542C2E07F50002A7D8 /* BaseReportsViewModel.swift in Sources */, E1EEE29A29EECF25009FE227 /* UwaziAddServerURLView.swift in Sources */, CC13138C2A5DB79B0057271C /* BottomButtonsView.swift in Sources */, 150913422B841C3F001E782A /* ResourceActionType.swift in Sources */, diff --git a/Tella/Components/Reports/BaseReportsViewModel.swift b/Tella/Components/Reports/BaseReportsViewModel.swift deleted file mode 100644 index 173b9322e..000000000 --- a/Tella/Components/Reports/BaseReportsViewModel.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// BaseReportsViewModel.swift -// Tella -// -// Created by gus valbuena on 6/27/24. -// Copyright © 2024 HORIZONTAL. All rights reserved. -// - -import Foundation - -protocol ReportsViewModelProtocol: ObservableObject { - var selectedCell: Page { get set } -} - -class BaseReportsViewModel: ObservableObject, ReportsViewModelProtocol { - var mainAppModel: MainAppModel - - @Published var selectedCell: Page = .draft - - init(mainAppModel: MainAppModel) { - self.mainAppModel = mainAppModel - } -} diff --git a/Tella/Scenes/Reports/Draft/DraftReportView.swift b/Tella/Scenes/Reports/Draft/DraftReportView.swift index 0f8f1f04e..b8fd893f6 100644 --- a/Tella/Scenes/Reports/Draft/DraftReportView.swift +++ b/Tella/Scenes/Reports/Draft/DraftReportView.swift @@ -30,7 +30,6 @@ struct DraftReportView_Previews: PreviewProvider { static var previews: some View { DraftReportView(mainAppModel: MainAppModel.stub()) - .environmentObject(BaseReportsViewModel(mainAppModel: MainAppModel.stub())) } } From 440ce7770cf549751b8cfd4033adcccfc370cf73 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 5 Aug 2024 16:35:08 -0300 Subject: [PATCH 117/167] rename reportMainViewModel to ReportsMainViewModel --- Tella.xcodeproj/project.pbxproj | 12 ++++++------ Tella/Domain/Entity/CommonReport/BaseReport.swift | 1 - .../ViewModels/OutboxMainViewModel.swift | 4 ++-- .../ViewModels/ReportMainViewModel.swift | 2 +- .../Views/Draft/DraftView.swift | 2 +- .../Views/ReportMainView.swift | 4 ++-- .../GDrive/ViewModel/GDriveOutboxViewModel.swift | 2 +- Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift | 2 +- .../Scenes/GDrive/Views/Draft/GDriveDraftView.swift | 2 +- .../ViewModels/NextcloudReportViewModel.swift | 2 +- Tella/Scenes/Reports/Draft/DraftReportView.swift | 2 +- Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift | 2 +- .../Reports/Submitted/SubmittedDetailsView.swift | 2 +- Tella/Scenes/Reports/View Model/OutboxReportVM.swift | 2 +- .../Scenes/Reports/View Model/ReportsViewModel.swift | 2 +- 15 files changed, 21 insertions(+), 22 deletions(-) diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index fb8500122..432858691 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -4116,7 +4116,7 @@ CODE_SIGN_ENTITLEMENTS = "Tella/Supporting Files/Tella.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = 6ZG9T42688; ENABLE_PREVIEWS = YES; @@ -4126,7 +4126,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.9.0; + MARKETING_VERSION = 1.10.0; PRODUCT_BUNDLE_IDENTIFIER = org.wearehorizontal.tella; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -4141,9 +4141,9 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "Tella/Supporting Files/Tella.entitlements"; - CODE_SIGN_IDENTITY = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 75; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = 6ZG9T42688; ENABLE_PREVIEWS = YES; @@ -4153,7 +4153,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.9.0; + MARKETING_VERSION = 1.10.0; PRODUCT_BUNDLE_IDENTIFIER = org.wearehorizontal.tella; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/Tella/Domain/Entity/CommonReport/BaseReport.swift b/Tella/Domain/Entity/CommonReport/BaseReport.swift index ac18f3d56..d300e0e33 100644 --- a/Tella/Domain/Entity/CommonReport/BaseReport.swift +++ b/Tella/Domain/Entity/CommonReport/BaseReport.swift @@ -16,7 +16,6 @@ protocol BaseReportProtocol: Hashable { var updatedDate: Date? { get } var status: ReportStatus { get } var reportFiles: [ReportFile]? { get } - var getReportDate: String { get } } diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift index d0953a435..345611722 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift @@ -12,7 +12,7 @@ import Combine class OutboxMainViewModel: ObservableObject { var mainAppModel : MainAppModel - var reportsViewModel : ReportMainViewModel + var reportsViewModel : ReportsMainViewModel @Published var reportViewModel : ReportViewModel = ReportViewModel() @Published var progressFileItems : [ProgressFileItemViewModel] = [] @@ -52,7 +52,7 @@ class OutboxMainViewModel: ObservableObject { } - init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, reportId : Int?) { + init(mainAppModel: MainAppModel, reportsViewModel : ReportsMainViewModel, reportId : Int?) { self.mainAppModel = mainAppModel self.reportsViewModel = reportsViewModel diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift index de4e06e99..940c4c37b 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportMainViewModel.swift @@ -9,7 +9,7 @@ import Foundation import Combine -class ReportMainViewModel: ObservableObject { +class ReportsMainViewModel: ObservableObject { @Published var draftReportsViewModel : [CommonCardViewModel] = [] @Published var outboxedReportsViewModel : [CommonCardViewModel] = [] diff --git a/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift index cffb37821..9993ef301 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift @@ -16,7 +16,7 @@ struct DraftView: View { @EnvironmentObject var sheetManager: SheetManager - var reportsViewModel : ReportMainViewModel + var reportsViewModel : ReportsMainViewModel @Environment(\.presentationMode) var presentationMode: Binding var body: some View { diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift index 7dee34a9e..8931b7e1e 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -11,12 +11,12 @@ import SwiftUI struct ReportMainView: View { - @ObservedObject var reportMainViewModel: ReportMainViewModel + @ObservedObject var reportMainViewModel: ReportsMainViewModel @EnvironmentObject var sheetManager: SheetManager let diContainer : DIContainer - init(reportMainViewModel: ReportMainViewModel, diContainer : DIContainer) { + init(reportMainViewModel: ReportsMainViewModel, diContainer : DIContainer) { self.reportMainViewModel = reportMainViewModel self.diContainer = diContainer } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index c381f6f86..0839168fb 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -17,7 +17,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { var server: GDriveServer? init(mainAppModel: MainAppModel, - reportsViewModel : ReportMainViewModel, + reportsViewModel : ReportsMainViewModel, reportId : Int?, repository: GDriveRepository) { diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift index 427c80613..c2cde2c66 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveViewModel.swift @@ -8,7 +8,7 @@ import Foundation import Combine -class GDriveViewModel: ReportMainViewModel { +class GDriveViewModel: ReportsMainViewModel { @Published var selectedReport: GDriveReport? @Published var server: GDriveServer? diff --git a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift index b92d0a564..57c466f09 100644 --- a/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift +++ b/Tella/Scenes/GDrive/Views/Draft/GDriveDraftView.swift @@ -11,7 +11,7 @@ import SwiftUI struct GDriveDraftView: View { @StateObject var gDriveDraftVM: GDriveDraftViewModel @EnvironmentObject var mainAppModel : MainAppModel - @EnvironmentObject var reportsViewModel : ReportMainViewModel + @EnvironmentObject var reportsViewModel : ReportsMainViewModel let gDriveDIContainer: GDriveDIContainer init(mainAppModel: MainAppModel, gDriveDIContainer: GDriveDIContainer, reportId: Int? = nil) { diff --git a/Tella/Scenes/Nextcloud/ViewModels/NextcloudReportViewModel.swift b/Tella/Scenes/Nextcloud/ViewModels/NextcloudReportViewModel.swift index 819a22077..38d6743b3 100644 --- a/Tella/Scenes/Nextcloud/ViewModels/NextcloudReportViewModel.swift +++ b/Tella/Scenes/Nextcloud/ViewModels/NextcloudReportViewModel.swift @@ -9,7 +9,7 @@ import Foundation import Combine -class NextcloudReportViewModel: ReportMainViewModel { +class NextcloudReportViewModel: ReportsMainViewModel { override func getReports() { diff --git a/Tella/Scenes/Reports/Draft/DraftReportView.swift b/Tella/Scenes/Reports/Draft/DraftReportView.swift index b8fd893f6..2913d7aaa 100644 --- a/Tella/Scenes/Reports/Draft/DraftReportView.swift +++ b/Tella/Scenes/Reports/Draft/DraftReportView.swift @@ -14,7 +14,7 @@ struct DraftReportView: View { @EnvironmentObject var mainAppModel : MainAppModel @EnvironmentObject var sheetManager : SheetManager - @EnvironmentObject var reportsViewModel : ReportMainViewModel + @EnvironmentObject var reportsViewModel : ReportsMainViewModel @Environment(\.presentationMode) var presentationMode: Binding init(mainAppModel: MainAppModel, reportId:Int? = nil) { diff --git a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift index d4cd67878..236a3d8e3 100644 --- a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift +++ b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift @@ -7,7 +7,7 @@ import SwiftUI struct OutboxDetailsView: View { @StateObject var outboxReportVM : OutboxMainViewModel - @EnvironmentObject var reportsViewModel : ReportMainViewModel + @EnvironmentObject var reportsViewModel : ReportsMainViewModel @EnvironmentObject var mainAppModel : MainAppModel @Environment(\.presentationMode) var presentationMode: Binding @EnvironmentObject private var sheetManager: SheetManager diff --git a/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift b/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift index b83f5a156..8be943faa 100644 --- a/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift +++ b/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift @@ -8,7 +8,7 @@ import SwiftUI struct SubmittedDetailsView: View { @StateObject var submittedReportVM : SubmittedMainViewModel - @EnvironmentObject var reportsViewModel : ReportMainViewModel + @EnvironmentObject var reportsViewModel : ReportsMainViewModel @EnvironmentObject var mainAppModel : MainAppModel @Environment(\.presentationMode) var presentationMode: Binding @EnvironmentObject private var sheetManager: SheetManager diff --git a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift index 04713cdf6..fa9f58963 100644 --- a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift +++ b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift @@ -12,7 +12,7 @@ class OutboxReportVM: OutboxMainViewModel { return !(reportViewModel.server?.autoDelete ?? true) } - override init(mainAppModel: MainAppModel, reportsViewModel : ReportMainViewModel, reportId : Int?) { + override init(mainAppModel: MainAppModel, reportsViewModel : ReportsMainViewModel, reportId : Int?) { super.init(mainAppModel: mainAppModel, reportsViewModel: reportsViewModel, reportId: reportId) diff --git a/Tella/Scenes/Reports/View Model/ReportsViewModel.swift b/Tella/Scenes/Reports/View Model/ReportsViewModel.swift index 99186d97d..64a1403e5 100644 --- a/Tella/Scenes/Reports/View Model/ReportsViewModel.swift +++ b/Tella/Scenes/Reports/View Model/ReportsViewModel.swift @@ -7,7 +7,7 @@ import Foundation import Combine import SwiftUI -class ReportsViewModel: ReportMainViewModel { +class ReportsViewModel: ReportsMainViewModel { @Published var selectedReport : Report? var sheetItems : [ListActionSheetItem] { return [ From af23571991b709064546aa9a1dd2749568e87609 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 5 Aug 2024 19:39:09 -0300 Subject: [PATCH 118/167] remove EnvironmentObject from AddFilesToDraftView --- .../Views/Draft/AddFilesToDraftView.swift | 2 +- .../Scenes/CommonConnectionReport/Views/Draft/DraftView.swift | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Tella/Scenes/CommonConnectionReport/Views/Draft/AddFilesToDraftView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/AddFilesToDraftView.swift index cd9fca8fe..b536f0708 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/Draft/AddFilesToDraftView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/Draft/AddFilesToDraftView.swift @@ -12,7 +12,7 @@ struct AddFilesToDraftView: View { @EnvironmentObject var appModel: MainAppModel @EnvironmentObject var sheetManager: SheetManager - @EnvironmentObject var draftReportVM: DraftMainViewModel + @StateObject var draftReportVM: DraftMainViewModel private let gridLayout: [GridItem] = [GridItem(spacing: 12), GridItem(spacing: 12), diff --git a/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift index 9993ef301..a36edba66 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift @@ -118,8 +118,7 @@ struct DraftView: View { Spacer() .frame(height: 24) - AddFilesToDraftView() - .environmentObject(viewModel) + AddFilesToDraftView(draftReportVM: viewModel) Spacer() }.padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) From 24f55de6efb3d02898e7278eb469cacdaa621913 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 9 Aug 2024 14:13:34 -0300 Subject: [PATCH 119/167] add debounceInterval to pause/resume to prevent app crashes --- .../Reports/Outbox/OutboxDetailsView.swift | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift index 236a3d8e3..d00b60df3 100644 --- a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift +++ b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift @@ -11,6 +11,8 @@ struct OutboxDetailsView: View { @EnvironmentObject var mainAppModel : MainAppModel @Environment(\.presentationMode) var presentationMode: Binding @EnvironmentObject private var sheetManager: SheetManager + @State private var isButtonDisabled = false + private let debounceInterval: TimeInterval = 1 var body: some View { @@ -98,9 +100,24 @@ struct OutboxDetailsView: View { buttonType: .yellow, destination: nil, isValid: .constant(true)) { - outboxReportVM.isSubmissionInProgress ? outboxReportVM.pauseSubmission() : outboxReportVM.submitReport() + debounceAction { + outboxReportVM.isSubmissionInProgress ? outboxReportVM.pauseSubmission() : outboxReportVM.submitReport() + } - }.padding(EdgeInsets(top: 30, leading: 24, bottom: 16, trailing: 24)) + } + .padding(EdgeInsets(top: 30, leading: 24, bottom: 16, trailing: 24)) + .disabled(isButtonDisabled) + } + } + + private func debounceAction(action: @escaping () -> Void) { + guard !isButtonDisabled else { return } + + isButtonDisabled = true + action() + + DispatchQueue.main.asyncAfter(deadline: .now() + debounceInterval) { + isButtonDisabled = false } } From bd62d6a09ab2e863ef41062516258ccd491c8774 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 12 Aug 2024 14:01:56 -0300 Subject: [PATCH 120/167] fix design feedback --- .../ViewModels/OutboxMainViewModel.swift | 6 +++--- .../Settings/ViewModel/GDriveAuthViewModel.swift | 13 +++++-------- .../Views/Servers/AddServer/SuccessLoginView.swift | 4 ---- .../Views/Servers/GDrive/CreateDriveFolder.swift | 9 ++++++++- .../Views/Servers/GDrive/SelectSharedDrive.swift | 9 ++++++++- .../Settings/Views/Servers/ServersListView.swift | 2 +- Tella/Supporting Files/en.lproj/Localizable.strings | 3 +++ Tella/Utils/Localizable/LocalizableReport.swift | 5 +++-- 8 files changed, 31 insertions(+), 20 deletions(-) diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift index 345611722..058d16a95 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift @@ -35,11 +35,11 @@ class OutboxMainViewModel: ObservableObject { switch reportViewModel.status { case .finalized: - return "Submit" + return LocalizableReport.submitOutbox.localized case .submissionInProgress: - return "Pause" + return LocalizableReport.pauseOutbox.localized default: - return "Resume" + return LocalizableReport.resumeOutbox.localized } } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift index 56362c5ee..f247937bd 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -19,21 +19,18 @@ class GDriveAuthViewModel: ObservableObject { func handleSignIn(completion: @escaping () -> Void) { self.signInState = .loading - Task { + Task { @MainActor in do { try await gDriveRepository.handleSignIn() - DispatchQueue.main.async { - self.signInState = .loaded(nil) - completion() - } + self.signInState = .loaded(nil) + completion() } catch let error { - DispatchQueue.main.async { - self.signInState = .error(error.localizedDescription) - } + self.signInState = .error(error.localizedDescription) } } } + func handleUrl(url: URL) { gDriveRepository.handleUrl(url: url) } diff --git a/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift b/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift index d1d72d6a1..180625430 100644 --- a/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift +++ b/Tella/Scenes/Settings/Views/Servers/AddServer/SuccessLoginView.swift @@ -73,10 +73,6 @@ struct SuccessLoginView: View { .multilineTextAlignment(.center) } } - - private var reportsView: some View { - ReportMainView(reportMainViewModel: ReportsViewModel(mainAppModel: mainAppModel), diContainer: GDriveDIContainer()) - } } struct SuccessLoginView_Previews: PreviewProvider { diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift index 44037b900..90b198de1 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift @@ -55,11 +55,18 @@ struct CreateDriveFolder: View { shouldHideBack: false, nextAction: { gDriveServerViewModel.createDriveFolder(folderName: fieldContent) { - navigateTo(destination: SuccessLoginView(navigateToAction: {self.popToRoot()}, type: .gDrive)) + navigateTo(destination: SuccessLoginView( + navigateToAction: {navigateTo(destination: reportsView)}, + type: .gDrive) + ) } }) } + + private var reportsView: some View { + ReportMainView(reportMainViewModel: GDriveViewModel(mainAppModel: gDriveServerViewModel.mainAppModel), diContainer: GDriveDIContainer()) + } } #Preview { diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index c925a3e95..f7399e634 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -65,9 +65,16 @@ struct SelectSharedDrive: View { return } gDriveServerViewModel.addServer(rootFolder: selectedDrive.id) { - navigateTo(destination: SuccessLoginView(navigateToAction: {self.popToRoot()}, type: .gDrive)) + navigateTo(destination: SuccessLoginView( + navigateToAction: {navigateTo(destination: reportsView)}, + type: .gDrive) + ) } } + + private var reportsView: some View { + ReportMainView(reportMainViewModel: GDriveViewModel(mainAppModel: gDriveServerViewModel.mainAppModel), diContainer: GDriveDIContainer()) + } } struct DriveCardView: View { diff --git a/Tella/Scenes/Settings/Views/Servers/ServersListView.swift b/Tella/Scenes/Settings/Views/Servers/ServersListView.swift index becfc92fe..6792a2cc4 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServersListView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServersListView.swift @@ -54,7 +54,7 @@ struct ServersListView: View { let filteredActionItems = server.serverType == .gDrive ? serverActionItems.filter { $0.type as? ServerActionType != .edit } : serverActionItems sheetManager.showBottomSheet(modalHeight: 176) { ActionListBottomSheet(items: filteredActionItems, - headerTitle: LocalizableVault.manageFilesSheetTitle.localized, + headerTitle: server.name ?? "", action: {item in serversViewModel.currentServer = server diff --git a/Tella/Supporting Files/en.lproj/Localizable.strings b/Tella/Supporting Files/en.lproj/Localizable.strings index d3b6518a0..17bdf2948 100644 --- a/Tella/Supporting Files/en.lproj/Localizable.strings +++ b/Tella/Supporting Files/en.lproj/Localizable.strings @@ -334,6 +334,9 @@ If you want to take a picture or a video, proceed in the following way:\ "Reports_Draft_SelectFiles_TellaFiles_SheetSelect" = "Select from Tella files"; "Reports_Draft_SelectFiles_ImportFromDevice_SheetSelect" = "Select from your device"; "Reports_Outbox_PercentangeUploaded_Expl" = "Waiting for connection"; +"Reports_Outbox_Pause" = "PAUSE"; +"Reports_Outbox_Resume" = "RESUME"; +"Reports_Outbox_Submit" = "Submit"; "Vault_DeleteFiles_SheetTitle" = "Delete files?"; "Vault_DeleteFiles_SheetExpl" = "%i files will be permanently deleted from Tella."; "Reports_DeleteDraftReport_SheetExpl" = "Are you sure you want to delete this draft?"; diff --git a/Tella/Utils/Localizable/LocalizableReport.swift b/Tella/Utils/Localizable/LocalizableReport.swift index 682b5cf18..4206c2aae 100644 --- a/Tella/Utils/Localizable/LocalizableReport.swift +++ b/Tella/Utils/Localizable/LocalizableReport.swift @@ -63,8 +63,9 @@ enum LocalizableReport: String, LocalizableDelegate { case galleryFilled = "Reports_Draft_SelectFiles_TellaFiles_SheetSelect" case phoneFilled = "Reports_Draft_SelectFiles_ImportFromDevice_SheetSelect" case waitingConnection = "Reports_Outbox_PercentangeUploaded_Expl" - - + case pauseOutbox = "Reports_Outbox_Pause" + case resumeOutbox = "Reports_Outbox_Resume" + case submitOutbox = "Reports_Outbox_Submit" case draftSavedToast = "Reports_DraftSaved_Toast" case reportDeletedToast = "Reports_ReportDeleted_Toast" case reportSubmittedToast = "Reports_ReportSubmitted_Toast" From 8b31cd6255ad772cd221cfa57a126599ef9a7920 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 14 Aug 2024 12:52:25 -0300 Subject: [PATCH 121/167] fix localizableSettings format --- Tella/Domain/Entity/Report/ServerType.swift | 2 +- .../Servers/GDrive/CreateDriveFolder.swift | 6 ++--- .../GDrive/SelectDriveConnection.swift | 12 +++++----- .../Servers/GDrive/SelectSharedDrive.swift | 2 +- .../Localizable/LocalizableSettings.swift | 22 +++++++++---------- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Tella/Domain/Entity/Report/ServerType.swift b/Tella/Domain/Entity/Report/ServerType.swift index 73f59abd4..d846aad71 100644 --- a/Tella/Domain/Entity/Report/ServerType.swift +++ b/Tella/Domain/Entity/Report/ServerType.swift @@ -16,7 +16,7 @@ extension ServerConnectionType { var successConnectionButtonContent: String { switch self { case .gDrive: - return LocalizableSettings.GDriveSuccessMessage.localized + return LocalizableSettings.gDriveSuccessMessage.localized case.tella: return LocalizableSettings.settServerReportsSuccessMessage.localized default: diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift index 90b198de1..6b5e0302b 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/CreateDriveFolder.swift @@ -31,8 +31,8 @@ struct CreateDriveFolder: View { var headerView: some View { ServerConnectionHeaderView( - title: LocalizableSettings.GDriveCreatePersonalFolderTitle.localized, - subtitle: LocalizableSettings.GDriveCreatePersonalFolderDesc.localized + title: LocalizableSettings.gDriveCreatePersonalFolderTitle.localized, + subtitle: LocalizableSettings.gDriveCreatePersonalFolderDesc.localized ) } @@ -41,7 +41,7 @@ struct CreateDriveFolder: View { isValid: $isValid, shouldShowError: .constant(false), fieldType: .text, - placeholder: LocalizableSettings.GDriveCreatePersonalFolderPlaceholder.localized) + placeholder: LocalizableSettings.gDriveCreatePersonalFolderPlaceholder.localized) .padding(.vertical, 12) .onChange(of: fieldContent) { newValue in isValid = !newValue.isEmpty diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index 1deeded66..b39cc53f4 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -29,27 +29,27 @@ struct SelectDriveConnection: View { } var selectDriveToolbar: some View { - NavigationHeaderView(title: LocalizableSettings.GDriveSelectTypeToolbar.localized ,type: .none) + NavigationHeaderView(title: LocalizableSettings.gDriveSelectTypeToolbar.localized ,type: .none) } var headerView: some View { ServerConnectionHeaderView( - title: LocalizableSettings.GDriveSelectTypeTitle.localized, - subtitle: LocalizableSettings.GDriveSelectTypeDesc.localized + title: LocalizableSettings.gDriveSelectTypeTitle.localized, + subtitle: LocalizableSettings.gDriveSelectTypeDesc.localized ) } var connectionsButtons: some View { VStack(spacing: 14) { TellaButtonView( - title: LocalizableSettings.GDriveSelectTypeShared.localized, + title: LocalizableSettings.gDriveSelectTypeShared.localized, nextButtonAction: .action, isOverlay: selectedDriveConnectionType == .shared, isValid: .constant(true), action: { selectedDriveConnectionType = .shared } ) TellaButtonView( - title: LocalizableSettings.GDriveSelectTypePersonal.localized, + title: LocalizableSettings.gDriveSelectTypePersonal.localized, nextButtonAction: .action, isOverlay: selectedDriveConnectionType == .personal, isValid: .constant(true), @@ -62,7 +62,7 @@ struct SelectDriveConnection: View { var moreInfoText: some View { Link(destination: URL(string: TellaUrls.gDriveURL)!) { - Text(LocalizableSettings.GDriveSelectTypeMoreInfo.localized) + Text(LocalizableSettings.gDriveSelectTypeMoreInfo.localized) .font(.custom(Styles.Fonts.regularFontName, size: 14)) .foregroundColor(Styles.Colors.yellow) .multilineTextAlignment(.center) diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index f7399e634..55bd582dc 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -55,7 +55,7 @@ struct SelectSharedDrive: View { var selectSharedDriveHeader: some View { NavigationHeaderView(backButtonAction:{ backButtonAction() }, - title: LocalizableSettings.GDriveSelectSharedDriveToolbar.localized, + title: LocalizableSettings.gDriveSelectSharedDriveToolbar.localized, type: .save) } diff --git a/Tella/Utils/Localizable/LocalizableSettings.swift b/Tella/Utils/Localizable/LocalizableSettings.swift index 8dad9c433..6bc0ecabb 100644 --- a/Tella/Utils/Localizable/LocalizableSettings.swift +++ b/Tella/Utils/Localizable/LocalizableSettings.swift @@ -121,17 +121,17 @@ enum LocalizableSettings: String, LocalizableDelegate { case UwaziSuccessMessage = "Setting_Server_Uwazi_Success_Message" //GDrive - case GDriveSelectTypeToolbar = "Setting_Server_GDrive_Select_Type_Toolbar" - case GDriveSelectTypeTitle = "Setting_Server_GDrive_Select_Type_Title" - case GDriveSelectTypeDesc = "Setting_Server_GDrive_Select_Type_Desc" - case GDriveSelectTypeShared = "Setting_Server_GDrive_Select_Type_Shared" - case GDriveSelectTypePersonal = "Setting_Server_GDrive_Select_Type_Personal" - case GDriveSelectTypeMoreInfo = "Setting_Server_GDrive_Select_Type_More_Info" - case GDriveSelectSharedDriveToolbar = "Setting_Server_GDrive_Select_Shared_Toolbar" - case GDriveCreatePersonalFolderTitle = "Setting_Server_GDrive_Create_Personal_Title" - case GDriveCreatePersonalFolderDesc = "Setting_Server_GDrive_Create_Personal_Desc" - case GDriveCreatePersonalFolderPlaceholder = "Setting_Server_GDrive_Create_Personal_Placeholder" - case GDriveSuccessMessage = "Setting_Server_GDrive_Success_Message" + case gDriveSelectTypeToolbar = "Setting_Server_GDrive_Select_Type_Toolbar" + case gDriveSelectTypeTitle = "Setting_Server_GDrive_Select_Type_Title" + case gDriveSelectTypeDesc = "Setting_Server_GDrive_Select_Type_Desc" + case gDriveSelectTypeShared = "Setting_Server_GDrive_Select_Type_Shared" + case gDriveSelectTypePersonal = "Setting_Server_GDrive_Select_Type_Personal" + case gDriveSelectTypeMoreInfo = "Setting_Server_GDrive_Select_Type_More_Info" + case gDriveSelectSharedDriveToolbar = "Setting_Server_GDrive_Select_Shared_Toolbar" + case gDriveCreatePersonalFolderTitle = "Setting_Server_GDrive_Create_Personal_Title" + case gDriveCreatePersonalFolderDesc = "Setting_Server_GDrive_Create_Personal_Desc" + case gDriveCreatePersonalFolderPlaceholder = "Setting_Server_GDrive_Create_Personal_Placeholder" + case gDriveSuccessMessage = "Setting_Server_GDrive_Success_Message" // About & Help case settAboutAppBar = "Settings_SettAbout_AppBar" From 904b96ca411d0b6e96d2ae828c1c2c59c0c008cd Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 14 Aug 2024 18:00:34 -0300 Subject: [PATCH 122/167] remove unused error --- Tella/Data/Networking/Repositories/GDriveRepository.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 1e1849d98..cd441c4a9 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -264,7 +264,6 @@ class GDriveRepository: GDriveRepositoryProtocol { } guard self.isUploading else { - promise(.failure(APIError.unexpectedResponse)) return } From f6d87dd4a9cf9a8d04473ccacc696cfa979b2cb3 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 15 Aug 2024 13:35:59 -0300 Subject: [PATCH 123/167] fix connection item title and change db version --- Tella/Data/Database/Common/DatabaseConstants.swift | 2 +- Tella/Data/Database/TellaDataBase.swift | 1 + .../HomeView/Views/Home/Connections/ConnectionsView.swift | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Tella/Data/Database/Common/DatabaseConstants.swift b/Tella/Data/Database/Common/DatabaseConstants.swift index 95c9d6e6b..1874caa81 100644 --- a/Tella/Data/Database/Common/DatabaseConstants.swift +++ b/Tella/Data/Database/Common/DatabaseConstants.swift @@ -13,7 +13,7 @@ struct D { /* DATABASE VERSION */ - static let databaseVersion = 5 + static let databaseVersion = 6 /* DEFAULT TYPES FOR DATABASE */ // MARK: - DEFAULT TYPES FOR DATABASE diff --git a/Tella/Data/Database/TellaDataBase.swift b/Tella/Data/Database/TellaDataBase.swift index 4e8eafbe8..f347355cd 100644 --- a/Tella/Data/Database/TellaDataBase.swift +++ b/Tella/Data/Database/TellaDataBase.swift @@ -39,6 +39,7 @@ class TellaDataBase : DataBase { createUwaziEntityInstancesTable() createUwaziEntityInstanceVaultFileTable() addRelationshipColumnToUwaziTemplate() + fallthrough case 5: createGDriveServerTable() createGDriveReportTable() diff --git a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift index eb9287045..8d07e11dd 100644 --- a/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift +++ b/Tella/Scenes/HomeView/Views/Home/Connections/ConnectionsView.swift @@ -107,6 +107,9 @@ struct ConnectionsItemView: View { Text(title) .font(.custom(Styles.Fonts.semiBoldFontName, size: 14)) .foregroundColor(.white) + .multilineTextAlignment(.center) + .frame(maxWidth: 80) + .lineLimit(2) } ) } From 58aa8c3e0f2ebb2c51cf7e8ef7b1a52c9ba3c0f8 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 15 Aug 2024 14:21:28 -0300 Subject: [PATCH 124/167] add some fixes to deleteServerTexts --- Tella/Scenes/Settings/Models/DeleteServerTexts.swift | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Tella/Scenes/Settings/Models/DeleteServerTexts.swift b/Tella/Scenes/Settings/Models/DeleteServerTexts.swift index d886bbbee..d0cbf2f55 100644 --- a/Tella/Scenes/Settings/Models/DeleteServerTexts.swift +++ b/Tella/Scenes/Settings/Models/DeleteServerTexts.swift @@ -19,9 +19,7 @@ enum DeleteServerTexts { switch self { case .tella(let name): return String(format: LocalizableSettings.settServerDeleteTellaConnectionTitle.localized, name) - case .uwazi(let name): - return String(format: LocalizableSettings.settServerDeleteConnectionTitle.localized, name) - case .gDrive(let name): + case .uwazi(let name), .gDrive(let name): return String(format: LocalizableSettings.settServerDeleteConnectionTitle.localized, name) case .unknown: return "" @@ -50,13 +48,14 @@ enum DeleteServerTexts { extension DeleteServerTexts { init(server: Server) { + let serverName = server.name ?? "" switch server.serverType { case .tella: - self = .tella(server.name ?? "") + self = .tella(serverName) case .uwazi: - self = .uwazi(server.name ?? "") + self = .uwazi(serverName) case .gDrive: - self = .gDrive(server.name ?? "") + self = .gDrive(serverName) default: self = .unknown } From b5830385e683f6ec231598b2af6a939913e65b1f Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 15 Aug 2024 15:51:32 -0300 Subject: [PATCH 125/167] fix localizable strings --- .../en.lproj/Localizable.strings | 32 +++++++++---------- .../Localizable/LocalizableSettings.swift | 32 +++++++++---------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Tella/Supporting Files/en.lproj/Localizable.strings b/Tella/Supporting Files/en.lproj/Localizable.strings index 17bdf2948..86e6c630a 100644 --- a/Tella/Supporting Files/en.lproj/Localizable.strings +++ b/Tella/Supporting Files/en.lproj/Localizable.strings @@ -243,13 +243,13 @@ If you want to take a picture or a video, proceed in the following way:\ "Setting_SettServer_GDrive" = "GOOGLE DRIVE"; "Setting_SettServer_No_Internet" = "No Internet connection. Try again when you are connected to the Internet."; "Setting_SettServer_Server_URL_Incorrect" = "Error: The server URL is incorrect"; -"Setting_SettServer_UnavailableConnections_Title" = "Unavailable connections"; -"Setting_SettServer_UnavailableConnections_Description" = "For the following categories, only one connection can be enabled at a time. To add a new connection, please delete the current one by going to Connections Settings."; +"Setting_SettServer_UnavailableConnections_Subhead" = "Unavailable connections"; +"Setting_SettServer_UnavailableConnections_Expl" = "For the following categories, only one connection can be enabled at a time. To add a new connection, please delete the current one by going to Connections Settings."; "Setting_SettServer_No_Token" = "No token present, please connect again"; -"Settings_SettServer_DeleteTellaConnection_Title" = "Delete %@ server?"; -"Settings_SettServre_DeleteConnection_Title" = "Delete \"%@\" connection?"; -"Settings_SettServer_DeleteConnection_Message" = "if you delete this server, all draft and submitted forms will be deleted from your device."; -"Settings_SettServer_DeleteUwaziConnection_Message" = "If you delete this server, all draft and submitted entities will be deleted from your device. Delete anyway?"; +"Settings_SettServer_DeleteTellaConnection_SheetTitle" = "Delete %@ server?"; +"Settings_SettServre_DeleteConnection_SheetTitle" = "Delete \"%@\" connection?"; +"Settings_SettServer_DeleteConnection_SheetExpl" = "if you delete this server, all draft and submitted forms will be deleted from your device."; +"Settings_SettServer_DeleteUwaziConnection_SheetExpl" = "If you delete this server, all draft and submitted entities will be deleted from your device. Delete anyway?"; "Settings_SettServer_Cancel_SheetAction" = "CANCEL"; "Settings_SettServer_Delete_SheetAction" = "DELETE"; "Home_RecentFiles_Subhead" = "Recent files"; @@ -273,16 +273,16 @@ If you want to take a picture or a video, proceed in the following way:\ "Setting_Server_Uwazi_Connect_Server" = "Connected to server"; "Setting_Server_Uwazi_Success_Message" = "You have successfully connected to the server and will be able to share your data."; -"Setting_Server_GDrive_Select_Type_Toolbar" = "Select Google drive"; -"Setting_Server_GDrive_Select_Type_Title" = "Select a Drive to connect to"; -"Setting_Server_GDrive_Select_Type_Desc" = "You can either connect to an organizational Shared Drive or create a new folder in your personal Drive."; -"Setting_Server_GDrive_Select_Type_Shared" = "USE SHARED DRIVE"; -"Setting_Server_GDrive_Select_Type_Personal" = "USE PERSONAL DRIVE"; -"Setting_Server_GDrive_Select_Type_More_Info" = "Learn more about the types of drives"; -"Setting_Server_GDrive_Select_Shared_Toolbar" = "Select shared drive"; -"Setting_Server_GDrive_Create_Personal_Title" = "Create new folder"; -"Setting_Server_GDrive_Create_Personal_Desc" = "Your reports will be uploaded to a new folder on your Google Drive. Choose a name for this folder here."; -"Setting_Server_GDrive_Create_Personal_Placeholder" = "Folder name"; +"Setting_Server_GDrive_SelectType_AppBar" = "Select Google drive"; +"Setting_Server_GDrive_SelectType_Subhead" = "Select a Drive to connect to"; +"Setting_Server_GDrive_SelectType_Expl" = "You can either connect to an organizational Shared Drive or create a new folder in your personal Drive."; +"Setting_Server_GDrive_SelectType_Shared" = "USE SHARED DRIVE"; +"Setting_Server_GDrive_SelectType_Personal" = "USE PERSONAL DRIVE"; +"Setting_Server_GDrive_SelectType_MoreInfo" = "Learn more about the types of drives"; +"Setting_Server_GDrive_SelectShared_Appbar" = "Select shared drive"; +"Setting_Server_GDrive_CreatePersonal_Title" = "Create new folder"; +"Setting_Server_GDrive_CreatePersonal_Desc" = "Your reports will be uploaded to a new folder on your Google Drive. Choose a name for this folder here."; +"Setting_Server_GDrive_CreatePersonal_Placeholder" = "Folder name"; "Setting_Server_GDrive_Success_Message" = "GO TO GOOGLE DRIVE"; "Setting_Server_Reports_Success_Message" = "GO TO REPORTS"; diff --git a/Tella/Utils/Localizable/LocalizableSettings.swift b/Tella/Utils/Localizable/LocalizableSettings.swift index 6bc0ecabb..feb3d26b1 100644 --- a/Tella/Utils/Localizable/LocalizableSettings.swift +++ b/Tella/Utils/Localizable/LocalizableSettings.swift @@ -91,13 +91,13 @@ enum LocalizableSettings: String, LocalizableDelegate { case settServerGDrive = "Setting_SettServer_GDrive" case settServerNoInternetConnection = "Setting_SettServer_No_Internet" case settServerServerURLIncorrect = "Setting_SettServer_Server_URL_Incorrect" - case settServerUnavailableConnectionsTitle = "Setting_SettServer_UnavailableConnections_Title" - case settServerUnavailableConnectionsDesc = "Setting_SettServer_UnavailableConnections_Description" + case settServerUnavailableConnectionsTitle = "Setting_SettServer_UnavailableConnections_Subhead" + case settServerUnavailableConnectionsDesc = "Setting_SettServer_UnavailableConnections_Expl" case settServerNoTokenPresent = "Setting_SettServer_No_Token" - case settServerDeleteConnectionTitle = "Settings_SettServre_DeleteConnection_Title" - case settServerDeleteTellaConnectionTitle = "Settings_SettServer_DeleteTellaConnection_Title" - case settServerDeleteConnectionMessage = "Settings_SettServer_DeleteConnection_Message" - case settServerDeleteUwaziConnectionMessage = "Settings_SettServer_DeleteUwaziConnection_Message" + case settServerDeleteConnectionTitle = "Settings_SettServre_DeleteConnection_SheetTitle" + case settServerDeleteTellaConnectionTitle = "Settings_SettServer_DeleteTellaConnection_SheetTitle" + case settServerDeleteConnectionMessage = "Settings_SettServer_DeleteConnection_SheetExpl" + case settServerDeleteUwaziConnectionMessage = "Settings_SettServer_DeleteUwaziConnection_SheetExpl" case settServerDeleteSheetAction = "Settings_SettServer_Delete_SheetAction" case settServerCancelSheetAction = "Settings_SettServer_Cancel_SheetAction" @@ -121,16 +121,16 @@ enum LocalizableSettings: String, LocalizableDelegate { case UwaziSuccessMessage = "Setting_Server_Uwazi_Success_Message" //GDrive - case gDriveSelectTypeToolbar = "Setting_Server_GDrive_Select_Type_Toolbar" - case gDriveSelectTypeTitle = "Setting_Server_GDrive_Select_Type_Title" - case gDriveSelectTypeDesc = "Setting_Server_GDrive_Select_Type_Desc" - case gDriveSelectTypeShared = "Setting_Server_GDrive_Select_Type_Shared" - case gDriveSelectTypePersonal = "Setting_Server_GDrive_Select_Type_Personal" - case gDriveSelectTypeMoreInfo = "Setting_Server_GDrive_Select_Type_More_Info" - case gDriveSelectSharedDriveToolbar = "Setting_Server_GDrive_Select_Shared_Toolbar" - case gDriveCreatePersonalFolderTitle = "Setting_Server_GDrive_Create_Personal_Title" - case gDriveCreatePersonalFolderDesc = "Setting_Server_GDrive_Create_Personal_Desc" - case gDriveCreatePersonalFolderPlaceholder = "Setting_Server_GDrive_Create_Personal_Placeholder" + case gDriveSelectTypeToolbar = "Setting_Server_GDrive_SelectType_AppBar" + case gDriveSelectTypeTitle = "Setting_Server_GDrive_SelectType_Subhead" + case gDriveSelectTypeDesc = "Setting_Server_GDrive_SelectType_Expl" + case gDriveSelectTypeShared = "Setting_Server_GDrive_SelectType_Shared" + case gDriveSelectTypePersonal = "Setting_Server_GDrive_SelectType_Personal" + case gDriveSelectTypeMoreInfo = "Setting_Server_GDrive_SelectType_MoreInfo" + case gDriveSelectSharedDriveToolbar = "Setting_Server_GDrive_SelectShared_Appbar" + case gDriveCreatePersonalFolderTitle = "Setting_Server_GDrive_CreatePersonal_Title" + case gDriveCreatePersonalFolderDesc = "Setting_Server_GDrive_CreatePersonal_Desc" + case gDriveCreatePersonalFolderPlaceholder = "Setting_Server_GDrive_CreatePersonal_Placeholder" case gDriveSuccessMessage = "Setting_Server_GDrive_Success_Message" // About & Help From 65b70432639cb2e2a76e3e177d94f0798f7728ad Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 15 Aug 2024 17:16:18 -0300 Subject: [PATCH 126/167] change disabling button to isValid in outbox details --- Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift index d00b60df3..68cbab46c 100644 --- a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift +++ b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift @@ -99,14 +99,13 @@ struct OutboxDetailsView: View { nextButtonAction: .action, buttonType: .yellow, destination: nil, - isValid: .constant(true)) { + isValid: .constant(!isButtonDisabled)) { debounceAction { outboxReportVM.isSubmissionInProgress ? outboxReportVM.pauseSubmission() : outboxReportVM.submitReport() } } .padding(EdgeInsets(top: 30, leading: 24, bottom: 16, trailing: 24)) - .disabled(isButtonDisabled) } } From 2d146660f163c2e136ea0b7658d757f76afd1d00 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Thu, 15 Aug 2024 17:27:54 -0300 Subject: [PATCH 127/167] hotfix for large files --- .../ViewModels/OutboxMainViewModel.swift | 1 + Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift | 3 ++- Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift index 058d16a95..a98d94d4b 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift @@ -27,6 +27,7 @@ class OutboxMainViewModel: ObservableObject { } @Published var shouldShowSubmittedReportView : Bool = false @Published var shouldShowMainView : Bool = false + @Published var isFileLoading : Bool = false var subscribers = Set() var filesToUpload : [FileToUpload] = [] diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 0839168fb..ff40da87a 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -78,6 +78,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { //submit report override func submitReport() { + self.isFileLoading = true if isSubmissionInProgress == false { self.updateReportStatus(reportStatus: .submissionInProgress) } @@ -126,7 +127,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { uploadNextFile(folderId: folderId) return } - + self.isFileLoading = false currentUploadCancellable = gDriveRepository.uploadFile(fileURL: fileUrl, fileId: fileToUpload.id ?? "", mimeType: fileToUpload.mimeType ?? "", folderId: folderId) .receive(on: DispatchQueue.main) .sink( diff --git a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift index 68cbab46c..401800ce0 100644 --- a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift +++ b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift @@ -99,7 +99,7 @@ struct OutboxDetailsView: View { nextButtonAction: .action, buttonType: .yellow, destination: nil, - isValid: .constant(!isButtonDisabled)) { + isValid: .constant(!isButtonDisabled && !outboxReportVM.isFileLoading)) { debounceAction { outboxReportVM.isSubmissionInProgress ? outboxReportVM.pauseSubmission() : outboxReportVM.submitReport() } From 98035354ca6439ece557752224b689e4870d642b Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 16 Aug 2024 12:03:04 -0300 Subject: [PATCH 128/167] remove server protocol and replace print for debugLog --- .../Repositories/GDriveRepository.swift | 6 +++--- Tella/Domain/Entity/CommonServer/Server.swift | 17 ----------------- Tella/Domain/Entity/GDrive/GDriveServer.swift | 4 ++-- Tella/Domain/Entity/Report/TellaServer.swift | 2 +- .../ViewModels/DraftMainViewModel.swift | 2 +- .../ViewModels/OutboxMainViewModel.swift | 2 +- .../ViewModels/ReportViewModel.swift | 2 +- .../Views/Draft/AddFilesToDraftView.swift | 2 +- .../Views/Draft/DraftView.swift | 2 +- .../Views/Draft/ReportFileGridView.swift | 2 +- .../Reports/Outbox/OutboxDetailsView.swift | 2 +- 11 files changed, 13 insertions(+), 30 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index cd441c4a9..04fd1d781 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -47,7 +47,7 @@ class GDriveRepository: GDriveRepositoryProtocol { }).store(in: &subscribers) } private var rootViewController: UIViewController? { - return UIApplication.shared.windows.first?.rootViewController + return UIApplication.getTopViewController() } private func ensureSignedIn() async throws { @@ -113,7 +113,7 @@ class GDriveRepository: GDriveRepositoryProtocol { driveService.executeQuery(query) { ticket, response, error in if let error = error { - print("Error fetching drives: \(error.localizedDescription)") + debugLog("Error fetching drives: \(error.localizedDescription)") promise(.failure(error)) } @@ -194,7 +194,7 @@ class GDriveRepository: GDriveRepositoryProtocol { driveService.executeQuery(query) { (ticket, file, error) in if let error = error { - print("Error creating folder: \(error.localizedDescription)") + debugLog("Error creating folder: \(error.localizedDescription)") promise(.failure(self.mapToAPIError(error))) return } diff --git a/Tella/Domain/Entity/CommonServer/Server.swift b/Tella/Domain/Entity/CommonServer/Server.swift index fd858ecd8..4d2c18d48 100644 --- a/Tella/Domain/Entity/CommonServer/Server.swift +++ b/Tella/Domain/Entity/CommonServer/Server.swift @@ -8,23 +8,6 @@ import Foundation -protocol ServerProtocol: Codable, Equatable, Hashable { - var id: Int? { get set } - var name: String? { get set } - var serverType: ServerConnectionType? { get set } - var allowMultiple: Bool? { get set } -} - -extension ServerProtocol { - static func == (lhs: Self, rhs: Self) -> Bool { - return lhs.id == rhs.id - } - - func hash(into hasher: inout Hasher) { - hasher.combine(id.hashValue) - } -} - class Server: Codable, Equatable, Hashable { var id: Int? diff --git a/Tella/Domain/Entity/GDrive/GDriveServer.swift b/Tella/Domain/Entity/GDrive/GDriveServer.swift index cd0529946..b2f9ceeb1 100644 --- a/Tella/Domain/Entity/GDrive/GDriveServer.swift +++ b/Tella/Domain/Entity/GDrive/GDriveServer.swift @@ -8,7 +8,7 @@ import Foundation -class GDriveServer: Server, ServerProtocol { +class GDriveServer: Server { var rootFolder: String? enum CodingKeys: String, CodingKey { @@ -16,7 +16,7 @@ class GDriveServer: Server, ServerProtocol { } init(id: Int? = nil, - name: String? = "Google Drive", + name: String? = LocalizableGDrive.gDriveAppBar.localized, rootFolder: String, serverType: ServerConnectionType? = .gDrive) { diff --git a/Tella/Domain/Entity/Report/TellaServer.swift b/Tella/Domain/Entity/Report/TellaServer.swift index b1672f9b9..ef3b10c50 100644 --- a/Tella/Domain/Entity/Report/TellaServer.swift +++ b/Tella/Domain/Entity/Report/TellaServer.swift @@ -5,7 +5,7 @@ import Foundation -class TellaServer : WebServer, ServerProtocol { +class TellaServer : WebServer { var activatedMetadata : Bool? var backgroundUpload : Bool? diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/DraftMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/DraftMainViewModel.swift index f22c4415e..09218e414 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/DraftMainViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/DraftMainViewModel.swift @@ -9,7 +9,7 @@ import Foundation import Combine -class DraftMainViewModel: ObservableObject { +class DraftMainViewModel: ObservableObject { var mainAppModel : MainAppModel // Report @Published var reportId : Int? diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift index a98d94d4b..b183d692c 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift @@ -9,7 +9,7 @@ import Foundation import Combine -class OutboxMainViewModel: ObservableObject { +class OutboxMainViewModel: ObservableObject { var mainAppModel : MainAppModel var reportsViewModel : ReportsMainViewModel diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportViewModel.swift index 9eac065fc..b900fd598 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportViewModel.swift @@ -4,7 +4,7 @@ import Foundation -class ReportViewModel { +class ReportViewModel { @Published var id : Int? @Published var title : String = "" @Published var description : String = "" diff --git a/Tella/Scenes/CommonConnectionReport/Views/Draft/AddFilesToDraftView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/AddFilesToDraftView.swift index b536f0708..24cf4624f 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/Draft/AddFilesToDraftView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/Draft/AddFilesToDraftView.swift @@ -8,7 +8,7 @@ import SwiftUI -struct AddFilesToDraftView: View { +struct AddFilesToDraftView: View { @EnvironmentObject var appModel: MainAppModel @EnvironmentObject var sheetManager: SheetManager diff --git a/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift index a36edba66..3db04ccdf 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift @@ -8,7 +8,7 @@ import SwiftUI -struct DraftView: View { +struct DraftView: View { @StateObject var viewModel: DraftMainViewModel @State private var menuFrame : CGRect = CGRectZero diff --git a/Tella/Scenes/CommonConnectionReport/Views/Draft/ReportFileGridView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/ReportFileGridView.swift index db988bc21..e55305147 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/Draft/ReportFileGridView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/Draft/ReportFileGridView.swift @@ -6,7 +6,7 @@ import SwiftUI -struct ReportFileGridView: View { +struct ReportFileGridView: View { var file: VaultFileDB diff --git a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift index 401800ce0..9f40b3b32 100644 --- a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift +++ b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift @@ -4,7 +4,7 @@ import SwiftUI -struct OutboxDetailsView: View { +struct OutboxDetailsView: View { @StateObject var outboxReportVM : OutboxMainViewModel @EnvironmentObject var reportsViewModel : ReportsMainViewModel From e10fb52b5f3c879a224be3c2c7e9fb2c530cff7b Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 16 Aug 2024 13:55:22 -0300 Subject: [PATCH 129/167] remove generic from draft report --- .../ViewModels/DraftMainViewModel.swift | 6 +++--- .../Views/Draft/AddFilesToDraftView.swift | 6 +++--- .../CommonConnectionReport/Views/Draft/DraftView.swift | 6 +++--- .../Views/Draft/ReportFileGridView.swift | 4 ++-- Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift | 4 ++-- Tella/Scenes/Reports/View Model/DraftReportVM.swift | 4 ++-- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/DraftMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/DraftMainViewModel.swift index 09218e414..e60444abe 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/DraftMainViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/DraftMainViewModel.swift @@ -9,14 +9,14 @@ import Foundation import Combine -class DraftMainViewModel: ObservableObject { +class DraftMainViewModel: ObservableObject { var mainAppModel : MainAppModel // Report @Published var reportId : Int? @Published var title : String = "" @Published var description : String = "" @Published var files : Set = [] - @Published var server : T? + @Published var server : Server? @Published var status : ReportStatus? @Published var apiID : String? @@ -41,7 +41,7 @@ class DraftMainViewModel: ObservableObject { var successSavingReportPublisher: Published.Publisher { $successSavingReport } var failureSavingReportPublisher: Published.Publisher { $failureSavingReport } - var serverArray : [T] = [] + var serverArray : [Server] = [] var cancellable : Cancellable? = nil var subscribers = Set() diff --git a/Tella/Scenes/CommonConnectionReport/Views/Draft/AddFilesToDraftView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/AddFilesToDraftView.swift index 24cf4624f..1eb4f2d50 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/Draft/AddFilesToDraftView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/Draft/AddFilesToDraftView.swift @@ -8,11 +8,11 @@ import SwiftUI -struct AddFilesToDraftView: View { +struct AddFilesToDraftView: View { @EnvironmentObject var appModel: MainAppModel @EnvironmentObject var sheetManager: SheetManager - @StateObject var draftReportVM: DraftMainViewModel + @StateObject var draftReportVM: DraftMainViewModel private let gridLayout: [GridItem] = [GridItem(spacing: 12), GridItem(spacing: 12), @@ -41,7 +41,7 @@ struct AddFilesToDraftView: View { var itemsGridView: some View { LazyVGrid(columns: gridLayout, alignment: .center, spacing: 12) { ForEach(draftReportVM.files.sorted{$0.created < $1.created}, id: \.id) { file in - ReportFileGridView(file: file) + ReportFileGridView(file: file) .frame(height: (UIScreen.screenWidth - 64) / 3 ) .environmentObject(draftReportVM) } diff --git a/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift index 3db04ccdf..afca373cf 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift @@ -8,8 +8,8 @@ import SwiftUI -struct DraftView: View { - @StateObject var viewModel: DraftMainViewModel +struct DraftView: View { + @StateObject var viewModel: DraftMainViewModel @State private var menuFrame : CGRect = CGRectZero @State private var shouldShowMenu : Bool = false @@ -118,7 +118,7 @@ struct DraftView: View { Spacer() .frame(height: 24) - AddFilesToDraftView(draftReportVM: viewModel) + AddFilesToDraftView(draftReportVM: viewModel) Spacer() }.padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) diff --git a/Tella/Scenes/CommonConnectionReport/Views/Draft/ReportFileGridView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/ReportFileGridView.swift index e55305147..6f0556fb0 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/Draft/ReportFileGridView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/Draft/ReportFileGridView.swift @@ -6,11 +6,11 @@ import SwiftUI -struct ReportFileGridView: View { +struct ReportFileGridView: View { var file: VaultFileDB - @EnvironmentObject var draftReportVM: DraftMainViewModel + @EnvironmentObject var draftReportVM: DraftMainViewModel var body: some View { fileGridView diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift index 86bd512bf..8d4efb332 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveDraftViewModel.swift @@ -9,7 +9,7 @@ import Foundation import Combine -class GDriveDraftViewModel: DraftMainViewModel { +class GDriveDraftViewModel: DraftMainViewModel{ private let gDriveRepository: GDriveRepositoryProtocol init(mainAppModel: MainAppModel, repository: GDriveRepositoryProtocol, reportId reportID: Int?) { @@ -51,7 +51,7 @@ class GDriveDraftViewModel: DraftMainViewModel { title: title, description: description, status: status ?? .unknown, - server: server, + server: server as! GDriveServer, folderId: nil, vaultFiles: self.files.compactMap { ReportFile( fileId: $0.id, status: .notSubmitted, diff --git a/Tella/Scenes/Reports/View Model/DraftReportVM.swift b/Tella/Scenes/Reports/View Model/DraftReportVM.swift index e66565793..51e54f024 100644 --- a/Tella/Scenes/Reports/View Model/DraftReportVM.swift +++ b/Tella/Scenes/Reports/View Model/DraftReportVM.swift @@ -7,7 +7,7 @@ import Foundation import Combine import SwiftUI -class DraftReportVM: DraftMainViewModel { +class DraftReportVM: DraftMainViewModel { override init(mainAppModel : MainAppModel, reportId:Int? = nil) { super.init(mainAppModel: mainAppModel, reportId: reportId) } @@ -73,7 +73,7 @@ class DraftReportVM: DraftMainViewModel { title: title, description: description, status: status, - server: server, + server: server as! TellaServer, vaultFiles: self.files.compactMap{ ReportFile(fileId: $0.id, status: .notSubmitted, bytesSent: 0, From 06c6b56c0d9131880c97d29281a1593e8f348a69 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 16 Aug 2024 14:26:45 -0300 Subject: [PATCH 130/167] remove drive report files when deleting a report --- Tella/Data/Database/GDriveDatabase.swift | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index 5221134dc..3a284fa0b 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -136,9 +136,7 @@ extension TellaDataBase { func updateDriveReportFiles(files: [ReportFile], reportId: Int) -> Result { do { - let reportFilesCondition = [KeyValue(key: D.cReportInstanceId, value: reportId)] - - try statementBuilder.delete(tableName: D.tGDriveInstanceVaultFile, primarykeyValue: reportFilesCondition) + try deleteDriveReportFiles(reportId: reportId) try files.forEach( { reportFiles in let reportFilesDict = reportFiles.dictionary @@ -214,6 +212,9 @@ extension TellaDataBase { try statementBuilder.delete(tableName: D.tGDriveReport, primarykeyValue: reportCondition) + // delete files + try deleteDriveReportFiles(reportId: reportId) + return .success(true) } catch let error { debugLog(error) @@ -222,6 +223,11 @@ extension TellaDataBase { } } + func deleteDriveReportFiles(reportId: Int?) throws { + let fileCondition = [KeyValue(key: D.cReportInstanceId, value: reportId)] + try statementBuilder.delete(tableName: D.tGDriveInstanceVaultFile, primarykeyValue: fileCondition) + } + func updateDriveReportStatus(idReport: Int, status: ReportStatus) -> Result { do { let valuesToUpdate = [KeyValue(key: D.cStatus, value: status.rawValue), From 45707dbbc25b97ad5ba8e7eb7d8c4f1eeaeefb5d Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 16 Aug 2024 15:02:31 -0300 Subject: [PATCH 131/167] add missing localizable strings --- .../ViewModels/OutboxMainViewModel.swift | 7 +++++-- .../ViewModels/SubmittedMainViewModel.swift | 5 +++-- Tella/Supporting Files/en.lproj/Localizable.strings | 4 ++++ Tella/Utils/Localizable/LocalizableReport.swift | 4 ++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift index b183d692c..b9847f3ff 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift @@ -81,9 +81,12 @@ class OutboxMainViewModel: ObservableObject { let formattedTotalSize = totalSize.getFormattedFileSize() DispatchQueue.main.async { - self.percentUploadedInfo = "\(Int(formattedPercentUploaded * 100))% uploaded" + self.percentUploadedInfo = "\(Int(formattedPercentUploaded * 100))% \(LocalizableReport.reportUploaded.localized)" self.percentUploaded = Float(percentUploaded) - self.uploadedFiles = " \(self.reportViewModel.files.count) files, \(formattedTotalUploaded)/\(formattedTotalSize) uploaded" + let filesCount = "\(self.reportViewModel.files.count) \(self.reportViewModel.files.count == 1 ? LocalizableReport.reportFile.localized : LocalizableReport.reportFiles.localized)" + let fileUploaded = "\(formattedTotalUploaded)/\(formattedTotalSize) \(LocalizableReport.reportUploaded.localized)" + + self.uploadedFiles = "\(filesCount), \(fileUploaded)" self.progressFileItems = self.reportViewModel.files.compactMap{ProgressFileItemViewModel(file: $0, progression: ($0.bytesSent.getFormattedFileSize()) + "/" + ($0.size.getFormattedFileSize()))} diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/SubmittedMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/SubmittedMainViewModel.swift index 9d6629732..8df3192af 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/SubmittedMainViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/SubmittedMainViewModel.swift @@ -57,11 +57,12 @@ class SubmittedMainViewModel: ObservableObject { let totalSize = self.files.reduce(0) { $0 + $1.size } if let date = report.createdDate { - self.uploadedDate = "Uploaded on \(date.getFormattedDateString(format: DateFormat.submittedReport.rawValue))" + let formattedDate = date.getFormattedDateString(format: DateFormat.submittedReport.rawValue) + self.uploadedDate = String(format: LocalizableReport.uploadedDate.localized, formattedDate) } let fileNumber = self.files.count - let fileString = fileNumber == 1 ? "file" : "files" + let fileString = fileNumber == 1 ? LocalizableReport.reportFile.localized : LocalizableReport.reportFiles.localized self.uploadedFiles = "\(fileNumber) \(fileString), \(totalSize.getFormattedFileSize())" } diff --git a/Tella/Supporting Files/en.lproj/Localizable.strings b/Tella/Supporting Files/en.lproj/Localizable.strings index 86e6c630a..b2a6a81e3 100644 --- a/Tella/Supporting Files/en.lproj/Localizable.strings +++ b/Tella/Supporting Files/en.lproj/Localizable.strings @@ -374,6 +374,10 @@ If you want to take a picture or a video, proceed in the following way:\ "Reports_Submitted_ClearAll_Cancel_SheetAction" = "CANCEL"; "Reports_Submitted_ClearAll_ClearSubmitted_SheetAction" = "CLEAR SUBMITTED"; "Reports_Submitted_Clear_AppBar" = "Clear"; +"Reports_Submitted_UploadedDate_Expl" = "Uploaded on %@"; +"Reports_Submitted_File_Title" = "file"; +"Reports_Submitted_Files_Title" = "files"; +"Reports_Outbox_Uploaded_Title" = "uploaded"; "Reports_DraftSaved_Toast" = "The report was saved as a draft"; "Reports_ReportDeleted_Toast" = "“%@” has been deleted."; "Reports_ReportSubmitted_Toast" = "Upload complete: “%@”"; diff --git a/Tella/Utils/Localizable/LocalizableReport.swift b/Tella/Utils/Localizable/LocalizableReport.swift index 4206c2aae..92999e1f3 100644 --- a/Tella/Utils/Localizable/LocalizableReport.swift +++ b/Tella/Utils/Localizable/LocalizableReport.swift @@ -76,4 +76,8 @@ enum LocalizableReport: String, LocalizableDelegate { case outboxListExpl = "Reports_Outbox_OutboxList_Expl" case submittedListExpl = "Reports_Submitted_SubmittedList_Expl" + case uploadedDate = "Reports_Submitted_UploadedDate_Expl" + case reportFile = "Reports_Submitted_File_Title" + case reportFiles = "Reports_Submitted_Files_Title" + case reportUploaded = "Reports_Outbox_Uploaded_Title" } From 59e4adc6ac60b12eb56c16e42e75875b0e0a209d Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 16 Aug 2024 15:05:56 -0300 Subject: [PATCH 132/167] move Components/connections to CommonConnectionReport --- Tella.xcodeproj/project.pbxproj | 2 +- .../Views}/Connections/Card/ConnectionCardDetails.swift | 0 .../Views}/Connections/Card/MoreButtonView.swift | 0 .../Views}/Connections/ConnectionEmptyView.swift | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename Tella/{Components => Scenes/CommonConnectionReport/Views}/Connections/Card/ConnectionCardDetails.swift (100%) rename Tella/{Components => Scenes/CommonConnectionReport/Views}/Connections/Card/MoreButtonView.swift (100%) rename Tella/{Components => Scenes/CommonConnectionReport/Views}/Connections/ConnectionEmptyView.swift (100%) diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 432858691..cd0f249ce 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -1628,6 +1628,7 @@ 125C789C2C36B50100440014 /* Views */ = { isa = PBXGroup; children = ( + CCF47F3F2ABE11F3000ABBBC /* Connections */, 1242135429B774A40002402D /* DeleteReportConfirmationView.swift */, 123048D3295F954E0015CD96 /* Submitted */, 12199C322940936B0041BD38 /* Outbox */, @@ -2279,7 +2280,6 @@ isa = PBXGroup; children = ( 15E656A92C2A142300BDEC91 /* Reports */, - CCF47F3F2ABE11F3000ABBBC /* Connections */, 12C07F032B0748BE0030AD6E /* TopSheetView */, 122E4D53291AD99A00562EB1 /* TellaButton */, 1272F25A27C919E40054F2E2 /* ImportFilesProgressView */, diff --git a/Tella/Components/Connections/Card/ConnectionCardDetails.swift b/Tella/Scenes/CommonConnectionReport/Views/Connections/Card/ConnectionCardDetails.swift similarity index 100% rename from Tella/Components/Connections/Card/ConnectionCardDetails.swift rename to Tella/Scenes/CommonConnectionReport/Views/Connections/Card/ConnectionCardDetails.swift diff --git a/Tella/Components/Connections/Card/MoreButtonView.swift b/Tella/Scenes/CommonConnectionReport/Views/Connections/Card/MoreButtonView.swift similarity index 100% rename from Tella/Components/Connections/Card/MoreButtonView.swift rename to Tella/Scenes/CommonConnectionReport/Views/Connections/Card/MoreButtonView.swift diff --git a/Tella/Components/Connections/ConnectionEmptyView.swift b/Tella/Scenes/CommonConnectionReport/Views/Connections/ConnectionEmptyView.swift similarity index 100% rename from Tella/Components/Connections/ConnectionEmptyView.swift rename to Tella/Scenes/CommonConnectionReport/Views/Connections/ConnectionEmptyView.swift From e5503436bd77e0b5cc3c685fec56de30a3415378 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 16 Aug 2024 15:29:14 -0300 Subject: [PATCH 133/167] simplify serverArray logic in HomeView --- Tella/Scenes/HomeView/ViewModel/HomeViewModel.swift | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Tella/Scenes/HomeView/ViewModel/HomeViewModel.swift b/Tella/Scenes/HomeView/ViewModel/HomeViewModel.swift index 13991fb32..590133677 100644 --- a/Tella/Scenes/HomeView/ViewModel/HomeViewModel.swift +++ b/Tella/Scenes/HomeView/ViewModel/HomeViewModel.swift @@ -37,12 +37,8 @@ class HomeViewModel: ObservableObject { var serverConnections: [ServerConnectionType: [Server]] = [:] for server in serverArray { - guard let serverType = server.serverType else { return } - if serverConnections[serverType] != nil { - serverConnections[serverType] = [server] - } else { - serverConnections[serverType] = [server] - } + guard let serverType = server.serverType else { continue } + serverConnections[serverType, default: []].append(server) } for (serverType, servers) in serverConnections { From b685476747b9298aa0a28b90d117e6003f3c274b Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 16 Aug 2024 16:15:37 -0300 Subject: [PATCH 134/167] add struct for simplifying upload file function params --- .../Repositories/GDriveRepository.swift | 40 ++++++++++--------- .../ViewModel/GDriveOutboxViewModel.swift | 8 +++- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 04fd1d781..88f740f8f 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -11,13 +11,19 @@ import GoogleSignIn import GoogleAPIClientForREST import Combine +struct FileUploadDetails { + let fileURL: URL + let fileId: String + let mimeType: String + let folderId: String +} protocol GDriveRepositoryProtocol { func handleSignIn() async throws func restorePreviousSignIn() async throws func handleUrl(url: URL) func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> func createDriveFolder(folderName: String, parentId: String?, description: String?) -> AnyPublisher - func uploadFile(fileURL: URL, fileId: String, mimeType: String, folderId: String) -> AnyPublisher + func uploadFile(fileUploadDetails: FileUploadDetails) -> AnyPublisher func pauseAllUploads() func resumeAllUploads() func signOut() -> Void @@ -209,10 +215,7 @@ class GDriveRepository: GDriveRepositoryProtocol { } func uploadFile( - fileURL: URL, - fileId: String, - mimeType: String, - folderId: String + fileUploadDetails: FileUploadDetails ) -> AnyPublisher { return Deferred { Future { promise in @@ -224,10 +227,7 @@ class GDriveRepository: GDriveRepositoryProtocol { do { try await self.ensureSignedIn() self.performUploadFile( - fileURL: fileURL, - fileId: fileId, - mimeType: mimeType, - folderId: folderId, + fileUploadDetails: fileUploadDetails, promise: promise ) @@ -247,10 +247,7 @@ class GDriveRepository: GDriveRepositoryProtocol { } private func performUploadFile( - fileURL: URL, - fileId: String, - mimeType: String, - folderId: String, + fileUploadDetails: FileUploadDetails, promise: @escaping (Result) -> Void ) { Task { @@ -275,6 +272,11 @@ class GDriveRepository: GDriveRepositoryProtocol { let driveService = GTLRDriveService() driveService.authorizer = user.fetcherAuthorizer + let fileURL = fileUploadDetails.fileURL + let mimeType = fileUploadDetails.mimeType + let fileId = fileUploadDetails.fileId + let folderId = fileUploadDetails.folderId + let fileName = fileURL.lastPathComponent let totalSize = UInt64((try? fileURL.resourceValues(forKeys: [.fileSizeKey]).fileSize) ?? 0) let uploadProgressInfo = UploadProgressInfo(fileId: fileId, status: .notSubmitted, total: Int(totalSize)) @@ -289,7 +291,7 @@ class GDriveRepository: GDriveRepositoryProtocol { promise(.success(uploadProgressInfo)) } else { // File doesn't exist, proceed with upload - self.uploadNewFile(fileURL: fileURL, fileId: fileId, mimeType: mimeType, folderId: folderId, driveService: driveService, uploadProgressInfo: uploadProgressInfo, promise: promise) + self.uploadNewFile(fileUploadDetails: fileUploadDetails, driveService: driveService, uploadProgressInfo: uploadProgressInfo, promise: promise) } } catch { promise(.failure(self.mapToAPIError(error))) @@ -298,14 +300,16 @@ class GDriveRepository: GDriveRepositoryProtocol { } private func uploadNewFile( - fileURL: URL, - fileId: String, - mimeType: String, - folderId: String, + fileUploadDetails: FileUploadDetails, driveService: GTLRDriveService, uploadProgressInfo: UploadProgressInfo, promise: @escaping (Result) -> Void ) { + let fileURL = fileUploadDetails.fileURL + let mimeType = fileUploadDetails.mimeType + let fileId = fileUploadDetails.fileId + let folderId = fileUploadDetails.folderId + let file = GTLRDrive_File() file.name = fileURL.lastPathComponent file.mimeType = mimeType diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index ff40da87a..7a50a9647 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -128,7 +128,13 @@ class GDriveOutboxViewModel: OutboxMainViewModel { return } self.isFileLoading = false - currentUploadCancellable = gDriveRepository.uploadFile(fileURL: fileUrl, fileId: fileToUpload.id ?? "", mimeType: fileToUpload.mimeType ?? "", folderId: folderId) + + let fileUploadDetails = FileUploadDetails(fileURL: fileUrl, + fileId: fileToUpload.id ?? "", + mimeType: fileToUpload.mimeType ?? "", + folderId: folderId) + + currentUploadCancellable = gDriveRepository.uploadFile(fileUploadDetails: fileUploadDetails) .receive(on: DispatchQueue.main) .sink( receiveCompletion: { [weak self] completion in From 376aac7edf296169ae804ce4d15ea9be5d1e9f31 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 19 Aug 2024 12:59:25 -0300 Subject: [PATCH 135/167] add new initializer to ReportFile class --- Tella/Domain/Entity/Report/ReportFile.swift | 10 ++++++++++ .../GDrive/ViewModel/GDriveOutboxViewModel.swift | 6 +----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Tella/Domain/Entity/Report/ReportFile.swift b/Tella/Domain/Entity/Report/ReportFile.swift index 31d2c3211..3c6a37c14 100644 --- a/Tella/Domain/Entity/Report/ReportFile.swift +++ b/Tella/Domain/Entity/Report/ReportFile.swift @@ -40,6 +40,16 @@ class ReportFile : Hashable, Codable { self.reportInstanceId = reportInstanceId } + init(file: ReportVaultFile, reportInstanceId: Int?) { + self.id = file.instanceId + self.fileId = file.id + self.status = file.status + self.bytesSent = file.bytesSent + self.createdDate = file.createdDate + self.updatedDate = file.updatedDate + self.reportInstanceId = reportInstanceId + } + static func == (lhs: ReportFile, rhs: ReportFile) -> Bool { lhs.id == rhs.id } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 7a50a9647..57d391048 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -202,11 +202,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { let reportFiles = reportViewModel.files.map { file in return ReportFile( - id: file.instanceId, - fileId: file.id, - status: file.status, - bytesSent: file.bytesSent, - createdDate: file.createdDate, + file: file, reportInstanceId: reportViewModel.id ) } From 715ee86c02b124e929f99253b2d9a008b3c41518 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 19 Aug 2024 15:06:15 -0300 Subject: [PATCH 136/167] remove server from driveOutboxVM --- Tella/Data/Database/GDriveDatabase.swift | 15 ++++++++++++--- .../GDrive/ViewModel/GDriveOutboxViewModel.swift | 9 +-------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index 3a284fa0b..c8716d23b 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -179,9 +179,18 @@ extension TellaDataBase { let gDriveReportsDict = try statementBuilder.getSelectQuery(tableName: D.tGDriveReport, equalCondition: reportsCondition ) - let decodedReports = try gDriveReportsDict.first?.decode(GDriveReport.self) - let reportFiles = getDriveVaultFiles(reportId: decodedReports?.id) - decodedReports?.reportFiles = reportFiles + + guard let dict = gDriveReportsDict.first else { + return nil + } + + let decodedReports = try dict.decode(GDriveReport.self) + let reportFiles = getDriveVaultFiles(reportId: decodedReports.id) + decodedReports.reportFiles = reportFiles + + let server = getDriveServers().first + decodedReports.server = server + return decodedReports } catch let error { debugLog(error) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 57d391048..41241e4a9 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -14,7 +14,6 @@ class GDriveOutboxViewModel: OutboxMainViewModel { private let gDriveRepository: GDriveRepositoryProtocol private var currentUploadCancellable: AnyCancellable? private var uploadQueue: [ReportVaultFile] = [] - var server: GDriveServer? init(mainAppModel: MainAppModel, reportsViewModel : ReportsMainViewModel, @@ -44,13 +43,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { } } - private func getServer() { - self.server = mainAppModel.tellaData?.gDriveServers.value.first - } - override func initVaultFile(reportId: Int?) { - getServer() - if let reportId, let report = self.mainAppModel.tellaData?.getDriveReport(id: reportId) { let vaultFileResult = mainAppModel.vaultFilesManager?.getVaultFiles(ids: report.reportFiles?.compactMap{$0.fileId} ?? []) @@ -68,7 +61,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { description: report.description ?? "", files: files, reportFiles: report.reportFiles ?? [], - server: server, + server: report.server, status: report.status, apiID: nil, folderId: report.folderId) From d270ddc0298d86fd2855e315d47f826183a835a7 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 19 Aug 2024 15:35:20 -0300 Subject: [PATCH 137/167] move processing of vault files to parent method --- .../ViewModels/OutboxMainViewModel.swift | 14 ++++++++++++++ .../GDrive/ViewModel/GDriveOutboxViewModel.swift | 11 +---------- .../Scenes/Reports/View Model/OutboxReportVM.swift | 11 +---------- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift index b9847f3ff..9b80a0a68 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift @@ -65,6 +65,20 @@ class OutboxMainViewModel: ObservableObject { func initVaultFile(reportId: Int?) {} + func processVaultFiles(reportFiles: [ReportFile]?) -> [ReportVaultFile] { + let vaultFileResult = mainAppModel.vaultFilesManager?.getVaultFiles(ids: reportFiles?.compactMap { $0.fileId } ?? []) + + var files: [ReportVaultFile] = [] + + reportFiles?.forEach { reportFile in + if let vaultFile = vaultFileResult?.first(where: { reportFile.fileId == $0.id }) { + let reportVaultFile = ReportVaultFile(reportFile: reportFile, vaultFile: vaultFile) + files.append(reportVaultFile) + } + } + + return files + } func initializeProgressionInfos() { let totalSize = self.reportViewModel.files.reduce(0) { $0 + ($1.size) } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 41241e4a9..6ede9082e 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -45,16 +45,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { override func initVaultFile(reportId: Int?) { if let reportId, let report = self.mainAppModel.tellaData?.getDriveReport(id: reportId) { - let vaultFileResult = mainAppModel.vaultFilesManager?.getVaultFiles(ids: report.reportFiles?.compactMap{$0.fileId} ?? []) - - var files: [ReportVaultFile] = [] - - report.reportFiles?.forEach({ reportFile in - if let vaultFile = vaultFileResult?.first(where: {reportFile.fileId == $0.id}) { - let reportVaultFile = ReportVaultFile(reportFile: reportFile, vaultFile: vaultFile) - files.append(reportVaultFile) - } - }) + let files = processVaultFiles(reportFiles: report.reportFiles) self.reportViewModel = ReportViewModel(id: report.id, title: report.title ?? "", diff --git a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift index fa9f58963..4734f968e 100644 --- a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift +++ b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift @@ -83,16 +83,7 @@ class OutboxReportVM: OutboxMainViewModel { if let reportId, let report = self.mainAppModel.tellaData?.getReport(reportId: reportId) { - let vaultFileResult = mainAppModel.vaultFilesManager?.getVaultFiles(ids: report.reportFiles?.compactMap{$0.fileId} ?? []) - - var files : [ReportVaultFile] = [] - - report.reportFiles?.forEach({ reportFile in - if let vaultFile = vaultFileResult?.first(where: {reportFile.fileId == $0.id}) { - let reportVaultFile = ReportVaultFile(reportFile: reportFile, vaultFile: vaultFile) - files.append(reportVaultFile) - } - }) + let files = processVaultFiles(reportFiles: report.reportFiles) self.reportViewModel = ReportViewModel(id: report.id, title: report.title ?? "", From cdaf1f0a5659b0d0b42bf4e810cb266c9ad3aeb9 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 19 Aug 2024 15:50:34 -0300 Subject: [PATCH 138/167] refactor initializers in reportViewModel --- .../Entity/CommonReport/BaseReport.swift | 13 +-------- .../ViewModels/ReportViewModel.swift | 29 +++++++++++++------ .../ViewModel/GDriveOutboxViewModel.swift | 10 +------ .../Reports/View Model/OutboxReportVM.swift | 9 +----- 4 files changed, 23 insertions(+), 38 deletions(-) diff --git a/Tella/Domain/Entity/CommonReport/BaseReport.swift b/Tella/Domain/Entity/CommonReport/BaseReport.swift index d300e0e33..0de9a564f 100644 --- a/Tella/Domain/Entity/CommonReport/BaseReport.swift +++ b/Tella/Domain/Entity/CommonReport/BaseReport.swift @@ -8,18 +8,7 @@ import Foundation -protocol BaseReportProtocol: Hashable { - var id: Int? { get } - var title: String? { get } - var description: String? { get } - var createdDate: Date? { get } - var updatedDate: Date? { get } - var status: ReportStatus { get } - var reportFiles: [ReportFile]? { get } - var getReportDate: String { get } -} - -class BaseReport : Hashable, Codable, BaseReportProtocol { +class BaseReport : Hashable, Codable { var id : Int? var title : String? diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportViewModel.swift index b900fd598..159202c46 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/ReportViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/ReportViewModel.swift @@ -18,17 +18,28 @@ class ReportViewModel { init() { } + init(report: Report, files: [ReportVaultFile]) where T == TellaServer { + self.id = report.id + self.title = report.title ?? "" + self.description = report.description ?? "" + self.files = files + self.reportFiles = report.reportFiles ?? [] + self.server = report.server + self.status = report.status + self.apiID = report.apiID + self.folderId = nil + } - init(id: Int?, title: String, description: String, files: [ReportVaultFile], reportFiles : [ReportFile], server: T?, status: ReportStatus?, apiID: String?, folderId: String? = nil) { - self.id = id - self.title = title - self.description = description + init(report: GDriveReport, files: [ReportVaultFile]) where T == GDriveServer { + self.id = report.id + self.title = report.title ?? "" + self.description = report.description ?? "" self.files = files - self.reportFiles = reportFiles - self.server = server - self.status = status - self.apiID = apiID - self.folderId = folderId + self.reportFiles = report.reportFiles ?? [] + self.server = report.server + self.status = report.status + self.apiID = nil + self.folderId = report.folderId } } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 6ede9082e..77fecdd73 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -47,15 +47,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { if let reportId, let report = self.mainAppModel.tellaData?.getDriveReport(id: reportId) { let files = processVaultFiles(reportFiles: report.reportFiles) - self.reportViewModel = ReportViewModel(id: report.id, - title: report.title ?? "", - description: report.description ?? "", - files: files, - reportFiles: report.reportFiles ?? [], - server: report.server, - status: report.status, - apiID: nil, - folderId: report.folderId) + self.reportViewModel = ReportViewModel(report: report, files: files) } } diff --git a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift index 4734f968e..92a09c503 100644 --- a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift +++ b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift @@ -85,14 +85,7 @@ class OutboxReportVM: OutboxMainViewModel { let files = processVaultFiles(reportFiles: report.reportFiles) - self.reportViewModel = ReportViewModel(id: report.id, - title: report.title ?? "", - description: report.description ?? "", - files: files, - reportFiles: report.reportFiles ?? [], - server: report.server, - status: report.status, - apiID: report.apiID) + self.reportViewModel = ReportViewModel(report: report, files: files) } } From 6276ae58aa5cbd505d9b4674d5c5d789135cb01d Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 21 Aug 2024 13:31:20 -0300 Subject: [PATCH 139/167] fix thread issues in pause/resume --- .../Repositories/GDriveRepository.swift | 96 ++++++++++--------- .../ViewModels/OutboxMainViewModel.swift | 52 +++++----- .../ViewModel/GDriveOutboxViewModel.swift | 3 - .../Reports/Outbox/OutboxDetailsView.swift | 19 +--- 4 files changed, 78 insertions(+), 92 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 88f740f8f..ff20fb399 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -32,8 +32,8 @@ protocol GDriveRepositoryProtocol { class GDriveRepository: GDriveRepositoryProtocol { private var googleUser: GIDGoogleUser? private var uploadTasks: [String: GTLRServiceTicket] = [:] - private let uploadLock = NSLock() private(set) var isUploading = false + private var isCancelled = false private let networkMonitor: NetworkMonitor var subscribers : Set = [] private let networkStatusSubject = PassthroughSubject() @@ -223,7 +223,7 @@ class GDriveRepository: GDriveRepositoryProtocol { promise(.failure(.noInternetConnection)) return } - Task { + Task { @MainActor in do { try await self.ensureSignedIn() self.performUploadFile( @@ -252,8 +252,9 @@ class GDriveRepository: GDriveRepositoryProtocol { ) { Task { do { - self.uploadLock.lock() - defer { self.uploadLock.unlock() } + if isCancelled { + return + } guard self.networkMonitor.isConnected else { promise(.failure(.noInternetConnection)) @@ -291,7 +292,9 @@ class GDriveRepository: GDriveRepositoryProtocol { promise(.success(uploadProgressInfo)) } else { // File doesn't exist, proceed with upload - self.uploadNewFile(fileUploadDetails: fileUploadDetails, driveService: driveService, uploadProgressInfo: uploadProgressInfo, promise: promise) + let result = try await self.uploadNewFile(fileUploadDetails: fileUploadDetails, driveService: driveService, uploadProgressInfo: uploadProgressInfo) + + promise(.success(result)) } } catch { promise(.failure(self.mapToAPIError(error))) @@ -299,12 +302,12 @@ class GDriveRepository: GDriveRepositoryProtocol { } } + @MainActor private func uploadNewFile( fileUploadDetails: FileUploadDetails, driveService: GTLRDriveService, - uploadProgressInfo: UploadProgressInfo, - promise: @escaping (Result) -> Void - ) { + uploadProgressInfo: UploadProgressInfo + ) async throws -> UploadProgressInfo { let fileURL = fileUploadDetails.fileURL let mimeType = fileUploadDetails.mimeType let fileId = fileUploadDetails.fileId @@ -321,38 +324,49 @@ class GDriveRepository: GDriveRepositoryProtocol { let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: uploadParameters) query.supportsAllDrives = true - let ticket = driveService.executeQuery(query) { [weak self] (ticket, file, error) in - guard let self = self else { return } - - self.uploadLock.lock() - defer { - self.uploadLock.unlock() - self.uploadTasks.removeValue(forKey: fileId) - } - - if !self.isUploading { - uploadProgressInfo.status = .notSubmitted - promise(.success(uploadProgressInfo)) - return - } - - if error != nil { - handleSubmissionError(uploadProgressInfo: uploadProgressInfo, promise: promise) - return - } - - guard file is GTLRDrive_File else { - handleSubmissionError(uploadProgressInfo: uploadProgressInfo, promise: promise) - return + return try await withCheckedThrowingContinuation { continuation in + let ticket = driveService.executeQuery(query) { [weak self] (ticket, file, error) in + guard let self = self else { + continuation.resume(throwing: APIError.unexpectedResponse) + return + } + + Task { @MainActor in + defer { + self.uploadTasks.removeValue(forKey: fileId) + } + + do { + if self.isCancelled { + return + } + + if !self.isUploading { + uploadProgressInfo.status = .notSubmitted + continuation.resume(returning: uploadProgressInfo) + return + } + + if let error = error { + throw self.mapToAPIError(error) + } + + guard file is GTLRDrive_File else { + throw APIError.unexpectedResponse + } + + uploadProgressInfo.bytesSent = Int(uploadProgressInfo.total!) + uploadProgressInfo.current = Int(uploadProgressInfo.total!) + uploadProgressInfo.status = .uploaded + continuation.resume(returning: uploadProgressInfo) + } catch { + continuation.resume(throwing: error) + } + } } - uploadProgressInfo.bytesSent = Int(uploadProgressInfo.total!) - uploadProgressInfo.current = Int(uploadProgressInfo.total!) - uploadProgressInfo.status = .uploaded - promise(.success(uploadProgressInfo)) + self.uploadTasks[fileId] = ticket } - - self.uploadTasks[fileId] = ticket } private func checkFileExists(fileName: String, folderId: String, driveService: GTLRDriveService) async throws -> Bool { @@ -379,19 +393,15 @@ class GDriveRepository: GDriveRepositoryProtocol { } func pauseAllUploads() { - uploadLock.lock() - defer { uploadLock.unlock() } - isUploading = false + isCancelled = true uploadTasks.forEach { $0.value.cancel() } uploadTasks.removeAll() } func resumeAllUploads() { - uploadLock.lock() - defer { uploadLock.unlock() } - isUploading = true + isCancelled = false } func signOut() { diff --git a/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift index 9b80a0a68..2db4606d8 100644 --- a/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift +++ b/Tella/Scenes/CommonConnectionReport/ViewModels/OutboxMainViewModel.swift @@ -27,7 +27,6 @@ class OutboxMainViewModel: ObservableObject { } @Published var shouldShowSubmittedReportView : Bool = false @Published var shouldShowMainView : Bool = false - @Published var isFileLoading : Bool = false var subscribers = Set() var filesToUpload : [FileToUpload] = [] @@ -93,20 +92,17 @@ class OutboxMainViewModel: ObservableObject { let formattedTotalUploaded = bytesSent.getFormattedFileSize().getFileSizeWithoutUnit() let formattedTotalSize = totalSize.getFormattedFileSize() - DispatchQueue.main.async { - - self.percentUploadedInfo = "\(Int(formattedPercentUploaded * 100))% \(LocalizableReport.reportUploaded.localized)" - self.percentUploaded = Float(percentUploaded) - let filesCount = "\(self.reportViewModel.files.count) \(self.reportViewModel.files.count == 1 ? LocalizableReport.reportFile.localized : LocalizableReport.reportFiles.localized)" - let fileUploaded = "\(formattedTotalUploaded)/\(formattedTotalSize) \(LocalizableReport.reportUploaded.localized)" - - self.uploadedFiles = "\(filesCount), \(fileUploaded)" - - self.progressFileItems = self.reportViewModel.files.compactMap{ProgressFileItemViewModel(file: $0, progression: ($0.bytesSent.getFormattedFileSize()) + "/" + ($0.size.getFormattedFileSize()))} - - self.objectWillChange.send() - - } + + self.percentUploadedInfo = "\(Int(formattedPercentUploaded * 100))% \(LocalizableReport.reportUploaded.localized)" + self.percentUploaded = Float(percentUploaded) + let filesCount = "\(self.reportViewModel.files.count) \(self.reportViewModel.files.count == 1 ? LocalizableReport.reportFile.localized : LocalizableReport.reportFiles.localized)" + let fileUploaded = "\(formattedTotalUploaded)/\(formattedTotalSize) \(LocalizableReport.reportUploaded.localized)" + + self.uploadedFiles = "\(filesCount), \(fileUploaded)" + + self.progressFileItems = self.reportViewModel.files.compactMap{ProgressFileItemViewModel(file: $0, progression: ($0.bytesSent.getFormattedFileSize()) + "/" + ($0.size.getFormattedFileSize()))} + + self.objectWillChange.send() } } @@ -155,22 +151,20 @@ class OutboxMainViewModel: ObservableObject { let formattedTotalUploaded = totalBytesSent.getFormattedFileSize().getFileSizeWithoutUnit() let formattedTotalSize = totalSize.getFormattedFileSize() - DispatchQueue.main.async { - // Progress Files - self.percentUploadedInfo = "\(Int(formattedPercentUploaded * 100))% uploaded" - self.percentUploaded = Float(formattedPercentUploaded) - self.uploadedFiles = " \(self.reportViewModel.files.count) files, \(formattedTotalUploaded)/\(formattedTotalSize) uploaded" + // Progress Files + self.percentUploadedInfo = "\(Int(formattedPercentUploaded * 100))% uploaded" + self.percentUploaded = Float(formattedPercentUploaded) + self.uploadedFiles = " \(self.reportViewModel.files.count) files, \(formattedTotalUploaded)/\(formattedTotalSize) uploaded" + + //Progress File Item + if let currentItem = self.progressFileItems.first(where: {$0.file.id == uploadProgressInfo.fileId}) { + + let size = currentItem.file.size.getFormattedFileSize() + let currentFileTotalBytesSent = currentFileTotalBytesSent.getFormattedFileSize().getFileSizeWithoutUnit() - //Progress File Item - if let currentItem = self.progressFileItems.first(where: {$0.file.id == uploadProgressInfo.fileId}) { - - let size = currentItem.file.size.getFormattedFileSize() - let currentFileTotalBytesSent = currentFileTotalBytesSent.getFormattedFileSize().getFileSizeWithoutUnit() - - currentItem.progression = "\(currentFileTotalBytesSent)/\(size )" - } - self.objectWillChange.send() + currentItem.progression = "\(currentFileTotalBytesSent)/\(size )" } + self.objectWillChange.send() } } diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 77fecdd73..908871874 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -54,7 +54,6 @@ class GDriveOutboxViewModel: OutboxMainViewModel { //submit report override func submitReport() { - self.isFileLoading = true if isSubmissionInProgress == false { self.updateReportStatus(reportStatus: .submissionInProgress) } @@ -103,7 +102,6 @@ class GDriveOutboxViewModel: OutboxMainViewModel { uploadNextFile(folderId: folderId) return } - self.isFileLoading = false let fileUploadDetails = FileUploadDetails(fileURL: fileUrl, fileId: fileToUpload.id ?? "", @@ -154,7 +152,6 @@ class GDriveOutboxViewModel: OutboxMainViewModel { if isSubmissionInProgress { updateReportStatus(reportStatus: .submissionPaused) gDriveRepository.pauseAllUploads() - currentUploadCancellable?.cancel() currentUploadCancellable = nil } } diff --git a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift index 9f40b3b32..12ccf8bee 100644 --- a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift +++ b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift @@ -11,8 +11,6 @@ struct OutboxDetailsView: View { @EnvironmentObject var mainAppModel : MainAppModel @Environment(\.presentationMode) var presentationMode: Binding @EnvironmentObject private var sheetManager: SheetManager - @State private var isButtonDisabled = false - private let debounceInterval: TimeInterval = 1 var body: some View { @@ -99,27 +97,14 @@ struct OutboxDetailsView: View { nextButtonAction: .action, buttonType: .yellow, destination: nil, - isValid: .constant(!isButtonDisabled && !outboxReportVM.isFileLoading)) { - debounceAction { - outboxReportVM.isSubmissionInProgress ? outboxReportVM.pauseSubmission() : outboxReportVM.submitReport() - } + isValid: .constant(true)) { + outboxReportVM.isSubmissionInProgress ? outboxReportVM.pauseSubmission() : outboxReportVM.submitReport() } .padding(EdgeInsets(top: 30, leading: 24, bottom: 16, trailing: 24)) } } - private func debounceAction(action: @escaping () -> Void) { - guard !isButtonDisabled else { return } - - isButtonDisabled = true - action() - - DispatchQueue.main.asyncAfter(deadline: .now() + debounceInterval) { - isButtonDisabled = false - } - } - private var reportInformations: some View { Group { Text(outboxReportVM.reportViewModel.title) From 7058044708b187d7ba65bde1186e01910af58e0e Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 21 Aug 2024 14:12:05 -0300 Subject: [PATCH 140/167] remove environmentObject --- .../Views/Draft/DraftView.swift | 5 ++--- .../CommonConnectionReport/Views/ReportMainView.swift | 10 ++++------ Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift | 11 +++++------ .../Reports/Submitted/SubmittedDetailsView.swift | 3 +-- Tella/Scenes/Reports/View Model/OutboxReportVM.swift | 1 + 5 files changed, 13 insertions(+), 17 deletions(-) diff --git a/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift index afca373cf..56d5fed11 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/Draft/DraftView.swift @@ -22,7 +22,6 @@ struct DraftView: View { var body: some View { ContainerView { contentView - .environmentObject(viewModel) serverListMenuView photoVideoPickerView } @@ -195,10 +194,10 @@ struct DraftView: View { switch reportsViewModel.connectionType { case .tella: let outboxVM = OutboxReportVM(mainAppModel: viewModel.mainAppModel, reportsViewModel: reportsViewModel, reportId: viewModel.reportId) - OutboxDetailsView(outboxReportVM: outboxVM).environmentObject(reportsViewModel) + OutboxDetailsView(outboxReportVM: outboxVM, reportsViewModel: reportsViewModel) case .gDrive: let outboxVM = GDriveOutboxViewModel(mainAppModel: viewModel.mainAppModel, reportsViewModel: reportsViewModel, reportId: viewModel.reportId, repository: GDriveRepository()) - OutboxDetailsView(outboxReportVM: outboxVM).environmentObject(reportsViewModel) + OutboxDetailsView(outboxReportVM: outboxVM, reportsViewModel: reportsViewModel) default: Text("") } diff --git a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift index 8931b7e1e..4c7ea57c9 100644 --- a/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift +++ b/Tella/Scenes/CommonConnectionReport/Views/ReportMainView.swift @@ -182,14 +182,12 @@ struct ReportMainView: View { switch reportMainViewModel.connectionType { case .tella: let outboxViewModel = OutboxReportVM(mainAppModel: reportMainViewModel.mainAppModel, reportsViewModel: reportMainViewModel, reportId: id) - let destination = OutboxDetailsView(outboxReportVM: outboxViewModel) - .environmentObject(reportMainViewModel) + let destination = OutboxDetailsView(outboxReportVM: outboxViewModel, reportsViewModel: reportMainViewModel) self.navigateTo(destination: destination) break case .gDrive: let outboxViewModel = GDriveOutboxViewModel(mainAppModel: reportMainViewModel.mainAppModel, reportsViewModel: reportMainViewModel, reportId: id, repository: GDriveRepository()) - let destination = OutboxDetailsView(outboxReportVM: outboxViewModel) - .environmentObject(reportMainViewModel) + let destination = OutboxDetailsView(outboxReportVM: outboxViewModel, reportsViewModel: reportMainViewModel) self.navigateTo(destination: destination) default: break @@ -201,11 +199,11 @@ struct ReportMainView: View { switch reportMainViewModel.connectionType { case .tella: let vm = SubmittedReportVM(mainAppModel: reportMainViewModel.mainAppModel, reportId: id) - let destination = SubmittedDetailsView(submittedReportVM: vm).environmentObject(reportMainViewModel) + let destination = SubmittedDetailsView(submittedReportVM: vm, reportsViewModel: reportMainViewModel) self.navigateTo(destination: destination) case .gDrive: let vm = GDriveSubmittedViewModel(mainAppModel: reportMainViewModel.mainAppModel, reportId: id) - let destination = SubmittedDetailsView(submittedReportVM: vm).environmentObject(reportMainViewModel) + let destination = SubmittedDetailsView(submittedReportVM: vm, reportsViewModel: reportMainViewModel) self.navigateTo(destination: destination) default: break diff --git a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift index 12ccf8bee..0e1efc985 100644 --- a/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift +++ b/Tella/Scenes/Reports/Outbox/OutboxDetailsView.swift @@ -7,8 +7,7 @@ import SwiftUI struct OutboxDetailsView: View { @StateObject var outboxReportVM : OutboxMainViewModel - @EnvironmentObject var reportsViewModel : ReportsMainViewModel - @EnvironmentObject var mainAppModel : MainAppModel + @StateObject var reportsViewModel : ReportsMainViewModel @Environment(\.presentationMode) var presentationMode: Binding @EnvironmentObject private var sheetManager: SheetManager @@ -179,11 +178,11 @@ struct OutboxDetailsView: View { Group { switch reportsViewModel.connectionType { case .tella: - let vm = SubmittedReportVM(mainAppModel: mainAppModel, reportId: outboxReportVM.reportViewModel.id) - SubmittedDetailsView(submittedReportVM: vm).environmentObject(reportsViewModel) + let vm = SubmittedReportVM(mainAppModel: outboxReportVM.mainAppModel, reportId: outboxReportVM.reportViewModel.id) + SubmittedDetailsView(submittedReportVM: vm, reportsViewModel: reportsViewModel) case .gDrive: - let vm = GDriveSubmittedViewModel(mainAppModel: mainAppModel, reportId: outboxReportVM.reportViewModel.id) - SubmittedDetailsView(submittedReportVM: vm).environmentObject(reportsViewModel) + let vm = GDriveSubmittedViewModel(mainAppModel: outboxReportVM.mainAppModel, reportId: outboxReportVM.reportViewModel.id) + SubmittedDetailsView(submittedReportVM: vm, reportsViewModel: reportsViewModel) default: Text("") } diff --git a/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift b/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift index 8be943faa..a63814a3c 100644 --- a/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift +++ b/Tella/Scenes/Reports/Submitted/SubmittedDetailsView.swift @@ -8,8 +8,7 @@ import SwiftUI struct SubmittedDetailsView: View { @StateObject var submittedReportVM : SubmittedMainViewModel - @EnvironmentObject var reportsViewModel : ReportsMainViewModel - @EnvironmentObject var mainAppModel : MainAppModel + @StateObject var reportsViewModel : ReportsMainViewModel @Environment(\.presentationMode) var presentationMode: Binding @EnvironmentObject private var sheetManager: SheetManager diff --git a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift index 92a09c503..5dc078650 100644 --- a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift +++ b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift @@ -25,6 +25,7 @@ class OutboxReportVM: OutboxMainViewModel { private func treat(uploadResponse: CurrentValueSubject?) { uploadResponse? + .receive(on: DispatchQueue.main) .sink { result in } receiveValue: { response in From 5edfda3f8a5590cb4bac8939c2d3e16dbae10208 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 21 Aug 2024 14:14:44 -0300 Subject: [PATCH 141/167] remove report initializaiton in submitReport method on tellaweb --- Tella/Scenes/Reports/View Model/OutboxReportVM.swift | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift index 5dc078650..a6d9b98f9 100644 --- a/Tella/Scenes/Reports/View Model/OutboxReportVM.swift +++ b/Tella/Scenes/Reports/View Model/OutboxReportVM.swift @@ -99,16 +99,6 @@ class OutboxReportVM: OutboxMainViewModel { } override func submitReport() { - - let report = Report(id: reportViewModel.id, - title: reportViewModel.title, - description: reportViewModel.description, - status: reportViewModel.status, - server: reportViewModel.server, - vaultFiles: self.reportViewModel.reportFiles, - - apiID: self.reportViewModel.apiID) - if isSubmissionInProgress == false { self.updateReportStatus(reportStatus: .submissionInProgress) From f2df9f3f27f5f156b21c3319df5230da1aa241ad Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 21 Aug 2024 14:42:00 -0300 Subject: [PATCH 142/167] remove isUploading from drive repository --- .../Repositories/GDriveRepository.swift | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index ff20fb399..03d0b7b23 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -32,7 +32,6 @@ protocol GDriveRepositoryProtocol { class GDriveRepository: GDriveRepositoryProtocol { private var googleUser: GIDGoogleUser? private var uploadTasks: [String: GTLRServiceTicket] = [:] - private(set) var isUploading = false private var isCancelled = false private let networkMonitor: NetworkMonitor var subscribers : Set = [] @@ -261,10 +260,6 @@ class GDriveRepository: GDriveRepositoryProtocol { return } - guard self.isUploading else { - return - } - guard let user = self.googleUser else { promise(.failure(APIError.noToken)) return @@ -338,15 +333,16 @@ class GDriveRepository: GDriveRepositoryProtocol { do { if self.isCancelled { - return - } - - if !self.isUploading { uploadProgressInfo.status = .notSubmitted - continuation.resume(returning: uploadProgressInfo) return } +// if !self.isUploading { +// uploadProgressInfo.status = .notSubmitted +// continuation.resume(returning: uploadProgressInfo) +// return +// } + if let error = error { throw self.mapToAPIError(error) } @@ -393,14 +389,12 @@ class GDriveRepository: GDriveRepositoryProtocol { } func pauseAllUploads() { - isUploading = false isCancelled = true uploadTasks.forEach { $0.value.cancel() } uploadTasks.removeAll() } func resumeAllUploads() { - isUploading = true isCancelled = false } From f942f94349397976db77775387da068e0ea3539c Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 21 Aug 2024 18:34:34 -0300 Subject: [PATCH 143/167] small fix in submitReport method for google drive --- Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 908871874..537ef91e2 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -54,9 +54,10 @@ class GDriveOutboxViewModel: OutboxMainViewModel { //submit report override func submitReport() { - if isSubmissionInProgress == false { - self.updateReportStatus(reportStatus: .submissionInProgress) - } + if isSubmissionInProgress { return } + + self.updateReportStatus(reportStatus: .submissionInProgress) + gDriveRepository.resumeAllUploads() guard let folderId = reportViewModel.folderId else { return createDriveFolder() From 330bbb1ce0e78cfa6b044e8f7e4ffefdd39323da Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 21 Aug 2024 20:09:40 -0300 Subject: [PATCH 144/167] convert fileURL method into an asynchronous operation --- .../ViewModel/GDriveOutboxViewModel.swift | 57 ++++++++++++------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 537ef91e2..d99fe3bc7 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -98,28 +98,34 @@ class GDriveOutboxViewModel: OutboxMainViewModel { return } - guard let fileUrl = self.mainAppModel.vaultManager.loadVaultFileToURL(file: fileToUpload) else { - uploadQueue.removeFirst() - uploadNextFile(folderId: folderId) - return - } - - let fileUploadDetails = FileUploadDetails(fileURL: fileUrl, - fileId: fileToUpload.id ?? "", - mimeType: fileToUpload.mimeType ?? "", - folderId: folderId) - - currentUploadCancellable = gDriveRepository.uploadFile(fileUploadDetails: fileUploadDetails) - .receive(on: DispatchQueue.main) - .sink( - receiveCompletion: { [weak self] completion in - guard let self = self else { return } - handleCompletionForUploadFile(completion, folderId: folderId) - }, - receiveValue: { [weak self] progressInfo in - self?.updateProgressInfos(uploadProgressInfo: progressInfo) + Task { + guard let fileUrl = await self.loadVaultFileToURLAsync(file: fileToUpload) else { + await MainActor.run { + uploadQueue.removeFirst() + uploadNextFile(folderId: folderId) } - ) + return + } + + let fileUploadDetails = FileUploadDetails(fileURL: fileUrl, + fileId: fileToUpload.id ?? "", + mimeType: fileToUpload.mimeType ?? "", + folderId: folderId) + + await MainActor.run { + currentUploadCancellable = gDriveRepository.uploadFile(fileUploadDetails: fileUploadDetails) + .receive(on: DispatchQueue.main) + .sink( + receiveCompletion: { [weak self] completion in + guard let self = self else { return } + self.handleCompletionForUploadFile(completion, folderId: folderId) + }, + receiveValue: { [weak self] progressInfo in + self?.updateProgressInfos(uploadProgressInfo: progressInfo) + } + ) + } + } } private func handleCompletionForUploadFile(_ completion: Subscribers.Completion, folderId: String) { @@ -183,4 +189,13 @@ class GDriveOutboxViewModel: OutboxMainViewModel { let _ = mainAppModel.tellaData?.updateDriveFiles(reportId: reportId, files: reportFiles) } + + func loadVaultFileToURLAsync(file: ReportVaultFile) async -> URL? { + await withCheckedContinuation { continuation in + DispatchQueue.global(qos: .userInitiated).async { + let result = self.mainAppModel.vaultManager.loadVaultFileToURL(file: file) + continuation.resume(returning: result) + } + } + } } From 39f373270cc6f632c6d3b89ba90c18a4346d0bb7 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 23 Aug 2024 12:23:51 -0300 Subject: [PATCH 145/167] check if drive upload queue is empty before removing an item --- Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index d99fe3bc7..5e21e3baa 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -131,7 +131,9 @@ class GDriveOutboxViewModel: OutboxMainViewModel { private func handleCompletionForUploadFile(_ completion: Subscribers.Completion, folderId: String) { switch completion { case .finished: - self.uploadQueue.removeFirst() + if !self.uploadQueue.isEmpty { + self.uploadQueue.removeFirst() + } self.uploadNextFile(folderId: folderId) case .failure( let error): switch error { From d3b80adef850ee0c8a1d518625471e1d6adf0164 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 23 Aug 2024 13:49:15 -0300 Subject: [PATCH 146/167] refactor drive errors --- Tella/Data/Networking/APICall/APIError.swift | 23 +++++++++++ .../Repositories/GDriveRepository.swift | 41 +++---------------- Tella/Utils/Constants.swift | 2 + 3 files changed, 31 insertions(+), 35 deletions(-) diff --git a/Tella/Data/Networking/APICall/APIError.swift b/Tella/Data/Networking/APICall/APIError.swift index 445fe7920..0434b19d4 100644 --- a/Tella/Data/Networking/APICall/APIError.swift +++ b/Tella/Data/Networking/APICall/APIError.swift @@ -12,6 +12,7 @@ enum APIError: Swift.Error { case noInternetConnection case badServer case noToken + case driveApiError(Error) } extension APIError: LocalizedError { @@ -30,6 +31,8 @@ extension APIError: LocalizedError { return LocalizableSettings.settServerServerURLIncorrect.localized case .noToken: return LocalizableSettings.settServerNoTokenPresent.localized + case .driveApiError(let error): + return customDriveErrorMessage(error: error) } } private func customErrorMessage(errorCode : Int) -> String { @@ -45,4 +48,24 @@ extension APIError: LocalizedError { return "Unexpected response from the server" } } + + private func customDriveErrorMessage(error: Error) -> String { + if let nsError = error as NSError? { + switch nsError.domain { + case GoogleAuthConstants.GTLRErrorObjectDomain: + let errorCode = nsError.code + let errorMessage = nsError.localizedDescription + + return customErrorMessage(errorCode: errorCode) + case GoogleAuthConstants.HTTPStatus: + return customErrorMessage(errorCode: nsError.code) + default: + if let errorString = nsError.userInfo["error"] as? String { + return errorString + } + } + } + + return "Unexpected response from the server" + } } diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 03d0b7b23..dd5871424 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -161,7 +161,7 @@ class GDriveRepository: GDriveRepositoryProtocol { description: description, promise: promise) } catch { - promise(.failure(self.mapToAPIError(error))) + promise(.failure(.driveApiError(error))) } } } @@ -200,7 +200,7 @@ class GDriveRepository: GDriveRepositoryProtocol { driveService.executeQuery(query) { (ticket, file, error) in if let error = error { debugLog("Error creating folder: \(error.localizedDescription)") - promise(.failure(self.mapToAPIError(error))) + promise(.failure(.driveApiError(error))) return } @@ -238,7 +238,7 @@ class GDriveRepository: GDriveRepositoryProtocol { } .store(in: &self.subscribers) } catch { - promise(.failure(self.mapToAPIError(error))) + promise(.failure(.driveApiError(error))) } } } @@ -261,7 +261,7 @@ class GDriveRepository: GDriveRepositoryProtocol { } guard let user = self.googleUser else { - promise(.failure(APIError.noToken)) + promise(.failure(.noToken)) return } @@ -292,7 +292,7 @@ class GDriveRepository: GDriveRepositoryProtocol { promise(.success(result)) } } catch { - promise(.failure(self.mapToAPIError(error))) + promise(.failure(.driveApiError(error))) } } } @@ -337,14 +337,8 @@ class GDriveRepository: GDriveRepositoryProtocol { return } -// if !self.isUploading { -// uploadProgressInfo.status = .notSubmitted -// continuation.resume(returning: uploadProgressInfo) -// return -// } - if let error = error { - throw self.mapToAPIError(error) + throw APIError.driveApiError(error) } guard file is GTLRDrive_File else { @@ -412,29 +406,6 @@ class GDriveRepository: GDriveRepositoryProtocol { uploadProgressInfo.error = APIError.unexpectedResponse promise(.failure(.unexpectedResponse)) } - - private func mapToAPIError(_ error: Error) -> APIError { - if let apiError = error as? APIError { - return apiError - } - - // Map other error types to APIError - if let nsError = error as NSError? { - switch nsError.code { - case NSURLErrorNotConnectedToInternet, - NSURLErrorNetworkConnectionLost, - NSURLErrorCannotConnectToHost, - NSURLErrorCannotFindHost: - return .noInternetConnection - case NSURLErrorTimedOut: - return networkMonitor.isConnected ? .unexpectedResponse : .noInternetConnection - default: - return .unexpectedResponse - } - } - - return .unexpectedResponse - } } diff --git a/Tella/Utils/Constants.swift b/Tella/Utils/Constants.swift index 3584ca22e..02bb99a04 100644 --- a/Tella/Utils/Constants.swift +++ b/Tella/Utils/Constants.swift @@ -14,4 +14,6 @@ struct TellaUrls { struct GoogleAuthConstants { static let gDriveScopes = "https://www.googleapis.com/auth/drive" static let gDriveFolderMimeType = "application/vnd.google-apps.folder" + static let GTLRErrorObjectDomain = "com.google.GTLRErrorObjectDomain" + static let HTTPStatus = "com.google.HTTPStatus" } From e13091be24c2b6eed862832a1e3de02d5061f753 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 23 Aug 2024 14:09:42 -0300 Subject: [PATCH 147/167] add rest of localizable errors --- Tella.xcodeproj/project.pbxproj | 4 ++++ Tella/Data/Networking/APICall/APIError.swift | 12 ++++++------ .../en.lproj/Localizable.strings | 5 +++++ Tella/Utils/Localizable/LocalizableError.swift | 16 ++++++++++++++++ 4 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 Tella/Utils/Localizable/LocalizableError.swift diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index cd0f249ce..3525f6ab7 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -386,6 +386,7 @@ 15994A0C2BFBC6F40017F153 /* SelectDriveConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */; }; 15994A0E2BFBE15F0017F153 /* SelectSharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */; }; 15994A112BFBF0E50017F153 /* SharedDrive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15994A102BFBF0E50017F153 /* SharedDrive.swift */; }; + 15A173442C78F64100E84F55 /* LocalizableError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15A173432C78F64100E84F55 /* LocalizableError.swift */; }; 15A505B32C2F623C0028C7CB /* GDriveData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15A505B22C2F623C0028C7CB /* GDriveData.swift */; }; 15B81F3A2C1A281C007C0E88 /* GDriveViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15B81F392C1A281C007C0E88 /* GDriveViewModel.swift */; }; 15BD9CA92BC740B300C3932B /* UwaziRelationshipWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15BD9CA82BC740B300C3932B /* UwaziRelationshipWidget.swift */; }; @@ -961,6 +962,7 @@ 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectDriveConnection.swift; sourceTree = ""; }; 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectSharedDrive.swift; sourceTree = ""; }; 15994A102BFBF0E50017F153 /* SharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedDrive.swift; sourceTree = ""; }; + 15A173432C78F64100E84F55 /* LocalizableError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizableError.swift; sourceTree = ""; }; 15A505B22C2F623C0028C7CB /* GDriveData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveData.swift; sourceTree = ""; }; 15B81F392C1A281C007C0E88 /* GDriveViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDriveViewModel.swift; sourceTree = ""; }; 15BD9CA82BC740B300C3932B /* UwaziRelationshipWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UwaziRelationshipWidget.swift; sourceTree = ""; }; @@ -2232,6 +2234,7 @@ 1501401C2B71243A00991D69 /* LocalizableResources.swift */, 12B84B842C32EF12006363F0 /* LocalizableNextcloud.swift */, 15E54AB82C5824DA00290DE8 /* LocalizableGDrive.swift */, + 15A173432C78F64100E84F55 /* LocalizableError.swift */, ); path = Localizable; sourceTree = ""; @@ -3524,6 +3527,7 @@ 123048D5295F95A40015CD96 /* SubmittedDetailsView.swift in Sources */, 1293F6682AD7EF3900F6CFBD /* CloseHeaderView.swift in Sources */, 1278B66127EB364500C9AC4D /* Utils.swift in Sources */, + 15A173442C78F64100E84F55 /* LocalizableError.swift in Sources */, 125D2321271F823100250FBB /* UIApplicationExtension.swift in Sources */, 12234BE029DAEC4A00D6F981 /* CustomNavigation.swift in Sources */, 126E1AF12C3D7603000AE4CE /* BaseReport.swift in Sources */, diff --git a/Tella/Data/Networking/APICall/APIError.swift b/Tella/Data/Networking/APICall/APIError.swift index 0434b19d4..aceefc312 100644 --- a/Tella/Data/Networking/APICall/APIError.swift +++ b/Tella/Data/Networking/APICall/APIError.swift @@ -20,11 +20,11 @@ extension APIError: LocalizedError { var errorDescription: String? { switch self { case .invalidURL: - return "Invalid URL" + return LocalizableError.invalidUrl.localized case let .httpCode(code): return customErrorMessage(errorCode: code) case .unexpectedResponse: - return "Unexpected response from the server" + return LocalizableError.unexpectedResponse.localized case .noInternetConnection: return LocalizableSettings.settServerNoInternetConnection.localized case .badServer: @@ -39,13 +39,13 @@ extension APIError: LocalizedError { let httpErrorCode = HTTPErrorCodes(rawValue: errorCode) switch httpErrorCode{ case .unauthorized: - return "Invalid username or password" + return LocalizableError.unauthorized.localized case .forbidden: - return "Account locked due to too many unsuccessful attempts." + return LocalizableError.forbidden.localized case .notFound: return LocalizableSettings.settServerServerURLIncorrect.localized default: - return "Unexpected response from the server" + return LocalizableError.unexpectedResponse.localized } } @@ -66,6 +66,6 @@ extension APIError: LocalizedError { } } - return "Unexpected response from the server" + return LocalizableError.unexpectedResponse.localized } } diff --git a/Tella/Supporting Files/en.lproj/Localizable.strings b/Tella/Supporting Files/en.lproj/Localizable.strings index b2a6a81e3..25e3b5431 100644 --- a/Tella/Supporting Files/en.lproj/Localizable.strings +++ b/Tella/Supporting Files/en.lproj/Localizable.strings @@ -550,3 +550,8 @@ This feedback is anonymous, so make sure to include contact information if you w "Nextcloud_AppBar" = "Nextcloud"; "GDrive_AppBar" = "Google Drive"; + +"Error_InvalidURL_Expl" = "Invalid URL"; +"Error_Unexpected_Response_Expl" = "Unexpected response from the server"; +"Error_Unauthorized_Expl" = "Invalid username or password"; +"Error_Forbidden_Expl" = "Account locked due to too many unsuccessful attempts." diff --git a/Tella/Utils/Localizable/LocalizableError.swift b/Tella/Utils/Localizable/LocalizableError.swift new file mode 100644 index 000000000..fc01faa4c --- /dev/null +++ b/Tella/Utils/Localizable/LocalizableError.swift @@ -0,0 +1,16 @@ +// +// LocalizableError.swift +// Tella +// +// Created by gus valbuena on 8/23/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +import Foundation + +enum LocalizableError : String, LocalizableDelegate { + case invalidUrl = "Error_InvalidURL_Expl" + case unexpectedResponse = "Error_Unexpected_Response_Expl" + case unauthorized = "Error_Unauthorized_Expl" + case forbidden = "Error_Forbidden_Expl" +} From 5dc437eb4a31ea06a0aae0f417d6f0e98e3bf068 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 23 Aug 2024 15:15:19 -0300 Subject: [PATCH 148/167] add folder name to driveserver --- Tella/Data/Database/Common/DatabaseConstants.swift | 1 + Tella/Data/Database/GDriveDatabase.swift | 8 +++++--- Tella/Domain/Entity/GDrive/GDriveServer.swift | 6 ++++++ .../Scenes/Settings/ViewModel/GDriveServerViewModel.swift | 6 +++--- .../Settings/Views/Servers/GDrive/SelectSharedDrive.swift | 2 +- Tella/Supporting Files/en.lproj/Localizable.strings | 2 +- 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Tella/Data/Database/Common/DatabaseConstants.swift b/Tella/Data/Database/Common/DatabaseConstants.swift index 1874caa81..316b1803c 100644 --- a/Tella/Data/Database/Common/DatabaseConstants.swift +++ b/Tella/Data/Database/Common/DatabaseConstants.swift @@ -97,6 +97,7 @@ struct D { //gDrive static let cRootFolder = "c_root_folder" static let cFolderId = "c_folder_id" + static let cRootFolderName = "c_root_folder_name" } diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index c8716d23b..1f5cbf26d 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -15,7 +15,8 @@ extension TellaDataBase { let columns = [ cddl(D.cId, D.integer, primaryKey: true, autoIncrement: true), cddl(D.cName, D.text), - cddl(D.cRootFolder, D.text) + cddl(D.cRootFolder, D.text), + cddl(D.cRootFolderName, D.text) ] statementBuilder.createTable(tableName: D.tGDriveServer, columns: columns) } @@ -23,7 +24,8 @@ extension TellaDataBase { func addGDriveServer(gDriveServer: GDriveServer) -> Result { do { let valuesToAdd = [KeyValue(key: D.cName, value: gDriveServer.name), - KeyValue(key: D.cRootFolder, value: gDriveServer.rootFolder) + KeyValue(key: D.cRootFolder, value: gDriveServer.rootFolder), + KeyValue(key: D.cRootFolderName, value: gDriveServer.rootFolderName) ] let serverId = try statementBuilder.insertInto(tableName: D.tGDriveServer, keyValue: valuesToAdd) @@ -37,7 +39,7 @@ extension TellaDataBase { do { let serversDict = try statementBuilder.selectQuery(tableName: D.tGDriveServer, andCondition: []) - let driveServer = try serversDict.decode(GDriveServer.self) + let driveServer = try serversDict.decode(GDriveServer.self) return driveServer } catch { debugLog("Error while fetching servers from \(D.tGDriveServer): \(error)") diff --git a/Tella/Domain/Entity/GDrive/GDriveServer.swift b/Tella/Domain/Entity/GDrive/GDriveServer.swift index b2f9ceeb1..a447cc9be 100644 --- a/Tella/Domain/Entity/GDrive/GDriveServer.swift +++ b/Tella/Domain/Entity/GDrive/GDriveServer.swift @@ -10,17 +10,21 @@ import Foundation class GDriveServer: Server { var rootFolder: String? + var rootFolderName: String? enum CodingKeys: String, CodingKey { case rootFolder = "c_root_folder" + case rootFolderName = "c_root_folder_name" } init(id: Int? = nil, name: String? = LocalizableGDrive.gDriveAppBar.localized, rootFolder: String, + rootFolderName: String, serverType: ServerConnectionType? = .gDrive) { self.rootFolder = rootFolder + self.rootFolderName = rootFolderName super.init(id: id, name: name, serverType: serverType, @@ -30,6 +34,7 @@ class GDriveServer: Server { required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.rootFolder = try container.decode(String?.self, forKey: .rootFolder) + self.rootFolderName = try container.decode(String?.self, forKey: .rootFolderName) try super.init(from: decoder) self.serverType = .gDrive self.allowMultiple = false @@ -38,6 +43,7 @@ class GDriveServer: Server { override func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(rootFolder, forKey: .rootFolder) + try container.encode(rootFolderName, forKey: .rootFolderName) try super.encode(to: encoder) } } diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 99cdb0860..38667de98 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -54,15 +54,15 @@ class GDriveServerViewModel: ObservableObject { } }, receiveValue: { folderId in self.createFolderState = .loaded(folderId) - self.addServer(rootFolder: folderId) { + self.addServer(rootFolder: folderId, rootFolderName: folderName) { completion() } }) .store(in: &cancellables) } - func addServer(rootFolder: String, completion: @escaping() -> Void ) { - let server = GDriveServer(rootFolder: rootFolder) + func addServer(rootFolder: String, rootFolderName: String, completion: @escaping() -> Void ) { + let server = GDriveServer(rootFolder: rootFolder, rootFolderName: rootFolderName) _ = mainAppModel.tellaData?.addGDriveServer(server: server) diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index 55bd582dc..7eb75e9ff 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -64,7 +64,7 @@ struct SelectSharedDrive: View { presentationMode.wrappedValue.dismiss() return } - gDriveServerViewModel.addServer(rootFolder: selectedDrive.id) { + gDriveServerViewModel.addServer(rootFolder: selectedDrive.id, rootFolderName: selectedDrive.name) { navigateTo(destination: SuccessLoginView( navigateToAction: {navigateTo(destination: reportsView)}, type: .gDrive) diff --git a/Tella/Supporting Files/en.lproj/Localizable.strings b/Tella/Supporting Files/en.lproj/Localizable.strings index 25e3b5431..a58b0cabb 100644 --- a/Tella/Supporting Files/en.lproj/Localizable.strings +++ b/Tella/Supporting Files/en.lproj/Localizable.strings @@ -554,4 +554,4 @@ This feedback is anonymous, so make sure to include contact information if you w "Error_InvalidURL_Expl" = "Invalid URL"; "Error_Unexpected_Response_Expl" = "Unexpected response from the server"; "Error_Unauthorized_Expl" = "Invalid username or password"; -"Error_Forbidden_Expl" = "Account locked due to too many unsuccessful attempts." +"Error_Forbidden_Expl" = "Account locked due to too many unsuccessful attempts."; From 0fa19a36aa4d0d66920515a091048b3ebb7fef32 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 23 Aug 2024 15:58:27 -0300 Subject: [PATCH 149/167] change db version to apply folder name changes --- Tella/Data/Database/Common/DatabaseConstants.swift | 2 +- Tella/Data/Database/GDriveDatabase.swift | 10 ++++++++++ Tella/Data/Database/TellaDataBase.swift | 3 +++ Tella/Domain/Entity/GDrive/GDriveServer.swift | 4 ++-- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Tella/Data/Database/Common/DatabaseConstants.swift b/Tella/Data/Database/Common/DatabaseConstants.swift index 316b1803c..fbf10ec2f 100644 --- a/Tella/Data/Database/Common/DatabaseConstants.swift +++ b/Tella/Data/Database/Common/DatabaseConstants.swift @@ -13,7 +13,7 @@ struct D { /* DATABASE VERSION */ - static let databaseVersion = 6 + static let databaseVersion = 7 /* DEFAULT TYPES FOR DATABASE */ // MARK: - DEFAULT TYPES FOR DATABASE diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index 1f5cbf26d..735e05d62 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -272,3 +272,13 @@ extension TellaDataBase { } } } + +extension TellaDataBase { + func addRootFolderNameColumn() { + do { + try statementBuilder.addColumnOn(tableName: D.tGDriveServer, columnName: D.cRootFolderName, type: D.text) + } catch let error { + debugLog(error) + } + } +} diff --git a/Tella/Data/Database/TellaDataBase.swift b/Tella/Data/Database/TellaDataBase.swift index f347355cd..123eb3e68 100644 --- a/Tella/Data/Database/TellaDataBase.swift +++ b/Tella/Data/Database/TellaDataBase.swift @@ -44,6 +44,9 @@ class TellaDataBase : DataBase { createGDriveServerTable() createGDriveReportTable() createGDriveReportFilesTable() + fallthrough + case 6: + addRootFolderNameColumn() default : break } diff --git a/Tella/Domain/Entity/GDrive/GDriveServer.swift b/Tella/Domain/Entity/GDrive/GDriveServer.swift index a447cc9be..101fafd9a 100644 --- a/Tella/Domain/Entity/GDrive/GDriveServer.swift +++ b/Tella/Domain/Entity/GDrive/GDriveServer.swift @@ -34,7 +34,7 @@ class GDriveServer: Server { required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.rootFolder = try container.decode(String?.self, forKey: .rootFolder) - self.rootFolderName = try container.decode(String?.self, forKey: .rootFolderName) + self.rootFolderName = try container.decodeIfPresent(String.self, forKey: .rootFolderName) try super.init(from: decoder) self.serverType = .gDrive self.allowMultiple = false @@ -43,7 +43,7 @@ class GDriveServer: Server { override func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(rootFolder, forKey: .rootFolder) - try container.encode(rootFolderName, forKey: .rootFolderName) + try container.encodeIfPresent(rootFolderName, forKey: .rootFolderName) try super.encode(to: encoder) } } From a9f2fc1d04b2a9d1a970a12263df433840df57d6 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Fri, 23 Aug 2024 16:41:08 -0300 Subject: [PATCH 150/167] preven duplicated folder name --- Tella/Data/Database/GDriveDatabase.swift | 3 +-- Tella/Data/Database/TellaDataBase.swift | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index 735e05d62..b4d1304f2 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -15,8 +15,7 @@ extension TellaDataBase { let columns = [ cddl(D.cId, D.integer, primaryKey: true, autoIncrement: true), cddl(D.cName, D.text), - cddl(D.cRootFolder, D.text), - cddl(D.cRootFolderName, D.text) + cddl(D.cRootFolder, D.text) ] statementBuilder.createTable(tableName: D.tGDriveServer, columns: columns) } diff --git a/Tella/Data/Database/TellaDataBase.swift b/Tella/Data/Database/TellaDataBase.swift index 123eb3e68..9455a20b9 100644 --- a/Tella/Data/Database/TellaDataBase.swift +++ b/Tella/Data/Database/TellaDataBase.swift @@ -70,6 +70,7 @@ class TellaDataBase : DataBase { createGDriveServerTable() createGDriveReportTable() createGDriveReportFilesTable() + addRootFolderNameColumn() } func createReportTable() { From 0a8c3559a8bf30cda152c872e6728440124aff2c Mon Sep 17 00:00:00 2001 From: Rimktarii <167132396+Rimktarii@users.noreply.github.com> Date: Mon, 26 Aug 2024 13:27:24 +0200 Subject: [PATCH 151/167] Allow only one instace of Uwazi (#172) --- Tella/Domain/Entity/Report/ServerType.swift | 2 ++ Tella/Domain/Entity/Uwazi/UwaziServer.swift | 1 + 2 files changed, 3 insertions(+) diff --git a/Tella/Domain/Entity/Report/ServerType.swift b/Tella/Domain/Entity/Report/ServerType.swift index d846aad71..f62b652b9 100644 --- a/Tella/Domain/Entity/Report/ServerType.swift +++ b/Tella/Domain/Entity/Report/ServerType.swift @@ -28,6 +28,8 @@ extension ServerConnectionType { switch self { case .gDrive: LocalizableSettings.settServerGDrive.localized + case .uwazi: + LocalizableSettings.settServerUwazi.localized default: "" } diff --git a/Tella/Domain/Entity/Uwazi/UwaziServer.swift b/Tella/Domain/Entity/Uwazi/UwaziServer.swift index 87792adcc..11195483c 100644 --- a/Tella/Domain/Entity/Uwazi/UwaziServer.swift +++ b/Tella/Domain/Entity/Uwazi/UwaziServer.swift @@ -31,6 +31,7 @@ class UwaziServer : WebServer { self.locale = locale self.accessToken = accessToken self.cookie = createCookie() + self.allowMultiple = false } required init(from decoder: Decoder) throws { From 3124106e48c27aa4061b5ce08dd25329f5c06930 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 26 Aug 2024 13:12:27 -0300 Subject: [PATCH 152/167] rollback to db version 6 --- Tella/Data/Database/Common/DatabaseConstants.swift | 2 +- Tella/Data/Database/GDriveDatabase.swift | 13 ++----------- Tella/Data/Database/TellaDataBase.swift | 4 ---- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/Tella/Data/Database/Common/DatabaseConstants.swift b/Tella/Data/Database/Common/DatabaseConstants.swift index fbf10ec2f..316b1803c 100644 --- a/Tella/Data/Database/Common/DatabaseConstants.swift +++ b/Tella/Data/Database/Common/DatabaseConstants.swift @@ -13,7 +13,7 @@ struct D { /* DATABASE VERSION */ - static let databaseVersion = 7 + static let databaseVersion = 6 /* DEFAULT TYPES FOR DATABASE */ // MARK: - DEFAULT TYPES FOR DATABASE diff --git a/Tella/Data/Database/GDriveDatabase.swift b/Tella/Data/Database/GDriveDatabase.swift index b4d1304f2..1f5cbf26d 100644 --- a/Tella/Data/Database/GDriveDatabase.swift +++ b/Tella/Data/Database/GDriveDatabase.swift @@ -15,7 +15,8 @@ extension TellaDataBase { let columns = [ cddl(D.cId, D.integer, primaryKey: true, autoIncrement: true), cddl(D.cName, D.text), - cddl(D.cRootFolder, D.text) + cddl(D.cRootFolder, D.text), + cddl(D.cRootFolderName, D.text) ] statementBuilder.createTable(tableName: D.tGDriveServer, columns: columns) } @@ -271,13 +272,3 @@ extension TellaDataBase { } } } - -extension TellaDataBase { - func addRootFolderNameColumn() { - do { - try statementBuilder.addColumnOn(tableName: D.tGDriveServer, columnName: D.cRootFolderName, type: D.text) - } catch let error { - debugLog(error) - } - } -} diff --git a/Tella/Data/Database/TellaDataBase.swift b/Tella/Data/Database/TellaDataBase.swift index 9455a20b9..f347355cd 100644 --- a/Tella/Data/Database/TellaDataBase.swift +++ b/Tella/Data/Database/TellaDataBase.swift @@ -44,9 +44,6 @@ class TellaDataBase : DataBase { createGDriveServerTable() createGDriveReportTable() createGDriveReportFilesTable() - fallthrough - case 6: - addRootFolderNameColumn() default : break } @@ -70,7 +67,6 @@ class TellaDataBase : DataBase { createGDriveServerTable() createGDriveReportTable() createGDriveReportFilesTable() - addRootFolderNameColumn() } func createReportTable() { From 9c36fd85e4639ca27b39e9ee7ddf93f357b0eae0 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 26 Aug 2024 16:40:40 -0300 Subject: [PATCH 153/167] remove hardcoded client id and fix logical error in server list --- Tella/Scenes/Settings/ViewModel/ServersViewModel.swift | 10 +++------- .../Settings/Views/Servers/ServerSelectionView.swift | 2 +- Tella/Supporting Files/Info.plist | 4 ++-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift b/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift index a78f5a230..e5a3cefce 100644 --- a/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift @@ -38,13 +38,9 @@ class ServersViewModel: ObservableObject { } func filterServerConnections() -> [ServerConnectionButton] { - if(self.unavailableServers.isEmpty) { - return serverConnections - } + let unavailableTypes = Set(unavailableServers.compactMap { $0.serverType }) return serverConnections.filter { connection in - unavailableServers.contains{ connection.type != $0.serverType } + !unavailableTypes.contains(connection.type) } - - } -} + }} diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 5a43aba62..2145810e7 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -107,7 +107,7 @@ struct ServerSelectionView: View { VStack(spacing: 20) { SectionTitle(text: LocalizableSettings.settServerUnavailableConnectionsTitle.localized) SectionMessage(text: LocalizableSettings.settServerUnavailableConnectionsDesc.localized) - ForEach(serversViewModel.unavailableServers, id: \.id) { server in + ForEach(serversViewModel.unavailableServers, id: \.serverType) { server in TellaButtonView( title: server.serverType?.serverTitle ?? "", nextButtonAction: .action, diff --git a/Tella/Supporting Files/Info.plist b/Tella/Supporting Files/Info.plist index d8d53371b..a439f1bb8 100644 --- a/Tella/Supporting Files/Info.plist +++ b/Tella/Supporting Files/Info.plist @@ -33,14 +33,14 @@ googleDrive CFBundleURLSchemes - com.googleusercontent.apps.299748721134-oqrpkd21ko4rfgqtp976cs8gndc868gv + $(GOOGLE_REVERSE_CLIENT_ID) CFBundleVersion $(CURRENT_PROJECT_VERSION) GIDClientID - 299748721134-oqrpkd21ko4rfgqtp976cs8gndc868gv.apps.googleusercontent.com + $(GOOGLE_CLIENT_ID) ITSAppUsesNonExemptEncryption LSApplicationCategoryType From 500664eaf4231f54dd2ed70578d69d4d3c84adf2 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Mon, 26 Aug 2024 17:29:14 -0300 Subject: [PATCH 154/167] fix bug in uwazi card --- Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift b/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift index f8761b6d5..1234cdae4 100644 --- a/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift +++ b/Tella/Scenes/Uwazi/ViewModel/UwaziCardViewModel.swift @@ -15,7 +15,6 @@ enum CardType { } class UwaziCardViewModel: CommonCardViewModel { - var templateId : Int? var entityInstanceID : Int? var serverId: Int? @@ -30,7 +29,7 @@ class UwaziCardViewModel: CommonCardViewModel { let deleteMessage = LocalizableUwazi.uwaziDeleteTemplateExpl.localized let deleteReportStrings = ConfirmDeleteConnectionStrings(deleteTitle: deleteTitle, deleteMessage: deleteMessage) - super.init(id: Int(UUID().uuidString), + super.init(id: template.id, title: title, iconImageName: nil, serverName: template.serverName ?? "", @@ -53,7 +52,7 @@ class UwaziCardViewModel: CommonCardViewModel { let listActionSheetItem = instance.status.listActionSheetItem let deleteReportStrings = instance.status.deleteReportStrings(title: title) - super.init(id: Int(UUID().uuidString) , + super.init(id: instance.id, title: title, iconImageName: iconImageName, serverName: serverName, From 5ca95d8f2f39440d118c3d63494ec7748deb819c Mon Sep 17 00:00:00 2001 From: Dhekra Rouatbi Date: Tue, 27 Aug 2024 13:43:54 +0100 Subject: [PATCH 155/167] Add TellaConfig --- .gitignore | 2 ++ Tella.xcodeproj/project.pbxproj | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 64e396f32..8cd87f7fa 100644 --- a/.gitignore +++ b/.gitignore @@ -99,3 +99,5 @@ iOSInjectionProject/ !*.xcodeproj/project.pbxproj !*.xcodeproj/xcshareddata .idea + +Tella/Supporting Files/TellaConfig.xcconfig diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 3525f6ab7..a34ba8c34 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -714,6 +714,7 @@ 125299E02AD0515600191CAB /* VaultFilesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VaultFilesManager.swift; sourceTree = ""; }; 1252F7042BDAB1C30076DF4B /* EntityInstanceToSend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntityInstanceToSend.swift; sourceTree = ""; }; 1252F7062BDAB2000076DF4B /* EntityAttachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntityAttachment.swift; sourceTree = ""; }; + 12543C962C7DFD8E003811F8 /* TellaConfig.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = TellaConfig.xcconfig; sourceTree = ""; }; 125595372AFCFAA400F71DFE /* SelectQuery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectQuery.swift; sourceTree = ""; }; 12567FEE2716B38F00A2D356 /* LockChoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockChoiceView.swift; sourceTree = ""; }; 12567FF02716E33500A2D356 /* OpenSans-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "OpenSans-Bold.ttf"; sourceTree = ""; }; @@ -1832,6 +1833,7 @@ F66E65BA23E32080000F93E5 /* Info.plist */, F66E65B723E32080000F93E5 /* LaunchScreen.storyboard */, 12A697B52840C50400BE5E9C /* Localizable.strings */, + 12543C962C7DFD8E003811F8 /* TellaConfig.xcconfig */, ); path = "Supporting Files"; sourceTree = ""; @@ -3995,6 +3997,7 @@ }; F66E65D123E32080000F93E5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 12543C962C7DFD8E003811F8 /* TellaConfig.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -4057,6 +4060,7 @@ }; F66E65D223E32080000F93E5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 12543C962C7DFD8E003811F8 /* TellaConfig.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; From 89d18ef502de90f9b730ad4aa6f23ea2203a98e7 Mon Sep 17 00:00:00 2001 From: rimKtarii Date: Tue, 27 Aug 2024 15:12:00 +0200 Subject: [PATCH 156/167] Refactor APIError errorMessage, remove optionnal message --- Tella/Data/Networking/APICall/APIError.swift | 2 +- .../ViewModel/GDriveOutboxViewModel.swift | 4 ++-- .../ViewModel/ResourcesViewModel.swift | 4 ++-- .../Settings/ViewModel/ServerViewModel.swift | 4 ++-- .../ViewModel/UwaziServerViewModel.swift | 18 +++++++++--------- .../Scenes/Uwazi/ViewModel/AddTemplateVM.swift | 2 +- Tella/Utils/Utils.swift | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Tella/Data/Networking/APICall/APIError.swift b/Tella/Data/Networking/APICall/APIError.swift index aceefc312..403eeb8fc 100644 --- a/Tella/Data/Networking/APICall/APIError.swift +++ b/Tella/Data/Networking/APICall/APIError.swift @@ -17,7 +17,7 @@ enum APIError: Swift.Error { extension APIError: LocalizedError { - var errorDescription: String? { + var errorMessage: String { switch self { case .invalidURL: return LocalizableError.invalidUrl.localized diff --git a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift index 5e21e3baa..59f0a97bc 100644 --- a/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift +++ b/Tella/Scenes/GDrive/ViewModel/GDriveOutboxViewModel.swift @@ -138,7 +138,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { case .failure( let error): switch error { default: - Toast.displayToast(message: error.errorDescription ?? error.localizedDescription) + Toast.displayToast(message: error.errorMessage) updateReportStatus(reportStatus: .submissionError) } } @@ -151,7 +151,7 @@ class GDriveOutboxViewModel: OutboxMainViewModel { case .failure( let error): switch error { default: - Toast.displayToast(message: error.errorDescription ?? error.localizedDescription) + Toast.displayToast(message: error.errorMessage) updateReportStatus(reportStatus: .submissionError) } } diff --git a/Tella/Scenes/Resources/ViewModel/ResourcesViewModel.swift b/Tella/Scenes/Resources/ViewModel/ResourcesViewModel.swift index 129665f95..933183318 100644 --- a/Tella/Scenes/Resources/ViewModel/ResourcesViewModel.swift +++ b/Tella/Scenes/Resources/ViewModel/ResourcesViewModel.swift @@ -76,7 +76,7 @@ class ResourcesViewModel: ObservableObject { case .failure( let error): switch error { case .noInternetConnection: - Toast.displayToast(message: error.errorDescription ?? error.localizedDescription) + Toast.displayToast(message: error.errorMessage) default: Toast.displayToast(message: LocalizableResources.resourcesAvailableErrorMsg.localized) } @@ -114,7 +114,7 @@ class ResourcesViewModel: ObservableObject { switch error { case .noInternetConnection: debugLog("Error downloading file: \(error)") - Toast.displayToast(message: error.errorDescription ?? error.localizedDescription) + Toast.displayToast(message: error.errorMessage) default: debugLog("Error downloading file: \(error)") Toast.displayToast(message: error.localizedDescription) diff --git a/Tella/Scenes/Settings/ViewModel/ServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/ServerViewModel.swift index 1023e934e..d0fae0e09 100644 --- a/Tella/Scenes/Settings/ViewModel/ServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/ServerViewModel.swift @@ -101,7 +101,7 @@ class ServerViewModel: ObservableObject { switch completion { case .failure(let error): self.shouldShowLoginError = true - self.loginErrorMessage = error.errorDescription ?? "" + self.loginErrorMessage = error.errorMessage ?? "" self.isLoading = false case .finished: @@ -130,7 +130,7 @@ class ServerViewModel: ObservableObject { switch completion { case .failure(let error): self.shouldShowLoginError = true - self.loginErrorMessage = error.errorDescription ?? "" + self.loginErrorMessage = error.errorMessage ?? "" case .finished: self.shouldShowLoginError = false self.loginErrorMessage = "" diff --git a/Tella/Scenes/Settings/ViewModel/UwaziServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/UwaziServerViewModel.swift index 2fc473bf9..88bc8b8b2 100644 --- a/Tella/Scenes/Settings/ViewModel/UwaziServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/UwaziServerViewModel.swift @@ -135,7 +135,7 @@ class UwaziServerViewModel: ObservableObject { debugLog(error) switch error { case .noInternetConnection: - Toast.displayToast(message: error.errorDescription ?? error.localizedDescription) + Toast.displayToast(message: error.errorMessage) default: break } @@ -176,12 +176,12 @@ class UwaziServerViewModel: ObservableObject { case .failure(let error): switch error { case .noInternetConnection: - Toast.displayToast(message: error.errorDescription ?? error.localizedDescription) + Toast.displayToast(message: error.errorMessage) case .httpCode(HTTPErrorCodes.unauthorized.rawValue): handlePrivateInstance() default: debugLog(error) - urlErrorMessage = error.errorDescription ?? error.localizedDescription + urlErrorMessage = error.errorMessage shouldShowURLError = true } } @@ -230,7 +230,7 @@ class UwaziServerViewModel: ObservableObject { switch error { case .invalidURL, .unexpectedResponse, .badServer: self.shouldShowLoginError = true - self.loginErrorMessage = error.errorDescription ?? "" + self.loginErrorMessage = error.errorMessage ?? "" case .httpCode(let code): // if the status code is 401 then username or password is not matching // if the status code is 409 then 2FA is needed @@ -240,10 +240,10 @@ class UwaziServerViewModel: ObservableObject { self.showNext2FAView = true default: self.shouldShowLoginError = true - self.loginErrorMessage = error.errorDescription ?? error.localizedDescription + self.loginErrorMessage = error.errorMessage } case .noInternetConnection: - Toast.displayToast(message: error.errorDescription ?? error.localizedDescription) + Toast.displayToast(message: error.errorMessage) default: break } @@ -293,7 +293,7 @@ class UwaziServerViewModel: ObservableObject { case .failure(let error): switch error { case .invalidURL, .unexpectedResponse, .badServer: - self.codeErrorMessage = error.errorDescription ?? "" + self.codeErrorMessage = error.errorMessage ?? "" case .httpCode(let code): // if the status code is 401 then the 2FA code is incorrect let httpError = HTTPErrorCodes(rawValue: code) ?? .unknown @@ -301,10 +301,10 @@ class UwaziServerViewModel: ObservableObject { case .unauthorized: self.codeErrorMessage = "Two-factor authentication failed." default: - self.codeErrorMessage = error.errorDescription ?? "" + self.codeErrorMessage = error.errorMessage ?? "" } case .noInternetConnection: - Toast.displayToast(message: error.errorDescription ?? error.localizedDescription) + Toast.displayToast(message: error.errorMessage) default: break } diff --git a/Tella/Scenes/Uwazi/ViewModel/AddTemplateVM.swift b/Tella/Scenes/Uwazi/ViewModel/AddTemplateVM.swift index d0a3b7a3e..79b30e716 100644 --- a/Tella/Scenes/Uwazi/ViewModel/AddTemplateVM.swift +++ b/Tella/Scenes/Uwazi/ViewModel/AddTemplateVM.swift @@ -96,7 +96,7 @@ class AddTemplateViewModel: ObservableObject { showToast = false case .failure(let error): self.showToast = true - self.toastMessage = error.errorDescription ?? "" + self.toastMessage = error.errorMessage ?? "" } self.isLoading = false } diff --git a/Tella/Utils/Utils.swift b/Tella/Utils/Utils.swift index 2774d77af..c1badae18 100644 --- a/Tella/Utils/Utils.swift +++ b/Tella/Utils/Utils.swift @@ -21,7 +21,7 @@ struct RuntimeError: Error { extension RuntimeError: LocalizedError { - public var errorDescription: String? { + public var errorMessage: String? { return message } } From e8b155fe5c5b8ad09c7414818ed7c17f2b255693 Mon Sep 17 00:00:00 2001 From: rimKtarii Date: Tue, 27 Aug 2024 15:21:07 +0200 Subject: [PATCH 157/167] Remove unused code --- Tella/Scenes/Settings/ViewModel/ServerViewModel.swift | 4 ++-- Tella/Scenes/Settings/ViewModel/UwaziServerViewModel.swift | 6 +++--- Tella/Scenes/Uwazi/ViewModel/AddTemplateVM.swift | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Tella/Scenes/Settings/ViewModel/ServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/ServerViewModel.swift index d0fae0e09..3d513e643 100644 --- a/Tella/Scenes/Settings/ViewModel/ServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/ServerViewModel.swift @@ -101,7 +101,7 @@ class ServerViewModel: ObservableObject { switch completion { case .failure(let error): self.shouldShowLoginError = true - self.loginErrorMessage = error.errorMessage ?? "" + self.loginErrorMessage = error.errorMessage self.isLoading = false case .finished: @@ -130,7 +130,7 @@ class ServerViewModel: ObservableObject { switch completion { case .failure(let error): self.shouldShowLoginError = true - self.loginErrorMessage = error.errorMessage ?? "" + self.loginErrorMessage = error.errorMessage case .finished: self.shouldShowLoginError = false self.loginErrorMessage = "" diff --git a/Tella/Scenes/Settings/ViewModel/UwaziServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/UwaziServerViewModel.swift index 88bc8b8b2..ca8fc8d0a 100644 --- a/Tella/Scenes/Settings/ViewModel/UwaziServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/UwaziServerViewModel.swift @@ -230,7 +230,7 @@ class UwaziServerViewModel: ObservableObject { switch error { case .invalidURL, .unexpectedResponse, .badServer: self.shouldShowLoginError = true - self.loginErrorMessage = error.errorMessage ?? "" + self.loginErrorMessage = error.errorMessage case .httpCode(let code): // if the status code is 401 then username or password is not matching // if the status code is 409 then 2FA is needed @@ -293,7 +293,7 @@ class UwaziServerViewModel: ObservableObject { case .failure(let error): switch error { case .invalidURL, .unexpectedResponse, .badServer: - self.codeErrorMessage = error.errorMessage ?? "" + self.codeErrorMessage = error.errorMessage case .httpCode(let code): // if the status code is 401 then the 2FA code is incorrect let httpError = HTTPErrorCodes(rawValue: code) ?? .unknown @@ -301,7 +301,7 @@ class UwaziServerViewModel: ObservableObject { case .unauthorized: self.codeErrorMessage = "Two-factor authentication failed." default: - self.codeErrorMessage = error.errorMessage ?? "" + self.codeErrorMessage = error.errorMessage } case .noInternetConnection: Toast.displayToast(message: error.errorMessage) diff --git a/Tella/Scenes/Uwazi/ViewModel/AddTemplateVM.swift b/Tella/Scenes/Uwazi/ViewModel/AddTemplateVM.swift index 79b30e716..77ca8d2ee 100644 --- a/Tella/Scenes/Uwazi/ViewModel/AddTemplateVM.swift +++ b/Tella/Scenes/Uwazi/ViewModel/AddTemplateVM.swift @@ -96,7 +96,7 @@ class AddTemplateViewModel: ObservableObject { showToast = false case .failure(let error): self.showToast = true - self.toastMessage = error.errorMessage ?? "" + self.toastMessage = error.errorMessage } self.isLoading = false } From b4d1b19c1d91f0278f80c31176956b25fc6f1e55 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 27 Aug 2024 10:31:15 -0300 Subject: [PATCH 158/167] more fixes --- Tella/Data/Database/Common/DatabaseConstants.swift | 2 +- .../Views/Servers/GDrive/SelectDriveConnection.swift | 2 +- .../Views/Servers/GDrive/SelectSharedDrive.swift | 6 +++--- Tella/Supporting Files/TellaConfig.xcconfig | 12 ++++++++++++ 4 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 Tella/Supporting Files/TellaConfig.xcconfig diff --git a/Tella/Data/Database/Common/DatabaseConstants.swift b/Tella/Data/Database/Common/DatabaseConstants.swift index 316b1803c..c659a5622 100644 --- a/Tella/Data/Database/Common/DatabaseConstants.swift +++ b/Tella/Data/Database/Common/DatabaseConstants.swift @@ -95,7 +95,7 @@ struct D { static let cSize = "c_size" //gDrive - static let cRootFolder = "c_root_folder" + static let cRootFolder = "c_root_folder_id" static let cFolderId = "c_folder_id" static let cRootFolderName = "c_root_folder_name" diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift index b39cc53f4..8d6098bc6 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectDriveConnection.swift @@ -79,7 +79,7 @@ struct SelectDriveConnection: View { switch selectedDriveConnectionType { case .shared: navigateTo( - destination: SelectSharedDrive() + destination: SelectSharedDriveView() .environmentObject(gDriveServerViewModel) ) case .personal: diff --git a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift index 7eb75e9ff..6ae240ea3 100644 --- a/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift +++ b/Tella/Scenes/Settings/Views/Servers/GDrive/SelectSharedDrive.swift @@ -9,7 +9,7 @@ import SwiftUI import GoogleAPIClientForREST -struct SelectSharedDrive: View { +struct SelectSharedDriveView: View { @EnvironmentObject var gDriveServerViewModel: GDriveServerViewModel @Environment(\.presentationMode) var presentationMode: Binding var body: some View { @@ -59,7 +59,7 @@ struct SelectSharedDrive: View { type: .save) } - func backButtonAction() -> Void { + func backButtonAction() { guard let selectedDrive = gDriveServerViewModel.selectedDrive else { presentationMode.wrappedValue.dismiss() return @@ -102,5 +102,5 @@ struct DriveCardView: View { #Preview { - SelectSharedDrive() + SelectSharedDriveView() } diff --git a/Tella/Supporting Files/TellaConfig.xcconfig b/Tella/Supporting Files/TellaConfig.xcconfig new file mode 100644 index 000000000..4cc693d39 --- /dev/null +++ b/Tella/Supporting Files/TellaConfig.xcconfig @@ -0,0 +1,12 @@ +// +// TellaConfig.xcconfig +// Tella +// +// Created by gus valbuena on 8/27/24. +// Copyright © 2024 HORIZONTAL. All rights reserved. +// + +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 +GOOGLE_CLIENT_ID = 299748721134-lbj77khp0n8nrekeuk3fq82bi7ll1o60.apps.googleusercontent.com +GOOGLE_REVERSE_CLIENT_ID = com.googleusercontent.apps.299748721134-lbj77khp0n8nrekeuk3fq82bi7ll1o60 From 4a641df9b318736fe41699c66f0a9a6e899e296f Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 27 Aug 2024 10:31:59 -0300 Subject: [PATCH 159/167] update g-drive server --- Tella/Domain/Entity/GDrive/GDriveServer.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tella/Domain/Entity/GDrive/GDriveServer.swift b/Tella/Domain/Entity/GDrive/GDriveServer.swift index 101fafd9a..bfddda44a 100644 --- a/Tella/Domain/Entity/GDrive/GDriveServer.swift +++ b/Tella/Domain/Entity/GDrive/GDriveServer.swift @@ -13,7 +13,7 @@ class GDriveServer: Server { var rootFolderName: String? enum CodingKeys: String, CodingKey { - case rootFolder = "c_root_folder" + case rootFolder = "c_root_folder_id" case rootFolderName = "c_root_folder_name" } From bf325395e0e0cfbe263abefe28df9607dea15b0e Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 27 Aug 2024 13:12:40 -0300 Subject: [PATCH 160/167] fix edge case in drive server connection --- Tella/Scenes/Settings/ViewModel/ServersViewModel.swift | 1 + Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift b/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift index e5a3cefce..9169d961d 100644 --- a/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift @@ -13,6 +13,7 @@ class ServersViewModel: ObservableObject { @Published var currentServer : Server? @Published var serverArray : [Server] = [] @Published var unavailableServers: [Server] = [] + @Published var shouldHideNextButton: Bool = false private var subscribers = Set() diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index 2145810e7..a0f1e6ca7 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -68,7 +68,7 @@ struct ServerSelectionView: View { fileprivate func bottomView() -> BottomLockView { return BottomLockView(isValid: .constant(true), nextButtonAction: .action, - shouldHideNext: false, + shouldHideNext: serversViewModel.shouldHideNextButton, shouldHideBack: true, nextAction: { switch selectedServerType { @@ -95,12 +95,14 @@ struct ServerSelectionView: View { } fileprivate func navigateToGDriveFlow() { + serversViewModel.shouldHideNextButton = true gDriveVM.handleSignIn { navigateTo( destination: SelectDriveConnection(gDriveServerViewModel: gDriveServerVM), title: LocalizableSettings.settServerGDrive.localized ) } + serversViewModel.shouldHideNextButton = false } fileprivate func unavailableConnectionsView() -> some View { From 61190cebd507fee4a5b9df0dd05d992d4fc7aa58 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 27 Aug 2024 13:47:43 -0300 Subject: [PATCH 161/167] refactor errors in gDrive --- Tella/Data/Networking/APICall/APIError.swift | 29 ++++++++++++------- .../en.lproj/Localizable.strings | 3 ++ .../Utils/Localizable/LocalizableError.swift | 3 ++ 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Tella/Data/Networking/APICall/APIError.swift b/Tella/Data/Networking/APICall/APIError.swift index aceefc312..ceb90ac56 100644 --- a/Tella/Data/Networking/APICall/APIError.swift +++ b/Tella/Data/Networking/APICall/APIError.swift @@ -16,7 +16,7 @@ enum APIError: Swift.Error { } extension APIError: LocalizedError { - + var errorDescription: String? { switch self { case .invalidURL: @@ -51,21 +51,28 @@ extension APIError: LocalizedError { private func customDriveErrorMessage(error: Error) -> String { if let nsError = error as NSError? { + let errorMessage = nsError.localizedDescription + switch nsError.domain { - case GoogleAuthConstants.GTLRErrorObjectDomain: - let errorCode = nsError.code - let errorMessage = nsError.localizedDescription - - return customErrorMessage(errorCode: errorCode) - case GoogleAuthConstants.HTTPStatus: - return customErrorMessage(errorCode: nsError.code) + case GoogleAuthConstants.GTLRErrorObjectDomain, GoogleAuthConstants.HTTPStatus: + return parseDriveErrorMessage(errorCode: nsError.code, fallbackMessage: errorMessage) default: - if let errorString = nsError.userInfo["error"] as? String { - return errorString - } + return errorMessage } } return LocalizableError.unexpectedResponse.localized } + + private func parseDriveErrorMessage(errorCode: Int, fallbackMessage: String) -> String { + let httpErrorCode = HTTPErrorCodes(rawValue: errorCode) + switch httpErrorCode { + case .unauthorized: + return LocalizableError.gDriveUnauthorized.localized + case .forbidden: + return LocalizableError.gDriveForbidden.localized + default: + return fallbackMessage + } + } } diff --git a/Tella/Supporting Files/en.lproj/Localizable.strings b/Tella/Supporting Files/en.lproj/Localizable.strings index a58b0cabb..7bffeff1f 100644 --- a/Tella/Supporting Files/en.lproj/Localizable.strings +++ b/Tella/Supporting Files/en.lproj/Localizable.strings @@ -555,3 +555,6 @@ This feedback is anonymous, so make sure to include contact information if you w "Error_Unexpected_Response_Expl" = "Unexpected response from the server"; "Error_Unauthorized_Expl" = "Invalid username or password"; "Error_Forbidden_Expl" = "Account locked due to too many unsuccessful attempts."; + +"Error_GDrive_Unauthorized_Expl" = "Request is missing required authentication credential. Please re authenticate"; +"Error_GDrive_Forbidden_Expl" = "You don't have permission to access this file or folder in Google Drive."; diff --git a/Tella/Utils/Localizable/LocalizableError.swift b/Tella/Utils/Localizable/LocalizableError.swift index fc01faa4c..5bc0c0d55 100644 --- a/Tella/Utils/Localizable/LocalizableError.swift +++ b/Tella/Utils/Localizable/LocalizableError.swift @@ -13,4 +13,7 @@ enum LocalizableError : String, LocalizableDelegate { case unexpectedResponse = "Error_Unexpected_Response_Expl" case unauthorized = "Error_Unauthorized_Expl" case forbidden = "Error_Forbidden_Expl" + + case gDriveUnauthorized = "Error_GDrive_Unauthorized_Expl" + case gDriveForbidden = "Error_GDrive_Forbidden_Expl" } From ca15a125bf54b6c62b9d59da315061121ff96352 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 27 Aug 2024 16:21:53 -0300 Subject: [PATCH 162/167] refactor errors --- Tella/Data/Networking/Repositories/GDriveRepository.swift | 6 +++--- Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index dd5871424..97b92f4c2 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -21,7 +21,7 @@ protocol GDriveRepositoryProtocol { func handleSignIn() async throws func restorePreviousSignIn() async throws func handleUrl(url: URL) - func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> + func getSharedDrives() -> AnyPublisher<[SharedDrive], APIError> func createDriveFolder(folderName: String, parentId: String?, description: String?) -> AnyPublisher func uploadFile(fileUploadDetails: FileUploadDetails) -> AnyPublisher func pauseAllUploads() @@ -105,7 +105,7 @@ class GDriveRepository: GDriveRepositoryProtocol { GIDSignIn.sharedInstance.handle(url) } - func getSharedDrives() -> AnyPublisher<[SharedDrive], Error> { + func getSharedDrives() -> AnyPublisher<[SharedDrive], APIError> { Deferred { Future { [weak self] promise in guard let user = self?.googleUser else { @@ -119,7 +119,7 @@ class GDriveRepository: GDriveRepositoryProtocol { driveService.executeQuery(query) { ticket, response, error in if let error = error { debugLog("Error fetching drives: \(error.localizedDescription)") - promise(.failure(error)) + promise(.failure(.driveApiError(error))) } guard let driveList = response as? GTLRDrive_DriveList, diff --git a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift index 38667de98..303914620 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveServerViewModel.swift @@ -31,7 +31,7 @@ class GDriveServerViewModel: ObservableObject { case .finished: break case.failure(let error): - self.sharedDriveState = .error(error.localizedDescription) + self.sharedDriveState = .error(error.errorMessage) } }, receiveValue: { [weak self] drives in @@ -50,7 +50,7 @@ class GDriveServerViewModel: ObservableObject { case .finished: break case .failure(let error): - self.createFolderState = .error(error.localizedDescription) + self.createFolderState = .error(error.errorMessage) } }, receiveValue: { folderId in self.createFolderState = .loaded(folderId) From 9f2fe270a5c8fa6588dbf2ce7c1c54ae8674c8e4 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Tue, 27 Aug 2024 18:07:48 -0300 Subject: [PATCH 163/167] parse auth drive error as APIError --- Tella/Data/Networking/Repositories/GDriveRepository.swift | 6 ++---- Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Tella/Data/Networking/Repositories/GDriveRepository.swift b/Tella/Data/Networking/Repositories/GDriveRepository.swift index 97b92f4c2..79e6f436f 100644 --- a/Tella/Data/Networking/Repositories/GDriveRepository.swift +++ b/Tella/Data/Networking/Repositories/GDriveRepository.swift @@ -19,7 +19,6 @@ struct FileUploadDetails { } protocol GDriveRepositoryProtocol { func handleSignIn() async throws - func restorePreviousSignIn() async throws func handleUrl(url: URL) func getSharedDrives() -> AnyPublisher<[SharedDrive], APIError> func createDriveFolder(folderName: String, parentId: String?, description: String?) -> AnyPublisher @@ -69,7 +68,7 @@ class GDriveRepository: GDriveRepositoryProtocol { } GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { signInResult, error in if let error = error { - continuation.resume(throwing: error) + continuation.resume(throwing: APIError.driveApiError(error)) } else { signInResult?.user.addScopes([GoogleAuthConstants.gDriveScopes], presenting: rootViewController) self.googleUser = signInResult?.user @@ -80,7 +79,7 @@ class GDriveRepository: GDriveRepositoryProtocol { } } - func restorePreviousSignIn() async throws { + private func restorePreviousSignIn() async throws { try await withCheckedThrowingContinuation{ (continuation: CheckedContinuation) in DispatchQueue.main.async { guard let rootViewController = self.rootViewController else { @@ -269,7 +268,6 @@ class GDriveRepository: GDriveRepositoryProtocol { driveService.authorizer = user.fetcherAuthorizer let fileURL = fileUploadDetails.fileURL - let mimeType = fileUploadDetails.mimeType let fileId = fileUploadDetails.fileId let folderId = fileUploadDetails.folderId diff --git a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift index f247937bd..cdd7413e0 100644 --- a/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/GDriveAuthViewModel.swift @@ -24,8 +24,8 @@ class GDriveAuthViewModel: ObservableObject { try await gDriveRepository.handleSignIn() self.signInState = .loaded(nil) completion() - } catch let error { - self.signInState = .error(error.localizedDescription) + } catch let error as APIError { + self.signInState = .error(error.errorMessage) } } } From 3cb37f1fe9dc10eca4727afd7688c4138236eaf0 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 28 Aug 2024 09:53:24 -0300 Subject: [PATCH 164/167] remove TellaConfig --- Tella.xcodeproj/project.pbxproj | 4 ---- Tella/Supporting Files/TellaConfig.xcconfig | 12 ------------ 2 files changed, 16 deletions(-) delete mode 100644 Tella/Supporting Files/TellaConfig.xcconfig diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index a34ba8c34..3525f6ab7 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -714,7 +714,6 @@ 125299E02AD0515600191CAB /* VaultFilesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VaultFilesManager.swift; sourceTree = ""; }; 1252F7042BDAB1C30076DF4B /* EntityInstanceToSend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntityInstanceToSend.swift; sourceTree = ""; }; 1252F7062BDAB2000076DF4B /* EntityAttachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntityAttachment.swift; sourceTree = ""; }; - 12543C962C7DFD8E003811F8 /* TellaConfig.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = TellaConfig.xcconfig; sourceTree = ""; }; 125595372AFCFAA400F71DFE /* SelectQuery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectQuery.swift; sourceTree = ""; }; 12567FEE2716B38F00A2D356 /* LockChoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockChoiceView.swift; sourceTree = ""; }; 12567FF02716E33500A2D356 /* OpenSans-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "OpenSans-Bold.ttf"; sourceTree = ""; }; @@ -1833,7 +1832,6 @@ F66E65BA23E32080000F93E5 /* Info.plist */, F66E65B723E32080000F93E5 /* LaunchScreen.storyboard */, 12A697B52840C50400BE5E9C /* Localizable.strings */, - 12543C962C7DFD8E003811F8 /* TellaConfig.xcconfig */, ); path = "Supporting Files"; sourceTree = ""; @@ -3997,7 +3995,6 @@ }; F66E65D123E32080000F93E5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 12543C962C7DFD8E003811F8 /* TellaConfig.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -4060,7 +4057,6 @@ }; F66E65D223E32080000F93E5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 12543C962C7DFD8E003811F8 /* TellaConfig.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; diff --git a/Tella/Supporting Files/TellaConfig.xcconfig b/Tella/Supporting Files/TellaConfig.xcconfig deleted file mode 100644 index 4cc693d39..000000000 --- a/Tella/Supporting Files/TellaConfig.xcconfig +++ /dev/null @@ -1,12 +0,0 @@ -// -// TellaConfig.xcconfig -// Tella -// -// Created by gus valbuena on 8/27/24. -// Copyright © 2024 HORIZONTAL. All rights reserved. -// - -// Configuration settings file format documentation can be found at: -// https://help.apple.com/xcode/#/dev745c5c974 -GOOGLE_CLIENT_ID = 299748721134-lbj77khp0n8nrekeuk3fq82bi7ll1o60.apps.googleusercontent.com -GOOGLE_REVERSE_CLIENT_ID = com.googleusercontent.apps.299748721134-lbj77khp0n8nrekeuk3fq82bi7ll1o60 From 1f3bae9b50c64c7a8e8c868cab1dcb06cd843730 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 28 Aug 2024 09:57:47 -0300 Subject: [PATCH 165/167] re create tella config file --- Tella.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 3525f6ab7..03bdc1328 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -959,6 +959,7 @@ 1589A6202B7672390048C775 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 1589A6212B7672430048C775 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; 15917D742B90FCC3005655AC /* ResourceCardType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceCardType.swift; sourceTree = ""; }; + 15944AD02C7F55F800FD03CA /* TellaConfig.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = TellaConfig.xcconfig; sourceTree = ""; }; 15994A0B2BFBC6F40017F153 /* SelectDriveConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectDriveConnection.swift; sourceTree = ""; }; 15994A0D2BFBE15F0017F153 /* SelectSharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectSharedDrive.swift; sourceTree = ""; }; 15994A102BFBF0E50017F153 /* SharedDrive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedDrive.swift; sourceTree = ""; }; @@ -1832,6 +1833,7 @@ F66E65BA23E32080000F93E5 /* Info.plist */, F66E65B723E32080000F93E5 /* LaunchScreen.storyboard */, 12A697B52840C50400BE5E9C /* Localizable.strings */, + 15944AD02C7F55F800FD03CA /* TellaConfig.xcconfig */, ); path = "Supporting Files"; sourceTree = ""; From 275780b5e85f8fb6af6549b96557ca07709e05c9 Mon Sep 17 00:00:00 2001 From: gus valbuena Date: Wed, 28 Aug 2024 09:58:36 -0300 Subject: [PATCH 166/167] add tella config to project configuration --- Tella.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 03bdc1328..7003d1e98 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -3997,6 +3997,7 @@ }; F66E65D123E32080000F93E5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15944AD02C7F55F800FD03CA /* TellaConfig.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -4059,6 +4060,7 @@ }; F66E65D223E32080000F93E5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15944AD02C7F55F800FD03CA /* TellaConfig.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; From c6ebb3735bfe1506a8860bb69653f1d96b9bb618 Mon Sep 17 00:00:00 2001 From: dhekra-rouatbi <91288060+dhekra-rouatbi@users.noreply.github.com> Date: Wed, 28 Aug 2024 20:42:05 +0100 Subject: [PATCH 167/167] Select server view : Fix next button action (#176) * Fix next button action * Fix next button action --- .../Settings/ViewModel/ServersViewModel.swift | 5 +++-- .../Views/Servers/ServerSelectionView.swift | 22 +++++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift b/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift index 9169d961d..f8cd17aab 100644 --- a/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift +++ b/Tella/Scenes/Settings/ViewModel/ServersViewModel.swift @@ -13,8 +13,9 @@ class ServersViewModel: ObservableObject { @Published var currentServer : Server? @Published var serverArray : [Server] = [] @Published var unavailableServers: [Server] = [] - @Published var shouldHideNextButton: Bool = false - + @Published var shouldEnableNextButton: Bool = false + @Published var selectedServerType: ServerConnectionType? + private var subscribers = Set() init(mainAppModel : MainAppModel) { diff --git a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift index a0f1e6ca7..a1233189d 100644 --- a/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift +++ b/Tella/Scenes/Settings/Views/Servers/ServerSelectionView.swift @@ -12,7 +12,6 @@ struct ServerSelectionView: View { @EnvironmentObject var serversViewModel : ServersViewModel @StateObject var serverViewModel : ServerViewModel @EnvironmentObject var mainAppModel : MainAppModel - @State var selectedServerType: ServerConnectionType? = nil @ObservedObject var gDriveVM: GDriveAuthViewModel @ObservedObject var gDriveServerVM: GDriveServerViewModel @Environment(\.presentationMode) var presentationMode: Binding @@ -54,11 +53,12 @@ struct ServerSelectionView: View { TellaButtonView( title: connection.title, nextButtonAction: .action, - isOverlay: selectedServerType == connection.type, + isOverlay: serversViewModel.selectedServerType == connection.type, isValid: .constant(true), action: { - selectedServerType = connection.type - } + serversViewModel.selectedServerType = connection.type + serversViewModel.shouldEnableNextButton = true + } ) .padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)) } @@ -66,12 +66,11 @@ struct ServerSelectionView: View { } fileprivate func bottomView() -> BottomLockView { - return BottomLockView(isValid: .constant(true), + return BottomLockView(isValid: $serversViewModel.shouldEnableNextButton, nextButtonAction: .action, - shouldHideNext: serversViewModel.shouldHideNextButton, shouldHideBack: true, nextAction: { - switch selectedServerType { + switch serversViewModel.selectedServerType { case .tella: navigateToTellaWebFlow() case .uwazi: @@ -81,8 +80,15 @@ struct ServerSelectionView: View { default: break } + + resetView() }) } + + fileprivate func resetView() { + serversViewModel.selectedServerType = nil + serversViewModel.shouldEnableNextButton = false + } fileprivate func navigateToTellaWebFlow() { navigateTo(destination: AddServerURLView(appModel: mainAppModel)) @@ -95,14 +101,12 @@ struct ServerSelectionView: View { } fileprivate func navigateToGDriveFlow() { - serversViewModel.shouldHideNextButton = true gDriveVM.handleSignIn { navigateTo( destination: SelectDriveConnection(gDriveServerViewModel: gDriveServerVM), title: LocalizableSettings.settServerGDrive.localized ) } - serversViewModel.shouldHideNextButton = false } fileprivate func unavailableConnectionsView() -> some View {