Add source code
This commit is contained in:
parent
69c08de01c
commit
0416d157d7
14 changed files with 1672 additions and 0 deletions
218
TetheringHider/Views/ContentView.swift
Normal file
218
TetheringHider/Views/ContentView.swift
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
//
|
||||
// ContentView.swift
|
||||
//
|
||||
//
|
||||
// Created by Jesús David Chapman Vélez on 12/08/26.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ContentView: View {
|
||||
@Environment(TTLManager.self) private var ttlManager
|
||||
@AppStorage("startMinimized") private var startMinimized = false
|
||||
@State private var hasHandledInitialLaunch = false
|
||||
@State private var isProcessing = false
|
||||
@State private var showError = false
|
||||
@State private var errorMessage = ""
|
||||
@Namespace private var shieldNamespace
|
||||
|
||||
private let authService = AuthenticationService()
|
||||
private let commandService = SystemCommandService()
|
||||
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
|
||||
private var accentColor: Color {
|
||||
if colorScheme == .light {
|
||||
return ttlManager.isProtected
|
||||
? Color(hue: 0.38, saturation: 0.85, brightness: 0.40)
|
||||
: Color(hue: 0.05, saturation: 0.90, brightness: 0.45)
|
||||
} else {
|
||||
return ttlManager.isProtected
|
||||
? Color(hue: 0.38, saturation: 0.70, brightness: 0.85)
|
||||
: Color(hue: 0.06, saturation: 0.70, brightness: 0.90)
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
// Background gradient
|
||||
backgroundGradient
|
||||
|
||||
VStack(spacing: 0) {
|
||||
// Header with glass
|
||||
headerSection
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.vertical, 10)
|
||||
.modifier(GlassInteractiveModifier(cornerRadius: 14, tintColor: accentColor))
|
||||
.padding(.top, 14)
|
||||
|
||||
Spacer(minLength: 12)
|
||||
|
||||
// Central antenna indicator
|
||||
StatusIndicator(
|
||||
isProtected: ttlManager.isProtected,
|
||||
isProcessing: isProcessing
|
||||
)
|
||||
.padding(.vertical, 10)
|
||||
|
||||
Spacer(minLength: 12)
|
||||
|
||||
// Control panel
|
||||
TTLControlPanel(
|
||||
currentTTL: ttlManager.currentTTL,
|
||||
currentIPv6HopLimit: ttlManager.currentIPv6HopLimit,
|
||||
targetTTL: ttlManager.targetTTL,
|
||||
defaultTTL: ttlManager.defaultTTL,
|
||||
isProtected: ttlManager.isProtected,
|
||||
isProcessing: isProcessing,
|
||||
onActivate: activateProtection,
|
||||
onDeactivate: deactivateProtection
|
||||
)
|
||||
.padding(.horizontal, 24)
|
||||
.padding(.bottom, 24)
|
||||
}
|
||||
}
|
||||
.frame(width: 400, height: 580)
|
||||
.alert("Error", isPresented: $showError) {
|
||||
Button("OK", role: .cancel) { }
|
||||
} message: {
|
||||
Text(errorMessage)
|
||||
}
|
||||
.task {
|
||||
ttlManager.refreshStatus()
|
||||
}
|
||||
}
|
||||
|
||||
private var backgroundGradient: some View {
|
||||
MeshGradient(
|
||||
width: 3, height: 3,
|
||||
points: [
|
||||
[0.0, 0.0], [0.5, 0.0], [1.0, 0.0],
|
||||
[0.0, 0.5], [0.5, 0.5], [1.0, 0.5],
|
||||
[0.0, 1.0], [0.5, 1.0], [1.0, 1.0]
|
||||
],
|
||||
colors: meshColors
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
.animation(.easeInOut(duration: 1.2), value: ttlManager.isProtected)
|
||||
.animation(.easeInOut(duration: 0.5), value: colorScheme)
|
||||
}
|
||||
|
||||
private var meshColors: [Color] {
|
||||
if colorScheme == .light {
|
||||
return ttlManager.isProtected ? [
|
||||
Color(hue: 0.44, saturation: 0.22, brightness: 0.95),
|
||||
Color(hue: 0.48, saturation: 0.18, brightness: 0.98),
|
||||
Color(hue: 0.52, saturation: 0.22, brightness: 0.94),
|
||||
Color(hue: 0.40, saturation: 0.16, brightness: 0.96),
|
||||
Color(hue: 0.46, saturation: 0.26, brightness: 0.93),
|
||||
Color(hue: 0.50, saturation: 0.18, brightness: 0.97),
|
||||
Color(hue: 0.42, saturation: 0.20, brightness: 0.95),
|
||||
Color(hue: 0.45, saturation: 0.16, brightness: 0.98),
|
||||
Color(hue: 0.51, saturation: 0.22, brightness: 0.94)
|
||||
] : [
|
||||
Color(hue: 0.04, saturation: 0.18, brightness: 0.96),
|
||||
Color(hue: 0.07, saturation: 0.14, brightness: 0.98),
|
||||
Color(hue: 0.09, saturation: 0.18, brightness: 0.95),
|
||||
Color(hue: 0.02, saturation: 0.14, brightness: 0.97),
|
||||
Color(hue: 0.05, saturation: 0.24, brightness: 0.94),
|
||||
Color(hue: 0.08, saturation: 0.16, brightness: 0.98),
|
||||
Color(hue: 0.03, saturation: 0.18, brightness: 0.95),
|
||||
Color(hue: 0.06, saturation: 0.14, brightness: 0.98),
|
||||
Color(hue: 0.08, saturation: 0.18, brightness: 0.94)
|
||||
]
|
||||
} else {
|
||||
return ttlManager.isProtected ? [
|
||||
Color(hue: 0.45, saturation: 0.4, brightness: 0.08),
|
||||
Color(hue: 0.50, saturation: 0.3, brightness: 0.10),
|
||||
Color(hue: 0.55, saturation: 0.4, brightness: 0.08),
|
||||
Color(hue: 0.40, saturation: 0.3, brightness: 0.12),
|
||||
Color(hue: 0.48, saturation: 0.5, brightness: 0.14),
|
||||
Color(hue: 0.52, saturation: 0.3, brightness: 0.10),
|
||||
Color(hue: 0.42, saturation: 0.4, brightness: 0.06),
|
||||
Color(hue: 0.47, saturation: 0.3, brightness: 0.10),
|
||||
Color(hue: 0.53, saturation: 0.4, brightness: 0.08)
|
||||
] : [
|
||||
Color(hue: 0.02, saturation: 0.3, brightness: 0.08),
|
||||
Color(hue: 0.05, saturation: 0.2, brightness: 0.10),
|
||||
Color(hue: 0.08, saturation: 0.3, brightness: 0.08),
|
||||
Color(hue: 0.00, saturation: 0.2, brightness: 0.12),
|
||||
Color(hue: 0.04, saturation: 0.4, brightness: 0.14),
|
||||
Color(hue: 0.07, saturation: 0.2, brightness: 0.10),
|
||||
Color(hue: 0.01, saturation: 0.3, brightness: 0.06),
|
||||
Color(hue: 0.03, saturation: 0.2, brightness: 0.10),
|
||||
Color(hue: 0.06, saturation: 0.3, brightness: 0.08)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Header
|
||||
|
||||
private var headerSection: some View {
|
||||
VStack(spacing: 6) {
|
||||
Text("TETHERING HIDER")
|
||||
.font(.system(size: 14, weight: .bold, design: .rounded))
|
||||
.tracking(4)
|
||||
.foregroundStyle(.secondary)
|
||||
|
||||
Text(ttlManager.isProtected ? "Tethering Hidden" : "Tethering Exposed")
|
||||
.font(.system(size: 13, weight: .medium))
|
||||
.foregroundStyle(ttlManager.isProtected
|
||||
? Color(hue: 0.38, saturation: 0.7, brightness: 0.85)
|
||||
: Color(hue: 0.06, saturation: 0.7, brightness: 0.90)
|
||||
)
|
||||
.contentTransition(.numericText())
|
||||
.animation(.easeInOut, value: ttlManager.isProtected)
|
||||
}
|
||||
}
|
||||
|
||||
private func activateProtection() {
|
||||
Task {
|
||||
isProcessing = true
|
||||
defer { isProcessing = false }
|
||||
|
||||
do {
|
||||
// Authenticate with Touch ID
|
||||
let authenticated = try await authService.authenticateWithBiometrics()
|
||||
guard authenticated else { return }
|
||||
|
||||
// Execute privileged command
|
||||
try await commandService.setTTL(ttlManager.targetTTL)
|
||||
|
||||
// Refresh status
|
||||
ttlManager.didSetTTL(ttlManager.targetTTL)
|
||||
} catch is AuthenticationError {
|
||||
|
||||
} catch SystemCommandError.userCancelledAuth {
|
||||
|
||||
} catch {
|
||||
errorMessage = error.localizedDescription
|
||||
showError = true
|
||||
ttlManager.setError(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func deactivateProtection() {
|
||||
Task {
|
||||
isProcessing = true
|
||||
defer { isProcessing = false }
|
||||
|
||||
do {
|
||||
let authenticated = try await authService.authenticateWithBiometrics()
|
||||
guard authenticated else { return }
|
||||
|
||||
try await commandService.resetTTL()
|
||||
ttlManager.didSetTTL(ttlManager.defaultTTL)
|
||||
} catch is AuthenticationError {
|
||||
|
||||
} catch SystemCommandError.userCancelledAuth {
|
||||
|
||||
} catch {
|
||||
errorMessage = error.localizedDescription
|
||||
showError = true
|
||||
ttlManager.setError(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue