Better UI layout on the device screen

This commit is contained in:
2024-01-27 23:14:26 +07:00
parent 18bd21fba1
commit 3b62743481
6 changed files with 67 additions and 58 deletions

View File

@@ -6,8 +6,10 @@ import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -139,7 +141,10 @@ class MainActivity : ComponentActivity() {
device device
) )
}, },
disconnectFromDevice = { bluetoothViewModel.disconnectFromDevice() }, disconnectFromDevice = {
preferencesViewModel.clearPreferences()
bluetoothViewModel.disconnectFromDevice()
},
deviceActionsList = defaultDeviceActionsList() deviceActionsList = defaultDeviceActionsList()
) )
if (preferencesViewModel.preferences != null) BackHandler {} if (preferencesViewModel.preferences != null) BackHandler {}
@@ -150,6 +155,9 @@ class MainActivity : ComponentActivity() {
title = backStackEntry.arguments?.getString("title") ?: "null", title = backStackEntry.arguments?.getString("title") ?: "null",
navigateBack = { navController.popBackStack() } navigateBack = { navController.popBackStack() }
) )
Button(onClick = { bluetoothViewModel.sendHelloWorld() }) {
Text("Click me!")
}
} }
composable("codeblocks/{title}") composable("codeblocks/{title}")
{ backStackEntry -> { backStackEntry ->

View File

@@ -1,7 +1,10 @@
package com.helible.pilot.components.deviceScreen package com.helible.pilot.components.deviceScreen
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@@ -11,6 +14,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
@@ -33,7 +37,7 @@ fun DeviceControlScreen(
scannerPageName: String = "scanner", scannerPageName: String = "scanner",
) { ) {
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
val preferences: AppPreferences? = getPreferences() val preferences = getPreferences()
if (preferences == null) { if (preferences == null) {
navigateToPage(scannerPageName) navigateToPage(scannerPageName)
} else { } else {
@@ -85,7 +89,12 @@ fun DeviceControlScreen(
) )
for (action in section.value) { for (action in section.value) {
TextButton( TextButton(
onClick = { navigateToPage(action.first + '/' + action.second.second) } onClick = { navigateToPage(action.first + '/' + action.second.second) },
modifier = Modifier.fillMaxWidth()
) {
Row(modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(5.dp),
verticalAlignment = Alignment.CenterVertically
) { ) {
Icon( Icon(
painter = painterResource(id = action.second.first.first), painter = painterResource(id = action.second.first.first),
@@ -95,12 +104,12 @@ fun DeviceControlScreen(
) )
Text( Text(
text = action.second.second, text = action.second.second,
color = MaterialTheme.colorScheme.inverseSurface, color = MaterialTheme.colorScheme.inverseSurface
modifier = Modifier.padding(horizontal = 5.dp)
) )
} }
} }
} }
}
TextButton(onClick = { TextButton(onClick = {
disconnectFromDevice() disconnectFromDevice()

View File

@@ -14,7 +14,7 @@ import android.os.Build
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import com.helible.pilot.BluetoothDataTransferService import com.helible.pilot.viewmodels.BluetoothDataTransferService
import com.helible.pilot.KMessage import com.helible.pilot.KMessage
import com.helible.pilot.dataclasses.BluetoothDeviceDomain import com.helible.pilot.dataclasses.BluetoothDeviceDomain
import com.helible.pilot.receivers.BluetoothAdapterStateReceiver import com.helible.pilot.receivers.BluetoothAdapterStateReceiver
@@ -40,7 +40,7 @@ import java.util.UUID
sealed interface ConnectionResult { sealed interface ConnectionResult {
object ConnectionEstablished : ConnectionResult object ConnectionEstablished : ConnectionResult
data class TransferSucceded(val message: KMessage) : ConnectionResult data class TransferSucceded(val message: String) : ConnectionResult
data class Error(val message: String) : ConnectionResult data class Error(val message: String) : ConnectionResult
} }
@@ -219,6 +219,7 @@ class AndroidBluetoothController(private val context: Context) : BluetoothContro
return flow {} return flow {}
} }
return flow { return flow {
Log.i("BluetoothController", "Connecting to device...")
currentClientSocket = currentClientSocket =
bluetoothAdapter.getRemoteDevice(device).createRfcommSocketToServiceRecord( bluetoothAdapter.getRemoteDevice(device).createRfcommSocketToServiceRecord(
UUID.fromString(SERVICE_UUID) UUID.fromString(SERVICE_UUID)
@@ -235,7 +236,9 @@ class AndroidBluetoothController(private val context: Context) : BluetoothContro
) )
} }
} catch (e: IOException) { } catch (e: IOException) {
closeConnection() socket.close()
currentClientSocket = null
Log.e("BluetoothController", e.toString())
emit(ConnectionResult.Error("Connection was interrupted")) emit(ConnectionResult.Error("Connection was interrupted"))
} }
} }
@@ -256,6 +259,7 @@ class AndroidBluetoothController(private val context: Context) : BluetoothContro
override fun closeConnection() { override fun closeConnection() {
currentClientSocket?.close() currentClientSocket?.close()
currentClientSocket = null currentClientSocket = null
Log.i("BluetoothController", "Connection closed")
} }
override fun onDestroy() { override fun onDestroy() {

View File

@@ -0,0 +1,9 @@
package com.helible.pilot.controllers
data class DeviceState(
val isHandshakeWaiting: Boolean = true,
val isIMUCalibrating: Boolean = false,
val flightMode: Boolean = false,
val batteryCharge: Int?,
val flightHeight: Float?
)

View File

@@ -1,6 +1,9 @@
package com.helible.pilot package com.helible.pilot.viewmodels
import android.bluetooth.BluetoothSocket import android.bluetooth.BluetoothSocket
import android.util.Log
import com.helible.pilot.KMessage
import com.helible.pilot.toKMessage
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
@@ -14,7 +17,7 @@ class TransferFailedException : IOException("Reading incoming data failed")
class BluetoothDataTransferService( class BluetoothDataTransferService(
private val socket: BluetoothSocket, private val socket: BluetoothSocket,
) { ) {
fun listenForIncomingMessages(): Flow<KMessage> { fun listenForIncomingMessages(): Flow<String> {
return flow { return flow {
if (!socket.isConnected) if (!socket.isConnected)
return@flow return@flow
@@ -25,11 +28,11 @@ class BluetoothDataTransferService(
} catch (e: IOException) { } catch (e: IOException) {
throw TransferFailedException() throw TransferFailedException()
} }
val strData: String = buffer.decodeToString(endIndex = byteCount)
emit( emit(
buffer.decodeToString( strData
endIndex = byteCount
).toKMessage()
) )
Log.i("BluetoothController", "Received: ${strData.dropLast(2)}")
} }
}.flowOn(Dispatchers.IO) }.flowOn(Dispatchers.IO)
} }

View File

@@ -94,7 +94,9 @@ class BluetoothViewModel(
} }
is ConnectionResult.TransferSucceded -> { is ConnectionResult.TransferSucceded -> {
TODO("Telemetry not implemented") _state.update { it.copy(
) }
} }
is ConnectionResult.Error -> { is ConnectionResult.Error -> {
@@ -108,14 +110,12 @@ class BluetoothViewModel(
} }
} }
} }
.catch { _ -> .catch { throwable ->
bluetoothController.closeConnection() bluetoothController.closeConnection()
_state.update { _state.update { it.copy(
it.copy(
isConnected = false, isConnected = false,
isConnecting = false isConnecting = false
) ) }
}
} }
.launchIn(viewModelScope) .launchIn(viewModelScope)
} }
@@ -123,7 +123,7 @@ class BluetoothViewModel(
private var deviceConnectionJob: Job? = null private var deviceConnectionJob: Job? = null
fun connectToDevice(device: String) { fun connectToDevice(device: String) {
if (_state.value.isConnected) { if (_state.value.isConnected and _state.value.isConnecting) {
return return
} }
_state.update { it.copy(isConnecting = true) } _state.update { it.copy(isConnecting = true) }
@@ -162,36 +162,12 @@ class BluetoothViewModel(
super.onCleared() super.onCleared()
} }
fun sendRotorsDutySpeed(rotorsState: RotorsSpeedMessage) { fun sendHelloWorld() {
viewModelScope.launch { viewModelScope.launch {
bluetoothController.trySendMessage( bluetoothController.trySendMessage(
rotorsStateMessegeAdapter.toJson(rotorsState).plus("\r").toByteArray() "{\"p1\": {\"p\": 1.5, \"i\": 1.5, \"d\": 1.5}}\n\r".toByteArray()
//"{\"p1\": [1.5, 1.5, 1.5]}\n\r".toByteArray()
) )
} }
} }
fun sendAlarmState(alarmStateMessage: AlarmStateMessage) {
viewModelScope.launch {
bluetoothController.trySendMessage(
alarmStateMessageAdapter.toJson(alarmStateMessage).plus("\r").toByteArray()
)
}
}
fun sendEmergStop() {
viewModelScope.launch {
bluetoothController.trySendMessage(
emergStopMessageAdapter.toJson(EmergStopMessage(true)).plus("\r").toByteArray()
)
}
}
fun sendR3Duty(r3: Int) {
viewModelScope.launch {
bluetoothController.trySendMessage(
"R3$r3\n\r".toByteArray()
)
delay(30)
}
}
} }