diff --git a/Tella.xcodeproj/project.pbxproj b/Tella.xcodeproj/project.pbxproj index 60bd234a5..f444a34ec 100644 --- a/Tella.xcodeproj/project.pbxproj +++ b/Tella.xcodeproj/project.pbxproj @@ -141,13 +141,15 @@ 128D6E1A28045C090082AB18 /* manageFilesItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = 128D6E1928045C090082AB18 /* manageFilesItems.swift */; }; 128D6E1C280480500082AB18 /* FileActionItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = 128D6E1B280480500082AB18 /* FileActionItems.swift */; }; 128D6E1E2804DA2A0082AB18 /* ListActionSheetItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 128D6E1D2804DA2A0082AB18 /* ListActionSheetItem.swift */; }; + 128EDB92280980DB00747B98 /* SequenceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 128EDB91280980DB00747B98 /* SequenceExtension.swift */; }; + 128EDB942809897C00747B98 /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 128EDB932809897C00747B98 /* HomeViewModel.swift */; }; 128F979A2799AF0100E63DA5 /* CircularActivityIndicatory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 128F97962799983800E63DA5 /* CircularActivityIndicatory.swift */; }; 128FD0B427F774FB00B24915 /* RecentFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 128FD0B327F774FB00B24915 /* RecentFile.swift */; }; 1290743B274CEB9B00F38A81 /* FileGridItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1290743A274CEB9B00F38A81 /* FileGridItem.swift */; }; 1291F4F227B52BF9006A34D3 /* QueuePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291F4F127B52BF9006A34D3 /* QueuePlayer.swift */; }; 1291F4F627B54300006A34D3 /* AudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291F4F527B54300006A34D3 /* AudioPlayer.swift */; }; 129533C227399A1B0053FA4B /* AddPhotoVideoBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129533C127399A1B0053FA4B /* AddPhotoVideoBottomSheet.swift */; }; - 129533C42739D5BC0053FA4B /* TextFieldBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129533C32739D5BC0053FA4B /* TextFieldBottomSheet.swift */; }; + 129533C42739D5BC0053FA4B /* TextFieldBottomSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129533C32739D5BC0053FA4B /* TextFieldBottomSheetView.swift */; }; 12A1488F27209F2800A1ADDC /* ViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12A1488E27209F2800A1ADDC /* ViewExtension.swift */; }; 12A148922720A32000A1ADDC /* LockPinData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12A148912720A32000A1ADDC /* LockPinData.swift */; }; 12A148942720A89E00A1ADDC /* BottomLockView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12A148932720A89E00A1ADDC /* BottomLockView.swift */; }; @@ -383,13 +385,15 @@ 128D6E1928045C090082AB18 /* manageFilesItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = manageFilesItems.swift; sourceTree = ""; }; 128D6E1B280480500082AB18 /* FileActionItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileActionItems.swift; sourceTree = ""; }; 128D6E1D2804DA2A0082AB18 /* ListActionSheetItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListActionSheetItem.swift; sourceTree = ""; }; + 128EDB91280980DB00747B98 /* SequenceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SequenceExtension.swift; sourceTree = ""; }; + 128EDB932809897C00747B98 /* HomeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewModel.swift; sourceTree = ""; }; 128F97962799983800E63DA5 /* CircularActivityIndicatory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularActivityIndicatory.swift; sourceTree = ""; }; 128FD0B327F774FB00B24915 /* RecentFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentFile.swift; sourceTree = ""; }; 1290743A274CEB9B00F38A81 /* FileGridItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileGridItem.swift; sourceTree = ""; }; 1291F4F127B52BF9006A34D3 /* QueuePlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueuePlayer.swift; sourceTree = ""; }; 1291F4F527B54300006A34D3 /* AudioPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioPlayer.swift; sourceTree = ""; }; 129533C127399A1B0053FA4B /* AddPhotoVideoBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddPhotoVideoBottomSheet.swift; sourceTree = ""; }; - 129533C32739D5BC0053FA4B /* TextFieldBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldBottomSheet.swift; sourceTree = ""; }; + 129533C32739D5BC0053FA4B /* TextFieldBottomSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldBottomSheetView.swift; sourceTree = ""; }; 12A1488E27209F2800A1ADDC /* ViewExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewExtension.swift; sourceTree = ""; }; 12A148912720A32000A1ADDC /* LockPinData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockPinData.swift; sourceTree = ""; }; 12A148932720A89E00A1ADDC /* BottomLockView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomLockView.swift; sourceTree = ""; }; @@ -713,6 +717,7 @@ 127369E227B3C4DA00CF7BE5 /* UIDeviceExtension.swift */, 1289B98627C5397200315FCE /* ScreenExtension.swift */, 1289B98C27C53C8400315FCE /* ImageExtension.swift */, + 128EDB91280980DB00747B98 /* SequenceExtension.swift */, ); path = Extensions; sourceTree = ""; @@ -874,6 +879,7 @@ 128D6E172804531B0082AB18 /* AddPhotoVideoItems.swift */, 128D6E1928045C090082AB18 /* manageFilesItems.swift */, 128D6E1B280480500082AB18 /* FileActionItems.swift */, + 128EDB932809897C00747B98 /* HomeViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -1085,7 +1091,7 @@ 1283C254272A7484009180CA /* CustomNavigationContainerView.swift */, 0E64C6A5265E7625005A7934 /* ActionListBottomSheet.swift */, 12732F86273C219700BCE0FB /* LeadingTitleToolbar.swift */, - 129533C32739D5BC0053FA4B /* TextFieldBottomSheet.swift */, + 129533C32739D5BC0053FA4B /* TextFieldBottomSheetView.swift */, 1EAE6BF424146C2100114244 /* QuickLook.swift */, 1244141827E35D120037D469 /* VaultFileImages.swift */, ); @@ -1662,7 +1668,7 @@ 125D2321271F823100250FBB /* UIApplicationExtension.swift in Sources */, 125D2324271F891500250FBB /* PinView.swift in Sources */, 125FA6D8278E2828004B9D06 /* DoubleExtension.swift in Sources */, - 129533C42739D5BC0053FA4B /* TextFieldBottomSheet.swift in Sources */, + 129533C42739D5BC0053FA4B /* TextFieldBottomSheetView.swift in Sources */, 1224DAF02719C71B001C0ED0 /* LockPasswordData.swift in Sources */, D572EACB263A43C100CE191A /* FileDetailView.swift in Sources */, 12A1488F27209F2800A1ADDC /* ViewExtension.swift in Sources */, @@ -1687,6 +1693,7 @@ 128D6E1A28045C090082AB18 /* manageFilesItems.swift in Sources */, 126ECFEA27C57FA600ED5161 /* CameraState.swift in Sources */, 12AB30D3272C36500020FFBF /* HomeData.swift in Sources */, + 128EDB92280980DB00747B98 /* SequenceExtension.swift in Sources */, 1289B98727C5397200315FCE /* ScreenExtension.swift in Sources */, 0D4D7512266316DC00D7A635 /* SettingsSecurity.swift in Sources */, 0D4D7514266316E500D7A635 /* SettingsAboutHelp.swift in Sources */, @@ -1758,6 +1765,7 @@ 1272F25D27C91ACD0054F2E2 /* ImportFileProgress.swift in Sources */, 125EDDB1271E40CA00E2789A /* LockViewModel.swift in Sources */, D5B823F0262775D80008E04B /* CryptoManager.swift in Sources */, + 128EDB942809897C00747B98 /* HomeViewModel.swift in Sources */, 0E170253267910B90069072A /* BlankFormsView.swift in Sources */, 0DC267A8267AEDAD00E55AFA /* DefaultFileManager.swift in Sources */, 0D4D7518266470A700D7A635 /* SettingsViews.swift in Sources */, @@ -2031,7 +2039,7 @@ CODE_SIGN_ENTITLEMENTS = "Tella/Supporting Files/Tella.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = 6ZG9T42688; ENABLE_PREVIEWS = YES; @@ -2041,7 +2049,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.6.3; + MARKETING_VERSION = 0.7.0; PRODUCT_BUNDLE_IDENTIFIER = org.wearehorizontal.tella; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2058,7 +2066,7 @@ CODE_SIGN_ENTITLEMENTS = "Tella/Supporting Files/Tella.entitlements"; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 11; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = 6ZG9T42688; ENABLE_PREVIEWS = YES; @@ -2068,7 +2076,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.6.3; + MARKETING_VERSION = 0.7.0; PRODUCT_BUNDLE_IDENTIFIER = org.wearehorizontal.tella; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "Tella (AppStore)"; diff --git a/Tella/Application/AppViewState.swift b/Tella/Application/AppViewState.swift index 85fa173c6..dc6d8a685 100644 --- a/Tella/Application/AppViewState.swift +++ b/Tella/Application/AppViewState.swift @@ -43,26 +43,11 @@ final class AppViewState: ObservableObject { viewStack = [.UNLOCK] } - func resetToMain() { homeViewModel = MainAppModel() viewStack = [.MAIN] } - - func resetToAudio() { - viewStack = [.MAIN] - - homeViewModel?.selectedType = [.audio] - homeViewModel?.showFilesList = true - } - - func resetToImageAndVideo() { - viewStack = [.MAIN] - - homeViewModel?.selectedType = [.image,.video] - homeViewModel?.showFilesList = true - } - + func resetApp() { AuthenticationManager().keysInitialized() ? self.resetToUnlock() : self.resetToLock() } diff --git a/Tella/Components/TextFieldBottomSheet.swift b/Tella/Components/TextFieldBottomSheetView.swift similarity index 70% rename from Tella/Components/TextFieldBottomSheet.swift rename to Tella/Components/TextFieldBottomSheetView.swift index a923c859d..4535ed567 100644 --- a/Tella/Components/TextFieldBottomSheet.swift +++ b/Tella/Components/TextFieldBottomSheetView.swift @@ -7,13 +7,14 @@ // import SwiftUI +import Combine enum FieldType { case text case fileName } -struct TextFieldBottomSheet: View { +struct TextFieldBottomSheetView: View { var titleText = "" var validateButtonText = "" @@ -23,7 +24,7 @@ struct TextFieldBottomSheet: View { var fieldType : FieldType var backgroundColor: Color = Styles.Colors.backgroundTab var didConfirmAction : (() -> ()) - + @State private var isValid : Bool = false @State private var errorMessage : String = "" @@ -46,11 +47,16 @@ struct TextFieldBottomSheet: View { Spacer() .frame(height:12) - TextField("", text: $fieldContent) - .textFieldStyle(FileNameStyle()) - .onChange(of: fieldContent, perform: { value in - self.isValid = fieldContent.textValidator() - }) + if #available(iOS 15.0, *) { + + FocusedTextFieldBottomSheet(fieldContent: $fieldContent, + isValid: $isValid, shouldFocus: $isPresented) + + } else { + TextFieldBottomSheet(fieldContent: $fieldContent, + isValid: $isValid) + + } Spacer() .frame(height:8) @@ -96,6 +102,45 @@ struct TextFieldBottomSheet: View { } } +@available(iOS 15.0, *) +struct FocusedTextFieldBottomSheet : View { + + @Binding var fieldContent : String + @Binding var isValid : Bool + @Binding var shouldFocus : Bool + + @FocusState private var isFocused : Bool + + var body: some View { + ZStack{ + TextField("", text: $fieldContent) + .textFieldStyle(FileNameStyle()) + .onChange(of: fieldContent, perform: { value in + self.isValid = fieldContent.textValidator() + }) + .focused($isFocused) + } + .onReceive(Just(shouldFocus)) { value in + isFocused = value + } + } +} + +struct TextFieldBottomSheet : View { + + @Binding var fieldContent : String + @Binding var isValid : Bool + + var body: some View { + + TextField("", text: $fieldContent) + .textFieldStyle(FileNameStyle()) + .onChange(of: fieldContent, perform: { value in + self.isValid = fieldContent.textValidator() + }) + } +} + struct FileNameStyle: TextFieldStyle { func _body(configuration: TextField) -> some View { @@ -131,12 +176,12 @@ struct BottomButtonActionSheetView : View { struct CreateNewFolderBottomSheet_Previews: PreviewProvider { static var previews: some View { - TextFieldBottomSheet(titleText: "Test", - validateButtonText: "OK", - isPresented: .constant(true), - fieldContent: .constant("Test"), - fileName: "name", - fieldType: FieldType.fileName, - didConfirmAction: {}) + TextFieldBottomSheetView(titleText: "Test", + validateButtonText: "OK", + isPresented: .constant(true), + fieldContent: .constant("Test"), + fileName: "name", + fieldType: FieldType.fileName, + didConfirmAction: {}) } } diff --git a/Tella/Components/VaultFileImages.swift b/Tella/Components/VaultFileImages.swift index d26777313..15a19fa88 100644 --- a/Tella/Components/VaultFileImages.swift +++ b/Tella/Components/VaultFileImages.swift @@ -17,8 +17,6 @@ extension VaultFile { Image(uiImage: self.bigIconImage) .frame(width: 33, height: 33) .aspectRatio(contentMode: .fit) - - self.fileNameText }.background(Color.white.opacity(0.2)) .frame(width: geometryReader.size.width, height: geometryReader.size.height) @@ -26,21 +24,6 @@ extension VaultFile { } ) } - - @ViewBuilder - var fileNameText: some View { - if self.type != .image || self.type != .video { - VStack { - Spacer() - Text(self.fileName) - .font(.custom(Styles.Fonts.regularFontName, size: 11)) - .foregroundColor(.white) - .lineLimit(1) - Spacer() - .frame(height: 6) - }.padding(EdgeInsets(top: 0, leading: 5, bottom: 0, trailing: 18)) - } - } } extension VaultFile { diff --git a/Tella/Scenes/Audio/AudioPlayer/Views/AudioPlayerView.swift b/Tella/Scenes/Audio/AudioPlayer/Views/AudioPlayerView.swift index 26c5240e4..782e51095 100644 --- a/Tella/Scenes/Audio/AudioPlayer/Views/AudioPlayerView.swift +++ b/Tella/Scenes/Audio/AudioPlayer/Views/AudioPlayerView.swift @@ -146,7 +146,7 @@ struct AudioPlayerView: View { struct AudioPlayerView_Previews: PreviewProvider { static var previews: some View { - AudioPlayerView(vaultFile: VaultFile(type: .folder, fileName: "folder")) + AudioPlayerView(vaultFile: VaultFile(type: .folder, fileName: "folder", pathArray: [])) } } diff --git a/Tella/Scenes/Audio/Recorder/Views/RecordView.swift b/Tella/Scenes/Audio/Recorder/Views/RecordView.swift index 266c8dc40..4f697a71f 100644 --- a/Tella/Scenes/Audio/Recorder/Views/RecordView.swift +++ b/Tella/Scenes/Audio/Recorder/Views/RecordView.swift @@ -12,7 +12,7 @@ import Foundation struct RecordView: View { @StateObject var viewModel : RecordViewModel - + var sourceView : SourceView var showingRecoredrView : Binding @@ -34,7 +34,7 @@ struct RecordView: View { self.showingRecoredrView = showingRecoredrView } - + func goBack() { self.appViewState.navigateBack() } @@ -71,9 +71,8 @@ struct RecordView: View { saveSuccessView - }.onAppear { -// self.viewModel.mainAppModel = mainAppModel } + .alert(isPresented: self.$viewModel.shouldShowSettingsAlert) { getSettingsAlertView() } @@ -111,34 +110,21 @@ struct RecordView: View { .hidden() Button(action: { -// self.viewModel.mainAppModel = mainAppModel self.viewModel.checkCameraAccess() }) { Image("mic.record") .frame(width: 83, height: 83) } - Button(action: { -// self.listenAudiFiles() + }) { Image("mic.listen") .resizable() .frame(width: 52, height: 52) - .navigateTo(destination:FileListView(appModel: mainAppModel, - rootFile: mainAppModel.vaultManager.root, - fileType: [.audio], - title: "Audio")) - + .navigateTo(destination:getFileListView()) } - - .navigateTo(destination:FileListView(appModel: mainAppModel, - rootFile: mainAppModel.vaultManager.root, - fileType: [.audio], - title: "Audio") - ) - -// } + .navigateTo(destination:getFileListView()) } } @@ -187,17 +173,17 @@ struct RecordView: View { .frame(width: 83, height: 83) } -// Button(action: { -// self.listenAudiFiles() -// }) { -// Image("mic.listen") -// .resizable() -// .frame(width: 52, height: 52) -// } + // Button(action: { + // self.listenAudiFiles() + // }) { + // Image("mic.listen") + // .resizable() + // .frame(width: 52, height: 52) + // } Button(action: { -// self.listenAudiFiles() + // self.listenAudiFiles() }) { Image("mic.listen") .resizable() @@ -260,15 +246,12 @@ struct RecordView: View { }.frame(height: 56) } - private func listenAudiFiles() { - appViewState.resetToAudio() - } - private func getFileListView() -> some View { FileListView(appModel: mainAppModel, rootFile: mainAppModel.vaultManager.root, fileType: [.audio], - title: "Audio") + title: "Audio", + fileListType: .recordList) } private var saveAudioConfirmationView : some View { @@ -295,7 +278,7 @@ struct RecordView: View { @ViewBuilder private var renameFileView : some View { if showingRenameFileConfirmationSheet { - TextFieldBottomSheet(titleText: LocalizableAudio.renameFileTitle.localized, + TextFieldBottomSheetView(titleText: LocalizableAudio.renameFileTitle.localized, validateButtonText: "SAVE", isPresented: $showingRenameFileConfirmationSheet, fieldContent: $fileName, @@ -304,7 +287,7 @@ struct RecordView: View { didConfirmAction: { viewModel.fileName = fileName }) - + } } diff --git a/Tella/Scenes/Authentication/Views/Lock/CommonView/PasswordTextFieldView.swift b/Tella/Scenes/Authentication/Views/Lock/CommonView/PasswordTextFieldView.swift index 80bfd859b..ed918a4da 100644 --- a/Tella/Scenes/Authentication/Views/Lock/CommonView/PasswordTextFieldView.swift +++ b/Tella/Scenes/Authentication/Views/Lock/CommonView/PasswordTextFieldView.swift @@ -19,6 +19,117 @@ struct PasswordTextFieldView : View { var disabled : Bool = false var onCommit : (() -> Void)? = ({}) + var body: some View { + + if #available(iOS 15.0, *) { + PasswordTextFieldViewWithFocus( fieldContent: $fieldContent, + isValid: $isValid, + shouldShowErrorMessage: $shouldShowErrorMessage, + shouldShowError: $shouldShowError, + disabled: disabled, + onCommit: onCommit) + } else { + PasswordTextFieldViewWithoutFocus( fieldContent: $fieldContent, + isValid: $isValid, + shouldShowErrorMessage: $shouldShowErrorMessage, + shouldShowError: $shouldShowError, + disabled: disabled, + onCommit: onCommit) + } + + } + private func validateField(value:String) { + self.isValid = value.passwordValidator() + shouldShowErrorMessage = false + self.shouldShowError = false + + } +} + + + +@available(iOS 15.0, *) +struct PasswordTextFieldViewWithFocus : View { + + @State var shouldShowPassword : Bool = false + @Binding var fieldContent : String + @Binding var isValid : Bool + @Binding var shouldShowErrorMessage : Bool + @Binding var shouldShowError : Bool + + var disabled : Bool = false + var onCommit : (() -> Void)? = ({}) + @FocusState var isFocused : Bool + var body: some View { + + VStack(spacing: 13) { + HStack { + Spacer() + .frame(width: 32) + + if shouldShowPassword { + TextField("", text: $fieldContent,onCommit: { + self.onCommit?() + }).focused($isFocused) + .textFieldStyle(PasswordStyle(shouldShowError: shouldShowError)) + .onChange(of: fieldContent, perform: { value in + validateField(value: value) + }) + .disabled(disabled) + .frame( height: 22) + + } else { + SecureField("", text: $fieldContent,onCommit: { + self.onCommit?() + }).focused($isFocused) + .textFieldStyle(SecurePasswordStyle(shouldShowError: shouldShowError)) + .onChange(of: fieldContent, perform: { value in + validateField(value: value) + }) + .disabled(disabled) + .frame( height: 22) + } + + Spacer() + .frame(width: 10) + + Button { + shouldShowPassword.toggle() + } label: { + Image(shouldShowPassword ? "lock.hide" : "lock.show") + .frame(width: 22, height: 20) + .aspectRatio(contentMode: .fit) + } + } + Divider() + .frame(height: 2) + .background(Styles.Colors.yellow) + }.padding(EdgeInsets(top: 0, leading: 24, bottom: 0, trailing: 24)) + .onAppear { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: { + isFocused = true + }) + } + } + private func validateField(value:String) { + self.isValid = value.passwordValidator() + shouldShowErrorMessage = false + self.shouldShowError = false + + } +} + +struct PasswordTextFieldViewWithoutFocus : View { + + @State var shouldShowPassword : Bool = false + @Binding var fieldContent : String + @Binding var isValid : Bool + @Binding var shouldShowErrorMessage : Bool + @Binding var shouldShowError : Bool + + var disabled : Bool = false + var onCommit : (() -> Void)? = ({}) + var body: some View { VStack(spacing: 13) { @@ -72,7 +183,6 @@ struct PasswordTextFieldView : View { } } - struct PasswordStyle: TextFieldStyle { var shouldShowError : Bool = false @@ -106,7 +216,6 @@ struct SecurePasswordStyle: TextFieldStyle { } } - struct PasswordTextFieldView_Previews: PreviewProvider { static var previews: some View { PasswordTextFieldView(fieldContent: .constant(""), diff --git a/Tella/Scenes/Authentication/Views/Lock/Pin/PinView.swift b/Tella/Scenes/Authentication/Views/Lock/Pin/PinView.swift index 61bd32f27..68722c661 100644 --- a/Tella/Scenes/Authentication/Views/Lock/Pin/PinView.swift +++ b/Tella/Scenes/Authentication/Views/Lock/Pin/PinView.swift @@ -30,26 +30,27 @@ struct PinView: View { self.delete(pin: item.text) } label: { Image(item.imageName) + .frame(width: 70, height: 70) } .disabled(!(self.fieldContent.count>0)) - .frame(width: 70, height: 70) + .buttonStyle(PinButtonStyle(enabled: self.fieldContent.count>0)) case .number: Button { self.appendPin(pin: item.text) } label: { Text(item.text) - }.frame(width: 70, height: 70) - .buttonStyle(PinButtonStyle()) + .frame(width: 70, height: 70) + } + .buttonStyle(PinButtonStyle(enabled: true)) case .done: Button { action?() } label: { Text(item.text) - .foregroundColor(self.fieldContent.passwordValidator() ? .white : .white.opacity(0.24) ) - }.buttonStyle(PinButtonStyle()) - .frame(width: 70, height: 70) + .frame(width: 70, height: 70) + }.buttonStyle(PinButtonStyle(enabled: self.fieldContent.passwordValidator())) .disabled(!self.fieldContent.passwordValidator()) default: @@ -70,10 +71,14 @@ struct PinView: View { struct PinButtonStyle : ButtonStyle { + var enabled : Bool + func makeBody(configuration: Configuration) -> some View { configuration.label .font(.custom(Styles.Fonts.lightRobotoFontName, size: 32)) - .foregroundColor(configuration.isPressed ? .gray : .white) + .foregroundColor(configuration.isPressed || !enabled ? .white.opacity(0.24) : .white) + .background(configuration.isPressed ? Color.white.opacity(0.24) : Color.clear) + .clipShape(Circle()) } } diff --git a/Tella/Scenes/Camera/Views/CameraControlsView.swift b/Tella/Scenes/Camera/Views/CameraControlsView.swift index 546f89f89..9d0fefac1 100644 --- a/Tella/Scenes/Camera/Views/CameraControlsView.swift +++ b/Tella/Scenes/Camera/Views/CameraControlsView.swift @@ -17,14 +17,14 @@ struct CameraControlsView: View { var updateCameraTypeAction: ((CameraType) -> Void) var toggleFlash: (() -> Void) var close: (() -> Void) - + // MARK: - Private properties - + @State private var selectedOption: CameraType = .image @State private var state : CameraState = .readyTakingImage @State private var flashIsOn: Bool = false @State private var shouldHideCloseButton: Bool = false - + @EnvironmentObject var cameraViewModel: CameraViewModel @EnvironmentObject var mainAppModel: MainAppModel @EnvironmentObject var appViewState: AppViewState @@ -32,7 +32,7 @@ struct CameraControlsView: View { var body: some View { VStack { - + cameraHeaderView() Spacer() @@ -71,7 +71,7 @@ struct CameraControlsView: View { } close() - + } label: { Image("close") } @@ -219,7 +219,7 @@ struct CameraControlsView: View { let data = file.thumbnail { Button { - + } label: { UIImage.image(fromData:data).rounded() .navigateTo(destination:getFileListView()) @@ -235,9 +235,10 @@ struct CameraControlsView: View { FileListView(appModel: mainAppModel, rootFile: mainAppModel.vaultManager.root, fileType: [.image, .video], - title: "Images and Videos") + title: "Images and Videos", + fileListType: .cameraGallery) } - + var bottomMenu : some View { HStack(spacing: 15) { @@ -279,13 +280,13 @@ struct CameraControlsView_Previews: PreviewProvider { static var previews: some View { CameraControlsView (showingCameraView:.constant(false), sourceView: .tab) { - + } recordVideoAction: { - + } toggleCamera: { - + } updateCameraTypeAction: { value in - + } toggleFlash: { } close: {} } diff --git a/Tella/Scenes/HomeView/ViewModel/FileListViewModel.swift b/Tella/Scenes/HomeView/ViewModel/FileListViewModel.swift index d70058e6e..2c57a536e 100644 --- a/Tella/Scenes/HomeView/ViewModel/FileListViewModel.swift +++ b/Tella/Scenes/HomeView/ViewModel/FileListViewModel.swift @@ -14,6 +14,12 @@ enum FileActionSource { case listView } +enum FileListType { + case cameraGallery + case recordList + case fileList +} + class FileListViewModel: ObservableObject { var appModel: MainAppModel @@ -21,7 +27,8 @@ class FileListViewModel: ObservableObject { var rootFile : VaultFile var oldRootFile : VaultFile var fileActionSource : FileActionSource = .listView - + var fileListType : FileListType = .fileList + @Published var sortBy: FileSortOptions = FileSortOptions.nameAZ @Published var viewType: FileViewType = FileViewType.list @@ -38,7 +45,7 @@ class FileListViewModel: ObservableObject { @Published var showingShareFileView = false @Published var showingCamera = false @Published var showingMicrophone = false - + var selectedFiles : [VaultFile] { return vaultFileStatusArray.filter{$0.isSelected}.compactMap{$0.file} } @@ -91,6 +98,9 @@ class FileListViewModel: ObservableObject { var filesAreAllSelected : Bool { return vaultFileStatusArray.filter{$0.isSelected == true}.count == vaultFileStatusArray.count } + var shouldHideViewsForGallery: Bool { + return (fileListType == .cameraGallery || fileListType == .recordList) + } var fileActionItems: [ListActionSheetItem] { @@ -110,7 +120,7 @@ class FileListViewModel: ObservableObject { return items } - init(appModel:MainAppModel, fileType:[FileType]?, rootFile:VaultFile, folderPathArray:[VaultFile]?,fileActionSource : FileActionSource = .listView) { + init(appModel:MainAppModel, fileType:[FileType]?, rootFile:VaultFile, folderPathArray:[VaultFile]?,fileActionSource : FileActionSource = .listView,fileListType : FileListType = .fileList) { self.appModel = appModel self.fileType = fileType @@ -118,7 +128,9 @@ class FileListViewModel: ObservableObject { self.oldRootFile = rootFile self.folderPathArray = folderPathArray ?? [] self.fileActionSource = fileActionSource + self.fileListType = fileListType initVaultFileStatusArray() + updateViewType() } func resetSelectedItems() { @@ -169,7 +181,7 @@ class FileListViewModel: ObservableObject { self.folderPathArray.removeSubrange(index + 1.. [Any] { appModel.getFilesForShare(files: selectedFiles) } - - var firstFileActionItems : [ListActionSheetItem] = [ - - ListActionSheetItem(imageName: "share-icon", - content: "Share", - // action: { - // fileListViewModel.showingFileActionMenu = false - // fileListViewModel.showingShareFileView = true - // }, - type: FileActionType.share) - ] - - } extension FileListViewModel { diff --git a/Tella/Scenes/HomeView/ViewModel/HomeViewModel.swift b/Tella/Scenes/HomeView/ViewModel/HomeViewModel.swift new file mode 100644 index 000000000..409a99d86 --- /dev/null +++ b/Tella/Scenes/HomeView/ViewModel/HomeViewModel.swift @@ -0,0 +1,25 @@ +// Tella +// +// Copyright © 2022 INTERNEWS. All rights reserved. +// + +import Foundation + +class HomeViewModel: ObservableObject { + + var appModel: MainAppModel + + @Published var showingDocumentPicker = false + @Published var showingAddFileSheet = false + var showingFilesTitle = false + + init(appModel:MainAppModel) { + self.appModel = appModel + } + + func getFiles() -> [RecentFile] { + let recentFile = appModel.vaultManager.root.getRecentFile() + showingFilesTitle = recentFile.count > 0 + return recentFile + } +} diff --git a/Tella/Scenes/HomeView/Views/FileListView/Add files/AddFileView.swift b/Tella/Scenes/HomeView/Views/FileListView/Add files/AddFileView.swift index ad3db45ba..d2007e703 100644 --- a/Tella/Scenes/HomeView/Views/FileListView/Add files/AddFileView.swift +++ b/Tella/Scenes/HomeView/Views/FileListView/Add files/AddFileView.swift @@ -28,7 +28,7 @@ struct AddFileView: View { AddPhotoVideoBottomSheet(isPresented: $showingAddPhotoVideoSheet) - TextFieldBottomSheet(titleText: "Create new folder", + TextFieldBottomSheetView(titleText: "Create new folder", validateButtonText: "CREATE", isPresented: $showingCreateNewFolderSheet, fieldContent: $fieldContent, diff --git a/Tella/Scenes/HomeView/Views/FileListView/File list/CreateNewFolderView.swift b/Tella/Scenes/HomeView/Views/FileListView/File list/CreateNewFolderView.swift index bb2a849d5..aa1722445 100644 --- a/Tella/Scenes/HomeView/Views/FileListView/File list/CreateNewFolderView.swift +++ b/Tella/Scenes/HomeView/Views/FileListView/File list/CreateNewFolderView.swift @@ -24,7 +24,7 @@ struct AddNewFolderView: View { .frame(height: 50) } - TextFieldBottomSheet(titleText: "Create new folder", + TextFieldBottomSheetView(titleText: "Create new folder", validateButtonText: "CREATE", isPresented: $showingCreateNewFolderSheet, fieldContent: $fieldContent, diff --git a/Tella/Scenes/HomeView/Views/FileListView/File list/FileActionMenu.swift b/Tella/Scenes/HomeView/Views/FileListView/File list/FileActionMenu.swift index e5efca73b..b92843e02 100644 --- a/Tella/Scenes/HomeView/Views/FileListView/File list/FileActionMenu.swift +++ b/Tella/Scenes/HomeView/Views/FileListView/File list/FileActionMenu.swift @@ -91,7 +91,7 @@ struct FileActionMenu: View { } var renameFileView : some View { - TextFieldBottomSheet(titleText: "Rename file", + TextFieldBottomSheetView(titleText: "Rename file", validateButtonText: "SAVE", isPresented: $showingRenameFileConfirmationSheet, fieldContent: $fileName, diff --git a/Tella/Scenes/HomeView/Views/FileListView/File list/FileGridItem.swift b/Tella/Scenes/HomeView/Views/FileListView/File list/FileGridItem.swift index bc38fd0b4..a51c5ed86 100644 --- a/Tella/Scenes/HomeView/Views/FileListView/File list/FileGridItem.swift +++ b/Tella/Scenes/HomeView/Views/FileListView/File list/FileGridItem.swift @@ -16,64 +16,101 @@ struct FileGridItem: View { @EnvironmentObject var fileListViewModel : FileListViewModel var body: some View { - GeometryReader { geometryReader in + + Button { + fileListViewModel.showFileDetails(file: file) + } label: { + fileGridView + } + } + + var fileGridView : some View { + + ZStack { + + file.gridImage - ZStack { + VStack(alignment: .trailing) { - file.gridImage + Spacer() - VStack(alignment: .trailing) { + HStack { Spacer() - HStack { - - Spacer() - - if !fileListViewModel.showingMoveFileView { - selectionButton - } + if !fileListViewModel.showingMoveFileView { + selectionButton } } + } + self.fileNameText + + selectingFilesView + } + } + + @ViewBuilder + var fileNameText: some View { + + if !fileListViewModel.shouldHideViewsForGallery { + + if self.file.type != .image || self.file.type != .video { + VStack { + Spacer() + Text(self.file.fileName) + .font(.custom(Styles.Fonts.regularFontName, size: 11)) + .foregroundColor(.white) + .lineLimit(1) + Spacer() + .frame(height: 6) + }.padding(EdgeInsets(top: 0, leading: 5, bottom: 0, trailing: 18)) + } + } + } + + @ViewBuilder + var selectionButton: some View { + if fileListViewModel.shouldHideNavigationBar { + Button { + fileListViewModel.showingFileActionMenu = true + fileListViewModel.updateSingleSelection(for: file) + + } label: { + Image("files.more") + .frame(width: 35, height: 35) + .padding(EdgeInsets(top: 0, leading: 0, bottom: -6, trailing: -12)) + }.frame(width: 35, height: 35) + } + } + + @ViewBuilder + var selectingFilesView: some View { + if fileListViewModel.selectingFiles { + GeometryReader { geometryReader in + + Color.black.opacity(0.32) + .onTapGesture { + fileListViewModel.updateSelection(for: file) + } + .frame(width: geometryReader.size.width, height: geometryReader.size.height) - if fileListViewModel.selectingFiles { - Color.black.opacity(0.32) - .onTapGesture { - fileListViewModel.updateSelection(for: file) - } - .frame(width: geometryReader.size.width, height: geometryReader.size.height) + HStack() { - HStack() { - - VStack(alignment: .leading) { - Image(fileListViewModel.getStatus(for: file) ? "files.selected" : "files.unselected") - .resizable() - .frame(width: 15, height: 15) - .padding(EdgeInsets(top: 6, leading: 6, bottom: 0, trailing: 0)) - Spacer() - - }.onTapGesture { - fileListViewModel.updateSelection(for: file) - } + VStack(alignment: .leading) { + Image(fileListViewModel.getStatus(for: file) ? "files.selected" : "files.unselected") + .resizable() + .frame(width: 15, height: 15) + .padding(EdgeInsets(top: 6, leading: 6, bottom: 0, trailing: 0)) Spacer() + + }.onTapGesture { + fileListViewModel.updateSelection(for: file) } + Spacer() } } } } - - var selectionButton: some View { - Button { - fileListViewModel.showingFileActionMenu = true - fileListViewModel.updateSingleSelection(for: file) - - } label: { - Image("files.more") - .frame(width: 35, height: 35) - .padding(EdgeInsets(top: 0, leading: 0, bottom: -6, trailing: -12)) - }.frame(width: 35, height: 35) - - } } struct FileGridItem_Previews: PreviewProvider { diff --git a/Tella/Scenes/HomeView/Views/FileListView/File list/FileItemsView.swift b/Tella/Scenes/HomeView/Views/FileListView/File list/FileItemsView.swift index f3724f149..4435ea9f3 100644 --- a/Tella/Scenes/HomeView/Views/FileListView/File list/FileItemsView.swift +++ b/Tella/Scenes/HomeView/Views/FileListView/File list/FileItemsView.swift @@ -30,31 +30,8 @@ struct FileItemsView: View { ScrollView { LazyVGrid(columns: gridLayout, alignment: .center, spacing: 6) { ForEach(files, id: \.self) { file in - - switch file.type { - case .folder: - - FileGridItem(file: file) - .frame(minHeight: minHeight) - .onTapGesture { - - if (fileListViewModel.showingMoveFileView && !fileListViewModel.selectedFiles.contains(file)) || !(fileListViewModel.showingMoveFileView) { - fileListViewModel.rootFile = file - fileListViewModel.folderPathArray.append(file) - } - } - default: - ZStack { - FileGridItem(file: file) - .frame( minHeight: minHeight) - .onTapGesture { - if !fileListViewModel.showingMoveFileView { - fileListViewModel.updateSingleSelection(for: file) - fileListViewModel.showFileDetails = true - } - } - } - } + FileGridItem(file: file) + .frame(minHeight: minHeight) } }.padding(EdgeInsets(top: 0, leading: 6, bottom: 0, trailing: 6)) } @@ -64,27 +41,8 @@ struct FileItemsView: View { ScrollView { LazyVStack(spacing: 1) { ForEach(files, id: \.self) { file in - switch file.type { - case .folder: - FileListItem(file: file) - .frame(height: 60) - .onTapGesture { - if (fileListViewModel.showingMoveFileView && !fileListViewModel.selectedFiles.contains(file)) || !(fileListViewModel.showingMoveFileView) { - fileListViewModel.rootFile = file - fileListViewModel.folderPathArray.append(file) - } - } - - default: - FileListItem(file: file) - .frame(height: 60) - .onTapGesture { - if !fileListViewModel.showingMoveFileView { - fileListViewModel.updateSingleSelection(for: file) - fileListViewModel.showFileDetails = true - } - } - } + FileListItem(file: file) + .frame(height: 60) } } } diff --git a/Tella/Scenes/HomeView/Views/FileListView/File list/FileListItem.swift b/Tella/Scenes/HomeView/Views/FileListView/File list/FileListItem.swift index 54c92cafc..5e3b53d1f 100644 --- a/Tella/Scenes/HomeView/Views/FileListView/File list/FileListItem.swift +++ b/Tella/Scenes/HomeView/Views/FileListView/File list/FileListItem.swift @@ -7,61 +7,75 @@ import SwiftUI struct FileListItem: View { var file: VaultFile - + @EnvironmentObject var appModel: MainAppModel @EnvironmentObject var fileListViewModel : FileListViewModel - + var body: some View { - GeometryReader { geometry in - ZStack { - HStack(alignment: .center, spacing: 0){ - RoundedRectangle(cornerRadius: 5) - .fill(Color.white.opacity(0.2)) - .frame(width: 35, height: 35, alignment: .center) - .overlay( - file.listImage - .frame(width: 35, height: 35) - .cornerRadius(5) - ) - VStack(alignment: .leading, spacing: 0){ - Spacer() - Text(file.fileName) - .font(.custom(Styles.Fonts.semiBoldFontName, size: 14)) - .foregroundColor(Color.white) - .lineLimit(1) - - Spacer() - .frame(height: 2) - - Text(file.formattedCreationDate) - .font(.custom(Styles.Fonts.regularFontName, size: 10)) - .foregroundColor(Color.white) + Button { + fileListViewModel.showFileDetails(file: file) + } label: { + fileListView + } + } + + var fileListView : some View { + + ZStack { + + GeometryReader { geometry in + + ZStack { + + HStack(alignment: .center, spacing: 0) { + RoundedRectangle(cornerRadius: 5) + .fill(Color.white.opacity(0.2)) + .frame(width: 35, height: 35, alignment: .center) + .overlay( + file.listImage + .frame(width: 35, height: 35) + .cornerRadius(5) + ) + VStack(alignment: .leading, spacing: 0){ + Spacer() + Text(file.fileName) + .font(.custom(Styles.Fonts.semiBoldFontName, size: 14)) + .foregroundColor(Color.white) + .lineLimit(1) + + Spacer() + .frame(height: 2) + + Text(file.formattedCreationDate) + .font(.custom(Styles.Fonts.regularFontName, size: 10)) + .foregroundColor(Color.white) + + Spacer() + + } + .padding(EdgeInsets(top: 0, leading: 18, bottom: 0, trailing: 0)) Spacer() + if !fileListViewModel.showingMoveFileView { + selectionButton + } } - .padding(EdgeInsets(top: 0, leading: 18, bottom: 0, trailing: 0)) + .padding(EdgeInsets(top: 12, leading: fileListViewModel.showingMoveFileView ? 8 : 16, bottom: 12, trailing: fileListViewModel.showingMoveFileView ? 8 : 16)) + .frame(height: 60) - Spacer() - if !fileListViewModel.showingMoveFileView { - selectionButton + if fileListViewModel.selectingFiles { + Rectangle() + .fill(Color.white.opacity(0.001)) + .frame(width: geometry.size.width, height: geometry.size.height) + .onTapGesture { + fileListViewModel.updateSelection(for: file) + } } } - .padding(EdgeInsets(top: 12, leading: fileListViewModel.showingMoveFileView ? 8 : 16, bottom: 12, trailing: fileListViewModel.showingMoveFileView ? 8 : 16)) - .frame(height: 60) - - if fileListViewModel.selectingFiles { - Rectangle() - .fill(Color.white.opacity(0.001)) - .frame(width: geometry.size.width, height: geometry.size.height) - .onTapGesture { - fileListViewModel.updateSelection(for: file) - - } - } + .background((fileListViewModel.getStatus(for: file) && fileListViewModel.selectingFiles) ? Color.white.opacity(0.16) : Color.white.opacity(0.001)) } - .background((fileListViewModel.getStatus(for: file) && fileListViewModel.selectingFiles) ? Color.white.opacity(0.16) : Color.white.opacity(0.001)) } } diff --git a/Tella/Scenes/HomeView/Views/FileListView/File list/FileListView.swift b/Tella/Scenes/HomeView/Views/FileListView/File list/FileListView.swift index a94f8c298..3fa917a3c 100644 --- a/Tella/Scenes/HomeView/Views/FileListView/File list/FileListView.swift +++ b/Tella/Scenes/HomeView/Views/FileListView/File list/FileListView.swift @@ -8,11 +8,12 @@ struct FileListView: View { @EnvironmentObject var appModel: MainAppModel @StateObject var fileListViewModel : FileListViewModel + @State var showFileDetails : Bool = false var title : String = "" - init(appModel: MainAppModel, rootFile: VaultFile , fileType: [FileType]? , title : String = "") { - _fileListViewModel = StateObject(wrappedValue: FileListViewModel(appModel: appModel,fileType:fileType, rootFile: rootFile, folderPathArray: [] )) + init(appModel: MainAppModel, rootFile: VaultFile , fileType: [FileType]? , title : String = "", fileListType : FileListType = .fileList) { + _fileListViewModel = StateObject(wrappedValue: FileListViewModel(appModel: appModel,fileType:fileType, rootFile: rootFile, folderPathArray: [], fileListType : fileListType)) self.title = title } @@ -42,12 +43,14 @@ struct FileListView: View { } } - AddFileView() + if !fileListViewModel.shouldHideViewsForGallery { + AddFileView() + } FileSortMenu() FileActionMenu() - + showFileDetailsLink } .toolbar { @@ -60,12 +63,13 @@ struct FileListView: View { @ViewBuilder private var showFileDetailsLink: some View { if let currentSelectedVaultFile = self.fileListViewModel.currentSelectedVaultFile { - + FileDetailView(appModel: appModel , file: currentSelectedVaultFile, videoFilesArray: fileListViewModel.rootFile.getVideos().sorted(by: fileListViewModel.sortBy), rootFile: fileListViewModel.rootFile, - folderPathArray: fileListViewModel.folderPathArray).addNavigationLink(isActive: $fileListViewModel.showFileDetails) + folderPathArray: fileListViewModel.folderPathArray) + .addNavigationLink(isActive: $fileListViewModel.showFileDetails) } } } diff --git a/Tella/Scenes/HomeView/Views/FileListView/File list/ManageFileView.swift b/Tella/Scenes/HomeView/Views/FileListView/File list/ManageFileView.swift index a8450b2cf..dfbd90bd9 100644 --- a/Tella/Scenes/HomeView/Views/FileListView/File list/ManageFileView.swift +++ b/Tella/Scenes/HomeView/Views/FileListView/File list/ManageFileView.swift @@ -72,16 +72,19 @@ struct ManageFileView: View { } } + @ViewBuilder private var viewTypeButton: some View { - Button { - fileListViewModel.viewType = fileListViewModel.viewType == .list ? FileViewType.grid : FileViewType.list - } label: { - HStack{ - fileListViewModel.viewType.image - .frame(width: 24, height: 24) + if !fileListViewModel.shouldHideViewsForGallery { + Button { + fileListViewModel.viewType = fileListViewModel.viewType == .list ? FileViewType.grid : FileViewType.list + } label: { + HStack{ + fileListViewModel.viewType.image + .frame(width: 24, height: 24) + } } + .frame(width: 50, height: 50) } - .frame(width: 50, height: 50) } } diff --git a/Tella/Scenes/HomeView/Views/Home/File groups/FileGroupsView.swift b/Tella/Scenes/HomeView/Views/Home/File groups/FileGroupsView.swift index f6bbcad09..8a2c8e4a2 100644 --- a/Tella/Scenes/HomeView/Views/Home/File groups/FileGroupsView.swift +++ b/Tella/Scenes/HomeView/Views/Home/File groups/FileGroupsView.swift @@ -7,6 +7,8 @@ import SwiftUI struct FileGroupsView: View { @EnvironmentObject var appModel: MainAppModel + + var shouldShowFilesTitle : Bool let columns = [GridItem(.flexible(),spacing: 16), GridItem(.flexible(),spacing: 16)] @@ -14,7 +16,7 @@ struct FileGroupsView: View { var body: some View { ScrollView { VStack(alignment: .leading, spacing: 16 ) { - if appModel.vaultManager.recentFiles.count > 0 { + if shouldShowFilesTitle { Text(LocalizableHome.tellaFiles.localized) .font(.custom(Styles.Fonts.semiBoldFontName, size: 14)) @@ -40,6 +42,6 @@ struct FileGroupsView: View { struct FileGroupsView_Previews: PreviewProvider { static var previews: some View { - FileGroupsView() + FileGroupsView(shouldShowFilesTitle: true) } } diff --git a/Tella/Scenes/HomeView/Views/Home/HomeView.swift b/Tella/Scenes/HomeView/Views/Home/HomeView.swift index 9a9da3518..be7cce5ce 100644 --- a/Tella/Scenes/HomeView/Views/Home/HomeView.swift +++ b/Tella/Scenes/HomeView/Views/Home/HomeView.swift @@ -5,15 +5,14 @@ import SwiftUI import UniformTypeIdentifiers -class HomeViewModel: ObservableObject { - @Published var showingDocumentPicker = false - @Published var showingAddFileSheet = false -} - struct HomeView: View { - + @EnvironmentObject var appModel: MainAppModel - @StateObject var viewModel = HomeViewModel() + @StateObject var viewModel : HomeViewModel + + init(appModel: MainAppModel) { + _viewModel = StateObject(wrappedValue: HomeViewModel(appModel: appModel)) + } var body: some View { @@ -23,39 +22,27 @@ struct HomeView: View { VStack(spacing: 15) { if appModel.settings.showRecentFiles { Spacer() - .frame( height: appModel.vaultManager.recentFiles.count > 0 ? 15 : 0 ) - RecentFilesListView() + .frame( height: viewModel.getFiles().count > 0 ? 15 : 0 ) + RecentFilesListView(recentFiles: viewModel.getFiles()) } } - FileGroupsView() + FileGroupsView(shouldShowFilesTitle: viewModel.showingFilesTitle) if appModel.settings.quickDelete { SwipeToActionView(completion: { appModel.removeAllFiles() }) } - - fileListWithTypeView } } .navigationBarTitle("Tella", displayMode: .inline) } - - var fileListWithTypeView : some View { - NavigationLink(destination: FileListView(appModel: appModel, - rootFile: appModel.vaultManager.root, - fileType: appModel.selectedType, - title: appModel.selectedType.getTitle()) - , isActive: $appModel.showFilesList) { - EmptyView() - } - } } struct HomeView_Previews: PreviewProvider { static var previews: some View { - HomeView() + HomeView(appModel: MainAppModel()) } } diff --git a/Tella/Scenes/HomeView/Views/Home/Recent files/RecentFilesListView.swift b/Tella/Scenes/HomeView/Views/Home/Recent files/RecentFilesListView.swift index e4e2fe9e5..0ffabbc4c 100644 --- a/Tella/Scenes/HomeView/Views/Home/Recent files/RecentFilesListView.swift +++ b/Tella/Scenes/HomeView/Views/Home/Recent files/RecentFilesListView.swift @@ -7,14 +7,16 @@ import SwiftUI struct RecentFilesListView: View { @EnvironmentObject var appModel: MainAppModel - @State private var moreRecentFilesLoaded = false + + var recentFiles : [RecentFile] + private var number : Int { - return moreRecentFilesLoaded ? appModel.vaultManager.recentFiles.count : 3 + return moreRecentFilesLoaded ? recentFiles.count : 3 } var body: some View { - if appModel.vaultManager.recentFiles.count > 0 { + if recentFiles.count > 0 { VStack(alignment: .leading, spacing: 15){ Text(LocalizableHome.recentFiles.localized) .font(.custom(Styles.Fonts.semiBoldFontName, size: 14)) @@ -28,7 +30,7 @@ struct RecentFilesListView: View { var recentFilesView: some View { ScrollView(.horizontal, showsIndicators: false) { - if (appModel.vaultManager.recentFiles.count > 3) { + if (recentFiles.count > 3) { allFilesItems } else { firstFilesItems @@ -41,18 +43,18 @@ struct RecentFilesListView: View { HStack(spacing: 7) { // The 3 first or all items ForEach(0.. 3 { + if !moreRecentFilesLoaded && recentFiles.count > 3 { Button { moreRecentFilesLoaded = true } label: { - LoadMoreCell(fileNumber: appModel.vaultManager.recentFiles.count) + LoadMoreCell(fileNumber: recentFiles.count - 3) } } }.padding(.trailing, 17) @@ -61,7 +63,7 @@ struct RecentFilesListView: View { var firstFilesItems : some View { HStack(spacing: 7) { - ForEach(appModel.vaultManager.recentFiles, id: \.self) { recentFile in + ForEach(recentFiles, id: \.self) { recentFile in RecentFileCell(recentFile: recentFile.file) .navigateTo(destination: FileDetailView(appModel: appModel, @@ -69,12 +71,11 @@ struct RecentFilesListView: View { rootFile: recentFile.rootFile, folderPathArray: recentFile.folderPathArray)) } }.padding(.trailing, 17) - } } struct ReventFilesListView_Previews: PreviewProvider { static var previews: some View { - RecentFilesListView() + RecentFilesListView(recentFiles: []) } } diff --git a/Tella/Scenes/MainView.swift b/Tella/Scenes/MainView.swift index 3090857a4..a4b711950 100644 --- a/Tella/Scenes/MainView.swift +++ b/Tella/Scenes/MainView.swift @@ -39,7 +39,7 @@ struct MainView: View { NavigationView { TabView(selection: $appModel.selectedTab) { - HomeView() + HomeView(appModel: appModel) .tabItem { Image("tab.home") Text("Home") diff --git a/Tella/Services Managers/MainAppModel.swift b/Tella/Services Managers/MainAppModel.swift index ffcfba2de..c6108ab75 100644 --- a/Tella/Services Managers/MainAppModel.swift +++ b/Tella/Services Managers/MainAppModel.swift @@ -7,9 +7,9 @@ import Combine protocol AppModelFileManagerProtocol { - func add(files: [URL], to parentFolder: VaultFile?, type: FileType, folderPathArray:[VaultFile]? ) - func add(audioFilePath: URL, to parentFolder: VaultFile?, type: FileType, fileName:String, folderPathArray:[VaultFile]?) - func add(folder: String, to parentFolder: VaultFile?) + func add(files: [URL], to parentFolder: VaultFile?, type: FileType, folderPathArray:[VaultFile] ) + func add(audioFilePath: URL, to parentFolder: VaultFile?, type: FileType, fileName:String, folderPathArray:[VaultFile]) + func add(folder: String, to parentFolder: VaultFile?, folderPathArray:[VaultFile]) func move(files: [VaultFile], from originalParentFolder: VaultFile?, to newParentFolder: VaultFile?) func cancelImportAndEncryption() @@ -17,7 +17,7 @@ protocol AppModelFileManagerProtocol { func rename(file : VaultFile, parent: VaultFile?) func getFilesForShare(files: [VaultFile]) -> [Any] func clearTmpDirectory() - func saveDataToTempFile(data:Data, pathExtension:String) -> URL? + func saveDataToTempFile(data:Data, pathExtension:String) -> URL? } class MainAppModel: ObservableObject, AppModelFileManagerProtocol { @@ -36,9 +36,6 @@ class MainAppModel: ObservableObject, AppModelFileManagerProtocol { @Published var selectedTab: Tabs = .home - @Published var selectedType: [FileType] = [.other] - @Published var showFilesList: Bool = false - var shouldUpdateLanguage = CurrentValueSubject(false) var shouldCancelImportAndEncryption = CurrentValueSubject(false) @@ -73,7 +70,7 @@ class MainAppModel: ObservableObject, AppModelFileManagerProtocol { selectedTab = newTab } - func add(files: [URL], to parentFolder: VaultFile?, type: FileType, folderPathArray:[VaultFile]? = nil) { + func add(files: [URL], to parentFolder: VaultFile?, type: FileType, folderPathArray:[VaultFile] = []) { vaultManager.progress.progress.sink { [weak self] value in self?.publishUpdates() @@ -87,14 +84,14 @@ class MainAppModel: ObservableObject, AppModelFileManagerProtocol { self.publishUpdates() } - func add(audioFilePath: URL, to parentFolder: VaultFile?, type: FileType, fileName:String, folderPathArray:[VaultFile]? = nil) { + func add(audioFilePath: URL, to parentFolder: VaultFile?, type: FileType, fileName:String, folderPathArray:[VaultFile] = []) { self.vaultManager.importFile(audioFilePath: audioFilePath, to: parentFolder, type: type, fileName: fileName, folderPathArray: folderPathArray) self.publishUpdates() } - func add(folder: String, to parentFolder: VaultFile?) { + func add(folder: String, to parentFolder: VaultFile?, folderPathArray:[VaultFile] = []) { DispatchQueue.global(qos: .background).async { - self.vaultManager.createNewFolder(name: folder, parent: parentFolder) + self.vaultManager.createNewFolder(name: folder, parent: parentFolder, folderPathArray: folderPathArray) self.publishUpdates() } } diff --git a/Tella/Utils/Extensions/ImageExtension.swift b/Tella/Utils/Extensions/ImageExtension.swift index 5ad821562..675ce34cc 100644 --- a/Tella/Utils/Extensions/ImageExtension.swift +++ b/Tella/Utils/Extensions/ImageExtension.swift @@ -4,7 +4,6 @@ import SwiftUI - extension Image { func rounded() -> some View { return self.resizable() diff --git a/Tella/Utils/Extensions/SequenceExtension.swift b/Tella/Utils/Extensions/SequenceExtension.swift new file mode 100644 index 000000000..ed55e0b9c --- /dev/null +++ b/Tella/Utils/Extensions/SequenceExtension.swift @@ -0,0 +1,14 @@ +// Tella +// +// Copyright © 2022 INTERNEWS. All rights reserved. +// + +import Foundation + +extension Sequence { + func limit(_ max: Int) -> [Element] { + return self.enumerated() + .filter { $0.offset < max } + .map { $0.element } + } +} diff --git a/Tella/VaultManager/RecentFile.swift b/Tella/VaultManager/RecentFile.swift index 55ddf4a2a..007c8677a 100644 --- a/Tella/VaultManager/RecentFile.swift +++ b/Tella/VaultManager/RecentFile.swift @@ -20,7 +20,6 @@ class RecentFile : Hashable { init(file : VaultFile, rootFile : VaultFile, folderPathArray : [VaultFile]?) { self.file = file self.rootFile = rootFile - self.rootFile = rootFile self.folderPathArray = folderPathArray } } diff --git a/Tella/VaultManager/VaultFile.swift b/Tella/VaultManager/VaultFile.swift index 83eba5cc2..6bb828575 100644 --- a/Tella/VaultManager/VaultFile.swift +++ b/Tella/VaultManager/VaultFile.swift @@ -31,14 +31,14 @@ class VaultFile: Codable, Hashable { var size : Int64 var resolution : CGSize? var duration : Double? - + var pathArray : [String] var isSelected: Bool = false static func rootFile(fileName: String, containerName: String) -> VaultFile { - return VaultFile(type: .folder, fileName: fileName, containerName: containerName, files: []) + return VaultFile(type: .folder, fileName: fileName, containerName: containerName, files: [], pathArray: []) } - init(type: FileType, fileName: String, containerName: String = UUID().uuidString, files: [VaultFile]? = nil, thumbnail: Data? = nil, fileExtension : String = "", size : Int64 = 0, resolution : CGSize? = nil, duration : Double? = nil) { + init(type: FileType, fileName: String, containerName: String = UUID().uuidString, files: [VaultFile]? = nil, thumbnail: Data? = nil, fileExtension : String = "", size : Int64 = 0, resolution : CGSize? = nil, duration : Double? = nil, pathArray :[String]) { self.type = type self.fileName = fileName self.containerName = containerName @@ -50,6 +50,7 @@ class VaultFile: Codable, Hashable { self.size = size self.duration = duration self.resolution = resolution + self.pathArray = pathArray } var thumbnailImage: UIImage { @@ -131,7 +132,7 @@ extension Array where Element == VaultFile { return self.filter({ filter == ($0.type) || (includeFolders && $0.type == .folder)}) } - func sorted(by sortOrder: FileSortOptions, folderPathArray:[VaultFile], root:VaultFile, fileType:[FileType]?) -> [VaultFile] { + func sorted(by sortOrder: FileSortOptions, folderPathArray:[VaultFile] = [], root:VaultFile, fileType:[FileType]? = nil) -> [VaultFile] { var filteredFiles : [VaultFile] = [] @@ -155,9 +156,10 @@ extension Array where Element == VaultFile { return filteredFiles.sorted(by: sortOrder) } + func sorted(by sortOrder: FileSortOptions) -> [VaultFile] { return self.sorted { file1, file2 in - + switch sortOrder { case .nameAZ: return file1.fileName < file2.fileName @@ -189,11 +191,11 @@ extension VaultFile { func getVideos() -> [VaultFile] { return self.files.filter{$0.type == .video} } - + } extension VaultFile { - + var formattedCreationDate : String { get { return created.fileCreationDate() @@ -229,3 +231,30 @@ extension VaultFile { } } } + +extension VaultFile { + + func getRecentFile() -> [RecentFile] { + + var vaultFileResult : [RecentFile] = [] + var rootFile = self + var folderPathArray : [VaultFile] = [] + + getRecentFile(root: self, vaultFileResult: &vaultFileResult,rootFile: &rootFile, folderPathArray: &folderPathArray) + return vaultFileResult.limit(10) + } + + func getRecentFile(root: VaultFile, vaultFileResult: inout [RecentFile], rootFile: inout VaultFile, folderPathArray:inout [VaultFile]) { + + root.files.forEach { file in + switch file.type { + case .folder: + getRecentFile(root: file, vaultFileResult: &vaultFileResult, rootFile: &rootFile, folderPathArray:&folderPathArray) + default: + let recentFile = RecentFile(file: file, rootFile: rootFile, folderPathArray: folderPathArray) + vaultFileResult.append(recentFile) + } + } + } +} + diff --git a/Tella/VaultManager/VaultManager.swift b/Tella/VaultManager/VaultManager.swift index 9caad3266..f87e89449 100644 --- a/Tella/VaultManager/VaultManager.swift +++ b/Tella/VaultManager/VaultManager.swift @@ -15,7 +15,7 @@ protocol VaultManagerInterface { func load(files vaultFiles: [VaultFile]) -> [URL] func save(_ data: Data, vaultFile: VaultFile, parent: VaultFile?) -> Bool? func save(_ object: T, vaultFile: VaultFile, parent: VaultFile? ) -> Bool? - func createNewFolder(name: String, parent: VaultFile?) + func createNewFolder(name: String, parent: VaultFile?, folderPathArray : [VaultFile]) func rename(file : VaultFile, parent: VaultFile?) func delete(file: VaultFile, parent: VaultFile?) func removeAllFiles() @@ -38,7 +38,6 @@ class VaultManager: VaultManagerInterface, ObservableObject { private let fileManager: FileManagerInterface @Published var root: VaultFile - @Published var recentFiles: [RecentFile] = [] @Published var progress : ImportProgress var shouldCancelImportAndEncryption = CurrentValueSubject(false) @@ -65,10 +64,10 @@ class VaultManager: VaultManagerInterface, ObservableObject { } } - func importFile(files: [URL], to parentFolder: VaultFile?, type: FileType, folderPathArray : [VaultFile]?) { + func importFile(files: [URL], to parentFolder: VaultFile?, type: FileType, folderPathArray : [VaultFile]) { Task { do{ - let filesInfo = try await self.getFilesInfo(files: files) + let filesInfo = try await self.getFilesInfo(files: files, folderPathArray: folderPathArray) self.progress.start(totalFiles: files.count, totalSize: filesInfo.1) @@ -110,7 +109,7 @@ class VaultManager: VaultManagerInterface, ObservableObject { } } - func importFile(audioFilePath: URL, to parentFolder: VaultFile?, type: FileType, fileName: String, folderPathArray : [VaultFile]?) { + func importFile(audioFilePath: URL, to parentFolder: VaultFile?, type: FileType, fileName: String, folderPathArray : [VaultFile]) { debugLog("\(audioFilePath)", space: .files) @@ -127,6 +126,7 @@ class VaultManager: VaultManagerInterface, ObservableObject { let duration = audioFilePath.getDuration() let size = FileManager.default.sizeOfFile(atPath: path) ?? 0 let containerName = UUID().uuidString + let pathArray = folderPathArray.compactMap{$0.containerName} let vaultFile = VaultFile(type: audioFilePath.fileType, fileName: fileName, @@ -136,12 +136,12 @@ class VaultManager: VaultManagerInterface, ObservableObject { fileExtension: fileExtension, size:size, resolution: nil, - duration: duration) + duration: duration, + pathArray: pathArray) if let _ = save(data, vaultFile: vaultFile, parent: parentFolder) { - addRecentFile(file: vaultFile, rootFile: parentFolder, folderPathArray: folderPathArray) save(file: root) } } catch let error { @@ -153,13 +153,13 @@ class VaultManager: VaultManagerInterface, ObservableObject { private func importFileAndEncrypt(data : Data, vaultFile:VaultFile, parentFolder :VaultFile?, type: FileType, folderPathArray : [VaultFile]?) { if let _ = self.save(data, vaultFile: vaultFile, parent: parentFolder) { - self.addRecentFile(file: vaultFile, rootFile: parentFolder, folderPathArray: folderPathArray) } } - func createNewFolder(name: String, parent: VaultFile?) { + func createNewFolder(name: String, parent: VaultFile?, folderPathArray : [VaultFile]) { debugLog("\(name)", space: .files) - let vaultFile = VaultFile(type: .folder, fileName: name, files: nil) + let pathArray = folderPathArray.compactMap{$0.containerName} + let vaultFile = VaultFile(type: .folder, fileName: name, files: nil, pathArray: pathArray) parent?.add(file: vaultFile) save(file: root) } @@ -297,13 +297,11 @@ class VaultManager: VaultManagerInterface, ObservableObject { // } root = VaultFile.rootFile(fileName: "..", containerName: rootFileName) save(file: root) - recentFiles = [] } func delete(file: VaultFile, parent: VaultFile?) { debugLog("\(file)", space: .files) parent?.remove(file: file) - removeRecentFile(file: file) for aFile in file.files { delete(file: aFile, parent: parent) @@ -331,19 +329,8 @@ class VaultManager: VaultManagerInterface, ObservableObject { in: .userDomainMask)[0].appendingPathComponent(containerPath) return url } - - //MARK: recent file - private func addRecentFile(file: VaultFile, rootFile:VaultFile?, folderPathArray : [VaultFile]?) { - debugLog("\(file)", space: .files) - guard let rootFile = rootFile else { return } - recentFiles.append(RecentFile(file: file, rootFile: rootFile, folderPathArray: folderPathArray)) - } - - private func removeRecentFile(file: VaultFile) { - recentFiles = recentFiles.filter({ $0.file.containerName != file.containerName }) - } - - private func getFilesInfo(files: [URL]) async throws ->([(Data,VaultFile)], Double) { + + private func getFilesInfo(files: [URL], folderPathArray:[VaultFile]) async throws ->([(Data,VaultFile)], Double) { var totalSizeArray : [Double] = [] var vaultFileArray : [(Data,VaultFile)] = [] @@ -365,6 +352,7 @@ class VaultManager: VaultManagerInterface, ObservableObject { let duration = filePath.getDuration() let size = FileManager.default.sizeOfFile(atPath: path) ?? 0 let containerName = UUID().uuidString + let pathArray = folderPathArray.compactMap({$0.containerName}) let vaultFile = await VaultFile(type: filePath.fileType, fileName: fileName, @@ -374,7 +362,8 @@ class VaultManager: VaultManagerInterface, ObservableObject { fileExtension: fileExtension, size:size, resolution: resolution, - duration: duration) + duration: duration, + pathArray: pathArray) return (data,vaultFile) } } diff --git a/TellaTests/ModelStubs.swift b/TellaTests/ModelStubs.swift index 2109cbd0e..157db2bcb 100644 --- a/TellaTests/ModelStubs.swift +++ b/TellaTests/ModelStubs.swift @@ -7,7 +7,7 @@ import SwiftUI extension VaultFile { static func stub(type: FileType) -> VaultFile { - let file = VaultFile(type: type, fileName: UUID().uuidString, containerName: UUID().uuidString, files: nil) + let file = VaultFile(type: type, fileName: UUID().uuidString, containerName: UUID().uuidString, files: nil, pathArray: []) return file }