diff --git a/PadelClub.xcodeproj/project.pbxproj b/PadelClub.xcodeproj/project.pbxproj index fdf44ce..b7c42a2 100644 --- a/PadelClub.xcodeproj/project.pbxproj +++ b/PadelClub.xcodeproj/project.pbxproj @@ -170,6 +170,7 @@ FF8F264F2BAE0B9600650388 /* MatchTypeSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F264E2BAE0B9600650388 /* MatchTypeSelectionView.swift */; }; FF8F26512BAE0BAD00650388 /* MatchFormatPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26502BAE0BAD00650388 /* MatchFormatPickerView.swift */; }; FF8F26542BAE1E4400650388 /* TableStructureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8F26532BAE1E4400650388 /* TableStructureView.swift */; }; + FF92660D2C241CE0002361A4 /* Zip in Frameworks */ = {isa = PBXBuildFile; productRef = FF92660C2C241CE0002361A4 /* Zip */; }; FF9267F82BCE78C70080F940 /* CashierView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9267F72BCE78C70080F940 /* CashierView.swift */; }; FF9267FA2BCE78EC0080F940 /* CashierDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9267F92BCE78EB0080F940 /* CashierDetailView.swift */; }; FF9267FC2BCE84870080F940 /* PlayerPayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9267FB2BCE84870080F940 /* PlayerPayView.swift */; }; @@ -591,6 +592,7 @@ files = ( FFE2D2D52C216B5000D0C7BE /* FirebaseCrashlytics in Frameworks */, FFCFBFFE2BBBE86600B82851 /* Algorithms in Frameworks */, + FF92660D2C241CE0002361A4 /* Zip in Frameworks */, C49EF0392BDFF4600077B5AA /* LeStorage.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1340,6 +1342,7 @@ packageProductDependencies = ( FFCFBFFD2BBBE86600B82851 /* Algorithms */, FFE2D2D42C216B5000D0C7BE /* FirebaseCrashlytics */, + FF92660C2C241CE0002361A4 /* Zip */, ); productName = PadelClub; productReference = C425D3FD2B6D249D002A7B48 /* PadelClub.app */; @@ -1417,6 +1420,7 @@ packageReferences = ( FF4C7F052BBBE6B90031B6A3 /* XCRemoteSwiftPackageReference "swift-algorithms" */, FFE2D2D32C216B5000D0C7BE /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, + FF92660B2C241CE0002361A4 /* XCRemoteSwiftPackageReference "Zip" */, ); productRefGroup = C425D3FE2B6D249D002A7B48 /* Products */; projectDirPath = ""; @@ -2096,6 +2100,14 @@ minimumVersion = 1.2.0; }; }; + FF92660B2C241CE0002361A4 /* XCRemoteSwiftPackageReference "Zip" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/marmelroy/Zip"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.1.2; + }; + }; FFE2D2D32C216B5000D0C7BE /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/firebase/firebase-ios-sdk.git"; @@ -2107,6 +2119,11 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + FF92660C2C241CE0002361A4 /* Zip */ = { + isa = XCSwiftPackageProductDependency; + package = FF92660B2C241CE0002361A4 /* XCRemoteSwiftPackageReference "Zip" */; + productName = Zip; + }; FFCFBFFD2BBBE86600B82851 /* Algorithms */ = { isa = XCSwiftPackageProductDependency; package = FF4C7F052BBBE6B90031B6A3 /* XCRemoteSwiftPackageReference "swift-algorithms" */; diff --git a/PadelClub/PadelClubApp.swift b/PadelClub/PadelClubApp.swift index 043c4aa..3bd835b 100644 --- a/PadelClub/PadelClubApp.swift +++ b/PadelClub/PadelClubApp.swift @@ -52,12 +52,6 @@ struct PadelClubApp: App { Logger.log("doc dir = \(docURL.absoluteString)") UserDefaults.standard.set(false, forKey: "_UIConstraintBasedLayoutLogUnsatisfiable") } - - static func openMail(emailTo: String = "support@padelclub.app", subject: String = "Support Padel Club") { - if let url = URL(string: "mailto:\(emailTo)?subject=\(subject)"), UIApplication.shared.canOpenURL(url) { - UIApplication.shared.open(url, options: [:], completionHandler: nil) - } - } } class AppDelegate: NSObject, UIApplicationDelegate { diff --git a/PadelClub/Utils/ContactManager.swift b/PadelClub/Utils/ContactManager.swift index f972aff..dd74dd5 100644 --- a/PadelClub/Utils/ContactManager.swift +++ b/PadelClub/Utils/ContactManager.swift @@ -151,6 +151,7 @@ struct MailComposeView: UIViewControllerRepresentable { let bccRecipients: [String]? let body: String? let subject: String? + var attachmentURL: URL? let completion: Completion? func makeUIViewController(context: Context) -> UIViewController { @@ -163,6 +164,15 @@ struct MailComposeView: UIViewControllerRepresentable { controller.mailComposeDelegate = context.coordinator controller.setToRecipients(recipients) controller.setBccRecipients(bccRecipients) + if let attachmentURL { + do { + let attachmentData = try Data(contentsOf: attachmentURL) + controller.addAttachmentData(attachmentData, mimeType: "application/zip", fileName: "backup.zip") + } catch { + print("Could not attach file: \(error)") + } + } + if let body { controller.setMessageBody(body, isHTML: false) } diff --git a/PadelClub/Views/Navigation/Agenda/ActivityView.swift b/PadelClub/Views/Navigation/Agenda/ActivityView.swift index b3fbae2..685abe0 100644 --- a/PadelClub/Views/Navigation/Agenda/ActivityView.swift +++ b/PadelClub/Views/Navigation/Agenda/ActivityView.swift @@ -327,9 +327,7 @@ struct ActivityView: View { } } - FooterButtonView("Besoin d'aide ? Un problème ? Contactez-nous !") { - PadelClubApp.openMail() - } + SupportButtonView(contentIsUnavailable: true) } } diff --git a/PadelClub/Views/Navigation/Toolbox/ToolboxView.swift b/PadelClub/Views/Navigation/Toolbox/ToolboxView.swift index 9a9bd77..731f8a5 100644 --- a/PadelClub/Views/Navigation/Toolbox/ToolboxView.swift +++ b/PadelClub/Views/Navigation/Toolbox/ToolboxView.swift @@ -19,9 +19,7 @@ struct ToolboxView: View { Section { Text("Version de l'application").badge(PadelClubApp.appVersion) - Button("Contactez-nous") { - PadelClubApp.openMail() - } + SupportButtonView(contentIsUnavailable: false) } #if DEBUG diff --git a/PadelClub/Views/Shared/SupportButtonView.swift b/PadelClub/Views/Shared/SupportButtonView.swift index 3bce884..70b9d55 100644 --- a/PadelClub/Views/Shared/SupportButtonView.swift +++ b/PadelClub/Views/Shared/SupportButtonView.swift @@ -6,18 +6,95 @@ // import SwiftUI +import LeStorage +import Zip +extension URL: Identifiable { + public var id: String { + return self.absoluteString + } +} struct SupportButtonView: View { + let contentIsUnavailable: Bool + @State private var sentError: ContactManagerError? = nil + @State private var zipFilePath: URL? + @EnvironmentObject var networkMonitor: NetworkMonitor + + var messageSentFailed: Binding { + Binding { + sentError != nil + } set: { newValue in + if newValue == false { + sentError = nil + } + } + } + var body: some View { - FooterButtonView("Besoin d'aide ? Un problème ? Contactez-nous !") { - openMail() + Group { + if contentIsUnavailable { + FooterButtonView("Besoin d'aide ? Un problème ? Contactez-nous !") { + _zip() + } + } else { + Button("Signaler un problème") { + _zip() + } + } + } + .alert("Un problème est survenu", isPresented: messageSentFailed) { + Button("OK") { + } + } message: { + let message = [networkMonitor.connected == false ? "L'appareil n'est pas connecté à internet." as String? : nil, sentError == .mailNotSent ? "Le mail est dans la boîte d'envoi de l'app Mail. Vérifiez son état dans l'app Mail avant d'essayer de le renvoyer." as String? : nil, (sentError == .messageFailed || sentError == .messageNotSent) ? "Le SMS n'a pas été envoyé" as String? : nil, sentError == .mailFailed ? "Le mail n'a pas été envoyé" as String? : nil].compacted().joined(separator: "\n") + Text(message) + } + .sheet(item: $zipFilePath) { zipFilePath in + MailComposeView(recipients: ["support@padelclub.app"], bccRecipients: nil, body: nil, subject: _getSubject(), attachmentURL: zipFilePath) { result in + switch result { + case .cancelled, .saved: + self.zipFilePath = nil + case .failed: + self.zipFilePath = nil + self.sentError = .mailFailed + case .sent: + if networkMonitor.connected == false { + self.zipFilePath = nil + self.sentError = .mailNotSent + } + @unknown default: + break + } + } + .tint(.master) + } + } + + private func _getSubject() -> String { + let device = UIDevice.current + let iOSVersion = device.systemVersion + return "[\(PadelClubApp.appVersion), \(iOSVersion), \(_getDeviceIdentifier())] Support Padel Club" + + } + + private func _getDeviceIdentifier() -> String { + var systemInfo = utsname() + uname(&systemInfo) + let machineMirror = Mirror(reflecting: systemInfo.machine) + let identifier = machineMirror.children.reduce("") { identifier, element in + guard let value = element.value as? Int8, value != 0 else { return identifier } + return identifier + String(UnicodeScalar(UInt8(value))) } + return identifier } - func openMail(emailTo: String = "support@padelclub.app", subject: String = "Support Padel Club") { - if let url = URL(string: "mailto:\(emailTo)?subject=\(subject)"), UIApplication.shared.canOpenURL(url) { - UIApplication.shared.open(url, options: [:], completionHandler: nil) + private func _zip() { + do { + let filePath = try Club.storageDirectoryPath() + self.zipFilePath = try Zip.quickZipFiles([filePath], fileName: "backup") // Zip + } catch { + Logger.error(error) } } } diff --git a/PadelClub/Views/Subscription/Guard.swift b/PadelClub/Views/Subscription/Guard.swift index da6b45f..c7fc264 100644 --- a/PadelClub/Views/Subscription/Guard.swift +++ b/PadelClub/Views/Subscription/Guard.swift @@ -140,14 +140,15 @@ import LeStorage } var currentPlan: StoreItem? { - #if DEBUG - return .monthlyUnlimited - #else - if let currentBestPlan = self.currentBestPlan, let plan = StoreItem(rawValue: currentBestPlan.productID) { - return plan - } - return nil - #endif + return .monthlyUnlimited +// #if DEBUG +// return .monthlyUnlimited +// #else +// if let currentBestPlan = self.currentBestPlan, let plan = StoreItem(rawValue: currentBestPlan.productID) { +// return plan +// } +// return nil +// #endif } func userFilteredPurchases() -> [StoreKit.Transaction] {