206 lines
6.6 KiB
Swift
206 lines
6.6 KiB
Swift
import SwiftUI
|
|
|
|
struct ContentView: View {
|
|
@EnvironmentObject var sdk: SDKManager
|
|
@State private var userId = "test-user-001"
|
|
@State private var fileKey = ""
|
|
|
|
var body: some View {
|
|
NavigationView {
|
|
List {
|
|
statusSection
|
|
scanSection
|
|
deviceSection
|
|
fileSection
|
|
logSection
|
|
}
|
|
.navigationTitle("BLE SDK Test")
|
|
}
|
|
}
|
|
|
|
// MARK: - Status
|
|
|
|
private var statusSection: some View {
|
|
Section("Status") {
|
|
HStack {
|
|
Text("Connection")
|
|
Spacer()
|
|
Text(sdk.btState)
|
|
.foregroundStyle(sdk.btState == "connected" ? .green : .secondary)
|
|
.fontWeight(.medium)
|
|
}
|
|
|
|
if let error = sdk.error {
|
|
HStack {
|
|
Image(systemName: "exclamationmark.triangle.fill")
|
|
.foregroundStyle(.red)
|
|
Text(error)
|
|
.foregroundStyle(.red)
|
|
.font(.caption)
|
|
}
|
|
}
|
|
|
|
HStack {
|
|
Text("SDK Ready")
|
|
Spacer()
|
|
Image(systemName: sdk.isSDKReady ? "checkmark.circle.fill" : "xmark.circle")
|
|
.foregroundStyle(sdk.isSDKReady ? .green : .red)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Scan
|
|
|
|
private var scanSection: some View {
|
|
Section("Scan") {
|
|
HStack {
|
|
Button("Scan") { sdk.scan() }
|
|
.buttonStyle(.borderedProminent)
|
|
.disabled(sdk.btState == "scanning")
|
|
|
|
Button("Stop") { sdk.stopScan() }
|
|
.buttonStyle(.bordered)
|
|
.disabled(sdk.btState != "scanning")
|
|
}
|
|
|
|
if sdk.discoveredDevices.isEmpty && sdk.btState == "scanning" {
|
|
HStack {
|
|
ProgressView()
|
|
Text("Searching...")
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
|
|
ForEach(sdk.discoveredDevices) { device in
|
|
Button {
|
|
sdk.stopScan()
|
|
sdk.connect(deviceId: device.id)
|
|
} label: {
|
|
HStack {
|
|
VStack(alignment: .leading) {
|
|
Text(device.name)
|
|
.font(.body)
|
|
Text(device.id)
|
|
.font(.caption2)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
Spacer()
|
|
Text("\(device.rssi) dBm")
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Device
|
|
|
|
private var deviceSection: some View {
|
|
Section("Device") {
|
|
if sdk.btState == "connected" {
|
|
if let device = sdk.connectedDevice {
|
|
LabeledContent("Name", value: device["name"] as? String ?? "—")
|
|
LabeledContent("ID", value: device["id"] as? String ?? "—")
|
|
}
|
|
|
|
LabeledContent("Version", value: sdk.version.isEmpty ? "—" : sdk.version)
|
|
|
|
if let info = sdk.deviceInfo {
|
|
LabeledContent("Brand", value: info.brand)
|
|
LabeledContent("Screen", value: info.screenSize)
|
|
LabeledContent("Battery", value: "\(info.batteryLevel)%")
|
|
LabeledContent("Storage", value: formatStorage(free: info.freeSpace, total: info.totalSpace))
|
|
}
|
|
|
|
HStack(spacing: 12) {
|
|
Button("Get Info") { sdk.getDeviceInfo() }
|
|
.buttonStyle(.bordered)
|
|
Button("Get Version") { sdk.getVersion() }
|
|
.buttonStyle(.bordered)
|
|
}
|
|
|
|
HStack {
|
|
TextField("User ID", text: $userId)
|
|
.textFieldStyle(.roundedBorder)
|
|
Button("Bind") { sdk.bind(userId: userId) }
|
|
.buttonStyle(.bordered)
|
|
}
|
|
|
|
HStack(spacing: 12) {
|
|
Button("Unbind") { sdk.unbind(userId: userId) }
|
|
.buttonStyle(.bordered)
|
|
Button("Disconnect") { sdk.disconnect() }
|
|
.buttonStyle(.bordered)
|
|
.tint(.red)
|
|
}
|
|
} else if sdk.btState == "connecting" {
|
|
HStack {
|
|
ProgressView()
|
|
Text("Connecting...")
|
|
}
|
|
} else {
|
|
Text("No device connected")
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - File
|
|
|
|
private var fileSection: some View {
|
|
Section("File Transfer") {
|
|
if sdk.btState == "connected" {
|
|
if sdk.transferProgress > 0 {
|
|
VStack(alignment: .leading) {
|
|
Text("Transfer: \(sdk.transferProgress)%")
|
|
.font(.caption)
|
|
ProgressView(value: Double(sdk.transferProgress), total: 100)
|
|
}
|
|
}
|
|
|
|
HStack {
|
|
TextField("File key to delete", text: $fileKey)
|
|
.textFieldStyle(.roundedBorder)
|
|
Button("Delete") { sdk.deleteFile(key: fileKey) }
|
|
.buttonStyle(.bordered)
|
|
.tint(.red)
|
|
.disabled(fileKey.isEmpty)
|
|
}
|
|
} else {
|
|
Text("Connect a device first")
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Log
|
|
|
|
private var logSection: some View {
|
|
Section("Event Log (\(sdk.logs.count))") {
|
|
ForEach(sdk.logs.prefix(50)) { entry in
|
|
VStack(alignment: .leading, spacing: 2) {
|
|
Text(entry.message)
|
|
.font(.caption)
|
|
Text(entry.time, style: .time)
|
|
.font(.caption2)
|
|
.foregroundStyle(.tertiary)
|
|
}
|
|
}
|
|
|
|
if sdk.logs.isEmpty {
|
|
Text("No events yet")
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Helpers
|
|
|
|
private func formatStorage(free: Int, total: Int) -> String {
|
|
let freeMB = free / 1_048_576
|
|
let totalMB = total / 1_048_576
|
|
return "\(freeMB)MB / \(totalMB)MB"
|
|
}
|
|
}
|