diff --git a/app/src/main/java/com/example/smart_watch_android/BLE/BleManager.kt b/app/src/main/java/com/example/smart_watch_android/BLE/BleManager.kt index 1c1a8a1..3f9770c 100644 --- a/app/src/main/java/com/example/smart_watch_android/BLE/BleManager.kt +++ b/app/src/main/java/com/example/smart_watch_android/BLE/BleManager.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.core.app.ActivityCompat +import java.util.UUID class BleManager(private val context: Context) { val deviceUUIDs = DeviceUUIDs @@ -72,11 +73,11 @@ class BleManager(private val context: Context) { Log.d("ESP32_BLE", "4. Verbunden! Starte discoverServices()...") gatt.discoverServices() } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { - Log.d("ESP32_BLE", "5. Getrennt worden.") isConnected = false gatt.close() bluetoothGatt = null + Log.d("ESP32_BLE", "5. Getrennt worden.") } } else { Log.d("ESP32_BLE", "Fehler in onConnectionStateChange! Status-Code: $status") @@ -88,7 +89,7 @@ class BleManager(private val context: Context) { Log.d("ESP32_BLE", "6. onServicesDiscovered aufgerufen mit Status: $status") if (status == BluetoothGatt.GATT_SUCCESS) { isConnected = true - writeToEsp32("Hallo ESP32") + writeToEsp32("Hallo ESP32", deviceUUIDs.TIME_CHARACTERISTIC_UUID, deviceUUIDs.TIME_CHARACTERISTIC_UUID) Log.d("ESP32_BLE", "7. Services erfolgreich gefunden! Verbindung komplett erfolgreich.") } } @@ -106,8 +107,20 @@ class BleManager(private val context: Context) { Log.d("ESP32_BLE", "Exception gefangen: ${e.message}") } } + @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) + fun disconnectEsp32() { + // Nur den Disconnect-Befehl senden. + // Das Schließen (close) überlassen wir dem Callback, wenn es wirklich so weit ist! + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED) { + bluetoothGatt?.disconnect() + Log.d("ESP32_BLE","disconnectEsp32") + } + else { + Log.d("BLE_DEBUG", "Permission BLUETOOTH_CONNECT fehlt!") + } + } - fun writeToEsp32(dataString: String) { + fun writeToEsp32(dataString: String, SERVICE_UUID: UUID?, TIME_CHARACTERISTIC_UUID: UUID?) { // Prüfen, ob die Verbindung steht und bluetoothGatt nicht null ist val gatt = bluetoothGatt if (gatt == null) { @@ -116,14 +129,14 @@ class BleManager(private val context: Context) { } // 1. Service holen - val service = gatt.getService(deviceUUIDs.SERVICE_UUID) + val service = gatt.getService(SERVICE_UUID) if (service == null) { Log.d("ESP32_BLE", "Fehler: Service UUID nicht gefunden!") return } // 2. Characteristic holen - val characteristic = service.getCharacteristic(deviceUUIDs.TIME_CHARACTERISTIC_UUID) + val characteristic = service.getCharacteristic(TIME_CHARACTERISTIC_UUID) if (characteristic == null) { Log.d("ESP32_BLE", "Fehler: Characteristic UUID nicht gefunden!") return diff --git a/app/src/main/java/com/example/smart_watch_android/BLE/DeviceUUIDs.kt b/app/src/main/java/com/example/smart_watch_android/BLE/DeviceUUIDs.kt index 4f9362e..f72e7fb 100644 --- a/app/src/main/java/com/example/smart_watch_android/BLE/DeviceUUIDs.kt +++ b/app/src/main/java/com/example/smart_watch_android/BLE/DeviceUUIDs.kt @@ -3,6 +3,6 @@ package com.example.smart_watch_android.BLE import java.util.UUID object DeviceUUIDs { - val SERVICE_UUID = UUID.fromString("791cadd7-de87-49f9-8986-94b7ae11940b") - val TIME_CHARACTERISTIC_UUID = UUID.fromString("3e4eac5b-eaa2-4e0c-a705-dcac4f606e02") + val SERVICE_UUID: UUID? = UUID.fromString("791cadd7-de87-49f9-8986-94b7ae11940b") + val TIME_CHARACTERISTIC_UUID: UUID? = UUID.fromString("3e4eac5b-eaa2-4e0c-a705-dcac4f606e02") } \ No newline at end of file diff --git a/app/src/main/java/com/example/smart_watch_android/ConnectButtonScreen.kt b/app/src/main/java/com/example/smart_watch_android/ConnectButtonScreen.kt deleted file mode 100644 index 5a4bbf9..0000000 --- a/app/src/main/java/com/example/smart_watch_android/ConnectButtonScreen.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.example.smart_watch_android - -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp - -@Composable -fun ConnectCircleScreen( - isConnected: Boolean, - onConnectClick: () -> Unit -) { - // Ein Container, der den gesamten Bildschirm ausfüllt - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center // Zentriert den Inhalt exakt in der Mitte - ) { - // Der Kreis-Button - Box( - modifier = Modifier - .size(180.dp) // Größe des Kreises - .clip(CircleShape) // Macht das Element zu einem perfekten Kreis - .background(if (isConnected) Color.Green else Color.Blue) // Grün = verbunden, Blau = Start/Verbinden - .clickable { onConnectClick() }, // Was passiert beim Drücken - contentAlignment = Alignment.Center - ) { - Text( - text = if (isConnected) "Verbunden" else "Connect", - color = Color.White, - fontSize = 20.sp, - fontWeight = FontWeight.Bold - ) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/smart_watch_android/MainActivity.kt b/app/src/main/java/com/example/smart_watch_android/MainActivity.kt index f8dbb26..f3de9c7 100644 --- a/app/src/main/java/com/example/smart_watch_android/MainActivity.kt +++ b/app/src/main/java/com/example/smart_watch_android/MainActivity.kt @@ -1,13 +1,5 @@ package com.example.smart_watch_android -import android.Manifest -import android.bluetooth.BluetoothGatt -import android.bluetooth.BluetoothGattCallback -import android.bluetooth.BluetoothGattCharacteristic -import android.bluetooth.BluetoothManager -import android.bluetooth.BluetoothProfile -import android.content.Context -import android.content.pm.PackageManager import android.os.Build import android.os.Bundle import android.util.Log @@ -15,8 +7,10 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.annotation.RequiresApi -import androidx.annotation.RequiresPermission -import androidx.core.app.ActivityCompat +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.ui.Modifier import com.example.smart_watch_android.BLE.BleManager class MainActivity : ComponentActivity() { @@ -29,13 +23,16 @@ class MainActivity : ComponentActivity() { bleManager.checkAndRequestBluetoothPermissions() enableEdgeToEdge() setContent { - ConnectCircleScreen( - isConnected = bleManager.isConnected, - onConnectClick = { - Log.d("ESP32_BLE", "Button wurde gedrückt!") - bleManager.connectToEsp32("10:BD:A3:8F:01:0E") + MaterialTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + // Hier wird deine AppNavigation aufgerufen, + // die die Screens steuert! + AppNavigation(bleManager) } - ) + } } } } diff --git a/app/src/main/java/com/example/smart_watch_android/Screens/ConnectScreen.kt b/app/src/main/java/com/example/smart_watch_android/Screens/ConnectScreen.kt new file mode 100644 index 0000000..01cd996 --- /dev/null +++ b/app/src/main/java/com/example/smart_watch_android/Screens/ConnectScreen.kt @@ -0,0 +1,30 @@ +package com.example.smart_watch_android.Screens + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color + +@Composable +fun ConnectScreen(isConnected: Boolean, onConnectClicked: () -> Unit) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Button( + onClick = onConnectClicked, + colors = if (isConnected) { + ButtonDefaults.buttonColors(containerColor = Color(0xFF4CAF50)) // Grün + } else { + ButtonDefaults.buttonColors() + } + ) { + Text(text = if (isConnected) "Verbunden" else "Connect") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/smart_watch_android/Screens/ControlPanelScreen.kt b/app/src/main/java/com/example/smart_watch_android/Screens/ControlPanelScreen.kt new file mode 100644 index 0000000..c1948b2 --- /dev/null +++ b/app/src/main/java/com/example/smart_watch_android/Screens/ControlPanelScreen.kt @@ -0,0 +1,76 @@ +package com.example.smart_watch_android.Screens + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.example.smart_watch_android.BLE.BleManager +import com.example.smart_watch_android.BLE.DeviceUUIDs + +@Composable +fun ControlPanelScreen( + bleManager: BleManager, + onDisconnectClicked: () -> Unit +) { + var textInput by remember { mutableStateOf("") } + + Column( + modifier = Modifier + .fillMaxSize() + .padding(16.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + // Eingabefeld für Text / Uhrzeit / Befehle + OutlinedTextField( + value = textInput, + onValueChange = { textInput = it }, + label = { Text("Nachricht an ESP32") }, + modifier = Modifier.fillMaxWidth() + ) + + Spacer(modifier = Modifier.height(16.dp)) + + // Send Button + Button( + onClick = { + if (textInput.isNotEmpty()) { + bleManager.writeToEsp32( + textInput, DeviceUUIDs.SERVICE_UUID, DeviceUUIDs.TIME_CHARACTERISTIC_UUID + ) + textInput = "" // Feld danach leeren + } + }, + modifier = Modifier.fillMaxWidth() + ) { + Text("Send") + } + + Spacer(modifier = Modifier.height(32.dp)) + + // Disconnect Button (z.B. in Rot, um ihn abzusetzen) + Button( + onClick = onDisconnectClicked, + colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFE53935)), + modifier = Modifier.fillMaxWidth() + ) { + Text("Disconnect") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/smart_watch_android/Screens/Screen.kt b/app/src/main/java/com/example/smart_watch_android/Screens/Screen.kt new file mode 100644 index 0000000..f6a417d --- /dev/null +++ b/app/src/main/java/com/example/smart_watch_android/Screens/Screen.kt @@ -0,0 +1,67 @@ +package com.example.smart_watch_android + +import android.Manifest +import androidx.annotation.RequiresPermission +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.example.smart_watch_android.BLE.BleManager +import com.example.smart_watch_android.BLE.DeviceUUIDs +import com.example.smart_watch_android.Screens.ConnectScreen +import com.example.smart_watch_android.Screens.ControlPanelScreen + +enum class Screen { + CONNECT, + CONTROL_PANEL +} +@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) +@Composable +fun AppNavigation(BLEManager: BleManager) { + var currentScreen by remember { mutableStateOf(Screen.CONNECT) } + val bleManager = BLEManager + + if (bleManager.isConnected && currentScreen == Screen.CONNECT) { + currentScreen = Screen.CONTROL_PANEL + } else if (!bleManager.isConnected && currentScreen == Screen.CONTROL_PANEL) { + currentScreen = Screen.CONNECT + } + + // Je nach Zustand den entsprechenden Screen anzeigen + when (currentScreen) { + Screen.CONNECT -> { + ConnectScreen( + isConnected = bleManager.isConnected, + onConnectClicked = { + bleManager.connectToEsp32("10:BD:A3:8F:01:0E") + } + ) + } + Screen.CONTROL_PANEL -> { + ControlPanelScreen( + bleManager, + onDisconnectClicked = { + bleManager.disconnectEsp32() + // Screen wechselt automatisch über den Check oben + } + ) + } + } +} \ No newline at end of file