Tools View & Crash Report & OOM Report

This commit is contained in:
世界
2026-04-23 08:12:52 +08:00
parent 73180f0230
commit b48f4ad97f
46 changed files with 4279 additions and 533 deletions
@@ -0,0 +1,92 @@
import SwiftUI
private struct OrderedStringMap {
let entries: [(key: String, value: String)]
init?(data: Data) {
guard let json = String(data: data, encoding: .utf8) else { return nil }
var entries: [(key: String, value: String)] = []
var rest = json[...]
func skip(_ ch: Character) -> Bool {
rest = rest.drop(while: \.isWhitespace)
guard rest.first == ch else { return false }
rest = rest.dropFirst()
return true
}
func readString() -> String? {
rest = rest.drop(while: \.isWhitespace)
guard rest.first == "\"" else { return nil }
rest = rest.dropFirst()
var s = ""
while let ch = rest.first, ch != "\"" {
if ch == "\\" { rest = rest.dropFirst() }
if let c = rest.first { s.append(c); rest = rest.dropFirst() }
}
if !rest.isEmpty { rest = rest.dropFirst() }
return s
}
guard skip("{") else { return nil }
while true {
guard let key = readString(), skip(":"), let value = readString() else { break }
if !value.isEmpty { entries.append((key: key, value: value)) }
if !skip(",") { break }
}
self.entries = entries
}
}
@MainActor
public struct MetadataFormView: View {
@State private var entries: [(key: String, value: String)] = []
@State private var isLoading = true
let url: URL
let title: String
public init(url: URL, title: String) {
self.url = url
self.title = title
}
public var body: some View {
FormView {
if !isLoading {
Section {
ForEach(entries, id: \.key) { entry in
FormTextItem(LocalizedStringKey(entry.key), entry.value)
}
}
}
}
.overlay {
if isLoading {
ProgressView()
} else if entries.isEmpty {
Text("Empty")
.foregroundStyle(.secondary)
}
}
.onAppear {
Task.detached {
let loaded = loadEntries()
await MainActor.run {
entries = loaded
isLoading = false
}
}
}
.navigationTitle(title)
}
private nonisolated func loadEntries() -> [(key: String, value: String)] {
guard let data = try? Data(contentsOf: url),
let map = OrderedStringMap(data: data)
else {
return []
}
return map.entries
}
}
@@ -0,0 +1,95 @@
#if canImport(UIKit)
import UIKit
#elseif canImport(AppKit)
import AppKit
#endif
import SwiftUI
#if os(tvOS)
struct PlainTextView: UIViewRepresentable {
let content: String
private static let monoFont = UIFont.monospacedSystemFont(ofSize: 24, weight: .regular)
func makeUIView(context _: Context) -> UITextView {
let textView = UITextView()
// isSelectable must be true for UITextView to be focusable on tvOS.
// Without focus, the Siri Remote cannot scroll the content.
// SwiftUI ScrollView + Text / LazyVStack + .focusable() do NOT work
// reliably inside navigation destinations on tvOS.
textView.isSelectable = true
textView.isUserInteractionEnabled = true
textView.isScrollEnabled = true
textView.backgroundColor = .clear
textView.textContainerInset = UIEdgeInsets(top: 40, left: 40, bottom: 40, right: 40)
textView.textContainer.lineFragmentPadding = 0
textView.font = Self.monoFont
textView.textColor = .label
textView.text = content
textView.panGestureRecognizer.allowedTouchTypes = [NSNumber(value: UITouch.TouchType.indirect.rawValue)]
return textView
}
func updateUIView(_: UITextView, context _: Context) {}
}
#elseif os(iOS)
struct PlainTextView: UIViewRepresentable {
let content: String
private static let monoFont = UIFont.monospacedSystemFont(ofSize: 12, weight: .regular)
func makeUIView(context _: Context) -> UITextView {
let textView = UITextView()
textView.isEditable = false
textView.isSelectable = true
textView.isScrollEnabled = false
textView.backgroundColor = .clear
textView.textContainerInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
textView.textContainer.lineFragmentPadding = 0
textView.font = Self.monoFont
textView.textColor = .label
textView.text = content
textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
return textView
}
func updateUIView(_: UITextView, context _: Context) {}
}
#elseif os(macOS)
struct PlainTextView: NSViewRepresentable {
let content: String
private static let monoFont = NSFont.monospacedSystemFont(ofSize: 12, weight: .regular)
func makeNSView(context _: Context) -> NSScrollView {
let scrollView = NSScrollView()
scrollView.hasVerticalScroller = true
scrollView.hasHorizontalScroller = false
scrollView.autohidesScrollers = true
let textView = NSTextView()
textView.isEditable = false
textView.isSelectable = true
textView.drawsBackground = false
textView.textContainerInset = NSSize(width: 16, height: 16)
textView.font = Self.monoFont
textView.textColor = .labelColor
textView.autoresizingMask = [.width]
textView.string = content
if let textContainer = textView.textContainer {
textContainer.widthTracksTextView = true
textContainer.containerSize = NSSize(width: scrollView.contentSize.width, height: .greatestFiniteMagnitude)
textContainer.lineFragmentPadding = 0
}
scrollView.documentView = textView
return scrollView
}
func updateNSView(_: NSScrollView, context _: Context) {}
}
#endif
@@ -82,7 +82,7 @@ public struct ShareButtonCompat<Label: View>: View {
do {
let shareItem = try await itemURL()
await MainActor.run {
presentShareController(shareItem)
presentShareSheet(shareItem)
}
} catch {
await MainActor.run {
@@ -91,22 +91,6 @@ public struct ShareButtonCompat<Label: View>: View {
}
}
private func presentShareController(_ 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
)
}
#elseif os(macOS)
private nonisolated func shareItemAsync() async {
do {
@@ -125,7 +109,7 @@ public struct ShareButtonCompat<Label: View>: View {
}
#if os(macOS)
private struct SharingServicePicker: NSViewRepresentable {
struct SharingServicePicker: NSViewRepresentable {
@Binding private var isPresented: Bool
@Binding private var alert: AlertState?
@Binding private var item: URL?