USB-Meter / USB Meter / Views / ContentView.swift
1 contributor
180 lines | 6.092kb
//
//  ContentView.swift
//  USB Meter
//
//  Created by Bogdan Timofte on 01/03/2020.
//  Copyright © 2020 Bogdan Timofte. All rights reserved.
//

//MARK: Bluetooth Icon: https://upload.wikimedia.org/wikipedia/commons/d/da/Bluetooth.svg

import SwiftUI

struct ContentView: View {
    
    @EnvironmentObject private var appData: AppData
    
    var body: some View {
        NavigationView {
            ScrollView {
                VStack(alignment: .leading, spacing: 18) {
                    headerCard
                    helpSection
                    devicesSection
                }
                .padding()
            }
            .background(
                LinearGradient(
                    colors: [
                        appData.bluetoothManager.managerState.color.opacity(0.18),
                        Color.clear
                    ],
                    startPoint: .topLeading,
                    endPoint: .bottomTrailing
                )
                .ignoresSafeArea()
            )
            .navigationBarTitle(Text("USB Meters"), displayMode: .inline)
        }
        .onAppear {
            appData.bluetoothManager.start()
        }
    }

    private var headerCard: some View {
        VStack(alignment: .leading, spacing: 10) {
            Text("USB Meters")
                .font(.system(.title2, design: .rounded).weight(.bold))
            Text("Browse nearby supported meters and jump into live diagnostics, charge records, and device controls.")
                .font(.footnote)
                .foregroundColor(.secondary)
            HStack {
                Label("Bluetooth", systemImage: "bolt.horizontal.circle.fill")
                    .font(.footnote.weight(.semibold))
                    .foregroundColor(appData.bluetoothManager.managerState.color)
                Spacer()
                Text(bluetoothStatusText)
                    .font(.caption.weight(.semibold))
                    .foregroundColor(.secondary)
            }
        }
        .padding(18)
        .meterCard(tint: appData.bluetoothManager.managerState.color, fillOpacity: 0.22, strokeOpacity: 0.26)
    }

    private var helpSection: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Help")
                .font(.headline)

            NavigationLink(destination: appData.bluetoothManager.managerState.helpView) {
                sidebarLinkCard(
                    title: "Bluetooth",
                    subtitle: "Permissions, adapter state, and connection tips.",
                    symbol: "bolt.horizontal.circle.fill",
                    tint: appData.bluetoothManager.managerState.color
                )
            }
            .buttonStyle(.plain)

            NavigationLink(destination: DeviceHelpView()) {
                sidebarLinkCard(
                    title: "Device",
                    subtitle: "Quick checks when a meter is not responding as expected.",
                    symbol: "questionmark.circle.fill",
                    tint: .orange
                )
            }
            .buttonStyle(.plain)
        }
    }

    private var devicesSection: some View {
        VStack(alignment: .leading, spacing: 12) {
            HStack {
                Text("Discovered Devices")
                    .font(.headline)
                Spacer()
                Text("\(appData.meters.count)")
                    .font(.caption.weight(.bold))
                    .padding(.horizontal, 10)
                    .padding(.vertical, 6)
                    .meterCard(tint: .blue, fillOpacity: 0.18, strokeOpacity: 0.24, cornerRadius: 999)
            }

            if appData.meters.isEmpty {
                Text("No supported meters are visible right now.")
                    .font(.footnote)
                    .foregroundColor(.secondary)
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .padding(18)
                    .meterCard(tint: .secondary, fillOpacity: 0.14, strokeOpacity: 0.20)
            } else {
                ForEach(discoveredMeters, id: \.self) { meter in
                    NavigationLink(destination: MeterView().environmentObject(meter)) {
                        MeterRowView()
                            .environmentObject(meter)
                    }
                    .buttonStyle(.plain)
                }
            }
        }
    }

    private var discoveredMeters: [Meter] {
        Array(appData.meters.values).sorted { lhs, rhs in
            lhs.name.localizedCaseInsensitiveCompare(rhs.name) == .orderedAscending
        }
    }

    private var bluetoothStatusText: String {
        switch appData.bluetoothManager.managerState {
        case .poweredOff:
            return "Off"
        case .poweredOn:
            return "On"
        case .resetting:
            return "Resetting"
        case .unauthorized:
            return "Unauthorized"
        case .unknown:
            return "Unknown"
        case .unsupported:
            return "Unsupported"
        @unknown default:
            return "Other"
        }
    }

    private func sidebarLinkCard(
        title: String,
        subtitle: String,
        symbol: String,
        tint: Color
    ) -> some View {
        HStack(spacing: 14) {
            Image(systemName: symbol)
                .font(.system(size: 18, weight: .semibold))
                .foregroundColor(tint)
                .frame(width: 42, height: 42)
                .background(Circle().fill(tint.opacity(0.18)))

            VStack(alignment: .leading, spacing: 4) {
                Text(title)
                    .font(.headline)
                Text(subtitle)
                    .font(.caption)
                    .foregroundColor(.secondary)
            }

            Spacer()

            Image(systemName: "chevron.right")
                .font(.footnote.weight(.bold))
                .foregroundColor(.secondary)
        }
        .padding(14)
        .meterCard(tint: tint, fillOpacity: 0.16, strokeOpacity: 0.22, cornerRadius: 18)
    }
}