mirror of
https://github.com/StikDebug/StikDebug.git
synced 2026-10-16 20:30:30 +00:00
111 lines
4 KiB
Swift
111 lines
4 KiB
Swift
import SwiftUI
|
|
import WebKit
|
|
|
|
struct MiniToolRunnerView: View {
|
|
let tool: MiniToolBundle
|
|
let toolInfo: ToolInfo
|
|
@StateObject private var runtime: MiniToolRuntime
|
|
@State private var showLogs = false
|
|
@State private var initiated = false
|
|
|
|
@AppStorage("appTheme") private var appThemeRaw: String = AppTheme.system.rawValue
|
|
@Environment(\.themeExpansionManager) private var themeExpansion
|
|
|
|
private var backgroundStyle: BackgroundStyle { themeExpansion?.backgroundStyle(for: appThemeRaw) ?? AppTheme.system.backgroundStyle }
|
|
private var preferredScheme: ColorScheme? { themeExpansion?.preferredColorScheme(for: appThemeRaw) }
|
|
|
|
init(tool: MiniToolBundle, toolInfo: ToolInfo) {
|
|
self.tool = tool
|
|
self.toolInfo = toolInfo
|
|
_runtime = StateObject(wrappedValue: MiniToolRuntime(tool: tool, toolInfo: toolInfo))
|
|
}
|
|
|
|
var body: some View {
|
|
ZStack {
|
|
ThemedBackground(style: backgroundStyle)
|
|
.ignoresSafeArea()
|
|
|
|
VStack(spacing: 12) {
|
|
MiniToolWebContainer(runtime: runtime)
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 16, style: .continuous))
|
|
.overlay(
|
|
RoundedRectangle(cornerRadius: 16, style: .continuous)
|
|
.strokeBorder(Color.white.opacity(0.12), lineWidth: 1)
|
|
)
|
|
.clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
|
|
|
|
if !runtime.logs.isEmpty && showLogs {
|
|
logList
|
|
}
|
|
}
|
|
.padding(16)
|
|
}
|
|
.navigationTitle(tool.name)
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.onAppear {
|
|
if !initiated {
|
|
runtime.start()
|
|
initiated = true
|
|
}
|
|
}
|
|
.toolbar {
|
|
ToolbarItemGroup(placement: .navigationBarTrailing) {
|
|
Button {
|
|
showLogs.toggle()
|
|
} label: {
|
|
Label("Toggle Log", systemImage: "bubble.left")
|
|
}
|
|
Button {
|
|
runtime.reload()
|
|
} label: {
|
|
Label("Reload", systemImage: "arrow.clockwise")
|
|
}
|
|
}
|
|
}
|
|
.preferredColorScheme(preferredScheme)
|
|
}
|
|
|
|
private var logList: some View {
|
|
VStack(alignment: .leading, spacing: 8) {
|
|
HStack {
|
|
Label("Messages", systemImage: "bubble.left")
|
|
.font(.subheadline.weight(.semibold))
|
|
Spacer()
|
|
}
|
|
ScrollViewReader { proxy in
|
|
ScrollView {
|
|
LazyVStack(alignment: .leading, spacing: 6) {
|
|
ForEach(Array(runtime.logs.enumerated()), id: \.offset) { index, line in
|
|
Text(line)
|
|
.font(.caption.monospaced())
|
|
.id(index)
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
}
|
|
}
|
|
}
|
|
.onChange(of: runtime.logs.count) { _, newCount in
|
|
guard newCount > 0 else { return }
|
|
withAnimation { proxy.scrollTo(newCount - 1, anchor: .bottom) }
|
|
}
|
|
}
|
|
}
|
|
.padding(12)
|
|
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 12, style: .continuous))
|
|
.overlay(
|
|
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
|
.strokeBorder(Color.white.opacity(0.12), lineWidth: 1)
|
|
)
|
|
}
|
|
}
|
|
|
|
private struct MiniToolWebContainer: UIViewRepresentable {
|
|
@ObservedObject var runtime: MiniToolRuntime
|
|
|
|
func makeUIView(context: Context) -> WKWebView {
|
|
runtime.webView!
|
|
}
|
|
|
|
func updateUIView(_ uiView: WKWebView, context: Context) {
|
|
}
|
|
}
|