174 lines
5.5 KiB
Swift
174 lines
5.5 KiB
Swift
//
|
|
// 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 ?? "<unknown>") (\(build ?? "<unknown>"))"
|
|
}
|
|
|
|
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()
|
|
}
|
|
}
|