From b0e93655185ded317cdb3a1a90495ddcbd0637b6 Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Wed, 31 May 2023 23:56:25 +0800 Subject: [PATCH 01/11] init. --- ClashX Dashboard Kit/.gitignore | 9 + ClashX Dashboard Kit/Package.swift | 47 ++ ClashX Dashboard Kit/README.md | 3 + .../ClashX Links/ApiRequest.swift | 0 .../Extensions/DateFormatter+.swift | 0 .../Extensions/String+Encode.swift | 0 .../General/Managers/ConfigManager.swift | 0 .../ClashX Links/Logger.swift | 0 .../ClashX Links/Models/ClashConfig.swift | 0 .../ClashX Links/Models/ClashConnection.swift | 0 .../ClashX Links/Models/ClashProvider.swift | 0 .../ClashX Links/Models/ClashProxy.swift | 0 .../ClashX Links/Models/ClashRule.swift | 0 .../Models/ClashRuleProvider.swift | 0 .../ClashX_Dashboard_Kit.swift | 13 + .../Models/DBConnectionSnapShot.swift | 0 .../Models/DBProviderStorage.swift | 0 .../Models/DBProxyStorage.swift | 0 .../Views/APISetting/APIServerItem.swift | 0 .../Views/APISetting/APISettingView.swift | 0 .../APISetting/ClashServerAppStorage.swift | 0 .../Views/APISetting/ProgressButton.swift | 0 .../Views/ArrayExtensions.swift | 0 .../Views/ClashApiDatasStorage.swift | 0 .../ContentTabs/Config/ConfigItemView.swift | 0 .../Views/ContentTabs/Config/ConfigView.swift | 0 .../Connections/CollectionTableCellView.xib | 0 .../Connections/CollectionsTableView.swift | 0 .../ContentTabs/Connections/Connections.swift | 0 .../Connections/ConnectionsView.swift | 0 .../Views/ContentTabs/Logs/LogsView.swift | 0 .../Overview/OverviewTopItemView.swift | 0 .../ContentTabs/Overview/OverviewView.swift | 0 .../Overview/TrafficGraphView.swift | 0 .../Providers/ProviderProxiesView.swift | 0 .../Providers/ProviderRowView.swift | 0 .../ContentTabs/Providers/ProvidersView.swift | 0 .../Providers/ProxyProviderInfoView.swift | 0 .../Providers/ProxyProvidersRowView.swift | 0 .../Providers/RuleProviderView.swift | 0 .../Providers/RuleProvidersRowView.swift | 0 .../ContentTabs/Proxies/ProxiesView.swift | 0 .../Proxies/ProxyGroupRowView.swift | 0 .../ContentTabs/Proxies/ProxyGroupView.swift | 0 .../ContentTabs/Proxies/ProxyItemView.swift | 0 .../ContentTabs/Rules/RuleItemView.swift | 0 .../Views/ContentTabs/Rules/RulesView.swift | 0 .../Views/ContentView.swift | 0 .../Views/SidebarView/SidebarItem.swift | 0 .../Views/SidebarView/SidebarItemView.swift | 0 .../Views/SidebarView/SidebarListView.swift | 0 .../Views/SidebarView/SidebarView.swift | 0 .../Views/SwiftUIViewExtensions.swift | 0 .../ClashX_Dashboard_KitTests.swift | 11 + ClashX Dashboard.xcodeproj/project.pbxproj | 457 +----------------- ClashX Dashboard/ClashX_DashboardApp.swift | 3 +- 56 files changed, 95 insertions(+), 448 deletions(-) create mode 100644 ClashX Dashboard Kit/.gitignore create mode 100644 ClashX Dashboard Kit/Package.swift create mode 100644 ClashX Dashboard Kit/README.md rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/ClashX Links/ApiRequest.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/ClashX Links/Extensions/DateFormatter+.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/ClashX Links/Extensions/String+Encode.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/ClashX Links/General/Managers/ConfigManager.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/ClashX Links/Logger.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/ClashX Links/Models/ClashConfig.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/ClashX Links/Models/ClashConnection.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/ClashX Links/Models/ClashProvider.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/ClashX Links/Models/ClashProxy.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/ClashX Links/Models/ClashRule.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/ClashX Links/Models/ClashRuleProvider.swift (100%) create mode 100644 ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX_Dashboard_Kit.swift rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Models/DBConnectionSnapShot.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Models/DBProviderStorage.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Models/DBProxyStorage.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/APISetting/APIServerItem.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/APISetting/APISettingView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/APISetting/ClashServerAppStorage.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/APISetting/ProgressButton.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ArrayExtensions.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ClashApiDatasStorage.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Config/ConfigItemView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Config/ConfigView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Connections/CollectionTableCellView.xib (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Connections/CollectionsTableView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Connections/Connections.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Connections/ConnectionsView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Logs/LogsView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Overview/OverviewTopItemView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Overview/OverviewView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Overview/TrafficGraphView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Providers/ProviderProxiesView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Providers/ProviderRowView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Providers/ProvidersView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Providers/ProxyProviderInfoView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Providers/ProxyProvidersRowView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Providers/RuleProviderView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Providers/RuleProvidersRowView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Proxies/ProxiesView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Proxies/ProxyGroupRowView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Proxies/ProxyGroupView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Proxies/ProxyItemView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Rules/RuleItemView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentTabs/Rules/RulesView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/ContentView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/SidebarView/SidebarItem.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/SidebarView/SidebarItemView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/SidebarView/SidebarListView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/SidebarView/SidebarView.swift (100%) rename {ClashX Dashboard => ClashX Dashboard Kit/Sources/ClashX Dashboard Kit}/Views/SwiftUIViewExtensions.swift (100%) create mode 100644 ClashX Dashboard Kit/Tests/ClashX Dashboard KitTests/ClashX_Dashboard_KitTests.swift diff --git a/ClashX Dashboard Kit/.gitignore b/ClashX Dashboard Kit/.gitignore new file mode 100644 index 0000000..3b29812 --- /dev/null +++ b/ClashX Dashboard Kit/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/ClashX Dashboard Kit/Package.swift b/ClashX Dashboard Kit/Package.swift new file mode 100644 index 0000000..fee3204 --- /dev/null +++ b/ClashX Dashboard Kit/Package.swift @@ -0,0 +1,47 @@ +// swift-tools-version: 5.7 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "ClashX Dashboard Kit", + platforms: [ + .macOS(.v12), + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "ClashX Dashboard Kit", + targets: ["ClashX Dashboard Kit"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.0.0"), + .package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", from: "5.0.0"), + .package(url: "https://github.com/daltoniam/Starscream.git", exact: "3.1.1"), + .package(url: "https://github.com/CocoaLumberjack/CocoaLumberjack.git", from: "3.0.0"), + .package(url: "https://github.com/ra1028/DifferenceKit.git", from: "1.0.0"), + .package(url: "https://github.com/dagronf/DSFSparkline.git", from: "4.0.0"), + .package(url: "https://github.com/siteline/SwiftUI-Introspect.git", from: "0.2.3"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "ClashX Dashboard Kit", + dependencies: [ + "Alamofire", + "CocoaLumberjack", + .product(name: "CocoaLumberjackSwift", package: "CocoaLumberjack"), + "DifferenceKit", + "DSFSparkline", + .product(name: "Introspect", package: "SwiftUI-Introspect"), + "Starscream", + "SwiftyJSON", + + ]), + .testTarget( + name: "ClashX Dashboard KitTests", + dependencies: ["ClashX Dashboard Kit"]), + ] +) diff --git a/ClashX Dashboard Kit/README.md b/ClashX Dashboard Kit/README.md new file mode 100644 index 0000000..d3e3905 --- /dev/null +++ b/ClashX Dashboard Kit/README.md @@ -0,0 +1,3 @@ +# ClashX Dashboard Kit + +A description of this package. diff --git a/ClashX Dashboard/ClashX Links/ApiRequest.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/ApiRequest.swift similarity index 100% rename from ClashX Dashboard/ClashX Links/ApiRequest.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/ApiRequest.swift diff --git a/ClashX Dashboard/ClashX Links/Extensions/DateFormatter+.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Extensions/DateFormatter+.swift similarity index 100% rename from ClashX Dashboard/ClashX Links/Extensions/DateFormatter+.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Extensions/DateFormatter+.swift diff --git a/ClashX Dashboard/ClashX Links/Extensions/String+Encode.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Extensions/String+Encode.swift similarity index 100% rename from ClashX Dashboard/ClashX Links/Extensions/String+Encode.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Extensions/String+Encode.swift diff --git a/ClashX Dashboard/ClashX Links/General/Managers/ConfigManager.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/General/Managers/ConfigManager.swift similarity index 100% rename from ClashX Dashboard/ClashX Links/General/Managers/ConfigManager.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/General/Managers/ConfigManager.swift diff --git a/ClashX Dashboard/ClashX Links/Logger.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Logger.swift similarity index 100% rename from ClashX Dashboard/ClashX Links/Logger.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Logger.swift diff --git a/ClashX Dashboard/ClashX Links/Models/ClashConfig.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Models/ClashConfig.swift similarity index 100% rename from ClashX Dashboard/ClashX Links/Models/ClashConfig.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Models/ClashConfig.swift diff --git a/ClashX Dashboard/ClashX Links/Models/ClashConnection.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Models/ClashConnection.swift similarity index 100% rename from ClashX Dashboard/ClashX Links/Models/ClashConnection.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Models/ClashConnection.swift diff --git a/ClashX Dashboard/ClashX Links/Models/ClashProvider.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Models/ClashProvider.swift similarity index 100% rename from ClashX Dashboard/ClashX Links/Models/ClashProvider.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Models/ClashProvider.swift diff --git a/ClashX Dashboard/ClashX Links/Models/ClashProxy.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Models/ClashProxy.swift similarity index 100% rename from ClashX Dashboard/ClashX Links/Models/ClashProxy.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Models/ClashProxy.swift diff --git a/ClashX Dashboard/ClashX Links/Models/ClashRule.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Models/ClashRule.swift similarity index 100% rename from ClashX Dashboard/ClashX Links/Models/ClashRule.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Models/ClashRule.swift diff --git a/ClashX Dashboard/ClashX Links/Models/ClashRuleProvider.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Models/ClashRuleProvider.swift similarity index 100% rename from ClashX Dashboard/ClashX Links/Models/ClashRuleProvider.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX Links/Models/ClashRuleProvider.swift diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX_Dashboard_Kit.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX_Dashboard_Kit.swift new file mode 100644 index 0000000..de23b0d --- /dev/null +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/ClashX_Dashboard_Kit.swift @@ -0,0 +1,13 @@ +import SwiftUI + +@available(macOS 12.0, *) +public struct DashboardView: View { + + public init() { + + } + + public var body: some View { + ContentView() + } +} diff --git a/ClashX Dashboard/Models/DBConnectionSnapShot.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Models/DBConnectionSnapShot.swift similarity index 100% rename from ClashX Dashboard/Models/DBConnectionSnapShot.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Models/DBConnectionSnapShot.swift diff --git a/ClashX Dashboard/Models/DBProviderStorage.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Models/DBProviderStorage.swift similarity index 100% rename from ClashX Dashboard/Models/DBProviderStorage.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Models/DBProviderStorage.swift diff --git a/ClashX Dashboard/Models/DBProxyStorage.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Models/DBProxyStorage.swift similarity index 100% rename from ClashX Dashboard/Models/DBProxyStorage.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Models/DBProxyStorage.swift diff --git a/ClashX Dashboard/Views/APISetting/APIServerItem.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/APISetting/APIServerItem.swift similarity index 100% rename from ClashX Dashboard/Views/APISetting/APIServerItem.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/APISetting/APIServerItem.swift diff --git a/ClashX Dashboard/Views/APISetting/APISettingView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/APISetting/APISettingView.swift similarity index 100% rename from ClashX Dashboard/Views/APISetting/APISettingView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/APISetting/APISettingView.swift diff --git a/ClashX Dashboard/Views/APISetting/ClashServerAppStorage.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/APISetting/ClashServerAppStorage.swift similarity index 100% rename from ClashX Dashboard/Views/APISetting/ClashServerAppStorage.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/APISetting/ClashServerAppStorage.swift diff --git a/ClashX Dashboard/Views/APISetting/ProgressButton.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/APISetting/ProgressButton.swift similarity index 100% rename from ClashX Dashboard/Views/APISetting/ProgressButton.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/APISetting/ProgressButton.swift diff --git a/ClashX Dashboard/Views/ArrayExtensions.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ArrayExtensions.swift similarity index 100% rename from ClashX Dashboard/Views/ArrayExtensions.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ArrayExtensions.swift diff --git a/ClashX Dashboard/Views/ClashApiDatasStorage.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ClashApiDatasStorage.swift similarity index 100% rename from ClashX Dashboard/Views/ClashApiDatasStorage.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ClashApiDatasStorage.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Config/ConfigItemView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Config/ConfigItemView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Config/ConfigItemView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Config/ConfigItemView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Config/ConfigView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Config/ConfigView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Config/ConfigView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Config/ConfigView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Connections/CollectionTableCellView.xib b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionTableCellView.xib similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Connections/CollectionTableCellView.xib rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionTableCellView.xib diff --git a/ClashX Dashboard/Views/ContentTabs/Connections/CollectionsTableView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionsTableView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Connections/CollectionsTableView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionsTableView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Connections/Connections.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/Connections.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Connections/Connections.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/Connections.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Connections/ConnectionsView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/ConnectionsView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Connections/ConnectionsView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/ConnectionsView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Logs/LogsView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Logs/LogsView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Logs/LogsView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Logs/LogsView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Overview/OverviewTopItemView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Overview/OverviewTopItemView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Overview/OverviewTopItemView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Overview/OverviewTopItemView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Overview/OverviewView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Overview/OverviewView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Overview/OverviewView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Overview/OverviewView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Overview/TrafficGraphView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Overview/TrafficGraphView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Overview/TrafficGraphView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Overview/TrafficGraphView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Providers/ProviderProxiesView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/ProviderProxiesView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Providers/ProviderProxiesView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/ProviderProxiesView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Providers/ProviderRowView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/ProviderRowView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Providers/ProviderRowView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/ProviderRowView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Providers/ProvidersView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/ProvidersView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Providers/ProvidersView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/ProvidersView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Providers/ProxyProviderInfoView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/ProxyProviderInfoView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Providers/ProxyProviderInfoView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/ProxyProviderInfoView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Providers/ProxyProvidersRowView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/ProxyProvidersRowView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Providers/ProxyProvidersRowView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/ProxyProvidersRowView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Providers/RuleProviderView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/RuleProviderView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Providers/RuleProviderView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/RuleProviderView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Providers/RuleProvidersRowView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/RuleProvidersRowView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Providers/RuleProvidersRowView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/RuleProvidersRowView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Proxies/ProxiesView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Proxies/ProxiesView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Proxies/ProxiesView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Proxies/ProxiesView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Proxies/ProxyGroupRowView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Proxies/ProxyGroupRowView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Proxies/ProxyGroupRowView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Proxies/ProxyGroupRowView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Proxies/ProxyGroupView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Proxies/ProxyGroupView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Proxies/ProxyGroupView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Proxies/ProxyGroupView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Proxies/ProxyItemView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Proxies/ProxyItemView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Proxies/ProxyItemView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Proxies/ProxyItemView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Rules/RuleItemView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Rules/RuleItemView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Rules/RuleItemView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Rules/RuleItemView.swift diff --git a/ClashX Dashboard/Views/ContentTabs/Rules/RulesView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Rules/RulesView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentTabs/Rules/RulesView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Rules/RulesView.swift diff --git a/ClashX Dashboard/Views/ContentView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentView.swift similarity index 100% rename from ClashX Dashboard/Views/ContentView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentView.swift diff --git a/ClashX Dashboard/Views/SidebarView/SidebarItem.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarItem.swift similarity index 100% rename from ClashX Dashboard/Views/SidebarView/SidebarItem.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarItem.swift diff --git a/ClashX Dashboard/Views/SidebarView/SidebarItemView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarItemView.swift similarity index 100% rename from ClashX Dashboard/Views/SidebarView/SidebarItemView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarItemView.swift diff --git a/ClashX Dashboard/Views/SidebarView/SidebarListView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarListView.swift similarity index 100% rename from ClashX Dashboard/Views/SidebarView/SidebarListView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarListView.swift diff --git a/ClashX Dashboard/Views/SidebarView/SidebarView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarView.swift similarity index 100% rename from ClashX Dashboard/Views/SidebarView/SidebarView.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarView.swift diff --git a/ClashX Dashboard/Views/SwiftUIViewExtensions.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SwiftUIViewExtensions.swift similarity index 100% rename from ClashX Dashboard/Views/SwiftUIViewExtensions.swift rename to ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SwiftUIViewExtensions.swift diff --git a/ClashX Dashboard Kit/Tests/ClashX Dashboard KitTests/ClashX_Dashboard_KitTests.swift b/ClashX Dashboard Kit/Tests/ClashX Dashboard KitTests/ClashX_Dashboard_KitTests.swift new file mode 100644 index 0000000..3638d71 --- /dev/null +++ b/ClashX Dashboard Kit/Tests/ClashX Dashboard KitTests/ClashX_Dashboard_KitTests.swift @@ -0,0 +1,11 @@ +import XCTest +@testable import ClashX_Dashboard_Kit + +final class ClashX_Dashboard_KitTests: XCTestCase { + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + XCTAssertEqual(ClashX_Dashboard_Kit().text, "Hello, World!") + } +} diff --git a/ClashX Dashboard.xcodeproj/project.pbxproj b/ClashX Dashboard.xcodeproj/project.pbxproj index db35c82..938032a 100644 --- a/ClashX Dashboard.xcodeproj/project.pbxproj +++ b/ClashX Dashboard.xcodeproj/project.pbxproj @@ -7,122 +7,19 @@ objects = { /* Begin PBXBuildFile section */ - 010F693B29ED639A00BAAFB5 /* ClashServerAppStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 010F693A29ED639A00BAAFB5 /* ClashServerAppStorage.swift */; }; - 01359A392A21D88B00A2B3FB /* SidebarListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01359A382A21D88B00A2B3FB /* SidebarListView.swift */; }; - 01505C4A2A147B84001ACC4F /* DBProviderStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01505C492A147B84001ACC4F /* DBProviderStorage.swift */; }; - 01505C4C2A14A1A3001ACC4F /* ProviderRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01505C4B2A14A1A3001ACC4F /* ProviderRowView.swift */; }; - 01505C4E2A14AAEB001ACC4F /* ProviderProxiesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01505C4D2A14AAEB001ACC4F /* ProviderProxiesView.swift */; }; - 015278082A15F9FD00516236 /* ProxyProviderInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 015278072A15F9FD00516236 /* ProxyProviderInfoView.swift */; }; - 0155D39629F2342F00869830 /* TrafficGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0155D39529F2342F00869830 /* TrafficGraphView.swift */; }; - 0155D39829F23BDE00869830 /* OverviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0155D39729F23BDE00869830 /* OverviewView.swift */; }; - 0172CB5129E5AE670072DDEF /* SwiftUIViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0172CB5029E5AE670072DDEF /* SwiftUIViewExtensions.swift */; }; - 0172F12F2A1FB06100EE2B6D /* DateFormatter+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0172F12C2A1FB06100EE2B6D /* DateFormatter+.swift */; }; - 0172F1312A1FB06100EE2B6D /* String+Encode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0172F12E2A1FB06100EE2B6D /* String+Encode.swift */; }; - 0172F1352A1FB0B900EE2B6D /* ConfigManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0172F1342A1FB0B900EE2B6D /* ConfigManager.swift */; }; - 0172F1372A1FB0CD00EE2B6D /* ApiRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0172F1362A1FB0CD00EE2B6D /* ApiRequest.swift */; }; - 0172F1392A1FB0E900EE2B6D /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0172F1382A1FB0E900EE2B6D /* Logger.swift */; }; - 0172F1412A1FB10D00EE2B6D /* DBConnectionSnapShot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0172F13B2A1FB10C00EE2B6D /* DBConnectionSnapShot.swift */; }; - 0172F1422A1FB10D00EE2B6D /* ClashRuleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0172F13C2A1FB10D00EE2B6D /* ClashRuleProvider.swift */; }; - 0172F1432A1FB10D00EE2B6D /* ClashRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0172F13D2A1FB10D00EE2B6D /* ClashRule.swift */; }; - 0172F1442A1FB10D00EE2B6D /* ClashConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0172F13E2A1FB10D00EE2B6D /* ClashConfig.swift */; }; - 0172F1452A1FB10D00EE2B6D /* ClashProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0172F13F2A1FB10D00EE2B6D /* ClashProvider.swift */; }; - 0172F1462A1FB10D00EE2B6D /* ClashProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0172F1402A1FB10D00EE2B6D /* ClashProxy.swift */; }; - 0172F1482A1FB90200EE2B6D /* ClashConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0172F1472A1FB90200EE2B6D /* ClashConnection.swift */; }; - 017753C029EF7FB2006999DB /* APIServerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017753BF29EF7FB1006999DB /* APIServerItem.swift */; }; - 017DCADD29E83BFD00B9622A /* RuleProviderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017DCADC29E83BFD00B9622A /* RuleProviderView.swift */; }; - 017F9AAA2A0DFEBD00B81497 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 017F9AA92A0DFEBD00B81497 /* Introspect */; }; - 017F9AAC2A0E0B2300B81497 /* ProxyGroupRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017F9AAB2A0E0B2300B81497 /* ProxyGroupRowView.swift */; }; - 018003B12A136DDB0070226E /* ProvidersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 018003B02A136DDB0070226E /* ProvidersView.swift */; }; - 018A61BD29E9A2ED008608C0 /* APISettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 018A61BC29E9A2ED008608C0 /* APISettingView.swift */; }; - 018AFEA52A1B5F7A0076E66B /* ProgressButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 018AFEA42A1B5F7A0076E66B /* ProgressButton.swift */; }; - 018C836C29E17505006366D3 /* ClashApiDatasStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 018C836B29E17505006366D3 /* ClashApiDatasStorage.swift */; }; + 011BFE462A279D1C0027AD15 /* ClashX Dashboard Kit in Frameworks */ = {isa = PBXBuildFile; productRef = 011BFE452A279D1C0027AD15 /* ClashX Dashboard Kit */; }; 0192315F29DD4DCF00539EDD /* ClashX_DashboardApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0192315E29DD4DCF00539EDD /* ClashX_DashboardApp.swift */; }; - 0192316129DD4DCF00539EDD /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0192316029DD4DCF00539EDD /* ContentView.swift */; }; 0192316329DD4DD100539EDD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0192316229DD4DD100539EDD /* Assets.xcassets */; }; 0192316629DD4DD100539EDD /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0192316529DD4DD100539EDD /* Preview Assets.xcassets */; }; - 0192317129DD566000539EDD /* SidebarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0192317029DD566000539EDD /* SidebarView.swift */; }; - 0192317829DD5DA500539EDD /* ProxiesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0192317729DD5DA500539EDD /* ProxiesView.swift */; }; - 0192317A29DD5DB000539EDD /* RulesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0192317929DD5DB000539EDD /* RulesView.swift */; }; - 0192317C29DD5DF200539EDD /* ConnectionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0192317B29DD5DF200539EDD /* ConnectionsView.swift */; }; - 0192317E29DD5E0100539EDD /* ConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0192317D29DD5E0100539EDD /* ConfigView.swift */; }; - 0192318029DD5E0B00539EDD /* LogsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0192317F29DD5E0B00539EDD /* LogsView.swift */; }; - 0192318329DD70B400539EDD /* SidebarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0192318229DD70B400539EDD /* SidebarItem.swift */; }; - 0192318529DD7DCD00539EDD /* SidebarItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0192318429DD7DCD00539EDD /* SidebarItemView.swift */; }; - 0192318729DD83FF00539EDD /* OverviewTopItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0192318629DD83FF00539EDD /* OverviewTopItemView.swift */; }; - 0192B5BA29DE50F8002CDBF3 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 0192B5B929DE50F8002CDBF3 /* Alamofire */; }; - 0192B5BD29DE5113002CDBF3 /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 0192B5BC29DE5113002CDBF3 /* SwiftyJSON */; }; - 0192B5C029DE5134002CDBF3 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = 0192B5BF29DE5134002CDBF3 /* Starscream */; }; - 0192B5D429DE5190002CDBF3 /* CocoaLumberjackSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 0192B5D329DE5190002CDBF3 /* CocoaLumberjackSwift */; }; - 019D6A8729F015DF00A6AC02 /* ArrayExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 019D6A8629F015DF00A6AC02 /* ArrayExtensions.swift */; }; - 019D6A9629F194C600A6AC02 /* DSFSparkline in Frameworks */ = {isa = PBXBuildFile; productRef = 019D6A9529F194C600A6AC02 /* DSFSparkline */; }; - 01A351A229DD8F440054894E /* RuleItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A351A129DD8F440054894E /* RuleItemView.swift */; }; - 01A351A929DD9CB00054894E /* Connections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A351A829DD9CB00054894E /* Connections.swift */; }; - 01A3EF042A120103003038B5 /* DBProxyStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A3EF032A120103003038B5 /* DBProxyStorage.swift */; }; - 01CD0A9229E93ABB00F4C17E /* DifferenceKit in Frameworks */ = {isa = PBXBuildFile; productRef = 01CD0A9129E93ABB00F4C17E /* DifferenceKit */; }; - 01DCEFB12A150E8B00DBBDB3 /* RuleProvidersRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DCEFB02A150E8B00DBBDB3 /* RuleProvidersRowView.swift */; }; - 01DCEFB32A150FB300DBBDB3 /* ProxyProvidersRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DCEFB22A150FB300DBBDB3 /* ProxyProvidersRowView.swift */; }; - 01F5E3F42A1E53F4008F3DEB /* ConfigItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F5E3F32A1E53F4008F3DEB /* ConfigItemView.swift */; }; - 01F885CF29DFD8DF008241EB /* CollectionsTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F885CE29DFD8DF008241EB /* CollectionsTableView.swift */; }; - 01F885D129E03F20008241EB /* CollectionTableCellView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 01F885D029E03F20008241EB /* CollectionTableCellView.xib */; }; - 01F885D329E04E21008241EB /* ProxyGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F885D229E04E21008241EB /* ProxyGroupView.swift */; }; - 01F885D529E053DE008241EB /* ProxyItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F885D429E053DE008241EB /* ProxyItemView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 010F693A29ED639A00BAAFB5 /* ClashServerAppStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClashServerAppStorage.swift; sourceTree = ""; }; - 01359A382A21D88B00A2B3FB /* SidebarListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarListView.swift; sourceTree = ""; }; - 01505C492A147B84001ACC4F /* DBProviderStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBProviderStorage.swift; sourceTree = ""; }; - 01505C4B2A14A1A3001ACC4F /* ProviderRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderRowView.swift; sourceTree = ""; }; - 01505C4D2A14AAEB001ACC4F /* ProviderProxiesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderProxiesView.swift; sourceTree = ""; }; - 015278072A15F9FD00516236 /* ProxyProviderInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyProviderInfoView.swift; sourceTree = ""; }; - 0155D39529F2342F00869830 /* TrafficGraphView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrafficGraphView.swift; sourceTree = ""; }; - 0155D39729F23BDE00869830 /* OverviewView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverviewView.swift; sourceTree = ""; }; - 0172CB5029E5AE670072DDEF /* SwiftUIViewExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIViewExtensions.swift; sourceTree = ""; }; - 0172F12C2A1FB06100EE2B6D /* DateFormatter+.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DateFormatter+.swift"; sourceTree = ""; }; - 0172F12E2A1FB06100EE2B6D /* String+Encode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Encode.swift"; sourceTree = ""; }; - 0172F1342A1FB0B900EE2B6D /* ConfigManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigManager.swift; sourceTree = ""; }; - 0172F1362A1FB0CD00EE2B6D /* ApiRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApiRequest.swift; sourceTree = ""; }; - 0172F1382A1FB0E900EE2B6D /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; }; - 0172F13B2A1FB10C00EE2B6D /* DBConnectionSnapShot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DBConnectionSnapShot.swift; sourceTree = ""; }; - 0172F13C2A1FB10D00EE2B6D /* ClashRuleProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClashRuleProvider.swift; sourceTree = ""; }; - 0172F13D2A1FB10D00EE2B6D /* ClashRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClashRule.swift; sourceTree = ""; }; - 0172F13E2A1FB10D00EE2B6D /* ClashConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClashConfig.swift; sourceTree = ""; }; - 0172F13F2A1FB10D00EE2B6D /* ClashProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClashProvider.swift; sourceTree = ""; }; - 0172F1402A1FB10D00EE2B6D /* ClashProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClashProxy.swift; sourceTree = ""; }; - 0172F1472A1FB90200EE2B6D /* ClashConnection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClashConnection.swift; sourceTree = ""; }; - 017753BF29EF7FB1006999DB /* APIServerItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIServerItem.swift; sourceTree = ""; }; - 017DCADC29E83BFD00B9622A /* RuleProviderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleProviderView.swift; sourceTree = ""; }; - 017F9AAB2A0E0B2300B81497 /* ProxyGroupRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyGroupRowView.swift; sourceTree = ""; }; - 018003B02A136DDB0070226E /* ProvidersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProvidersView.swift; sourceTree = ""; }; - 018A61BC29E9A2ED008608C0 /* APISettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APISettingView.swift; sourceTree = ""; }; - 018AFEA42A1B5F7A0076E66B /* ProgressButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressButton.swift; sourceTree = ""; }; - 018C836B29E17505006366D3 /* ClashApiDatasStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClashApiDatasStorage.swift; sourceTree = ""; }; + 011BFE402A2799550027AD15 /* ClashX Dashboard Kit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = "ClashX Dashboard Kit"; sourceTree = ""; }; 0192315B29DD4DCF00539EDD /* ClashX Dashboard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ClashX Dashboard.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 0192315E29DD4DCF00539EDD /* ClashX_DashboardApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClashX_DashboardApp.swift; sourceTree = ""; }; - 0192316029DD4DCF00539EDD /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 0192316229DD4DD100539EDD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 0192316529DD4DD100539EDD /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 0192316729DD4DD100539EDD /* ClashX_Dashboard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ClashX_Dashboard.entitlements; sourceTree = ""; }; - 0192317029DD566000539EDD /* SidebarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarView.swift; sourceTree = ""; }; - 0192317729DD5DA500539EDD /* ProxiesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxiesView.swift; sourceTree = ""; }; - 0192317929DD5DB000539EDD /* RulesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RulesView.swift; sourceTree = ""; }; - 0192317B29DD5DF200539EDD /* ConnectionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionsView.swift; sourceTree = ""; }; - 0192317D29DD5E0100539EDD /* ConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigView.swift; sourceTree = ""; }; - 0192317F29DD5E0B00539EDD /* LogsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogsView.swift; sourceTree = ""; }; - 0192318229DD70B400539EDD /* SidebarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarItem.swift; sourceTree = ""; }; - 0192318429DD7DCD00539EDD /* SidebarItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarItemView.swift; sourceTree = ""; }; - 0192318629DD83FF00539EDD /* OverviewTopItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverviewTopItemView.swift; sourceTree = ""; }; - 019D6A8629F015DF00A6AC02 /* ArrayExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayExtensions.swift; sourceTree = ""; }; - 01A351A129DD8F440054894E /* RuleItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleItemView.swift; sourceTree = ""; }; - 01A351A829DD9CB00054894E /* Connections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Connections.swift; sourceTree = ""; }; - 01A3EF032A120103003038B5 /* DBProxyStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBProxyStorage.swift; sourceTree = ""; }; - 01DCEFB02A150E8B00DBBDB3 /* RuleProvidersRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleProvidersRowView.swift; sourceTree = ""; }; - 01DCEFB22A150FB300DBBDB3 /* ProxyProvidersRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyProvidersRowView.swift; sourceTree = ""; }; - 01F5E3F32A1E53F4008F3DEB /* ConfigItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigItemView.swift; sourceTree = ""; }; - 01F885CE29DFD8DF008241EB /* CollectionsTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionsTableView.swift; sourceTree = ""; }; - 01F885D029E03F20008241EB /* CollectionTableCellView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CollectionTableCellView.xib; sourceTree = ""; }; - 01F885D229E04E21008241EB /* ProxyGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyGroupView.swift; sourceTree = ""; }; - 01F885D429E053DE008241EB /* ProxyItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyItemView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -130,109 +27,27 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 0192B5BD29DE5113002CDBF3 /* SwiftyJSON in Frameworks */, - 0192B5BA29DE50F8002CDBF3 /* Alamofire in Frameworks */, - 019D6A9629F194C600A6AC02 /* DSFSparkline in Frameworks */, - 0192B5D429DE5190002CDBF3 /* CocoaLumberjackSwift in Frameworks */, - 017F9AAA2A0DFEBD00B81497 /* Introspect in Frameworks */, - 01CD0A9229E93ABB00F4C17E /* DifferenceKit in Frameworks */, - 0192B5C029DE5134002CDBF3 /* Starscream in Frameworks */, + 011BFE462A279D1C0027AD15 /* ClashX Dashboard Kit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 010F693929ED638B00BAAFB5 /* APISetting */ = { + 011BFE442A279D1C0027AD15 /* Frameworks */ = { isa = PBXGroup; children = ( - 018A61BC29E9A2ED008608C0 /* APISettingView.swift */, - 018AFEA42A1B5F7A0076E66B /* ProgressButton.swift */, - 017753BF29EF7FB1006999DB /* APIServerItem.swift */, - 010F693A29ED639A00BAAFB5 /* ClashServerAppStorage.swift */, ); - path = APISetting; - sourceTree = ""; - }; - 0172F12B2A1FB05900EE2B6D /* Extensions */ = { - isa = PBXGroup; - children = ( - 0172F12C2A1FB06100EE2B6D /* DateFormatter+.swift */, - 0172F12E2A1FB06100EE2B6D /* String+Encode.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 0172F1322A1FB0AA00EE2B6D /* General */ = { - isa = PBXGroup; - children = ( - 0172F1332A1FB0B000EE2B6D /* Managers */, - ); - path = General; - sourceTree = ""; - }; - 0172F1332A1FB0B000EE2B6D /* Managers */ = { - isa = PBXGroup; - children = ( - 0172F1342A1FB0B900EE2B6D /* ConfigManager.swift */, - ); - path = Managers; - sourceTree = ""; - }; - 0172F13A2A1FB10300EE2B6D /* Models */ = { - isa = PBXGroup; - children = ( - 0172F13E2A1FB10D00EE2B6D /* ClashConfig.swift */, - 0172F1472A1FB90200EE2B6D /* ClashConnection.swift */, - 0172F13F2A1FB10D00EE2B6D /* ClashProvider.swift */, - 0172F1402A1FB10D00EE2B6D /* ClashProxy.swift */, - 0172F13D2A1FB10D00EE2B6D /* ClashRule.swift */, - 0172F13C2A1FB10D00EE2B6D /* ClashRuleProvider.swift */, - ); - path = Models; - sourceTree = ""; - }; - 018003AF2A136D3E0070226E /* Providers */ = { - isa = PBXGroup; - children = ( - 018003B02A136DDB0070226E /* ProvidersView.swift */, - 01DCEFB22A150FB300DBBDB3 /* ProxyProvidersRowView.swift */, - 01DCEFB02A150E8B00DBBDB3 /* RuleProvidersRowView.swift */, - 017DCADC29E83BFD00B9622A /* RuleProviderView.swift */, - 01505C4B2A14A1A3001ACC4F /* ProviderRowView.swift */, - 01505C4D2A14AAEB001ACC4F /* ProviderProxiesView.swift */, - 015278072A15F9FD00516236 /* ProxyProviderInfoView.swift */, - ); - path = Providers; - sourceTree = ""; - }; - 018C836929E1703D006366D3 /* Logs */ = { - isa = PBXGroup; - children = ( - 0192317F29DD5E0B00539EDD /* LogsView.swift */, - ); - path = Logs; - sourceTree = ""; - }; - 018C836A29E174CB006366D3 /* Views */ = { - isa = PBXGroup; - children = ( - 0192316029DD4DCF00539EDD /* ContentView.swift */, - 018C836B29E17505006366D3 /* ClashApiDatasStorage.swift */, - 010F693929ED638B00BAAFB5 /* APISetting */, - 0192318129DD709500539EDD /* SidebarView */, - 0192317429DD5D7400539EDD /* ContentTabs */, - 019D6A8629F015DF00A6AC02 /* ArrayExtensions.swift */, - 0172CB5029E5AE670072DDEF /* SwiftUIViewExtensions.swift */, - ); - path = Views; + name = Frameworks; sourceTree = ""; }; 0192315229DD4DCF00539EDD = { isa = PBXGroup; children = ( + 011BFE402A2799550027AD15 /* ClashX Dashboard Kit */, 0192315D29DD4DCF00539EDD /* ClashX Dashboard */, 0192315C29DD4DCF00539EDD /* Products */, + 011BFE442A279D1C0027AD15 /* Frameworks */, ); sourceTree = ""; }; @@ -248,9 +63,6 @@ isa = PBXGroup; children = ( 0192315E29DD4DCF00539EDD /* ClashX_DashboardApp.swift */, - 01A3EF022A120032003038B5 /* Models */, - 018C836A29E174CB006366D3 /* Views */, - 0192B5B529DE506D002CDBF3 /* ClashX Links */, 0192316229DD4DD100539EDD /* Assets.xcassets */, 0192316729DD4DD100539EDD /* ClashX_Dashboard.entitlements */, 0192316429DD4DD100539EDD /* Preview Content */, @@ -266,103 +78,6 @@ path = "Preview Content"; sourceTree = ""; }; - 0192317429DD5D7400539EDD /* ContentTabs */ = { - isa = PBXGroup; - children = ( - 01A351A529DD9B2D0054894E /* Overview */, - 01A351A629DD9BB50054894E /* Proxies */, - 018003AF2A136D3E0070226E /* Providers */, - 01A351A029DD8F210054894E /* Rules */, - 01A351A729DD9C7F0054894E /* Connections */, - 01A7335F29E2CBD600205699 /* Config */, - 018C836929E1703D006366D3 /* Logs */, - ); - path = ContentTabs; - sourceTree = ""; - }; - 0192318129DD709500539EDD /* SidebarView */ = { - isa = PBXGroup; - children = ( - 0192317029DD566000539EDD /* SidebarView.swift */, - 01359A382A21D88B00A2B3FB /* SidebarListView.swift */, - 0192318429DD7DCD00539EDD /* SidebarItemView.swift */, - 0192318229DD70B400539EDD /* SidebarItem.swift */, - ); - path = SidebarView; - sourceTree = ""; - }; - 0192B5B529DE506D002CDBF3 /* ClashX Links */ = { - isa = PBXGroup; - children = ( - 0172F1362A1FB0CD00EE2B6D /* ApiRequest.swift */, - 0172F1382A1FB0E900EE2B6D /* Logger.swift */, - 0172F1322A1FB0AA00EE2B6D /* General */, - 0172F12B2A1FB05900EE2B6D /* Extensions */, - 0172F13A2A1FB10300EE2B6D /* Models */, - ); - path = "ClashX Links"; - sourceTree = ""; - }; - 01A351A029DD8F210054894E /* Rules */ = { - isa = PBXGroup; - children = ( - 0192317929DD5DB000539EDD /* RulesView.swift */, - 01A351A129DD8F440054894E /* RuleItemView.swift */, - ); - path = Rules; - sourceTree = ""; - }; - 01A351A529DD9B2D0054894E /* Overview */ = { - isa = PBXGroup; - children = ( - 0155D39729F23BDE00869830 /* OverviewView.swift */, - 0192318629DD83FF00539EDD /* OverviewTopItemView.swift */, - 0155D39529F2342F00869830 /* TrafficGraphView.swift */, - ); - path = Overview; - sourceTree = ""; - }; - 01A351A629DD9BB50054894E /* Proxies */ = { - isa = PBXGroup; - children = ( - 0192317729DD5DA500539EDD /* ProxiesView.swift */, - 017F9AAB2A0E0B2300B81497 /* ProxyGroupRowView.swift */, - 01F885D229E04E21008241EB /* ProxyGroupView.swift */, - 01F885D429E053DE008241EB /* ProxyItemView.swift */, - ); - path = Proxies; - sourceTree = ""; - }; - 01A351A729DD9C7F0054894E /* Connections */ = { - isa = PBXGroup; - children = ( - 0192317B29DD5DF200539EDD /* ConnectionsView.swift */, - 01A351A829DD9CB00054894E /* Connections.swift */, - 01F885CE29DFD8DF008241EB /* CollectionsTableView.swift */, - 01F885D029E03F20008241EB /* CollectionTableCellView.xib */, - ); - path = Connections; - sourceTree = ""; - }; - 01A3EF022A120032003038B5 /* Models */ = { - isa = PBXGroup; - children = ( - 01A3EF032A120103003038B5 /* DBProxyStorage.swift */, - 01505C492A147B84001ACC4F /* DBProviderStorage.swift */, - 0172F13B2A1FB10C00EE2B6D /* DBConnectionSnapShot.swift */, - ); - path = Models; - sourceTree = ""; - }; - 01A7335F29E2CBD600205699 /* Config */ = { - isa = PBXGroup; - children = ( - 0192317D29DD5E0100539EDD /* ConfigView.swift */, - 01F5E3F32A1E53F4008F3DEB /* ConfigItemView.swift */, - ); - path = Config; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -380,13 +95,7 @@ ); name = "ClashX Dashboard"; packageProductDependencies = ( - 0192B5B929DE50F8002CDBF3 /* Alamofire */, - 0192B5BC29DE5113002CDBF3 /* SwiftyJSON */, - 0192B5BF29DE5134002CDBF3 /* Starscream */, - 0192B5D329DE5190002CDBF3 /* CocoaLumberjackSwift */, - 01CD0A9129E93ABB00F4C17E /* DifferenceKit */, - 019D6A9529F194C600A6AC02 /* DSFSparkline */, - 017F9AA92A0DFEBD00B81497 /* Introspect */, + 011BFE452A279D1C0027AD15 /* ClashX Dashboard Kit */, ); productName = "ClashX Dashboard"; productReference = 0192315B29DD4DCF00539EDD /* ClashX Dashboard.app */; @@ -417,13 +126,6 @@ ); mainGroup = 0192315229DD4DCF00539EDD; packageReferences = ( - 0192B5B829DE50F8002CDBF3 /* XCRemoteSwiftPackageReference "Alamofire" */, - 0192B5BB29DE5113002CDBF3 /* XCRemoteSwiftPackageReference "SwiftyJSON" */, - 0192B5BE29DE5134002CDBF3 /* XCRemoteSwiftPackageReference "Starscream" */, - 0192B5D229DE5190002CDBF3 /* XCRemoteSwiftPackageReference "CocoaLumberjack" */, - 01CD0A9029E93ABB00F4C17E /* XCRemoteSwiftPackageReference "DifferenceKit" */, - 019D6A9429F194C600A6AC02 /* XCRemoteSwiftPackageReference "DSFSparkline" */, - 017F9AA82A0DFEBD00B81497 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */, ); productRefGroup = 0192315C29DD4DCF00539EDD /* Products */; projectDirPath = ""; @@ -440,7 +142,6 @@ buildActionMask = 2147483647; files = ( 0192316629DD4DD100539EDD /* Preview Assets.xcassets in Resources */, - 01F885D129E03F20008241EB /* CollectionTableCellView.xib in Resources */, 0192316329DD4DD100539EDD /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -452,55 +153,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0192317A29DD5DB000539EDD /* RulesView.swift in Sources */, - 019D6A8729F015DF00A6AC02 /* ArrayExtensions.swift in Sources */, - 01505C4C2A14A1A3001ACC4F /* ProviderRowView.swift in Sources */, - 0192316129DD4DCF00539EDD /* ContentView.swift in Sources */, - 01DCEFB32A150FB300DBBDB3 /* ProxyProvidersRowView.swift in Sources */, - 0192318729DD83FF00539EDD /* OverviewTopItemView.swift in Sources */, - 0192318029DD5E0B00539EDD /* LogsView.swift in Sources */, - 0172F1392A1FB0E900EE2B6D /* Logger.swift in Sources */, - 01505C4E2A14AAEB001ACC4F /* ProviderProxiesView.swift in Sources */, - 0172F1412A1FB10D00EE2B6D /* DBConnectionSnapShot.swift in Sources */, - 0192318529DD7DCD00539EDD /* SidebarItemView.swift in Sources */, - 0172F1442A1FB10D00EE2B6D /* ClashConfig.swift in Sources */, - 0172F1452A1FB10D00EE2B6D /* ClashProvider.swift in Sources */, - 0192317E29DD5E0100539EDD /* ConfigView.swift in Sources */, - 0155D39629F2342F00869830 /* TrafficGraphView.swift in Sources */, - 01A3EF042A120103003038B5 /* DBProxyStorage.swift in Sources */, - 0172F1432A1FB10D00EE2B6D /* ClashRule.swift in Sources */, - 017F9AAC2A0E0B2300B81497 /* ProxyGroupRowView.swift in Sources */, - 0172F1372A1FB0CD00EE2B6D /* ApiRequest.swift in Sources */, - 017DCADD29E83BFD00B9622A /* RuleProviderView.swift in Sources */, - 0192318329DD70B400539EDD /* SidebarItem.swift in Sources */, - 0155D39829F23BDE00869830 /* OverviewView.swift in Sources */, - 018C836C29E17505006366D3 /* ClashApiDatasStorage.swift in Sources */, - 018A61BD29E9A2ED008608C0 /* APISettingView.swift in Sources */, - 0172F1462A1FB10D00EE2B6D /* ClashProxy.swift in Sources */, - 010F693B29ED639A00BAAFB5 /* ClashServerAppStorage.swift in Sources */, - 01F885D329E04E21008241EB /* ProxyGroupView.swift in Sources */, 0192315F29DD4DCF00539EDD /* ClashX_DashboardApp.swift in Sources */, - 018003B12A136DDB0070226E /* ProvidersView.swift in Sources */, - 01A351A229DD8F440054894E /* RuleItemView.swift in Sources */, - 01F885D529E053DE008241EB /* ProxyItemView.swift in Sources */, - 0172F1312A1FB06100EE2B6D /* String+Encode.swift in Sources */, - 01359A392A21D88B00A2B3FB /* SidebarListView.swift in Sources */, - 01DCEFB12A150E8B00DBBDB3 /* RuleProvidersRowView.swift in Sources */, - 01F5E3F42A1E53F4008F3DEB /* ConfigItemView.swift in Sources */, - 0172F1352A1FB0B900EE2B6D /* ConfigManager.swift in Sources */, - 0192317129DD566000539EDD /* SidebarView.swift in Sources */, - 0192317C29DD5DF200539EDD /* ConnectionsView.swift in Sources */, - 0172F12F2A1FB06100EE2B6D /* DateFormatter+.swift in Sources */, - 017753C029EF7FB2006999DB /* APIServerItem.swift in Sources */, - 0172F1422A1FB10D00EE2B6D /* ClashRuleProvider.swift in Sources */, - 015278082A15F9FD00516236 /* ProxyProviderInfoView.swift in Sources */, - 0192317829DD5DA500539EDD /* ProxiesView.swift in Sources */, - 01F885CF29DFD8DF008241EB /* CollectionsTableView.swift in Sources */, - 0172F1482A1FB90200EE2B6D /* ClashConnection.swift in Sources */, - 018AFEA52A1B5F7A0076E66B /* ProgressButton.swift in Sources */, - 01505C4A2A147B84001ACC4F /* DBProviderStorage.swift in Sources */, - 0172CB5129E5AE670072DDEF /* SwiftUIViewExtensions.swift in Sources */, - 01A351A929DD9CB00054894E /* Connections.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -695,100 +348,10 @@ }; /* End XCConfigurationList section */ -/* Begin XCRemoteSwiftPackageReference section */ - 017F9AA82A0DFEBD00B81497 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/siteline/SwiftUI-Introspect"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 0.2.3; - }; - }; - 0192B5B829DE50F8002CDBF3 /* XCRemoteSwiftPackageReference "Alamofire" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/Alamofire/Alamofire"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 5.0.0; - }; - }; - 0192B5BB29DE5113002CDBF3 /* XCRemoteSwiftPackageReference "SwiftyJSON" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/SwiftyJSON/SwiftyJSON"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 5.0.0; - }; - }; - 0192B5BE29DE5134002CDBF3 /* XCRemoteSwiftPackageReference "Starscream" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/daltoniam/Starscream"; - requirement = { - kind = exactVersion; - version = 3.1.1; - }; - }; - 0192B5D229DE5190002CDBF3 /* XCRemoteSwiftPackageReference "CocoaLumberjack" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/CocoaLumberjack/CocoaLumberjack"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 3.0.0; - }; - }; - 019D6A9429F194C600A6AC02 /* XCRemoteSwiftPackageReference "DSFSparkline" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/dagronf/DSFSparkline"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 4.0.0; - }; - }; - 01CD0A9029E93ABB00F4C17E /* XCRemoteSwiftPackageReference "DifferenceKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ra1028/DifferenceKit"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.0.0; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - /* Begin XCSwiftPackageProductDependency section */ - 017F9AA92A0DFEBD00B81497 /* Introspect */ = { + 011BFE452A279D1C0027AD15 /* ClashX Dashboard Kit */ = { isa = XCSwiftPackageProductDependency; - package = 017F9AA82A0DFEBD00B81497 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */; - productName = Introspect; - }; - 0192B5B929DE50F8002CDBF3 /* Alamofire */ = { - isa = XCSwiftPackageProductDependency; - package = 0192B5B829DE50F8002CDBF3 /* XCRemoteSwiftPackageReference "Alamofire" */; - productName = Alamofire; - }; - 0192B5BC29DE5113002CDBF3 /* SwiftyJSON */ = { - isa = XCSwiftPackageProductDependency; - package = 0192B5BB29DE5113002CDBF3 /* XCRemoteSwiftPackageReference "SwiftyJSON" */; - productName = SwiftyJSON; - }; - 0192B5BF29DE5134002CDBF3 /* Starscream */ = { - isa = XCSwiftPackageProductDependency; - package = 0192B5BE29DE5134002CDBF3 /* XCRemoteSwiftPackageReference "Starscream" */; - productName = Starscream; - }; - 0192B5D329DE5190002CDBF3 /* CocoaLumberjackSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 0192B5D229DE5190002CDBF3 /* XCRemoteSwiftPackageReference "CocoaLumberjack" */; - productName = CocoaLumberjackSwift; - }; - 019D6A9529F194C600A6AC02 /* DSFSparkline */ = { - isa = XCSwiftPackageProductDependency; - package = 019D6A9429F194C600A6AC02 /* XCRemoteSwiftPackageReference "DSFSparkline" */; - productName = DSFSparkline; - }; - 01CD0A9129E93ABB00F4C17E /* DifferenceKit */ = { - isa = XCSwiftPackageProductDependency; - package = 01CD0A9029E93ABB00F4C17E /* XCRemoteSwiftPackageReference "DifferenceKit" */; - productName = DifferenceKit; + productName = "ClashX Dashboard Kit"; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/ClashX Dashboard/ClashX_DashboardApp.swift b/ClashX Dashboard/ClashX_DashboardApp.swift index c291fba..ca7e88c 100644 --- a/ClashX Dashboard/ClashX_DashboardApp.swift +++ b/ClashX Dashboard/ClashX_DashboardApp.swift @@ -5,12 +5,13 @@ // import SwiftUI +import ClashX_Dashboard_Kit @main struct ClashX_DashboardApp: App { var body: some Scene { WindowGroup { - ContentView() + DashboardView() } .commands { SidebarCommands() From 3340b37f3cbe2cf4a0ffe783747ed61a5e3945ef Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Thu, 1 Jun 2023 01:02:14 +0800 Subject: [PATCH 02/11] misc: ConnsTableCellView --- .../Connections/CollectionTableCellView.xib | 37 ------------- .../Connections/CollectionsTableView.swift | 55 +++++++++++++++++-- 2 files changed, 50 insertions(+), 42 deletions(-) delete mode 100644 ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionTableCellView.xib diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionTableCellView.xib b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionTableCellView.xib deleted file mode 100644 index aab0fcd..0000000 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionTableCellView.xib +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionsTableView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionsTableView.swift index 20e07ed..69d473e 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionsTableView.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionsTableView.swift @@ -55,8 +55,6 @@ struct CollectionsTableView: NSViewRepresentable { tableView.delegate = context.coordinator tableView.dataSource = context.coordinator - tableView.register(.init(nibNamed: .init("CollectionTableCellView"), bundle: .main), forIdentifier: .init(rawValue: "CollectionTableCellView")) - TableColumn.allCases.forEach { let tableColumn = NSTableColumn(identifier: .init($0.rawValue)) tableColumn.title = $0.rawValue @@ -174,14 +172,15 @@ struct CollectionsTableView: NSViewRepresentable { func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { - guard let cell = tableView.makeView(withIdentifier: .init(rawValue: "CollectionTableCellView"), owner: nil) as? NSTableCellView, + + guard let cellView = createCellView(tableView), let s = tableColumn?.identifier.rawValue.split(separator: ".").last, let tc = TableColumn(rawValue: String(s)) else { return nil } let conn = conns[row] - cell.textField?.objectValue = { + cellView.textField?.objectValue = { switch tc { case .host: return conn.host @@ -208,7 +207,7 @@ struct CollectionsTableView: NSViewRepresentable { } }() - return cell + return cellView } func tableView(_ tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) { @@ -216,6 +215,52 @@ struct CollectionsTableView: NSViewRepresentable { tableView.reloadData() } + func createCellView(_ tableView: NSTableView) -> NSTableCellView? { + // https://stackoverflow.com/a/27624927 + + var cellView: NSTableCellView? + if let spareView = tableView.makeView(withIdentifier: .init("ConnsTableCellView"), + owner: self) as? NSTableCellView { + + // We can use an old cell - no need to do anything. + cellView = spareView + + } else { + + // Create a text field for the cell + let textField = NSTextField() + textField.backgroundColor = NSColor.clear + textField.translatesAutoresizingMaskIntoConstraints = false + textField.isBordered = false + textField.font = .systemFont(ofSize: 13) + + // Create a cell + let newCell = NSTableCellView() + newCell.identifier = .init("ConnsTableCellView") + newCell.addSubview(textField) + newCell.textField = textField + + // Constrain the text field within the cell + newCell.addConstraints( + NSLayoutConstraint.constraints(withVisualFormat: "H:|[textField]|", + options: [], + metrics: nil, + views: ["textField" : textField])) + + newCell.addConstraint(.init(item: textField, attribute: .centerY, relatedBy: .equal, toItem: newCell, attribute: .centerY, multiplier: 1, constant: 0)) + + + textField.bind(NSBindingName.value, + to: newCell, + withKeyPath: "objectValue", + options: nil) + + cellView = newCell + } + + return cellView + } + } } From c0d2493e7aa12807f035d500ace4dfaaf2817531 Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Thu, 1 Jun 2023 21:41:17 +0800 Subject: [PATCH 03/11] misc: extension createCellView --- .../Connections/CollectionsTableView.swift | 95 ++++++++++--------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionsTableView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionsTableView.swift index 69d473e..7ef4eb1 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionsTableView.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionsTableView.swift @@ -173,7 +173,7 @@ struct CollectionsTableView: NSViewRepresentable { func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { - guard let cellView = createCellView(tableView), + guard let cellView = tableView.createCellView(with: "ConnsTableCellView"), let s = tableColumn?.identifier.rawValue.split(separator: ".").last, let tc = TableColumn(rawValue: String(s)) else { return nil } @@ -215,52 +215,7 @@ struct CollectionsTableView: NSViewRepresentable { tableView.reloadData() } - func createCellView(_ tableView: NSTableView) -> NSTableCellView? { - // https://stackoverflow.com/a/27624927 - - var cellView: NSTableCellView? - if let spareView = tableView.makeView(withIdentifier: .init("ConnsTableCellView"), - owner: self) as? NSTableCellView { - // We can use an old cell - no need to do anything. - cellView = spareView - - } else { - - // Create a text field for the cell - let textField = NSTextField() - textField.backgroundColor = NSColor.clear - textField.translatesAutoresizingMaskIntoConstraints = false - textField.isBordered = false - textField.font = .systemFont(ofSize: 13) - - // Create a cell - let newCell = NSTableCellView() - newCell.identifier = .init("ConnsTableCellView") - newCell.addSubview(textField) - newCell.textField = textField - - // Constrain the text field within the cell - newCell.addConstraints( - NSLayoutConstraint.constraints(withVisualFormat: "H:|[textField]|", - options: [], - metrics: nil, - views: ["textField" : textField])) - - newCell.addConstraint(.init(item: textField, attribute: .centerY, relatedBy: .equal, toItem: newCell, attribute: .centerY, multiplier: 1, constant: 0)) - - - textField.bind(NSBindingName.value, - to: newCell, - withKeyPath: "objectValue", - options: nil) - - cellView = newCell - } - - return cellView - } - } } @@ -313,4 +268,52 @@ extension NSTableView { } } + + func createCellView(with identifier: String) -> NSTableCellView? { + // https://stackoverflow.com/a/27624927 + + var cellView: NSTableCellView? + if let spareView = makeView(withIdentifier: .init(identifier), + owner: self) as? NSTableCellView { + + // We can use an old cell - no need to do anything. + cellView = spareView + + } else { + + // Create a text field for the cell + let textField = NSTextField() + textField.backgroundColor = NSColor.clear + textField.translatesAutoresizingMaskIntoConstraints = false + textField.isBordered = false + textField.font = .systemFont(ofSize: 13) + textField.lineBreakMode = .byTruncatingTail + + // Create a cell + let newCell = NSTableCellView() + newCell.identifier = .init(identifier) + newCell.addSubview(textField) + newCell.textField = textField + + // Constrain the text field within the cell + newCell.addConstraints( + NSLayoutConstraint.constraints(withVisualFormat: "H:|[textField]|", + options: [], + metrics: nil, + views: ["textField" : textField])) + + newCell.addConstraint(.init(item: textField, attribute: .centerY, relatedBy: .equal, toItem: newCell, attribute: .centerY, multiplier: 1, constant: 0)) + + + textField.bind(NSBindingName.value, + to: newCell, + withKeyPath: "objectValue", + options: nil) + + cellView = newCell + } + + return cellView + } + } From b8c4e4b74c104fa17914a595e712f6ec3ff2ee9e Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Sat, 3 Jun 2023 14:45:39 +0800 Subject: [PATCH 04/11] misc: AppDelegate --- ClashX Dashboard.xcodeproj/project.pbxproj | 12 + ClashX Dashboard/AppDelegate.swift | 22 + ClashX Dashboard/ClashX_DashboardApp.swift | 2 +- ClashX Dashboard/Main.storyboard | 684 +++++++++++++++++++++ 4 files changed, 719 insertions(+), 1 deletion(-) create mode 100644 ClashX Dashboard/AppDelegate.swift create mode 100644 ClashX Dashboard/Main.storyboard diff --git a/ClashX Dashboard.xcodeproj/project.pbxproj b/ClashX Dashboard.xcodeproj/project.pbxproj index 938032a..023a167 100644 --- a/ClashX Dashboard.xcodeproj/project.pbxproj +++ b/ClashX Dashboard.xcodeproj/project.pbxproj @@ -11,6 +11,8 @@ 0192315F29DD4DCF00539EDD /* ClashX_DashboardApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0192315E29DD4DCF00539EDD /* ClashX_DashboardApp.swift */; }; 0192316329DD4DD100539EDD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0192316229DD4DD100539EDD /* Assets.xcassets */; }; 0192316629DD4DD100539EDD /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0192316529DD4DD100539EDD /* Preview Assets.xcassets */; }; + 01A78B7F2A2B188F0058D1CA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 01A78B7E2A2B188E0058D1CA /* Main.storyboard */; }; + 01FE884C2A29BB590084902C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FE884B2A29BB590084902C /* AppDelegate.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -20,6 +22,8 @@ 0192316229DD4DD100539EDD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 0192316529DD4DD100539EDD /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 0192316729DD4DD100539EDD /* ClashX_Dashboard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ClashX_Dashboard.entitlements; sourceTree = ""; }; + 01A78B7E2A2B188E0058D1CA /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; + 01FE884B2A29BB590084902C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -63,6 +67,8 @@ isa = PBXGroup; children = ( 0192315E29DD4DCF00539EDD /* ClashX_DashboardApp.swift */, + 01FE884B2A29BB590084902C /* AppDelegate.swift */, + 01A78B7E2A2B188E0058D1CA /* Main.storyboard */, 0192316229DD4DD100539EDD /* Assets.xcassets */, 0192316729DD4DD100539EDD /* ClashX_Dashboard.entitlements */, 0192316429DD4DD100539EDD /* Preview Content */, @@ -141,6 +147,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 01A78B7F2A2B188F0058D1CA /* Main.storyboard in Resources */, 0192316629DD4DD100539EDD /* Preview Assets.xcassets in Resources */, 0192316329DD4DD100539EDD /* Assets.xcassets in Resources */, ); @@ -153,6 +160,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 01FE884C2A29BB590084902C /* AppDelegate.swift in Sources */, 0192315F29DD4DCF00539EDD /* ClashX_DashboardApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -286,6 +294,8 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSMainStoryboardFile = Main; + INFOPLIST_KEY_UILaunchStoryboardName = ""; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -312,6 +322,8 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSMainStoryboardFile = Main; + INFOPLIST_KEY_UILaunchStoryboardName = ""; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", diff --git a/ClashX Dashboard/AppDelegate.swift b/ClashX Dashboard/AppDelegate.swift new file mode 100644 index 0000000..4b7a0f8 --- /dev/null +++ b/ClashX Dashboard/AppDelegate.swift @@ -0,0 +1,22 @@ +// +// AppDelegate.swift +// ClashX Dashboard +// +// + +import Cocoa +import ClashX_Dashboard_Kit + + +@main +class AppDelegate: NSObject, NSApplicationDelegate { + + func applicationDidFinishLaunching(_ notification: Notification) { + + } + + + func applicationWillTerminate(_ notification: Notification) { + + } +} diff --git a/ClashX Dashboard/ClashX_DashboardApp.swift b/ClashX Dashboard/ClashX_DashboardApp.swift index ca7e88c..f492a15 100644 --- a/ClashX Dashboard/ClashX_DashboardApp.swift +++ b/ClashX Dashboard/ClashX_DashboardApp.swift @@ -7,7 +7,7 @@ import SwiftUI import ClashX_Dashboard_Kit -@main +//@main struct ClashX_DashboardApp: App { var body: some Scene { WindowGroup { diff --git a/ClashX Dashboard/Main.storyboard b/ClashX Dashboard/Main.storyboard new file mode 100644 index 0000000..77e2634 --- /dev/null +++ b/ClashX Dashboard/Main.storyboard @@ -0,0 +1,684 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 4ecc5bb3d1517e3e94492f6775f22a7153511dc5 Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Sat, 3 Jun 2023 14:46:31 +0800 Subject: [PATCH 05/11] feat: AppKit toolbar --- .../DashboardViewContoller.swift | 270 ++++++++++++++++++ .../NotificationNames.swift | 16 ++ .../Connections/ConnectionsView.swift | 13 +- .../Views/ContentTabs/Logs/LogsView.swift | 18 +- .../ContentTabs/Providers/ProvidersView.swift | 8 + .../ContentTabs/Proxies/ProxiesView.swift | 8 + .../Views/ContentTabs/Rules/RulesView.swift | 4 + .../Views/SidebarView/SidebarItem.swift | 31 +- .../Views/SidebarView/SidebarItemView.swift | 28 -- .../Views/SidebarView/SidebarListView.swift | 28 +- .../Views/SidebarView/SidebarView.swift | 13 + ClashX Dashboard/AppDelegate.swift | 13 + 12 files changed, 381 insertions(+), 69 deletions(-) create mode 100644 ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift create mode 100644 ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/NotificationNames.swift delete mode 100644 ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarItemView.swift diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift new file mode 100644 index 0000000..3badef1 --- /dev/null +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift @@ -0,0 +1,270 @@ +// +// DashboardViewContoller.swift +// ClashX +// +// Created by yicheng on 2018/8/28. +// Copyright © 2018年 west2online. All rights reserved. +// + +import Cocoa +import SwiftUI + +public class DashboardWindowController: NSWindowController { + public var onWindowClose: (() -> Void)? + + public static func create() -> DashboardWindowController { + let win = NSWindow() + win.center() + let wc = DashboardWindowController(window: win) + wc.contentViewController = DashboardViewContoller() + return wc + } + + public override func showWindow(_ sender: Any?) { + super.showWindow(sender) + NSApp.activate(ignoringOtherApps: true) + window?.makeKeyAndOrderFront(self) + window?.delegate = self + } +} + +extension DashboardWindowController: NSWindowDelegate { + public func windowWillClose(_ notification: Notification) { + NSApp.setActivationPolicy(.accessory) + onWindowClose?() + if let contentVC = contentViewController as? DashboardViewContoller, let win = window { + if !win.styleMask.contains(.fullScreen) { + contentVC.lastSize = win.frame.size + } + } + } +} + +class DashboardViewContoller: NSViewController { + let contentView = NSHostingView(rootView: DashboardView()) + let minSize = NSSize(width: 920, height: 580) + var lastSize: CGSize? { + set { + if let size = newValue { + UserDefaults.standard.set(NSStringFromSize(size), forKey: "ClashWebViewContoller.lastSize") + } + } + get { + if let str = UserDefaults.standard.value(forKey: "ClashWebViewContoller.lastSize") as? String { + return NSSizeFromString(str) as CGSize + } + return nil + } + } + + let effectView = NSVisualEffectView() + + private let levels = [ + ClashLogLevel.silent, + .error, + .warning, + .info, + .debug + ] + + private var sidebarItemObserver: NSObjectProtocol? + + func createWindowController() -> NSWindowController { + let sb = NSStoryboard(name: "Main", bundle: Bundle.main) + let vc = sb.instantiateController(withIdentifier: "DashboardViewContoller") as! DashboardViewContoller + let wc = NSWindowController(window: NSWindow()) + wc.contentViewController = vc + return wc + } + + override func loadView() { + view = contentView + } + + override func viewDidLoad() { + super.viewDidLoad() + + sidebarItemObserver = NotificationCenter.default.addObserver(forName: .sidebarItemChanged, object: nil, queue: .main) { + guard let item = $0.userInfo?["item"] as? SidebarItem else { return } + + var items = [NSToolbarItem.Identifier]() + items.append(.toggleSidebar) + + switch item { + case .overview, .config: + break + case .proxies, .providers: + items.append(.hideNamesItem) + items.append(.searchItem) + case .conns, .rules: + items.append(.searchItem) + case .logs: + items.append(.logLevelItem) + items.append(.searchItem) + } + self.reinitToolbar(items) + } + } + + public override func viewWillAppear() { + super.viewWillAppear() + view.window?.styleMask.insert(.fullSizeContentView) + + view.window?.isOpaque = false + view.window?.styleMask.insert(.closable) + view.window?.styleMask.insert(.resizable) + view.window?.styleMask.insert(.miniaturizable) + + let toolbar = NSToolbar(identifier: .init("DashboardToolbar")) + toolbar.displayMode = .iconOnly + toolbar.delegate = self + + view.window?.toolbar = toolbar + view.window?.title = "Dashboard" + reinitToolbar([]) + + view.window?.minSize = minSize + if let lastSize = lastSize, lastSize != .zero { + view.window?.setContentSize(lastSize) + } + view.window?.center() + if NSApp.activationPolicy() == .accessory { + NSApp.setActivationPolicy(.regular) + } + } + + func reinitToolbar(_ items: [NSToolbarItem.Identifier]) { + guard let toolbar = view.window?.toolbar else { return } + + toolbar.items.enumerated().reversed().forEach { + toolbar.removeItem(at: $0.offset) + } + + items.reversed().forEach { + toolbar.insertItem(withItemIdentifier: $0, at: 0) + } + } + + deinit { + if let sidebarItemObserver { + NotificationCenter.default.removeObserver(sidebarItemObserver) + } + NSApp.setActivationPolicy(.accessory) + } +} + + +extension NSToolbarItem.Identifier { + static let hideNamesItem = NSToolbarItem.Identifier("HideNamesItem") + static let stopConnsItem = NSToolbarItem.Identifier("StopConnsItem") + static let logLevelItem = NSToolbarItem.Identifier("LogLevelItem") + static let searchItem = NSToolbarItem.Identifier("SearchItem") +} + +extension DashboardViewContoller: NSSearchFieldDelegate { + + func controlTextDidChange(_ obj: Notification) { + guard let obj = obj.object as? NSSearchField else { return } + NotificationCenter.default.post(name: .toolbarSearchString, object: nil, userInfo: ["String": obj.stringValue]) + } + + @IBAction func stopConns(_ sender: NSToolbarItem) { + NotificationCenter.default.post(name: .stopConns, object: nil) + } + + @IBAction func hideNames(_ sender: NSToolbarItem) { + switch sender.tag { + case 0: + sender.tag = 1 + sender.image = NSImage(systemSymbolName: "eyeglasses", accessibilityDescription: nil) + case 1: + sender.tag = 0 + sender.image = NSImage(systemSymbolName: "wand.and.stars", accessibilityDescription: nil) + default: + break + } + + NotificationCenter.default.post(name: .hideNames, object: nil, userInfo: ["hide": sender.tag == 1]) + } + + @objc func setLogLevel(_ sender: NSToolbarItemGroup) { + guard sender.selectedIndex < levels.count, sender.selectedIndex >= 0 else { return } + let level = levels[sender.selectedIndex] + + NotificationCenter.default.post(name: .logLevelChanged, object: nil, userInfo: ["level": level]) + } + +} + +extension DashboardViewContoller: NSToolbarDelegate, NSToolbarItemValidation { + + func validateToolbarItem(_ item: NSToolbarItem) -> Bool { + return true + } + + func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { + + switch itemIdentifier { + case .searchItem: + let item = NSSearchToolbarItem(itemIdentifier: .searchItem) + item.resignsFirstResponderWithCancel = true + item.searchField.delegate = self + item.toolTip = "Search" + return item + case .toggleSidebar: + return NSTrackingSeparatorToolbarItem(itemIdentifier: .toggleSidebar) + case .logLevelItem: + + let titles = levels.map { + $0.rawValue.capitalized + } + + let group = NSToolbarItemGroup(itemIdentifier: .logLevelItem, titles: titles, selectionMode: .selectOne, labels: titles, target: nil, action: #selector(setLogLevel(_:))) + group.selectionMode = .selectOne + group.controlRepresentation = .collapsed + group.selectedIndex = levels.firstIndex(of: ConfigManager.selectLoggingApiLevel) ?? 0 + + return group + case .hideNamesItem: + let item = NSToolbarItem(itemIdentifier: .hideNamesItem) + item.target = self + item.action = #selector(hideNames(_:)) + item.isBordered = true + item.tag = 0 + item.image = NSImage(systemSymbolName: "wand.and.stars", accessibilityDescription: nil) + return item + case .stopConnsItem: + let item = NSToolbarItem(itemIdentifier: .stopConnsItem) + item.target = self + item.action = #selector(stopConns(_:)) + item.isBordered = true + item.image = NSImage(systemSymbolName: "stop.circle.fill", accessibilityDescription: nil) + return item + default: + break + } + + return nil + } + + + func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { + [ + .toggleSidebar, + .stopConnsItem, + .hideNamesItem, + .logLevelItem, + .searchItem + ] + } + + func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { + [ + .toggleSidebar, + .stopConnsItem, + .hideNamesItem, + .logLevelItem, + .searchItem + ] + } +} diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/NotificationNames.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/NotificationNames.swift new file mode 100644 index 0000000..88d61c1 --- /dev/null +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/NotificationNames.swift @@ -0,0 +1,16 @@ +// +// NotificationNames.swift +// +// +// + +import Foundation + +extension NSNotification.Name { + static let sidebarItemChanged = NSNotification.Name("SidebarItemChanged") + + static let toolbarSearchString = NSNotification.Name("ToolbarSearchString") + static let stopConns = NSNotification.Name("StopConns") + static let hideNames = NSNotification.Name("HideNames") + static let logLevelChanged = NSNotification.Name("LogLevelChanged") +} diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/ConnectionsView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/ConnectionsView.swift index bee6d84..b4c6d9b 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/ConnectionsView.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/ConnectionsView.swift @@ -18,16 +18,27 @@ struct ConnectionsView: View { filterString: searchString) .background(Color(nsColor: .textBackgroundColor)) .searchable(text: $searchString) + .onReceive(NotificationCenter.default.publisher(for: .toolbarSearchString)) { + guard let string = $0.userInfo?["String"] as? String else { return } + searchString = string + } + .onReceive(NotificationCenter.default.publisher(for: .stopConns)) { _ in + stopConns() + } .toolbar { ToolbarItem { Button { - ApiRequest.closeAllConnection() + stopConns() } label: { Image(systemName: "stop.circle.fill") } } } } + + func stopConns() { + ApiRequest.closeAllConnection() + } } struct ConnectionsView_Previews: PreviewProvider { diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Logs/LogsView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Logs/LogsView.swift index 5b11790..775c16b 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Logs/LogsView.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Logs/LogsView.swift @@ -46,6 +46,14 @@ struct LogsView: View { TableColumn("", value: \.log) } .searchable(text: $searchString) + .onReceive(NotificationCenter.default.publisher(for: .toolbarSearchString)) { + guard let string = $0.userInfo?["String"] as? String else { return } + searchString = string + } + .onReceive(NotificationCenter.default.publisher(for: .logLevelChanged)) { + guard let level = $0.userInfo?["level"] as? ClashLogLevel else { return } + logLevelChanged(level) + } .toolbar { ToolbarItem { Picker("", selection: $logLevel) { @@ -62,13 +70,17 @@ struct LogsView: View { .pickerStyle(.menu) .onChange(of: logLevel) { newValue in guard newValue != ConfigManager.selectLoggingApiLevel else { return } - logStorage.logs.removeAll() - ConfigManager.selectLoggingApiLevel = newValue - ApiRequest.shared.resetLogStreamApi() + logLevelChanged(newValue) } } } } + + func logLevelChanged(_ level: ClashLogLevel) { + logStorage.logs.removeAll() + ConfigManager.selectLoggingApiLevel = level + ApiRequest.shared.resetLogStreamApi() + } } struct LogsView_Previews: PreviewProvider { diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/ProvidersView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/ProvidersView.swift index d4a2bc7..3ab574d 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/ProvidersView.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Providers/ProvidersView.swift @@ -20,6 +20,14 @@ struct ProvidersView: View { EmptyView() } .searchable(text: $searchString.string) + .onReceive(NotificationCenter.default.publisher(for: .toolbarSearchString)) { + guard let string = $0.userInfo?["String"] as? String else { return } + searchString.string = string + } + .onReceive(NotificationCenter.default.publisher(for: .hideNames)) { + guard let hide = $0.userInfo?["hide"] as? Bool else { return } + hideProxyNames.hide = hide + } .environmentObject(searchString) .onAppear { loadProviders() diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Proxies/ProxiesView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Proxies/ProxiesView.swift index 77ebb09..48790e1 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Proxies/ProxiesView.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Proxies/ProxiesView.swift @@ -34,6 +34,14 @@ struct ProxiesView: View { EmptyView() } .searchable(text: $searchString.string) + .onReceive(NotificationCenter.default.publisher(for: .toolbarSearchString)) { + guard let string = $0.userInfo?["String"] as? String else { return } + searchString.string = string + } + .onReceive(NotificationCenter.default.publisher(for: .hideNames)) { + guard let hide = $0.userInfo?["hide"] as? Bool else { return } + hideProxyNames.hide = hide + } .environmentObject(searchString) .onAppear { loadProxies() diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Rules/RulesView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Rules/RulesView.swift index c122ae0..4b000aa 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Rules/RulesView.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Rules/RulesView.swift @@ -29,6 +29,10 @@ struct RulesView: View { } } .searchable(text: $searchString) + .onReceive(NotificationCenter.default.publisher(for: .toolbarSearchString)) { + guard let string = $0.userInfo?["String"] as? String else { return } + searchString = string + } .onAppear { ruleItems.removeAll() ApiRequest.getRules { diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarItem.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarItem.swift index c445966..2d4514b 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarItem.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarItem.swift @@ -7,27 +7,12 @@ import Cocoa import SwiftUI - -class SidebarItems: ObservableObject, Identifiable { - let id = UUID() - @Published var items: [SidebarItem] - @Published var selectedIndex = 0 - - init(_ items: [SidebarItem]) { - self.items = items - } -} - -class SidebarItem: ObservableObject { - let id = UUID() - let name: String - let icon: String - let view: AnyView - - - init(name: String, icon: String, view: AnyView) { - self.name = name - self.icon = icon - self.view = view - } +enum SidebarItem: String { + case overview = "Overview" + case proxies = "Proxies" + case providers = "Providers" + case rules = "Rules" + case conns = "Conns" + case config = "Config" + case logs = "Logs" } diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarItemView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarItemView.swift deleted file mode 100644 index 3f6fdf8..0000000 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarItemView.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// SidebarItemView.swift -// ClashX Dashboard -// -// - -import SwiftUI - -struct SidebarItemView: View { - - @State var item: SidebarItem - - @Binding var selectionName: String? - - var body: some View { - NavigationLink(destination: item.view, tag: item.name, selection: $selectionName) { - Label(item.name, systemImage: item.icon) - } - } -} - -//struct SidebarItemView_Previews: PreviewProvider { -// static var previews: some View { -// SidebarItemView(item: .init(name: "Overview", -// icon: "chart.bar.xaxis", -// view: AnyView(OverviewView()))) -// } -//} diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarListView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarListView.swift index 80ae113..dd1f88c 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarListView.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarListView.swift @@ -14,45 +14,45 @@ struct SidebarListView: View { List { NavigationLink(destination: OverviewView(), - tag: "Overview", + tag: SidebarItem.overview.rawValue, selection: $selectionName) { - Label("Overview", systemImage: "chart.bar.xaxis") + Label(SidebarItem.overview.rawValue, systemImage: "chart.bar.xaxis") } NavigationLink(destination: ProxiesView(), - tag: "Proxies", + tag: SidebarItem.proxies.rawValue, selection: $selectionName) { - Label("Proxies", systemImage: "globe.asia.australia") + Label(SidebarItem.proxies.rawValue, systemImage: "globe.asia.australia") } NavigationLink(destination: ProvidersView(), - tag: "Providers", + tag: SidebarItem.providers.rawValue, selection: $selectionName) { - Label("Providers", systemImage: "link.icloud") + Label(SidebarItem.providers.rawValue, systemImage: "link.icloud") } NavigationLink(destination: RulesView(), - tag: "Rules", + tag: SidebarItem.rules.rawValue, selection: $selectionName) { - Label("Rules", systemImage: "waveform.and.magnifyingglass") + Label(SidebarItem.rules.rawValue, systemImage: "waveform.and.magnifyingglass") } NavigationLink(destination: ConnectionsView(), - tag: "Conns", + tag: SidebarItem.conns.rawValue, selection: $selectionName) { - Label("Conns", systemImage: "app.connected.to.app.below.fill") + Label(SidebarItem.conns.rawValue, systemImage: "app.connected.to.app.below.fill") } NavigationLink(destination: ConfigView(), - tag: "Config", + tag: SidebarItem.config.rawValue, selection: $selectionName) { - Label("Config", systemImage: "slider.horizontal.3") + Label(SidebarItem.config.rawValue, systemImage: "slider.horizontal.3") } NavigationLink(destination: LogsView(), - tag: "Logs", + tag: SidebarItem.logs.rawValue, selection: $selectionName) { - Label("Logs", systemImage: "wand.and.stars.inverse") + Label(SidebarItem.logs.rawValue, systemImage: "wand.and.stars.inverse") } diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarView.swift index 33128da..b1d7246 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarView.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarView.swift @@ -27,6 +27,8 @@ struct SidebarView: View { ConfigManager.selectLoggingApiLevel = .info } + sidebarItemChanged(sidebarSelectionName) + clashApiDatasStorage.resetStreamApi() connsQueue.sync { clashApiDatasStorage.connsStorage.conns @@ -35,9 +37,13 @@ struct SidebarView: View { updateConnections() } + .onChange(of: sidebarSelectionName) { newValue in + sidebarItemChanged(newValue) + } .onReceive(timer, perform: { _ in updateConnections() }) + } func updateConnections() { @@ -50,6 +56,13 @@ struct SidebarView: View { } } } + + func sidebarItemChanged(_ name: String?) { + guard let str = name, + let item = SidebarItem(rawValue: str) else { return } + + NotificationCenter.default.post(name: .sidebarItemChanged, object: nil, userInfo: ["item": item]) + } } //struct SidebarView_Previews: PreviewProvider { diff --git a/ClashX Dashboard/AppDelegate.swift b/ClashX Dashboard/AppDelegate.swift index 4b7a0f8..8b3cd0e 100644 --- a/ClashX Dashboard/AppDelegate.swift +++ b/ClashX Dashboard/AppDelegate.swift @@ -11,8 +11,21 @@ import ClashX_Dashboard_Kit @main class AppDelegate: NSObject, NSApplicationDelegate { + var dashboardWindowController: DashboardWindowController? + func applicationDidFinishLaunching(_ notification: Notification) { + if dashboardWindowController == nil { + dashboardWindowController = DashboardWindowController.create() + dashboardWindowController?.onWindowClose = { + [weak self] in + self?.dashboardWindowController = nil + } + } + dashboardWindowController?.showWindow(nil) + + + } From e53503cdbe5fcd8550b05fa334227c2e35d41cfa Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Sat, 3 Jun 2023 23:47:06 +0800 Subject: [PATCH 06/11] fix: sidebar default selection --- .../Views/SidebarView/SidebarListView.swift | 28 ++++++++++++------- .../Views/SidebarView/SidebarView.swift | 11 +++----- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarListView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarListView.swift index dd1f88c..b543425 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarListView.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarListView.swift @@ -5,57 +5,65 @@ // import SwiftUI +import Introspect struct SidebarListView: View { - @Binding var selectionName: String? + @Binding var selectionName: SidebarItem? var body: some View { List { - NavigationLink(destination: OverviewView(), - tag: SidebarItem.overview.rawValue, + tag: SidebarItem.overview, selection: $selectionName) { Label(SidebarItem.overview.rawValue, systemImage: "chart.bar.xaxis") } NavigationLink(destination: ProxiesView(), - tag: SidebarItem.proxies.rawValue, + tag: SidebarItem.proxies, selection: $selectionName) { Label(SidebarItem.proxies.rawValue, systemImage: "globe.asia.australia") } NavigationLink(destination: ProvidersView(), - tag: SidebarItem.providers.rawValue, + tag: SidebarItem.providers, selection: $selectionName) { Label(SidebarItem.providers.rawValue, systemImage: "link.icloud") } NavigationLink(destination: RulesView(), - tag: SidebarItem.rules.rawValue, + tag: SidebarItem.rules, selection: $selectionName) { Label(SidebarItem.rules.rawValue, systemImage: "waveform.and.magnifyingglass") } NavigationLink(destination: ConnectionsView(), - tag: SidebarItem.conns.rawValue, + tag: SidebarItem.conns, selection: $selectionName) { Label(SidebarItem.conns.rawValue, systemImage: "app.connected.to.app.below.fill") } NavigationLink(destination: ConfigView(), - tag: SidebarItem.config.rawValue, + tag: SidebarItem.config, selection: $selectionName) { Label(SidebarItem.config.rawValue, systemImage: "slider.horizontal.3") } NavigationLink(destination: LogsView(), - tag: SidebarItem.logs.rawValue, + tag: SidebarItem.logs, selection: $selectionName) { Label(SidebarItem.logs.rawValue, systemImage: "wand.and.stars.inverse") } - + } + .introspectTableView { + if selectionName == nil { + selectionName = SidebarItem.overview + $0.allowsEmptySelection = false + if $0.selectedRow == -1 { + $0.selectRowIndexes(.init(integer: 0), byExtendingSelection: false) + } + } } .listStyle(.sidebar) } diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarView.swift index b1d7246..3a847c9 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarView.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarView.swift @@ -13,10 +13,10 @@ struct SidebarView: View { private let connsQueue = DispatchQueue(label: "thread-safe-connsQueue", attributes: .concurrent) private let timer = Timer.publish(every: 1, on: .main, in: .default).autoconnect() - @State private var sidebarSelectionName: String? = "Overview" + @State private var sidebarSelectionName: SidebarItem? var body: some View { - ScrollViewReader { scrollViewProxy in + Group { SidebarListView(selectionName: $sidebarSelectionName) } .environmentObject(clashApiDatasStorage.overviewData) @@ -27,8 +27,6 @@ struct SidebarView: View { ConfigManager.selectLoggingApiLevel = .info } - sidebarItemChanged(sidebarSelectionName) - clashApiDatasStorage.resetStreamApi() connsQueue.sync { clashApiDatasStorage.connsStorage.conns @@ -57,9 +55,8 @@ struct SidebarView: View { } } - func sidebarItemChanged(_ name: String?) { - guard let str = name, - let item = SidebarItem(rawValue: str) else { return } + func sidebarItemChanged(_ item: SidebarItem?) { + guard let item else { return } NotificationCenter.default.post(name: .sidebarItemChanged, object: nil, userInfo: ["item": item]) } From 8fc7bec255d0bafa969ada477c194b15adfc0b28 Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Sat, 3 Jun 2023 23:49:11 +0800 Subject: [PATCH 07/11] misc: dashboard api url --- .../ClashX Dashboard Kit/DashboardViewContoller.swift | 8 +++++++- ClashX Dashboard/AppDelegate.swift | 5 ++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift index 3badef1..00e88af 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift @@ -26,6 +26,12 @@ public class DashboardWindowController: NSWindowController { window?.makeKeyAndOrderFront(self) window?.delegate = self } + + public func set(_ apiURL: String, secret: String? = nil) { + ConfigManager.shared.isRunning = true + ConfigManager.shared.overrideApiURL = .init(string: apiURL) + ConfigManager.shared.overrideSecret = secret + } } extension DashboardWindowController: NSWindowDelegate { @@ -266,5 +272,5 @@ extension DashboardViewContoller: NSToolbarDelegate, NSToolbarItemValidation { .logLevelItem, .searchItem ] - } + } } diff --git a/ClashX Dashboard/AppDelegate.swift b/ClashX Dashboard/AppDelegate.swift index 8b3cd0e..1d1aebb 100644 --- a/ClashX Dashboard/AppDelegate.swift +++ b/ClashX Dashboard/AppDelegate.swift @@ -22,10 +22,9 @@ class AppDelegate: NSObject, NSApplicationDelegate { self?.dashboardWindowController = nil } } + + dashboardWindowController?.set("http://127.0.0.1:9021") dashboardWindowController?.showWindow(nil) - - - } From 42b6c2da0e614d9d4d79728f7e5ff23200bdd94e Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Sun, 4 Jun 2023 14:53:01 +0800 Subject: [PATCH 08/11] refactor: log tableview --- .../Views/ClashApiDatasStorage.swift | 16 +- .../ContentTabs/Logs/LogsTableView.swift | 158 ++++++++++++++++++ .../Views/ContentTabs/Logs/LogsView.swift | 32 +--- 3 files changed, 170 insertions(+), 36 deletions(-) create mode 100644 ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Logs/LogsTableView.swift diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ClashApiDatasStorage.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ClashApiDatasStorage.swift index 6577606..addab5a 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ClashApiDatasStorage.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ClashApiDatasStorage.swift @@ -7,6 +7,7 @@ import Cocoa import SwiftUI import CocoaLumberjackSwift +import DifferenceKit class ClashApiDatasStorage: NSObject, ObservableObject { @@ -125,14 +126,17 @@ class ClashOverviewData: ObservableObject, Identifiable { class ClashLogStorage: ObservableObject { @Published var logs = [ClashLog]() - class ClashLog: NSObject, ObservableObject, Identifiable { + class ClashLog: NSObject, ObservableObject, Identifiable, Differentiable { let id: String + var differenceIdentifier: String { + return id + } let date: Date let level: ClashLogLevel @objc let log: String - let levelColor: Color + let levelColor: NSColor @objc let levelString: String init(level: String, log: String) { @@ -144,13 +148,13 @@ class ClashLogStorage: ObservableObject { self.levelString = level switch self.level { case .info: - levelColor = .blue + levelColor = .systemBlue case .warning: - levelColor = .yellow + levelColor = .systemYellow case .error: - levelColor = .red + levelColor = .systemRed case .debug: - levelColor = .green + levelColor = .systemGreen default: levelColor = .white } diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Logs/LogsTableView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Logs/LogsTableView.swift new file mode 100644 index 0000000..b7ea20c --- /dev/null +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Logs/LogsTableView.swift @@ -0,0 +1,158 @@ +// +// LogsTableView.swift +// +// +// + +import Cocoa +import SwiftUI +import DifferenceKit + +struct LogsTableView: NSViewRepresentable { + + enum TableColumn: String, CaseIterable { + case date = "Date" + case level = "Level" + case log = "Log" + } + + var data: [Item] + var filterString: String + + class NonRespondingScrollView: NSScrollView { + override var acceptsFirstResponder: Bool { false } + } + + class NonRespondingTableView: NSTableView { + override var acceptsFirstResponder: Bool { false } + } + + func makeNSView(context: Context) -> NSScrollView { + + let scrollView = NonRespondingScrollView() + scrollView.hasVerticalScroller = true + scrollView.hasHorizontalScroller = false + scrollView.autohidesScrollers = true + + let tableView = NonRespondingTableView() + tableView.usesAlternatingRowBackgroundColors = true + + tableView.delegate = context.coordinator + tableView.dataSource = context.coordinator + + TableColumn.allCases.forEach { + let tableColumn = NSTableColumn(identifier: .init($0.rawValue)) + tableColumn.title = $0.rawValue + tableColumn.isEditable = false + + switch $0 { + case .date: + tableColumn.minWidth = 60 + tableColumn.maxWidth = 140 + tableColumn.width = 135 + case .level: + tableColumn.minWidth = 40 + tableColumn.maxWidth = 65 + default: + tableColumn.minWidth = 120 + tableColumn.maxWidth = .infinity + } + + tableView.addTableColumn(tableColumn) + } + + scrollView.documentView = tableView + + return scrollView + } + + func updateNSView(_ nsView: NSScrollView, context: Context) { + context.coordinator.parent = self + guard let tableView = nsView.documentView as? NSTableView, + let data = data as? [ClashLogStorage.ClashLog] else { + return + } + + let target = updateSorts(data, tableView: tableView) + + let source = context.coordinator.logs + let changeset = StagedChangeset(source: source, target: target) + + + tableView.reload(using: changeset) { data in + context.coordinator.logs = data + } + } + + func updateSorts(_ objects: [ClashLogStorage.ClashLog], + tableView: NSTableView) -> [ClashLogStorage.ClashLog] { + var re = objects + + let filterKeys = [ + "levelString", + "log", + ] + + re = re.filtered(filterString, for: filterKeys) + + return re + } + + + func makeCoordinator() -> Coordinator { + Coordinator(parent: self) + } + + + class Coordinator: NSObject, NSTableViewDelegate, NSTableViewDataSource { + + var parent: LogsTableView + var logs = [ClashLogStorage.ClashLog]() + + let dateFormatter = { + let df = DateFormatter() + df.dateFormat = "MM/dd HH:mm:ss.SSS" + return df + }() + + + init(parent: LogsTableView) { + self.parent = parent + } + + + func numberOfRows(in tableView: NSTableView) -> Int { + logs.count + } + + + func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { + + guard let cellView = tableView.createCellView(with: "LogsTableCellView"), + let s = tableColumn?.identifier.rawValue.split(separator: ".").last, + let tc = TableColumn(rawValue: String(s)) + else { return nil } + + let log = logs[row] + let tf = cellView.textField + + switch tc { + case .date: + tf?.lineBreakMode = .byTruncatingHead + tf?.textColor = .orange + tf?.stringValue = dateFormatter.string(from: log.date) + case .level: + tf?.lineBreakMode = .byTruncatingTail + tf?.textColor = log.levelColor + tf?.stringValue = log.levelString + case .log: + tf?.lineBreakMode = .byTruncatingTail + tf?.textColor = .labelColor + tf?.stringValue = log.log + } + + return cellView + } + + } +} diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Logs/LogsView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Logs/LogsView.swift index 775c16b..5928e32 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Logs/LogsView.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Logs/LogsView.swift @@ -13,37 +13,9 @@ struct LogsView: View { @State var searchString: String = "" @State var logLevel = ConfigManager.selectLoggingApiLevel - var logs: [ClashLogStorage.ClashLog] { - let logs: [ClashLogStorage.ClashLog] = logStorage.logs.reversed() - if searchString.isEmpty { - return logs - } else { - return logs.filtered(searchString, for: ["log", "levelString"]) - } - } - var body: some View { - Table(logs) { - TableColumn("Date") { - Text($0.date.formatted( - Date.FormatStyle() - .year(.twoDigits) - .month(.twoDigits) - .day(.twoDigits) - .hour(.twoDigits(amPM: .omitted)) - .minute(.twoDigits) - .second(.twoDigits) - )) - .foregroundColor(.orange) - .truncationMode(.head) - } - .width(min: 60, max: 130) - TableColumn("Level") { - Text("[\($0.level.rawValue)]") - .foregroundColor($0.levelColor) - } - .width(min: 40, max: 65) - TableColumn("", value: \.log) + Group { + LogsTableView(data: logStorage.logs.reversed(), filterString: searchString) } .searchable(text: $searchString) .onReceive(NotificationCenter.default.publisher(for: .toolbarSearchString)) { From 41da4015f4c24016b1823515c21ac61878e0d48d Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Sun, 4 Jun 2023 15:39:47 +0800 Subject: [PATCH 09/11] misc: auto hide scrollers --- .../Views/ContentTabs/Connections/CollectionsTableView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionsTableView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionsTableView.swift index 7ef4eb1..1c81bf9 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionsTableView.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/ContentTabs/Connections/CollectionsTableView.swift @@ -48,6 +48,7 @@ struct CollectionsTableView: NSViewRepresentable { let scrollView = NonRespondingScrollView() scrollView.hasVerticalScroller = true scrollView.hasHorizontalScroller = true + scrollView.autohidesScrollers = true let tableView = NonRespondingTableView() tableView.usesAlternatingRowBackgroundColors = true From 1a4cd5c7f67a34ce248b26206217546fb251d1f6 Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Sun, 4 Jun 2023 15:39:58 +0800 Subject: [PATCH 10/11] fix: conns stop item --- .../ClashX Dashboard Kit/DashboardViewContoller.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift index 00e88af..71ca5fd 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift @@ -102,7 +102,10 @@ class DashboardViewContoller: NSViewController { case .proxies, .providers: items.append(.hideNamesItem) items.append(.searchItem) - case .conns, .rules: + case .rules: + items.append(.searchItem) + case .conns: + items.append(.stopConnsItem) items.append(.searchItem) case .logs: items.append(.logLevelItem) From 064b7ace97d3984c322b9053516a33c45f6a09ce Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Mon, 5 Jun 2023 22:43:15 +0800 Subject: [PATCH 11/11] feat: reload func --- .../ClashX Dashboard Kit/DashboardViewContoller.swift | 4 ++++ .../Sources/ClashX Dashboard Kit/NotificationNames.swift | 1 + .../Views/SidebarView/SidebarListView.swift | 7 +++++++ 3 files changed, 12 insertions(+) diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift index 71ca5fd..b7af820 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/DashboardViewContoller.swift @@ -32,6 +32,10 @@ public class DashboardWindowController: NSWindowController { ConfigManager.shared.overrideApiURL = .init(string: apiURL) ConfigManager.shared.overrideSecret = secret } + + public func reload() { + NotificationCenter.default.post(name: .reloadDashboard, object: nil) + } } extension DashboardWindowController: NSWindowDelegate { diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/NotificationNames.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/NotificationNames.swift index 88d61c1..a3cf2a5 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/NotificationNames.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/NotificationNames.swift @@ -7,6 +7,7 @@ import Foundation extension NSNotification.Name { + static let reloadDashboard = NSNotification.Name("ReloadDashboard") static let sidebarItemChanged = NSNotification.Name("SidebarItemChanged") static let toolbarSearchString = NSNotification.Name("ToolbarSearchString") diff --git a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarListView.swift b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarListView.swift index b543425..e19e4c0 100644 --- a/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarListView.swift +++ b/ClashX Dashboard Kit/Sources/ClashX Dashboard Kit/Views/SidebarView/SidebarListView.swift @@ -11,6 +11,9 @@ struct SidebarListView: View { @Binding var selectionName: SidebarItem? + @State private var reloadID = UUID().uuidString + + var body: some View { List { NavigationLink(destination: OverviewView(), @@ -66,6 +69,10 @@ struct SidebarListView: View { } } .listStyle(.sidebar) + .id(reloadID) + .onReceive(NotificationCenter.default.publisher(for: .reloadDashboard)) { _ in + reloadID = UUID().uuidString + } } }