summaryrefslogtreecommitdiff
path: root/LearnMapKit/App/RefactoredApp.swift
diff options
context:
space:
mode:
Diffstat (limited to 'LearnMapKit/App/RefactoredApp.swift')
-rw-r--r--LearnMapKit/App/RefactoredApp.swift277
1 files changed, 277 insertions, 0 deletions
diff --git a/LearnMapKit/App/RefactoredApp.swift b/LearnMapKit/App/RefactoredApp.swift
new file mode 100644
index 0000000..fbd7417
--- /dev/null
+++ b/LearnMapKit/App/RefactoredApp.swift
@@ -0,0 +1,277 @@
+//
+// RefactoredApp.swift
+// LearnMapKit
+//
+// Refactored app entry point with dependency injection
+//
+
+import SwiftUI
+import ArgumentParser
+
+@main
+struct RefactoredLearnMapKitApp: App {
+ private let container = DependencyContainer()
+
+ init() {
+ setupFromCommandLineArguments()
+ }
+
+ var body: some Scene {
+ WindowGroup {
+ MainContentView()
+ .environmentObject(container.makeAircraftTrackingViewModel())
+ .environmentObject(container.configurationManager)
+ }
+ }
+
+ private func setupFromCommandLineArguments() {
+ guard let args = parseCommandLineArguments() else { return }
+
+ Task {
+ // Configure based on command line arguments
+ if let hostname = args.hostname, let port = args.port {
+ await configureNetworkMode(hostname: hostname, port: port)
+ } else if let inputFile = args.inputfile {
+ await configureFileMode(filePath: inputFile)
+ }
+ // Otherwise use default configuration
+ }
+ }
+
+ private func parseCommandLineArguments() -> CommandLineArgs? {
+ do {
+ return try CommandLineArgs.parse()
+ } catch {
+ // If parsing fails, continue with default configuration
+ print("Command line parsing failed: \(error)")
+ return nil
+ }
+ }
+
+ private func configureNetworkMode(hostname: String, port: Int) async {
+ let networkConfig = NetworkDataSourceConfiguration(hostname: hostname, port: port)
+ let config = AppConfiguration(
+ dataSource: networkConfig,
+ displaySettings: DisplaySettings(),
+ mapSettings: MapSettings(),
+ networkSettings: NetworkSettings()
+ )
+ await container.configurationManager.updateConfiguration(config)
+ }
+
+ private func configureFileMode(filePath: String) async {
+ let fileConfig = FileDataSourceConfiguration(filePath: filePath)
+ let config = AppConfiguration(
+ dataSource: fileConfig,
+ displaySettings: DisplaySettings(),
+ mapSettings: MapSettings(),
+ networkSettings: NetworkSettings()
+ )
+ await container.configurationManager.updateConfiguration(config)
+ }
+}
+
+// MARK: - Main Content View
+struct MainContentView: View {
+ @EnvironmentObject var viewModel: AircraftTrackingViewModel
+ @EnvironmentObject var configurationManager: ConfigurationManager
+
+ var body: some View {
+ NavigationView {
+ ZStack {
+ AircraftMapView(
+ aircraft: viewModel.aircraft,
+ selectedAircraft: viewModel.selectedAircraft,
+ mapRegion: $viewModel.mapRegion,
+ onAircraftSelected: { aircraft in
+ viewModel.selectAircraft(aircraft)
+ }
+ )
+
+ VStack {
+ Spacer()
+ HStack {
+ ConnectionStatusBar(
+ state: viewModel.connectionState,
+ aircraftCount: viewModel.aircraftCount
+ )
+ Spacer()
+ }
+ .padding()
+ }
+
+ if viewModel.isLoading {
+ LoadingOverlay()
+ }
+ }
+ .navigationTitle("Aircraft Tracking")
+ .toolbar {
+ ToolbarItemGroup(placement: .primaryAction) {
+ ConnectionControlButton(
+ connectionState: viewModel.connectionState,
+ onStart: {
+ Task { await viewModel.startTracking() }
+ },
+ onStop: {
+ Task { await viewModel.stopTracking() }
+ },
+ onReconnect: {
+ Task { await viewModel.reconnect() }
+ }
+ )
+
+ Button("Settings") {
+ viewModel.showingSettings = true
+ }
+ }
+ }
+ .sheet(isPresented: $viewModel.showingSettings) {
+ SettingsView()
+ .environmentObject(viewModel)
+ }
+ .alert("Error", isPresented: .constant(viewModel.errorMessage != nil)) {
+ Button("OK") {
+ viewModel.clearError()
+ }
+ } message: {
+ Text(viewModel.errorMessage ?? "")
+ }
+ }
+ .task {
+ // Auto-start tracking when view appears
+ await viewModel.startTracking()
+ }
+ }
+}
+
+// MARK: - Supporting Views
+struct ConnectionStatusBar: View {
+ let state: DataSourceState
+ let aircraftCount: Int
+
+ var body: some View {
+ HStack(spacing: 12) {
+ StatusIndicator(state: state)
+ Text(statusText)
+ .font(.caption)
+ .foregroundColor(.secondary)
+ }
+ .padding(.horizontal, 12)
+ .padding(.vertical, 6)
+ .background(.regularMaterial, in: RoundedRectangle(cornerRadius: 8))
+ }
+
+ private var statusText: String {
+ switch state {
+ case .connected:
+ return "Connected • \(aircraftCount) aircraft"
+ case .connecting:
+ return "Connecting..."
+ case .disconnected:
+ return "Disconnected"
+ case .error(let message):
+ return "Error: \(message)"
+ case .idle:
+ return "Ready"
+ case .configuring:
+ return "Configuring..."
+ }
+ }
+}
+
+struct StatusIndicator: View {
+ let state: DataSourceState
+
+ var body: some View {
+ Circle()
+ .fill(indicatorColor)
+ .frame(width: 8, height: 8)
+ }
+
+ private var indicatorColor: Color {
+ switch state {
+ case .connected:
+ return .green
+ case .connecting, .configuring:
+ return .orange
+ case .disconnected, .idle:
+ return .gray
+ case .error:
+ return .red
+ }
+ }
+}
+
+struct ConnectionControlButton: View {
+ let connectionState: DataSourceState
+ let onStart: () -> Void
+ let onStop: () -> Void
+ let onReconnect: () -> Void
+
+ var body: some View {
+ Button(action: buttonAction) {
+ Image(systemName: buttonIconName)
+ }
+ }
+
+ private var buttonIconName: String {
+ switch connectionState {
+ case .connected:
+ return "stop.circle"
+ case .connecting, .configuring:
+ return "stop.circle"
+ case .disconnected, .idle:
+ return "play.circle"
+ case .error:
+ return "arrow.clockwise.circle"
+ }
+ }
+
+ private func buttonAction() {
+ switch connectionState {
+ case .connected, .connecting, .configuring:
+ onStop()
+ case .disconnected, .idle:
+ onStart()
+ case .error:
+ onReconnect()
+ }
+ }
+}
+
+struct LoadingOverlay: View {
+ var body: some View {
+ ZStack {
+ Color.black.opacity(0.3)
+ .ignoresSafeArea()
+
+ VStack(spacing: 16) {
+ ProgressView()
+ .scaleEffect(1.2)
+ Text("Connecting...")
+ .font(.caption)
+ .foregroundColor(.secondary)
+ }
+ .padding()
+ .background(.regularMaterial, in: RoundedRectangle(cornerRadius: 12))
+ }
+ }
+}
+
+// MARK: - Command Line Arguments (Updated)
+struct CommandLineArgs: ParsableCommand {
+ @Option(name: .shortAndLong, help: "Hostname for network mode")
+ var hostname: String?
+
+ @Option(name: .shortAndLong, help: "Port for network mode")
+ var port: Int?
+
+ @Option(name: .shortAndLong, help: "Input file path for file mode")
+ var inputfile: String?
+
+ @Flag(name: .shortAndLong, help: "Enable debug mode")
+ var debug: Bool = false
+
+ @Flag(name: .shortAndLong, help: "Show version information")
+ var version: Bool = false
+} \ No newline at end of file