// // AboutView.swift // Tusker // // Created by Shadowfacts on 12/21/22. // Copyright © 2022 Shadowfacts. All rights reserved. // import SwiftUI import MessageUI struct AboutView: View { @State private var logData: Data? @State private var isGettingLogData = false @State private var isShowingMailSheet = false private var version: String { let marketing = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String return "\(marketing ?? "") (\(build ?? ""))" } var body: some View { List { iconOrGame .frame(maxWidth: .infinity, alignment: .center) .listRowInsets(EdgeInsets(top: 9, leading: 0, bottom: 0, trailing: 0)) .listRowBackground(EmptyView()) Section { HStack { Text("Version") Spacer() Text(version) .foregroundColor(.secondary) } .contextMenu { Button { UIPasteboard.general.string = version } label: { Label("Copy", systemImage: "doc.on.doc") } } } .appGroupedListRowBackground() Section { Link("Website", destination: URL(string: "https://vaccor.space/tusker")!) Button { if MFMailComposeViewController.canSendMail() { Task { await showMailSheet() } } else { UIApplication.shared.open(URL(string: "mailto:hello@vaccor.space?subject=Tusker%20Support")!) } } label: { HStack { Text("Get Support") Spacer() if isGettingLogData { ProgressView() .progressViewStyle(.circular) } } } .disabled(isGettingLogData) Link("Source Code", destination: URL(string: "https://git.shadowfacts.net/shadowfacts/Tusker")!) Link("Issue Tracker", destination: URL(string: "https://git.shadowfacts.net/shadowfacts/Tusker/issues")!) } .appGroupedListRowBackground() } .listStyle(.insetGrouped) .appGroupedListBackground(container: PreferencesNavigationController.self) .sheet(isPresented: $isShowingMailSheet) { MailSheet(logData: logData) } } @ViewBuilder private var iconOrGame: some View { if #available(iOS 16.0, *) { FlipView { appIcon } back: { TTTView() } } else { appIcon } } private var appIcon: some View { VStack { AppIconView() .shadow(radius: 6, y: 3) .frame(width: 256, height: 256) Text("Tusker") .font(.title2.bold()) } } private func showMailSheet() async { isGettingLogData = true logData = await withCheckedContinuation({ continuation in DispatchQueue.global().async { continuation.resume(returning: Logging.getLogData()) } }) isGettingLogData = false isShowingMailSheet = true } } private struct AppIconView: UIViewRepresentable { func makeUIView(context: Context) -> UIImageView { let view = UIImageView(image: UIImage(named: "AboutIcon")) view.contentMode = .scaleAspectFit view.layer.cornerRadius = 256 / 6.4 view.layer.cornerCurve = .continuous view.layer.masksToBounds = true return view } func updateUIView(_ uiView: UIImageView, context: Context) { } } private struct MailSheet: UIViewControllerRepresentable { typealias UIViewControllerType = MFMailComposeViewController let logData: Data? @Environment(\.dismiss) private var dismiss func makeUIViewController(context: Context) -> MFMailComposeViewController { let vc = MFMailComposeViewController() vc.mailComposeDelegate = context.coordinator vc.setToRecipients(["hello@vaccor.space"]) vc.setSubject("Tusker Support") if let logData { let timestamp = ISO8601DateFormatter().string(from: Date()) vc.addAttachmentData(logData, mimeType: "text/plain", fileName: "Tusker-\(timestamp).log") } return vc } func updateUIViewController(_ uiViewController: MFMailComposeViewController, context: Context) { } func makeCoordinator() -> Coordinator { return Coordinator(dismiss: dismiss) } class Coordinator: NSObject, MFMailComposeViewControllerDelegate { let dismiss: DismissAction init(dismiss: DismissAction) { self.dismiss = dismiss } func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { dismiss() } } } struct AboutView_Previews: PreviewProvider { static var previews: some View { AboutView() } }