Reformat code
This commit is contained in:
@@ -8,7 +8,7 @@ struct EncodedBlock {
|
|||||||
let bytes: Int
|
let bytes: Int
|
||||||
let checksum: UInt32
|
let checksum: UInt32
|
||||||
|
|
||||||
// Binary format: degree(4) + indices(4*n) + k(4) + bytes(4) + checksum(4) + data
|
/// Binary format: degree(4) + indices(4*n) + k(4) + bytes(4) + checksum(4) + data
|
||||||
func toBinary() -> Data {
|
func toBinary() -> Data {
|
||||||
var result = Data()
|
var result = Data()
|
||||||
|
|
||||||
|
|||||||
@@ -12,19 +12,26 @@ final class LubyTransformDecoder {
|
|||||||
private var disposedEncodedBlocks: [Int: [() -> Void]] = [:]
|
private var disposedEncodedBlocks: [Int: [() -> Void]] = [:]
|
||||||
private(set) var meta: EncodedBlock?
|
private(set) var meta: EncodedBlock?
|
||||||
|
|
||||||
var k: Int { meta?.k ?? 0 }
|
var k: Int {
|
||||||
|
meta?.k ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
var progress: Double {
|
var progress: Double {
|
||||||
guard k > 0 else { return 0 }
|
guard k > 0 else { return 0 }
|
||||||
return Double(decodedCount) / Double(k)
|
return Double(decodedCount) / Double(k)
|
||||||
}
|
}
|
||||||
|
|
||||||
var isComplete: Bool { meta != nil && decodedCount == k }
|
var isComplete: Bool {
|
||||||
|
meta != nil && decodedCount == k
|
||||||
|
}
|
||||||
|
|
||||||
private class BlockWrapper: Hashable {
|
private class BlockWrapper: Hashable {
|
||||||
var block: EncodedBlock
|
var block: EncodedBlock
|
||||||
let id = UUID()
|
let id = UUID()
|
||||||
|
|
||||||
init(_ block: EncodedBlock) { self.block = block }
|
init(_ block: EncodedBlock) {
|
||||||
|
self.block = block
|
||||||
|
}
|
||||||
|
|
||||||
static func == (lhs: BlockWrapper, rhs: BlockWrapper) -> Bool {
|
static func == (lhs: BlockWrapper, rhs: BlockWrapper) -> Bool {
|
||||||
lhs.id == rhs.id
|
lhs.id == rhs.id
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ final class LubyTransformEncoder {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ideal Soliton Distribution for degree selection
|
/// Ideal Soliton Distribution for degree selection
|
||||||
private func getRandomDegree() -> Int {
|
private func getRandomDegree() -> Int {
|
||||||
guard k > 1 else { return k }
|
guard k > 1 else { return k }
|
||||||
var probabilities = [Double](repeating: 0, count: k)
|
var probabilities = [Double](repeating: 0, count: k)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import Library
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
public extension View {
|
public extension View {
|
||||||
@ViewBuilder
|
|
||||||
func alert(_ binding: Binding<AlertState?>, isLoading: Binding<Bool>) -> some View {
|
func alert(_ binding: Binding<AlertState?>, isLoading: Binding<Bool>) -> some View {
|
||||||
alert(
|
alert(
|
||||||
binding.wrappedValue?.title ?? "",
|
binding.wrappedValue?.title ?? "",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
public struct DeleteButton<Label>: View where Label: View {
|
public struct DeleteButton<Label: View>: View {
|
||||||
private let action: () async -> Void
|
private let action: () async -> Void
|
||||||
private let label: Label
|
private let label: Label
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import SwiftUI
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
public struct ProfileShareButton<Label>: View where Label: View {
|
public struct ProfileShareButton<Label: View>: View {
|
||||||
private let alert: Binding<AlertState?>
|
private let alert: Binding<AlertState?>
|
||||||
private let profile: Profile
|
private let profile: Profile
|
||||||
private let label: () -> Label
|
private let label: () -> Label
|
||||||
@@ -40,7 +40,7 @@ public struct ProfileShareButton<Label>: View where Label: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ShareButtonCompat<Label>: View where Label: View {
|
public struct ShareButtonCompat<Label: View>: View {
|
||||||
private let label: () -> Label
|
private let label: () -> Label
|
||||||
private let itemURL: () async throws -> URL
|
private let itemURL: () async throws -> URL
|
||||||
|
|
||||||
@@ -137,8 +137,7 @@ public struct ShareButtonCompat<Label>: View where Label: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func makeNSView(context _: Context) -> NSView {
|
func makeNSView(context _: Context) -> NSView {
|
||||||
let view = NSView()
|
NSView()
|
||||||
return view
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNSView(_ nsView: NSView, context: Context) {
|
func updateNSView(_ nsView: NSView, context: Context) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ public extension View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func onChangeCompat<V>(of value: V, _ action: @escaping (_ newValue: V) -> Void) -> some View where V: Equatable {
|
func onChangeCompat<V: Equatable>(of value: V, _ action: @escaping (_ newValue: V) -> Void) -> some View {
|
||||||
onChange(of: value, perform: action)
|
onChange(of: value, perform: action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,7 +147,6 @@ public extension View {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
public extension View {
|
public extension View {
|
||||||
@ViewBuilder
|
|
||||||
func cardStyle() -> some View {
|
func cardStyle() -> some View {
|
||||||
modifier(CardStyleModifier())
|
modifier(CardStyleModifier())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ import SwiftUI
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder private var overviewPage: some View {
|
private var overviewPage: some View {
|
||||||
OverviewView(
|
OverviewView(
|
||||||
$coordinator.profileList,
|
$coordinator.profileList,
|
||||||
$coordinator.selectedProfileID,
|
$coordinator.selectedProfileID,
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ public enum DashboardCard: String, CaseIterable, Identifiable, Codable, Hashable
|
|||||||
case clashMode
|
case clashMode
|
||||||
case profile
|
case profile
|
||||||
|
|
||||||
public var id: String { rawValue }
|
public var id: String {
|
||||||
|
rawValue
|
||||||
|
}
|
||||||
|
|
||||||
public var title: LocalizedStringKey {
|
public var title: LocalizedStringKey {
|
||||||
switch self {
|
switch self {
|
||||||
|
|||||||
@@ -188,7 +188,6 @@ public struct ProfileCard: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private func actionButtonsRow(for profile: ProfilePreview) -> some View {
|
private func actionButtonsRow(for profile: ProfilePreview) -> some View {
|
||||||
HStack(spacing: actionButtonSpacing) {
|
HStack(spacing: actionButtonSpacing) {
|
||||||
editButton(for: profile)
|
editButton(for: profile)
|
||||||
@@ -201,7 +200,6 @@ public struct ProfileCard: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private func editButton(for profile: ProfilePreview) -> some View {
|
private func editButton(for profile: ProfilePreview) -> some View {
|
||||||
Button {
|
Button {
|
||||||
viewModel.profileToEdit = profile.origin
|
viewModel.profileToEdit = profile.origin
|
||||||
@@ -213,7 +211,6 @@ public struct ProfileCard: View {
|
|||||||
.actionButtonStyle()
|
.actionButtonStyle()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private func updateButton(for profile: ProfilePreview) -> some View {
|
private func updateButton(for profile: ProfilePreview) -> some View {
|
||||||
Button {
|
Button {
|
||||||
viewModel.isUpdating = true
|
viewModel.isUpdating = true
|
||||||
@@ -436,7 +433,6 @@ public struct ProfileCard: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private func profileInfo(for profile: ProfilePreview) -> some View {
|
private func profileInfo(for profile: ProfilePreview) -> some View {
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
|
|||||||
@@ -437,7 +437,6 @@ struct ProfilePickerSheet: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
@ViewBuilder
|
|
||||||
private func macOSProfileRow(_ profile: ProfilePreview) -> some View {
|
private func macOSProfileRow(_ profile: ProfilePreview) -> some View {
|
||||||
ProfilePickerRow(
|
ProfilePickerRow(
|
||||||
profile: profile,
|
profile: profile,
|
||||||
@@ -928,7 +927,6 @@ private struct ProfilePickerRow: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
@ViewBuilder
|
|
||||||
private var shareMenu: some View {
|
private var shareMenu: some View {
|
||||||
Menu {
|
Menu {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
@@ -1345,7 +1343,6 @@ private struct ProfilePickerRow: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private var shareMenu: some View {
|
private var shareMenu: some View {
|
||||||
Menu {
|
Menu {
|
||||||
Button {
|
Button {
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ public struct ExtensionStatusView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct StatusItem<T>: View where T: View {
|
private struct StatusItem<T: View>: View {
|
||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
|
|
||||||
private let title: String
|
private let title: String
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ public struct DashboardView: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private func importRemoteProfileSheet(for request: ImportRemoteProfileRequest) -> some View {
|
private func importRemoteProfileSheet(for request: ImportRemoteProfileRequest) -> some View {
|
||||||
NavigationSheet(title: "Import Profile", onDismiss: {
|
NavigationSheet(title: "Import Profile", onDismiss: {
|
||||||
environments.profileUpdate.send()
|
environments.profileUpdate.send()
|
||||||
@@ -99,7 +98,6 @@ public struct DashboardView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private var activeDashboardView: some View {
|
private var activeDashboardView: some View {
|
||||||
ActiveDashboardView(coordinator: coordinator)
|
ActiveDashboardView(coordinator: coordinator)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -272,7 +272,6 @@ private struct LogContentInnerView: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private var emptyContent: some View {
|
private var emptyContent: some View {
|
||||||
Group {
|
Group {
|
||||||
if dataModel.isConnected {
|
if dataModel.isConnected {
|
||||||
@@ -427,7 +426,9 @@ private struct LogContentInnerView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private struct LogTextDocument: FileDocument {
|
private struct LogTextDocument: FileDocument {
|
||||||
static var readableContentTypes: [UTType] { [.plainText] }
|
static var readableContentTypes: [UTType] {
|
||||||
|
[.plainText]
|
||||||
|
}
|
||||||
|
|
||||||
private let url: URL
|
private let url: URL
|
||||||
|
|
||||||
@@ -466,8 +467,7 @@ private struct LogContentInnerView: View {
|
|||||||
@Binding var alert: AlertState?
|
@Binding var alert: AlertState?
|
||||||
|
|
||||||
func makeNSView(context _: Context) -> NSView {
|
func makeNSView(context _: Context) -> NSView {
|
||||||
let view = NSView()
|
NSView()
|
||||||
return view
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNSView(_ nsView: NSView, context _: Context) {
|
func updateNSView(_ nsView: NSView, context _: Context) {
|
||||||
|
|||||||
@@ -25,8 +25,13 @@ public class LogDataModel: ObservableObject {
|
|||||||
|
|
||||||
private static let maxVisibleLogs = 1000
|
private static let maxVisibleLogs = 1000
|
||||||
|
|
||||||
public var isEmpty: Bool { commandClient.logList.isEmpty }
|
public var isEmpty: Bool {
|
||||||
public var isConnected: Bool { commandClient.isConnected }
|
commandClient.logList.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
public var isConnected: Bool {
|
||||||
|
commandClient.isConnected
|
||||||
|
}
|
||||||
|
|
||||||
private func updateVisibleLogs() {
|
private func updateVisibleLogs() {
|
||||||
if filteredLogs.count <= Self.maxVisibleLogs {
|
if filteredLogs.count <= Self.maxVisibleLogs {
|
||||||
|
|||||||
@@ -28,8 +28,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
DevicePicker(
|
DevicePicker(
|
||||||
.applicationService(name: "sing-box:profile"))
|
.applicationService(name: "sing-box:profile")
|
||||||
{ endpoint in
|
) { endpoint in
|
||||||
viewModel.selected = true
|
viewModel.selected = true
|
||||||
Task {
|
Task {
|
||||||
await viewModel.handleEndpoint(endpoint, environments: environments)
|
await viewModel.handleEndpoint(endpoint, environments: environments)
|
||||||
|
|||||||
@@ -11,13 +11,19 @@ public struct NewProfileView: View {
|
|||||||
private var onSuccess: ((Profile) async -> Void)?
|
private var onSuccess: ((Profile) async -> Void)?
|
||||||
|
|
||||||
public struct ImportRequest: Codable, Hashable, Identifiable {
|
public struct ImportRequest: Codable, Hashable, Identifiable {
|
||||||
public var id: String { url }
|
public var id: String {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
|
||||||
public let name: String
|
public let name: String
|
||||||
public let url: String
|
public let url: String
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct LocalImportRequest: Hashable, Identifiable {
|
public struct LocalImportRequest: Hashable, Identifiable {
|
||||||
public var id: String { fileURL.absoluteString }
|
public var id: String {
|
||||||
|
fileURL.absoluteString
|
||||||
|
}
|
||||||
|
|
||||||
public let name: String
|
public let name: String
|
||||||
public let fileURL: URL
|
public let fileURL: URL
|
||||||
|
|
||||||
|
|||||||
@@ -242,8 +242,7 @@
|
|||||||
let controller: QRScannerController
|
let controller: QRScannerController
|
||||||
|
|
||||||
func makeUIViewController(context _: Context) -> UIViewController {
|
func makeUIViewController(context _: Context) -> UIViewController {
|
||||||
let viewController = QRScannerViewController(controller: controller)
|
QRScannerViewController(controller: controller)
|
||||||
return viewController
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUIViewController(_: UIViewController, context _: Context) {}
|
func updateUIViewController(_: UIViewController, context _: Context) {}
|
||||||
|
|||||||
@@ -247,8 +247,7 @@
|
|||||||
let controller: QRScannerController
|
let controller: QRScannerController
|
||||||
|
|
||||||
func makeNSViewController(context _: Context) -> NSViewController {
|
func makeNSViewController(context _: Context) -> NSViewController {
|
||||||
let viewController = QRScannerViewController(controller: controller)
|
QRScannerViewController(controller: controller)
|
||||||
return viewController
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNSViewController(_: NSViewController, context _: Context) {}
|
func updateNSViewController(_: NSViewController, context _: Context) {}
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ private enum OnDemandMode: String, CaseIterable, Identifiable {
|
|||||||
case alwaysOn
|
case alwaysOn
|
||||||
case enabled
|
case enabled
|
||||||
|
|
||||||
var id: String { rawValue }
|
var id: String {
|
||||||
|
rawValue
|
||||||
|
}
|
||||||
|
|
||||||
var name: String {
|
var name: String {
|
||||||
switch self {
|
switch self {
|
||||||
@@ -114,7 +116,6 @@ public struct OnDemandRulesView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private var rulesSection: some View {
|
private var rulesSection: some View {
|
||||||
Section {
|
Section {
|
||||||
if rules.isEmpty {
|
if rules.isEmpty {
|
||||||
@@ -463,7 +464,6 @@ private struct OnDemandRuleEditView: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private var connectionRulesSection: some View {
|
private var connectionRulesSection: some View {
|
||||||
Section {
|
Section {
|
||||||
if rule.connectionRules.isEmpty {
|
if rule.connectionRules.isEmpty {
|
||||||
|
|||||||
@@ -128,7 +128,6 @@ public struct SettingView: View {
|
|||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
@MainActor
|
@MainActor
|
||||||
@ViewBuilder
|
|
||||||
private static func destinationView(for page: SettingsPage) -> some View {
|
private static func destinationView(for page: SettingsPage) -> some View {
|
||||||
Group {
|
Group {
|
||||||
switch page {
|
switch page {
|
||||||
|
|||||||
@@ -95,11 +95,25 @@ class FileProviderItem: NSObject, NSFileProviderItem {
|
|||||||
|
|
||||||
// MARK: - Local File Status
|
// MARK: - Local File Status
|
||||||
|
|
||||||
var isUploaded: Bool { true }
|
var isUploaded: Bool {
|
||||||
var isUploading: Bool { false }
|
true
|
||||||
var isDownloaded: Bool { true }
|
}
|
||||||
var isDownloading: Bool { false }
|
|
||||||
var isMostRecentVersionDownloaded: Bool { true }
|
var isUploading: Bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
var isDownloaded: Bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
var isDownloading: Bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
var isMostRecentVersionDownloaded: Bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
private var isDirectory: Bool {
|
private var isDirectory: Bool {
|
||||||
var isDir: ObjCBool = false
|
var isDir: ObjCBool = false
|
||||||
|
|||||||
@@ -218,7 +218,9 @@ public extension UTType {
|
|||||||
// MARK: - FileDocument for Export
|
// MARK: - FileDocument for Export
|
||||||
|
|
||||||
public struct ProfileExportDocument: FileDocument {
|
public struct ProfileExportDocument: FileDocument {
|
||||||
public static var readableContentTypes: [UTType] { [.profile] }
|
public static var readableContentTypes: [UTType] {
|
||||||
|
[.profile]
|
||||||
|
}
|
||||||
|
|
||||||
public let data: Data
|
public let data: Data
|
||||||
public let filename: String
|
public let filename: String
|
||||||
@@ -245,7 +247,9 @@ public extension UTType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public struct ProfileJSONExportDocument: FileDocument {
|
public struct ProfileJSONExportDocument: FileDocument {
|
||||||
public static var readableContentTypes: [UTType] { [.json] }
|
public static var readableContentTypes: [UTType] {
|
||||||
|
[.json]
|
||||||
|
}
|
||||||
|
|
||||||
public let content: String
|
public let content: String
|
||||||
public let filename: String
|
public let filename: String
|
||||||
@@ -274,7 +278,9 @@ public extension UTType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public struct ProfileAnyExportDocument: FileDocument {
|
public struct ProfileAnyExportDocument: FileDocument {
|
||||||
public static var readableContentTypes: [UTType] { [.data, .json] }
|
public static var readableContentTypes: [UTType] {
|
||||||
|
[.data, .json]
|
||||||
|
}
|
||||||
|
|
||||||
public let data: Data
|
public let data: Data
|
||||||
public let filename: String
|
public let filename: String
|
||||||
|
|||||||
@@ -77,7 +77,10 @@ public class CommandClient: ObservableObject {
|
|||||||
@Published public var isConnected: Bool
|
@Published public var isConnected: Bool
|
||||||
// Coalesce traffic updates so SwiftUI re-renders once per status tick.
|
// Coalesce traffic updates so SwiftUI re-renders once per status tick.
|
||||||
@Published private var trafficSnapshot = TrafficSnapshot()
|
@Published private var trafficSnapshot = TrafficSnapshot()
|
||||||
public var status: LibboxStatusMessage? { trafficSnapshot.status }
|
public var status: LibboxStatusMessage? {
|
||||||
|
trafficSnapshot.status
|
||||||
|
}
|
||||||
|
|
||||||
public var statusPublisher: AnyPublisher<LibboxStatusMessage?, Never> {
|
public var statusPublisher: AnyPublisher<LibboxStatusMessage?, Never> {
|
||||||
$trafficSnapshot
|
$trafficSnapshot
|
||||||
.map(\.status)
|
.map(\.status)
|
||||||
@@ -97,8 +100,13 @@ public class CommandClient: ObservableObject {
|
|||||||
@Published public var hasAnyConnection: Bool = false
|
@Published public var hasAnyConnection: Bool = false
|
||||||
private var connectionsStore: LibboxConnections?
|
private var connectionsStore: LibboxConnections?
|
||||||
|
|
||||||
public var uplinkHistory: [CGFloat] { trafficSnapshot.uplinkHistory }
|
public var uplinkHistory: [CGFloat] {
|
||||||
public var downlinkHistory: [CGFloat] { trafficSnapshot.downlinkHistory }
|
trafficSnapshot.uplinkHistory
|
||||||
|
}
|
||||||
|
|
||||||
|
public var downlinkHistory: [CGFloat] {
|
||||||
|
trafficSnapshot.downlinkHistory
|
||||||
|
}
|
||||||
|
|
||||||
// Batch processing for logs
|
// Batch processing for logs
|
||||||
private var pendingLogs: [LogEntry] = []
|
private var pendingLogs: [LogEntry] = []
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ public struct AlertState: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public extension View {
|
public extension View {
|
||||||
@ViewBuilder
|
|
||||||
func alert(_ binding: Binding<AlertState?>) -> some View {
|
func alert(_ binding: Binding<AlertState?>) -> some View {
|
||||||
alert(
|
alert(
|
||||||
binding.wrappedValue?.title ?? "",
|
binding.wrappedValue?.title ?? "",
|
||||||
@@ -119,7 +118,10 @@ public extension View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public struct ImportRemoteProfileRequest: Hashable, Identifiable {
|
public struct ImportRemoteProfileRequest: Hashable, Identifiable {
|
||||||
public var id: String { url }
|
public var id: String {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
|
||||||
public let name: String
|
public let name: String
|
||||||
public let url: String
|
public let url: String
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,14 @@ extension ExtensionStartupError: LocalizedError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension ExtensionStartupError: CustomNSError {
|
extension ExtensionStartupError: CustomNSError {
|
||||||
public static var errorDomain: String { "ExtensionStartupError" }
|
public static var errorDomain: String {
|
||||||
public var errorCode: Int { 1 }
|
"ExtensionStartupError"
|
||||||
|
}
|
||||||
|
|
||||||
|
public var errorCode: Int {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
public var errorUserInfo: [String: Any] {
|
public var errorUserInfo: [String: Any] {
|
||||||
[NSLocalizedDescriptionKey: message]
|
[NSLocalizedDescriptionKey: message]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -262,8 +262,7 @@ public class ExtensionProfile: ObservableObject {
|
|||||||
if managers.isEmpty {
|
if managers.isEmpty {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
let profile = ExtensionProfile(managers[0])
|
return ExtensionProfile(managers[0])
|
||||||
return profile
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func install() async throws {
|
public static func install() async throws {
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ public enum OnDemandRuleAction: Int, Codable, CaseIterable, Identifiable {
|
|||||||
case evaluateConnection = 3
|
case evaluateConnection = 3
|
||||||
case ignore = 4
|
case ignore = 4
|
||||||
|
|
||||||
public var id: Int { rawValue }
|
public var id: Int {
|
||||||
|
rawValue
|
||||||
|
}
|
||||||
|
|
||||||
public var name: String {
|
public var name: String {
|
||||||
switch self {
|
switch self {
|
||||||
@@ -46,7 +48,9 @@ public enum OnDemandRuleInterfaceType: Int, Codable, Identifiable {
|
|||||||
case cellular = 3
|
case cellular = 3
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public var id: Int { rawValue }
|
public var id: Int {
|
||||||
|
rawValue
|
||||||
|
}
|
||||||
|
|
||||||
public var name: String {
|
public var name: String {
|
||||||
switch self {
|
switch self {
|
||||||
@@ -80,7 +84,9 @@ public enum EvaluateConnectionRuleAction: Int, Codable, CaseIterable, Identifiab
|
|||||||
case connectIfNeeded = 1
|
case connectIfNeeded = 1
|
||||||
case neverConnect = 2
|
case neverConnect = 2
|
||||||
|
|
||||||
public var id: Int { rawValue }
|
public var id: Int {
|
||||||
|
rawValue
|
||||||
|
}
|
||||||
|
|
||||||
public var name: String {
|
public var name: String {
|
||||||
switch self {
|
switch self {
|
||||||
|
|||||||
@@ -22,16 +22,41 @@ public enum AppConfiguration {
|
|||||||
return String(appGroupID[..<dotIndex])
|
return String(appGroupID[..<dotIndex])
|
||||||
}
|
}
|
||||||
|
|
||||||
public static var extensionBundleID: String { "\(packageName).extension" }
|
public static var extensionBundleID: String {
|
||||||
public static var systemExtensionBundleID: String { "\(packageName).system" }
|
"\(packageName).extension"
|
||||||
public static var fileProviderDomainID: String { "\(packageName).workingdir" }
|
}
|
||||||
public static var widgetControlKind: String { "\(packageName).widget.ServiceToggle" }
|
|
||||||
public static var profileUTType: String { "\(packageName).profile" }
|
public static var systemExtensionBundleID: String {
|
||||||
public static var backgroundTaskID: String { "\(packageName).update_profiles" }
|
"\(packageName).system"
|
||||||
public static var iCloudContainerID: String { "iCloud.\(packageName)" }
|
}
|
||||||
|
|
||||||
|
public static var fileProviderDomainID: String {
|
||||||
|
"\(packageName).workingdir"
|
||||||
|
}
|
||||||
|
|
||||||
|
public static var widgetControlKind: String {
|
||||||
|
"\(packageName).widget.ServiceToggle"
|
||||||
|
}
|
||||||
|
|
||||||
|
public static var profileUTType: String {
|
||||||
|
"\(packageName).profile"
|
||||||
|
}
|
||||||
|
|
||||||
|
public static var backgroundTaskID: String {
|
||||||
|
"\(packageName).update_profiles"
|
||||||
|
}
|
||||||
|
|
||||||
|
public static var iCloudContainerID: String {
|
||||||
|
"iCloud.\(packageName)"
|
||||||
|
}
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
public static var rootHelperBundleID: String { "\(packageName).helper" }
|
public static var rootHelperBundleID: String {
|
||||||
public static var rootHelperMachService: String { "\(appGroupID).helper" }
|
"\(packageName).helper"
|
||||||
|
}
|
||||||
|
|
||||||
|
public static var rootHelperMachService: String {
|
||||||
|
"\(appGroupID).helper"
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ open class ApplicationDelegate: NSObject, NSApplicationDelegate, UNUserNotificat
|
|||||||
],
|
],
|
||||||
intentIdentifiers: []
|
intentIdentifiers: []
|
||||||
),
|
),
|
||||||
]
|
])
|
||||||
)
|
|
||||||
notificationCenter.delegate = self
|
notificationCenter.delegate = self
|
||||||
let event = NSAppleEventManager.shared().currentAppleEvent
|
let event = NSAppleEventManager.shared().currentAppleEvent
|
||||||
let launchedAsLogInItem =
|
let launchedAsLogInItem =
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ struct EditProfileContentWindow: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private var defaultEditorView: some View {
|
private var defaultEditorView: some View {
|
||||||
Group {
|
Group {
|
||||||
if readOnly {
|
if readOnly {
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ public struct SidebarView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private var disconnectedContent: some View {
|
private var disconnectedContent: some View {
|
||||||
List(selection: $localSelection) {
|
List(selection: $localSelection) {
|
||||||
ForEach(NavigationPage.allCases.filter { $0.visible(nil) }, id: \.self) { it in
|
ForEach(NavigationPage.allCases.filter { $0.visible(nil) }, id: \.self) { it in
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ class ApplicationDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCe
|
|||||||
],
|
],
|
||||||
intentIdentifiers: []
|
intentIdentifiers: []
|
||||||
),
|
),
|
||||||
]
|
])
|
||||||
)
|
|
||||||
notificationCenter.delegate = self
|
notificationCenter.delegate = self
|
||||||
setup()
|
setup()
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ struct MainView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private var baseTabView: some View {
|
private var baseTabView: some View {
|
||||||
tabView(showsBottomAccessory: false)
|
tabView(showsBottomAccessory: false)
|
||||||
}
|
}
|
||||||
@@ -66,7 +65,6 @@ struct MainView: View {
|
|||||||
tabView(showsBottomAccessory: shouldShowBottomAccessory)
|
tabView(showsBottomAccessory: shouldShowBottomAccessory)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private func tabView(showsBottomAccessory: Bool) -> some View {
|
private func tabView(showsBottomAccessory: Bool) -> some View {
|
||||||
TabView(selection: $selection) {
|
TabView(selection: $selection) {
|
||||||
ForEach(NavigationPage.allCases, id: \.self) { page in
|
ForEach(NavigationPage.allCases, id: \.self) { page in
|
||||||
@@ -95,7 +93,6 @@ struct MainView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private func tabBarBackgroundIfAvailable(_ content: some View) -> some View {
|
private func tabBarBackgroundIfAvailable(_ content: some View) -> some View {
|
||||||
content
|
content
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ final class SnapshotTests: XCTestCase {
|
|||||||
app.launch()
|
app.launch()
|
||||||
}
|
}
|
||||||
|
|
||||||
func test01Dashboard() throws {
|
func test01Dashboard() {
|
||||||
snapshot("01_Dashboard")
|
snapshot("01_Dashboard")
|
||||||
}
|
}
|
||||||
|
|
||||||
func test02Logs() throws {
|
func test02Logs() {
|
||||||
if app.tabBars.buttons["Logs"].exists {
|
if app.tabBars.buttons["Logs"].exists {
|
||||||
app.tabBars.buttons["Logs"].firstMatch.tap()
|
app.tabBars.buttons["Logs"].firstMatch.tap()
|
||||||
} else if app.buttons["Logs"].exists {
|
} else if app.buttons["Logs"].exists {
|
||||||
@@ -24,7 +24,7 @@ final class SnapshotTests: XCTestCase {
|
|||||||
snapshot("02_Logs")
|
snapshot("02_Logs")
|
||||||
}
|
}
|
||||||
|
|
||||||
func test03Settings() throws {
|
func test03Settings() {
|
||||||
// iPad on iOS 18+ uses floating tab bar which creates nested elements
|
// iPad on iOS 18+ uses floating tab bar which creates nested elements
|
||||||
// Use firstMatch to handle multiple matching elements
|
// Use firstMatch to handle multiple matching elements
|
||||||
if app.tabBars.buttons["Settings"].exists {
|
if app.tabBars.buttons["Settings"].exists {
|
||||||
|
|||||||
@@ -61,17 +61,17 @@ final class SnapshotTests: XCTestCase {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func test01Dashboard() throws {
|
func test01Dashboard() {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
snapshot("01_Dashboard")
|
snapshot("01_Dashboard")
|
||||||
}
|
}
|
||||||
|
|
||||||
func test02Logs() throws {
|
func test02Logs() {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
snapshot("02_Logs")
|
snapshot("02_Logs")
|
||||||
}
|
}
|
||||||
|
|
||||||
func test03Settings() throws {
|
func test03Settings() {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
snapshot("03_Settings")
|
snapshot("03_Settings")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,17 +55,17 @@ final class SnapshotTests: XCTestCase {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func test01Dashboard() throws {
|
func test01Dashboard() {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
snapshot("01_Dashboard")
|
snapshot("01_Dashboard")
|
||||||
}
|
}
|
||||||
|
|
||||||
func test02Logs() throws {
|
func test02Logs() {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
snapshot("02_Logs")
|
snapshot("02_Logs")
|
||||||
}
|
}
|
||||||
|
|
||||||
func test03Settings() throws {
|
func test03Settings() {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
snapshot("03_Settings")
|
snapshot("03_Settings")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ final class SnapshotTests: XCTestCase {
|
|||||||
app.launch()
|
app.launch()
|
||||||
}
|
}
|
||||||
|
|
||||||
func test01Dashboard() throws {
|
func test01Dashboard() {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
if app.outlines.staticTexts["Dashboard"].exists {
|
if app.outlines.staticTexts["Dashboard"].exists {
|
||||||
app.outlines.staticTexts["Dashboard"].click()
|
app.outlines.staticTexts["Dashboard"].click()
|
||||||
@@ -20,7 +20,7 @@ final class SnapshotTests: XCTestCase {
|
|||||||
snapshot("01_Dashboard")
|
snapshot("01_Dashboard")
|
||||||
}
|
}
|
||||||
|
|
||||||
func test02Logs() throws {
|
func test02Logs() {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
if app.tabBars.buttons["Logs"].exists {
|
if app.tabBars.buttons["Logs"].exists {
|
||||||
app.tabBars.buttons["Logs"].firstMatch.tap()
|
app.tabBars.buttons["Logs"].firstMatch.tap()
|
||||||
@@ -47,7 +47,7 @@ final class SnapshotTests: XCTestCase {
|
|||||||
snapshot("02_Logs")
|
snapshot("02_Logs")
|
||||||
}
|
}
|
||||||
|
|
||||||
func test03Settings() throws {
|
func test03Settings() {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
if app.tabBars.buttons["Settings"].exists {
|
if app.tabBars.buttons["Settings"].exists {
|
||||||
app.tabBars.buttons["Settings"].firstMatch.tap()
|
app.tabBars.buttons["Settings"].firstMatch.tap()
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ final class UITests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
func testExample() throws {
|
func testExample() {
|
||||||
// UI tests must launch the application that they test.
|
// UI tests must launch the application that they test.
|
||||||
let app = XCUIApplication()
|
let app = XCUIApplication()
|
||||||
app.launch()
|
app.launch()
|
||||||
@@ -31,7 +31,7 @@ final class UITests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
func testLaunchPerformance() throws {
|
func testLaunchPerformance() {
|
||||||
// This measures how long it takes to launch your application.
|
// This measures how long it takes to launch your application.
|
||||||
measure(metrics: [XCTApplicationLaunchMetric()]) {
|
measure(metrics: [XCTApplicationLaunchMetric()]) {
|
||||||
XCUIApplication().launch()
|
XCUIApplication().launch()
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ final class UITestsLaunchTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
func testLaunch() throws {
|
func testLaunch() {
|
||||||
let app = XCUIApplication()
|
let app = XCUIApplication()
|
||||||
app.launch()
|
app.launch()
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ enum WidgetAppConfiguration {
|
|||||||
return value
|
return value
|
||||||
}()
|
}()
|
||||||
|
|
||||||
static var widgetControlKind: String { "\(packageName).widget.ServiceToggle" }
|
static var widgetControlKind: String {
|
||||||
|
"\(packageName).widget.ServiceToggle"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NEVPNStatus {
|
extension NEVPNStatus {
|
||||||
@@ -67,4 +69,3 @@ enum WidgetTunnelControl {
|
|||||||
return managers.first
|
return managers.first
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user