diff --git a/enzevalos_iphone/SwiftUI/Compose/AddAttachmentsModel.swift b/enzevalos_iphone/SwiftUI/Compose/AddAttachmentsModel.swift index 664785f2f2a9af498eac1c8dc076acac78db75cd..c89945f381ec7fd41ea26ec7cb9160daf6036026 100644 --- a/enzevalos_iphone/SwiftUI/Compose/AddAttachmentsModel.swift +++ b/enzevalos_iphone/SwiftUI/Compose/AddAttachmentsModel.swift @@ -22,6 +22,7 @@ struct Attachment: DisplayAttachment, Equatable { myID = UUID() } + /// a func that removes the calling attachment`s copy from the Documents Directory func removeFileFromDocumentsDirectory() { /// a func that returns the URL of the Documents Directory func getDocumentsDirectory() -> URL { diff --git a/enzevalos_iphone/SwiftUI/Compose/AddAttachmentsView.swift b/enzevalos_iphone/SwiftUI/Compose/AddAttachmentsView.swift index 811b1bbec0dc44cb7ede047b5dc961af9ec37478..0ed6b60f707074c99af5d48eece832700befdc87 100644 --- a/enzevalos_iphone/SwiftUI/Compose/AddAttachmentsView.swift +++ b/enzevalos_iphone/SwiftUI/Compose/AddAttachmentsView.swift @@ -11,63 +11,17 @@ struct AddAttachmentsView: View { @ObservedObject var model: ComposeModel // properties regarding attaching files used to control the fileUploadButton - @State var importNewFile = false + @State private var importNewFile = false // the attachment that is supposed to be viewed fullscreen - @State var fullScreenAttachment: Attachment? + @State private var fullScreenAttachment: Attachment? // properties regarding attaching images, used to store the imported image - @State var image: Image? + @State private var image: Image? @State private var inputImage: UIImage? // properties to handle several sheet views (only one .sheet(...) is allowed) - @State var showSheet = false - @State var currentSheetState: SheetStates? - - /// SheetStates to controll several sheet views - enum SheetStates { - case imageImport // user presses imageUploadButton - case fullScreenFilePreview // user taps on a file preview - } - - /// a func that returns the right sheet content according to the sheetState - @ViewBuilder - private func sheetContent() -> some View { - switch currentSheetState { - case .imageImport: - // open the gallery and let user pick an image - ImagePicker(image: self.$inputImage) - case .fullScreenFilePreview: - // open the attachment in 'fullScreenAttachment' fullscreen - if let attachment = fullScreenAttachment { - // file name - Text(attachment.myName) - .font(Font.headline.weight(.semibold)) - // file preview - // here shallDL should be false, because we have already downloaded the attachment into - // the Documents Directory - QuickLookView(name: attachment.myName, data: attachment.myData, shallDL: false) - .aspectRatio(100/141, contentMode: .fit) - } - default: - EmptyView() - } - } - - /// a func that returns the right onDismiss parameter according to the sheetState - private func sheetOnDismiss() { - switch currentSheetState { - case .imageImport: - // TODO: currently no inputImage is imported even if user chose one - guard let inputImage = inputImage else { return } - image = Image(uiImage: inputImage) - self.currentSheetState = nil - case .fullScreenFilePreview: - self.showSheet = false - self.currentSheetState = nil - self.fullScreenAttachment = nil - default: return - } - } + @State private var showSheet = false + @State private var currentSheetState: SheetStates? /// a view that enables uploading an previewing files and pictures as attachments // TODO: image import and preview are currently not fully supported @@ -84,7 +38,8 @@ struct AddAttachmentsView: View { filePreviews } .padding(4) - // using .sheet with multiple sheet views accoring to sheetStates + // recycling the sheet for different occassions + // (image import and fullscreen file preview) .sheet(isPresented: $showSheet, onDismiss: sheetOnDismiss) { sheetContent() } @@ -123,8 +78,7 @@ struct AddAttachmentsView: View { /// a view that contains the upload button for pictures var imageUploadButton: some View { Button { - self.currentSheetState = .imageImport - showSheet.toggle() + showNewSheet(newSheetState: .imageImport) } label: { // try to imitate SF Symbol "doc.badge.plus" // with "photo" @@ -157,14 +111,17 @@ struct AddAttachmentsView: View { .background(RoundedRectangle(cornerRadius: 5) .stroke(Color.secondary, lineWidth: 2)) + // a window that disables the interaction with QuickLookView Rectangle().fill(Color(.systemBackground).opacity(0.1)) - - Rectangle().fill(Color(.systemBackground).opacity(0.1)) + .onTapGesture(count: 2) { + self.fullScreenAttachment = currentFile + showNewSheet(newSheetState: .fullScreenFilePreview) + } VStack(alignment: .trailing) { // delete button in upper right corner Button { - // remove from attachments list and remove from Documents Directory + // remove from attachments list and remove copy from Documents Directory // to keep DD clean if let deleteIndex = model.attachments.firstIndex(of: currentFile) { model.attachments[deleteIndex].removeFileFromDocumentsDirectory() @@ -192,5 +149,57 @@ struct AddAttachmentsView: View { .frame(width: 100) } } + + /// SheetStates to controll several sheet views + enum SheetStates { + case imageImport // user presses imageUploadButton + case fullScreenFilePreview // user taps on a file preview + } + + /// a func that activates the sheet with the right content + private func showNewSheet(newSheetState: SheetStates) { + self.currentSheetState = newSheetState + showSheet.toggle() + } + + /// a func that returns the right sheet content according to the sheetState + @ViewBuilder + private func sheetContent() -> some View { + if currentSheetState == .imageImport { + // open the gallery and let user pick an image + ImagePicker(image: self.$inputImage) + } + else if currentSheetState == .fullScreenFilePreview { + // open the attachment in 'fullScreenAttachment' fullscreen + if let attachment = fullScreenAttachment { + // file name + Text(attachment.myName) + .font(Font.headline.weight(.semibold)) + // file preview + // here shallDL should be false, because we have already downloaded the attachment into + // the Documents Directory + QuickLookView(name: attachment.myName, data: attachment.myData, shallDL: false) + .aspectRatio(100/141, contentMode: .fit) + } + } + else { + Text("Something went wrong!") + } + } + + /// a func that returns the right onDismiss parameter according to the sheetState + private func sheetOnDismiss() { + if self.currentSheetState == .imageImport { + // TODO: currently no inputImage is imported even if user chose one + guard let inputImage = inputImage else { return } + image = Image(uiImage: inputImage) + } + else if self.currentSheetState == .fullScreenFilePreview { + self.fullScreenAttachment = nil + } + else { + return + } + } } diff --git a/enzevalos_iphone/SwiftUI/Compose/ComposeHeaderView.swift b/enzevalos_iphone/SwiftUI/Compose/ComposeHeaderView.swift index 0dd5fc9f8cc9338f2cacdddf5f17d9b2a6062271..b759ac4f29d1993a7cbd596cf24d7cb2bd0a089c 100644 --- a/enzevalos_iphone/SwiftUI/Compose/ComposeHeaderView.swift +++ b/enzevalos_iphone/SwiftUI/Compose/ComposeHeaderView.swift @@ -38,11 +38,6 @@ struct ComposeViewHeader: View { presentationMode.wrappedValue.dismiss() } model.resumeSend = true - // remove the attachments from the Documents Directory - // to keep the DD clean - for current in model.attachments { - current.removeFileFromDocumentsDirectory() - } } .disabled(model.recipientsModel.hasNoRecipients) } diff --git a/enzevalos_iphone/SwiftUI/Compose/ComposeModel.swift b/enzevalos_iphone/SwiftUI/Compose/ComposeModel.swift index 27fdbc8b4c811aa51be68cd5431363270e79a932..d3ed6f0fcf5d75cca6311b67a78d1af263ed0bb7 100644 --- a/enzevalos_iphone/SwiftUI/Compose/ComposeModel.swift +++ b/enzevalos_iphone/SwiftUI/Compose/ComposeModel.swift @@ -40,6 +40,13 @@ class ComposeModel: ObservableObject { return allWords.contains(where: self.body.contains) || allWords.contains(where: self.subject.contains) } + /// a func that deletes all the copies of the attachment files in the Documents Directory to keep it clean + func removeAttachmentCopiesFromDocumentsDirectory() { + for current in attachments { + current.removeFileFromDocumentsDirectory() + } + } + // TODO: Add security state functionality /// Generates mail and sends it. diff --git a/enzevalos_iphone/SwiftUI/Compose/ComposeView.swift b/enzevalos_iphone/SwiftUI/Compose/ComposeView.swift index c2e90851248dddd2f29ed8805d4089cda079cb84..d43e62c629f792d654aae9d719d16c0c9704c768 100644 --- a/enzevalos_iphone/SwiftUI/Compose/ComposeView.swift +++ b/enzevalos_iphone/SwiftUI/Compose/ComposeView.swift @@ -82,6 +82,12 @@ struct ComposeView: View { .padding() .animation(.easeInOut) .ignoresSafeArea(edges: /*@START_MENU_TOKEN@*/.bottom/*@END_MENU_TOKEN@*/) + .onDisappear{ + // when the ComposeView is closed, we make sure to + // clean the Documents Directory from all the remaining + // copies of attachment files + model.removeAttachmentCopiesFromDocumentsDirectory() + } } } @@ -93,6 +99,9 @@ struct ComposeView: View { primaryButton: .destructive(Text("Attachment.Alert.PrimaryButton").foregroundColor(Color.blue)) { // send the mail anyway model.sendMail() + // remove the attachments from the Documents Directory + // to keep the DD clean + model.removeAttachmentCopiesFromDocumentsDirectory() presentationMode.wrappedValue.dismiss() }, secondaryButton: .destructive(Text("Attachment.Alert.SecondaryButton").foregroundColor(Color.blue)) { @@ -100,6 +109,13 @@ struct ComposeView: View { } ) } + + /// a func that deletes all the copies of the attachment files in the Documents Directory to keep it clean + func removeAttachmentCopiesFromDocumentsDirectory() { + for current in model.attachments { + current.removeFileFromDocumentsDirectory() + } + } } /// A view in which recipients get added or removed. diff --git a/enzevalos_iphone/SwiftUI/Inbox/InboxView.swift b/enzevalos_iphone/SwiftUI/Inbox/InboxView.swift index 3739f49021eaa261e1f7d0e01600efa3f5c6e38b..b142011ba752c51314c18b75b080b746957b6ba9 100644 --- a/enzevalos_iphone/SwiftUI/Inbox/InboxView.swift +++ b/enzevalos_iphone/SwiftUI/Inbox/InboxView.swift @@ -38,6 +38,7 @@ struct InboxView: View { } } + private var mailListView: some View { MailListView(folderPath: folderPath, folderName: name) .environment(\.managedObjectContext,