From e9d965bc14b4ccb8930842bc9897e93596e8a21b Mon Sep 17 00:00:00 2001 From: Hugues Date: Mon, 18 Nov 2019 17:00:54 -0500 Subject: [PATCH] #41: send both the pdf and the Excel file for the local StatsReportFromDate. --- Core Classes/DataModel.swift | 156 +++++++++++++++++++++---- Core Classes/StatsReportFromDate.swift | 17 +++ 2 files changed, 148 insertions(+), 25 deletions(-) diff --git a/Core Classes/DataModel.swift b/Core Classes/DataModel.swift index 7b77433..37111de 100644 --- a/Core Classes/DataModel.swift +++ b/Core Classes/DataModel.swift @@ -9,6 +9,7 @@ import MessageUI import CoreLocation import CoreData +import MobileCoreServices final class TimesheetsDataModel: NSObject, AddPilotPopoverDelegate, NSFetchedResultsControllerDelegate, GPSmanagerDelegate, NDHTMLtoPDFDelegate, MFMailComposeViewControllerDelegate, iBeaconDelegate, SelectGlidingCentreDelegate { @@ -627,67 +628,172 @@ final class TimesheetsDataModel: NSObject, AddPilotPopoverDelegate, NSFetchedRes func emailLocalStatsReportFromDate(_ startDate: Date, toDate endDate:Date) { - class ResultAccumulator : NDHTMLtoPDFDelegate + // TODO: missing some error management!! And clean-up... + class ResultAccumulator : NSObject, NDHTMLtoPDFDelegate, MFMailComposeViewControllerDelegate { var urls = [URL]() let controller : UIViewController? + let param : StatsReportFromDateParameters + var html : String? - init(_ controller : UIViewController?) + init(_ controller : UIViewController?, _ param : StatsReportFromDateParameters) { self.controller = controller + self.param = param } - func HTMLtoPDFDidSucceed(_ htmlToPDF: NDHTMLtoPDF) { - if let url = htmlToPDF.URL { + func HTMLtoPDFDidSucceed(_ htmlToPDF: NDHTMLtoPDF) + { + if let url = htmlToPDF.URL + { urls.append(url) } - if let path = htmlToPDF.PDFpath { + if let path = htmlToPDF.PDFpath + { urls.append(URL(fileURLWithPath: path)) } complete() } - func HTMLtoPDFDidFail(_ htmlToPDF: NDHTMLtoPDF) { + func HTMLtoPDFDidFail(_ htmlToPDF: NDHTMLtoPDF) + { // could not generate the PDF... nothing to add. complete() } - - private func complete() { + + func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) + { + controller.presentingViewController?.dismiss(animated: true, completion: nil) + for url in urls + { + try! FileManager.default.removeItem(at: url) + } + } + + private func complete() + { guard urls.count > 0 else { return } - if MFMailComposeViewController.canSendMail() { + if MFMailComposeViewController.canSendMail() + { // send email let picker = MFMailComposeViewController() - picker.mailComposeDelegate = self as! MFMailComposeViewControllerDelegate - - } else { + picker.mailComposeDelegate = self + picker.setSubject(getSubject()) + picker.setToRecipients(getRecipients()) + for url in urls + { + picker.addAttachmentData((try? Data(contentsOf: url))!, mimeType: getMimeType(for: url), fileName: getFileName(for: url)) + } + picker.setMessageBody(getBody(), isHTML: true) + present(picker) + } + else + { // activity let vc = UIActivityViewController(activityItems: urls, applicationActivities: nil) - if regularFormat + present(vc) + } + } + + private func present(_ view : UIViewController) + { + if regularFormat + { + if let controller = dataModel.aircraftAreaController?.parent { - controller?.present(vc, animated:true, completion:nil) + controller.dismiss(animated: true, completion: nil) + controller.present(view, animated: true, completion: nil) } - else + } + else + { + UIViewController.presentOnTopmostViewController(view) + } + } + + private func getBody() -> String + { + let html = self.html ?? "" + let printWarning = "This report is attached as a PDF for easy printing. Please print the attachment, do not print this email message directly.

" + return "\(printWarning)\(html)" + } + + private func getHtmlContent() -> String + { + for url in urls + { + if url.pathExtension == "html" { + return (try? String(contentsOf: url)) ?? "" + } + } + return "" + } + + private func getSubject() -> String + { + let centre = (regularFormat == true && dataModel.viewPreviousRecords == true) ? dataModel.previousRecordsGlidingCentre! : dataModel.glidingCentre + let subjectLine = "\(centre!.name) Stats Report \(param.startDate.militaryFormatShort) to \(param.endDate.militaryFormatShort)" + return subjectLine + } + + private func getFileName(for url : URL) -> String + { + return "\(param.glidingCentre!.name)-Stats-Report-\(param.startDate.militaryFormatShort)-\(param.endDate.militaryFormatShort).\(url.pathExtension)" + } + + private func getMimeType(for url : URL) -> String + { + let ext = url.pathExtension as CFString + if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, nil)?.takeUnretainedValue(), + let mimeUTI = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeUnretainedValue() + { + return mimeUTI as String + } + return "" + } + + private func getRecipients() -> [String] + { + let defaults = UserDefaults.standard + var toRecipients = Set() + + for i in 1...6 + { + let key = "Stats Address \(i)" + if let value = defaults.string(forKey: key) + { + toRecipients.insert(value) + } + } + + var invalidEmails = Set() + for address in toRecipients + { + if stringIsValidEmail(address) == false { - UIViewController.presentOnTopmostViewController(vc) + invalidEmails.insert(address) } } + + toRecipients.subtract(invalidEmails) + return Array(toRecipients) } } - let resultAccumulator = ResultAccumulator(aircraftAreaController?.parent) - - //guard checkIfCanSendMailAndAlertUserIfNot() else {return} + // set report parameters + let GC = (regularFormat && viewPreviousRecords) ? previousRecordsGlidingCentre! : glidingCentre + let regionName = (UserDefaults.standard.string(forKey: "Region")?.uppercased()) ?? "unknown region" + let param = StatsReportFromDateParameters(startDate: startDate, endDate: endDate, glidingCentre: GC, regionName: regionName) reportTypeBeingGenerated = ReportType.statsReport self.startDate = startDate self.endDate = endDate - let GC = (regularFormat && viewPreviousRecords) ? previousRecordsGlidingCentre! : glidingCentre + let report = StatsReportFromDate(param) + + let resultAccumulator = ResultAccumulator(aircraftAreaController?.parent, param) - let regionName = (UserDefaults.standard.string(forKey: "Region")?.uppercased()) ?? "unknown region" - let report = StatsReportFromDate(startDate, toDate: endDate, glidingCentre: GC, regionName: regionName) - let excelFormatter = ExcelStatsReportFromDateFormater() report.generate(with: excelFormatter) excelFormatter.generateResult { @@ -697,11 +803,11 @@ final class TimesheetsDataModel: NSObject, AddPilotPopoverDelegate, NSFetchedRes } let htmlFormatter = HtmlStatsReportFromDateFormater() report.generate(with: htmlFormatter) - self.tableText = htmlFormatter.result() + resultAccumulator.html = htmlFormatter.result() let pathArray = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as [String] let pathForPDF = pathArray.first?.stringByAppendingPathComponent("StatsReport.pdf") ?? "" - self.PDFgenerator = NDHTMLtoPDF.createPDFWithHTML(self.tableText!, pathForPDF: pathForPDF, delegate:resultAccumulator, pageSize:CGSize(width: 612,height: 792), margins:UIEdgeInsets.init(top: 30, left: 30, bottom: 30, right: 30)) + self.PDFgenerator = NDHTMLtoPDF.createPDFWithHTML(resultAccumulator.html!, pathForPDF: pathForPDF, delegate:resultAccumulator, pageSize:CGSize(width: 612,height: 792), margins:UIEdgeInsets.init(top: 30, left: 30, bottom: 30, right: 30)) } } diff --git a/Core Classes/StatsReportFromDate.swift b/Core Classes/StatsReportFromDate.swift index a78b8af..611f2cd 100644 --- a/Core Classes/StatsReportFromDate.swift +++ b/Core Classes/StatsReportFromDate.swift @@ -7,6 +7,14 @@ import Foundation +struct StatsReportFromDateParameters +{ + let startDate : Date + let endDate : Date + let glidingCentre : GlidingCentre? + let regionName : String +} + class StatsReportFromDate { let startDate : Date @@ -18,6 +26,15 @@ class StatsReportFromDate } let regionName : String + init(_ parameters : StatsReportFromDateParameters) + { + self.startDate = parameters.startDate + self.endDate = parameters.endDate + self.glidingCentre = parameters.glidingCentre + self.siteSpecific = glidingCentre != nil + self.regionName = parameters.regionName + } + init(_ startDate: Date, toDate endDate: Date, glidingCentre : GlidingCentre?, regionName : String) { self.startDate = startDate