Files
sing-box-for-apple/ApplicationLibrary/Views/Tools/ReportShared.swift
T

128 lines
4.4 KiB
Swift

import Libbox
import Library
import SwiftUI
#if canImport(UIKit)
import UIKit
#endif
struct ReportLabel: View {
let date: Date
let isRead: Bool
let origin: String?
var body: some View {
HStack(spacing: 8) {
Circle()
.fill(isRead ? .clear : .blue)
.frame(width: 10, height: 10)
VStack(alignment: .leading, spacing: 2) {
Text(date, format: .dateTime)
.fontWeight(isRead ? .regular : .semibold)
HStack(spacing: 4) {
Image(systemName: origin == ReportArchive.tvOSDeviceOrigin ? "appletv.fill" : Self.localDeviceIcon)
Text(origin == ReportArchive.tvOSDeviceOrigin ? "Apple TV" : "Local")
}
.font(.caption)
.foregroundStyle(.secondary)
}
}
}
#if os(iOS)
private static let localDeviceIcon = "iphone"
#elseif os(macOS)
private static let localDeviceIcon = "desktopcomputer"
#elseif os(tvOS)
private static let localDeviceIcon = "appletv.fill"
#endif
}
@MainActor
struct ReportFileContentView: View {
@State private var content = ""
@State private var isLoading = true
let fileURL: URL
let displayName: String
var body: some View {
Group {
if isLoading {
ProgressView()
.onAppear {
Task {
content = await Self.loadContent(fileURL: fileURL)
isLoading = false
}
}
} else if content.isEmpty {
Text("Empty")
.foregroundStyle(.secondary)
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else {
#if os(iOS)
ScrollView {
PlainTextView(content: content)
}
#else
PlainTextView(content: content)
#endif
}
}
.navigationTitle(displayName)
}
private nonisolated static func loadContent(fileURL: URL) async -> String {
await BlockingIO.run {
guard let data = try? Data(contentsOf: fileURL) else {
return ""
}
return String(data: data, encoding: .utf8) ?? ""
}
}
}
#if !os(tvOS)
@MainActor
func createReportZip(reportID: String, fileURL: URL, cacheSubdirectory: String, includeConfig: Bool) async throws -> URL {
try await BlockingIO.run {
let tempDir = FilePath.cacheDirectory.appendingPathComponent(cacheSubdirectory, isDirectory: true)
try? FileManager.default.createDirectory(at: tempDir, withIntermediateDirectories: true)
let tempURL = tempDir.appendingPathComponent("\(reportID).zip")
try? FileManager.default.removeItem(at: tempURL)
let strippedURL = tempDir.appendingPathComponent(reportID, isDirectory: true)
try? FileManager.default.removeItem(at: strippedURL)
try FileManager.default.copyItem(at: fileURL, to: strippedURL)
try? FileManager.default.removeItem(at: strippedURL.appendingPathComponent(ReportArchive.readMarkerFileName))
if !includeConfig {
try? FileManager.default.removeItem(at: strippedURL.appendingPathComponent(ReportArchive.configFileName))
}
var error: NSError?
LibboxCreateZipArchive(strippedURL.path, tempURL.path, &error)
try? FileManager.default.removeItem(at: strippedURL)
if let error { throw error }
return tempURL
}
}
#if os(iOS)
@MainActor
func presentShareSheet(_ item: URL) {
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let rootViewController = windowScene.keyWindow?.rootViewController
else {
return
}
var topViewController = rootViewController
while let presented = topViewController.presentedViewController {
topViewController = presented
}
topViewController.present(
UIActivityViewController(activityItems: [item], applicationActivities: nil),
animated: true
)
}
#endif
#endif