import Library import NetworkExtension import SwiftUI @MainActor public struct ToolsView: View { @EnvironmentObject private var environments: ExtensionEnvironments @StateObject private var viewModel = SettingViewModel() @StateObject private var tailscaleViewModel = TailscaleStatusViewModel() #if os(iOS) @State private var showCrashReportList = false @State private var showOOMReportList = false #endif public init() {} public var body: some View { FormView { if !tailscaleViewModel.endpoints.isEmpty { Section("Endpoints") { ForEach(tailscaleViewModel.endpoints) { endpoint in FormNavigationLink { TailscaleEndpointView(viewModel: tailscaleViewModel, endpointTag: endpoint.endpointTag) } label: { if tailscaleViewModel.endpoints.count == 1 { Label("Tailscale", systemImage: "point.3.filled.connected.trianglepath.dotted") } else { Label("Tailscale: \(endpoint.endpointTag)", systemImage: "point.3.filled.connected.trianglepath.dotted") } } } } } Section("Network") { FormNavigationLink { NetworkQualityView() } label: { Label("Network Quality", systemImage: "network") } FormNavigationLink { STUNTestView() } label: { Label("STUN Test", systemImage: "arrow.triangle.swap") } } Section("Debug") { #if os(iOS) NavigationLink(isActive: $showCrashReportList) { CrashReportListView() } label: { Label("Crash Report", systemImage: "ladybug.fill") .badge(environments.crashReportManager.unreadCount) } .onReceive(NotificationCenter.default.publisher(for: .reportReceived)) { notification in Task { try? await Task.sleep(nanoseconds: NSEC_PER_MSEC * 300) if let reportType = notification.object as? ReportType { switch reportType { case .crash: showCrashReportList = true case .oom: showOOMReportList = true } } } } NavigationLink(isActive: $showOOMReportList) { OOMReportListView() } label: { Label("OOM Report", systemImage: "memorychip") .badge(environments.oomReportManager.unreadCount) } #else FormNavigationLink { CrashReportListView() } label: { #if os(tvOS) HStack { Label("Crash Report", systemImage: "ladybug.fill") Spacer() if environments.crashReportManager.unreadCount > 0 { Text(verbatim: "\(environments.crashReportManager.unreadCount)") .foregroundStyle(.secondary) } } #else Label("Crash Report", systemImage: "ladybug.fill") .badge(environments.crashReportManager.unreadCount) #endif } #endif #if !os(iOS) FormNavigationLink { OOMReportListView() } label: { #if os(tvOS) HStack { Label("OOM Report", systemImage: "memorychip") Spacer() if environments.oomReportManager.unreadCount > 0 { Text(verbatim: "\(environments.oomReportManager.unreadCount)") .foregroundStyle(.secondary) } } #else Label("OOM Report", systemImage: "memorychip") .badge(environments.oomReportManager.unreadCount) #endif } #endif FormTextItem("Taiwan Flag Available", "touchid") { if viewModel.isLoading { Text("Loading...") .onAppear { Task.detached { await viewModel.checkTaiwanFlagAvailability() } } } else { Text(viewModel.taiwanFlagAvailable.toString()) } } } } .modifier(TailscaleStatusObserver(profile: environments.extensionProfile, viewModel: tailscaleViewModel)) .alert($tailscaleViewModel.alert) } } private struct TailscaleStatusObserver: ViewModifier { var profile: ExtensionProfile? var viewModel: TailscaleStatusViewModel func body(content: Content) -> some View { if let profile { content .modifier(ActiveObserver(profile: profile, viewModel: viewModel)) } else { content } } private struct ActiveObserver: ViewModifier { @ObservedObject var profile: ExtensionProfile var viewModel: TailscaleStatusViewModel func body(content: Content) -> some View { content .onChangeCompat(of: profile.status) { status in if status.isConnectedStrict { viewModel.subscribe() } else { viewModel.cancel() } } .onAppear { if profile.status.isConnectedStrict { viewModel.subscribe() } } } } }