// // CBManagerState.swift // USB Meter // // Created by Bogdan Timofte on 02/03/2020. // Copyright © 2020 Bogdan Timofte. All rights reserved. // //import Foundation import CoreBluetooth import SwiftUI //Manager States //.poweredOff A state that indicates Bluetooth is currently powered off. //.poweredOn A state that indicates Bluetooth is currently powered on and available to use. //.resetting A state that indicates the connection with the system service was momentarily lost. //.unauthorized A state that indicates the application isn’t authorized to use the Bluetooth low energy role. //.unknown The manager’s state is unknown. //.unsupported A state that indicates this device doesn’t support the Bluetooth low energy central or client role. extension CBManagerState { var description: String { switch self { case .poweredOff: return "CBManagerState.poweredOff" case .poweredOn: return "CBManagerState.poweredOn" case .resetting: return "CBManagerState.resetting" case .unauthorized: return "CBManagerState.unauthorized" case .unknown: return "CBManagerState.unknown" case .unsupported: return "CBManagerState.unsupported" default: return "CBManagerState.other" } } var color: Color { switch self { case .poweredOff: return Color.red case .poweredOn: return Color.blue case .resetting: return Color.green case .unauthorized: return Color.orange case .unknown: return Color.secondary case .unsupported: return Color.gray default: return Color.yellow } } var helpView: AnyView { switch self { case .poweredOff: return AnyView(poweredOffHelperView()) case .poweredOn: return AnyView(poweredOnHelperView()) case .resetting: return AnyView(resettingHelperView()) case .unauthorized: return AnyView(unauthorizedHelperView()) case .unknown: return AnyView(unknownHelperView()) case .unsupported: return AnyView(unsupportedHelperView()) default: return AnyView(defaultHelperView()) } } private struct poweredOffHelperView: View { var body: some View { BluetoothHelpCard( title: "Bluetooth Off", detail: "Bluetooth is turned off on this device. You can enable it in Settings > Bluetooth.", tint: .red ) } } private struct poweredOnHelperView: View { var body: some View { BluetoothHelpCard( title: "Bluetooth Ready", detail: "Bluetooth is powered on and ready for scanning.", tint: .blue ) } } private struct resettingHelperView: View { var body: some View { BluetoothHelpCard( title: "Bluetooth Resetting", detail: "The Bluetooth stack is temporarily resetting. Wait a moment and try again.", tint: .green ) } } private struct unauthorizedHelperView: View { var body: some View { VStack(alignment: .leading, spacing: 12) { Text("Bluetooth Access Needed") .font(.headline) Text("This application does not have permission to access Bluetooth. You can enable it in Settings.") .font(.footnote) .foregroundColor(.secondary) Button(action: { UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil) }) { Text("Settings") } .padding(.horizontal, 14) .padding(.vertical, 10) .meterCard(tint: .orange, fillOpacity: 0.16, strokeOpacity: 0.22, cornerRadius: 14) .buttonStyle(.plain) } .frame(maxWidth: .infinity, alignment: .leading) .padding(20) .meterCard(tint: .orange, fillOpacity: 0.18, strokeOpacity: 0.24) .padding() } } private struct unknownHelperView: View { var body: some View { BluetoothHelpCard( title: "Unknown Bluetooth State", detail: "Bluetooth is reporting an unknown state. Wait a moment and check again.", tint: .secondary ) } } private struct unsupportedHelperView: View { var body: some View { BluetoothHelpCard( title: "Bluetooth Unsupported", detail: "This device does not support the Bluetooth capabilities required by these USB meters.", tint: .gray ) } } private struct defaultHelperView: View { var body: some View { BluetoothHelpCard( title: "Other Bluetooth State", detail: "Bluetooth is in an unexpected state. Try again, then contact the developer if it persists.", tint: .yellow ) } } private struct BluetoothHelpCard: View { let title: String let detail: String let tint: Color var body: some View { ScrollView { VStack(alignment: .leading, spacing: 10) { Text(title) .font(.system(.title3, design: .rounded).weight(.bold)) Text(detail) .font(.footnote) .foregroundColor(.secondary) } .frame(maxWidth: .infinity, alignment: .leading) .padding(20) .meterCard(tint: tint, fillOpacity: 0.18, strokeOpacity: 0.24) .padding() } .background( LinearGradient( colors: [tint.opacity(0.14), Color.clear], startPoint: .topLeading, endPoint: .bottomTrailing ) .ignoresSafeArea() ) } } }