diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c39e7ef..8468bbf 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -100,6 +100,7 @@ android { } dependencies { + implementation ("com.github.franmontiel:PersistentCookieJar:v1.0.1") implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.14") implementation("io.github.webrtc-sdk:android:125.6422.06.1") implementation("androidx.compose.material:material-icons-extended") diff --git a/app/src/main/java/com/example/neurology_project_android/FormManager.kt b/app/src/main/java/com/example/neurology_project_android/FormManager.kt new file mode 100644 index 0000000..f0fab03 --- /dev/null +++ b/app/src/main/java/com/example/neurology_project_android/FormManager.kt @@ -0,0 +1,171 @@ +package com.example.neurology_project_android + +import android.util.Log +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.* +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import org.json.JSONArray +import org.json.JSONObject +import java.io.IOException + +object FormManager { + + fun submitFormToServer(form: NIHForm, client: OkHttpClient, onResult: (Boolean) -> Unit) { + val json = JSONObject().apply { + put("patientName", form.patientName) + put("DOB", form.dob) + put("formDate", form.date) + put("results", form.formData) + put("username", form.username) + } + + val requestBody = RequestBody.create( + "application/json; charset=utf-8".toMediaTypeOrNull(), + json.toString() + ) + + val request = Request.Builder() + .url("https://videochat-signaling-app.ue.r.appspot.com/key=peerjs/post") + .post(requestBody) + .addHeader("Content-Type", "application/json") + .addHeader("Action", "submitStrokeScale") + .build() + + client.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + onResult(false) + } + + override fun onResponse(call: Call, response: Response) { + onResult(response.isSuccessful) + } + }) + } + + suspend fun fetchFormsForUser( + username: String, + client: OkHttpClient + ): List = withContext(Dispatchers.IO) { + val forms = mutableListOf() + + val json = JSONObject().apply { + put("username", username) + } + + val requestBody = RequestBody.create( + "application/json; charset=utf-8".toMediaTypeOrNull(), + json.toString() + ) + + val request = Request.Builder() + .url("https://videochat-signaling-app.ue.r.appspot.com/key=peerjs/post") + .post(requestBody) + .addHeader("Content-Type", "application/json") + .addHeader("Action", "getUsersForms") + .build() + + try { + val response = client.newCall(request).execute() + if (response.isSuccessful) { + val bodyString = response.body?.string() + val jsonArray = JSONArray(bodyString) + + for (i in 0 until jsonArray.length()) { + val item = jsonArray.getJSONObject(i) + forms.add( + NIHForm( + id = item.getInt("id"), + patientName = item.getString("name"), + dob = item.getString("dob"), + date = item.getString("form_date"), + formData = item.getString("results"), + username = item.getString("username") + ) + ) + } + } else { + Log.e("FORM_MANAGER", "Server error: ${response.code}") + } + } catch (e: IOException) { + Log.e("FORM_MANAGER", "Network error: ${e.message}") + } + + return@withContext forms + } + + fun deleteForm(formId: Int, username: String, client: OkHttpClient, callback: (Boolean) -> Unit) { + val json = JSONObject().apply { + put("id", formId) + put("username", username) + } + + val requestBody = RequestBody.create( + "application/json; charset=utf-8".toMediaTypeOrNull(), + json.toString() + ) + + val request = Request.Builder() + .url("https://videochat-signaling-app.ue.r.appspot.com/key=peerjs/post") + .post(requestBody) + .addHeader("Content-Type", "application/json") + .addHeader("Action", "deleteForm") + .build() + + client.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + Log.e("DELETE", "Failed: ${e.message}") + callback(false) + } + + override fun onResponse(call: Call, response: Response) { + Log.d("DELETE", "Response code: ${response.code}") + callback(response.isSuccessful) + } + }) + } + + fun updateForm(form: NIHForm, client: OkHttpClient, onComplete: (Boolean) -> Unit) { + val json = JSONObject().apply { + put("id", form.id) + put("patientName", form.patientName) + put("dob", form.dob) + put("formDate", form.date) + put("results", form.formData) + put("username", form.username) + } + + val requestBody = RequestBody.create( + "application/json; charset=utf-8".toMediaTypeOrNull(), + json.toString() + ) + + val request = Request.Builder() + .url("https://videochat-signaling-app.ue.r.appspot.com/key=peerjs/post") + .post(requestBody) + .addHeader("Content-Type", "application/json") + .addHeader("Action", "updateForm") + .build() + + client.newCall(request).enqueue(SimpleCallback("UPDATE", onComplete)) + } + + private fun SimpleCallback(tag: String, onComplete: (Boolean) -> Unit) = object : Callback { + override fun onFailure(call: okhttp3.Call, e: java.io.IOException) { + Log.e(tag, "Request failed: ${e.message}") + onComplete(false) + } + + override fun onResponse(call: okhttp3.Call, response: okhttp3.Response) { + if (response.isSuccessful) { + Log.d(tag, "Request successful") + onComplete(true) + } else { + Log.e(tag, "Server error: ${response.code}") + onComplete(false) + } + } + } +} diff --git a/app/src/main/java/com/example/neurology_project_android/ListNIHFormActivity.kt b/app/src/main/java/com/example/neurology_project_android/ListNIHFormActivity.kt index 705d94a..23bfa1d 100644 --- a/app/src/main/java/com/example/neurology_project_android/ListNIHFormActivity.kt +++ b/app/src/main/java/com/example/neurology_project_android/ListNIHFormActivity.kt @@ -22,25 +22,32 @@ import androidx.compose.ui.unit.sp import androidx.compose.ui.tooling.preview.Preview class ListNIHFormActivity : ComponentActivity() { + private var refreshTrigger by mutableStateOf(0) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { - ListNIHFormScreen() + ListNIHFormScreen(refreshTrigger) } } + + override fun onResume() { + super.onResume() + refreshTrigger++ + } } @Composable -fun ListNIHFormScreen() { +fun ListNIHFormScreen(refreshTrigger: Int) { val context = LocalContext.current - val nihFormDao = NIHFormDatabase.getDatabase(context).nihFormDao() + val sessionManager = remember { SessionManager(context) } + val client = sessionManager.client + val username = sessionManager.fetchUsername() ?: "anonymous" var savedForms by remember { mutableStateOf>(emptyList()) } - LaunchedEffect(Unit) { - nihFormDao.getAllForms().collect { forms -> - savedForms = forms - } + LaunchedEffect(refreshTrigger) { // runs every time refreshTrigger changes + val fetchedForms = FormManager.fetchFormsForUser(username, sessionManager.client) + savedForms = fetchedForms } Column( @@ -82,8 +89,14 @@ fun ListNIHFormScreen() { SavedFormItem( form = SavedForm(form.patientName, form.date), onClick = { - val intent = Intent(context, SavedNIHFormActivity::class.java) - intent.putExtra("formId", form.id) + val intent = Intent(context, SavedNIHFormActivity::class.java).apply { + putExtra("formId", form.id) + putExtra("patientName", form.patientName) + putExtra("dob", form.dob) + putExtra("date", form.date) + putExtra("formData", form.formData) + putExtra("username", form.username) + } context.startActivity(intent) } ) @@ -129,9 +142,3 @@ fun SavedFormItem(form: SavedForm, onClick: () -> Unit) { } data class SavedForm(val patientName: String, val dateRecorded: String) - -@Preview(showBackground = true) -@Composable -fun ListNIHFormScreenPreview() { - ListNIHFormScreen() -} diff --git a/app/src/main/java/com/example/neurology_project_android/LoginActivity.kt b/app/src/main/java/com/example/neurology_project_android/LoginActivity.kt index bd64fd4..8997ad5 100644 --- a/app/src/main/java/com/example/neurology_project_android/LoginActivity.kt +++ b/app/src/main/java/com/example/neurology_project_android/LoginActivity.kt @@ -67,6 +67,7 @@ fun LoginScreen(sessionManager: SessionManager, onLoginSuccess: () -> Unit) { var password by remember { mutableStateOf("") } var isLoading by remember { mutableStateOf(false) } var error by remember { mutableStateOf(null) } + val client = sessionManager.client GradientBackground { Box( @@ -118,7 +119,6 @@ fun LoginScreen(sessionManager: SessionManager, onLoginSuccess: () -> Unit) { isLoading = true error = null - val client = OkHttpClient() val json = """ { "username": "$username", @@ -141,23 +141,28 @@ fun LoginScreen(sessionManager: SessionManager, onLoginSuccess: () -> Unit) { client.newCall(request).enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { - isLoading = false - error = "Network error: ${e.message}" + (context as ComponentActivity).runOnUiThread { + isLoading = false + error = "Network error: ${e.message}" + } } override fun onResponse(call: Call, response: Response) { - isLoading = false - if (response.isSuccessful) { - val token = response.body?.string()?.trim() ?: "" - var authToken = response.headers.value(9).substringAfter("authorization=") - authToken = authToken.substringBefore(";") + val success = response.isSuccessful + val bodyString = response.body?.string()?.trim() ?: "" + var authToken = response.headers.value(9)?.substringAfter("authorization=")?.substringBefore(";") ?: "" - sessionManager.saveAuthToken(authToken.toString(), username) + if (success) { + sessionManager.saveAuthToken(authToken, username) (context as ComponentActivity).runOnUiThread { + isLoading = false onLoginSuccess() } } else { - error = "Login failed: ${response.code}" + (context as ComponentActivity).runOnUiThread { + isLoading = false + error = "Login failed: ${response.code}" + } } } }) diff --git a/app/src/main/java/com/example/neurology_project_android/MainActivity.kt b/app/src/main/java/com/example/neurology_project_android/MainActivity.kt index 7870c61..037862e 100644 --- a/app/src/main/java/com/example/neurology_project_android/MainActivity.kt +++ b/app/src/main/java/com/example/neurology_project_android/MainActivity.kt @@ -29,12 +29,15 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.Card +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect 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 @@ -198,6 +201,8 @@ class MainActivity : ComponentActivity() { @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) @Composable fun HomeScreen(modifier: Modifier = Modifier, peerId: String, peers: List) { + val context = LocalContext.current + val sessionManager = remember { SessionManager(context) } // Refresh UI every 3 seconds LaunchedEffect(peers) { // This will trigger recomposition whenever peers update @@ -209,6 +214,25 @@ class MainActivity : ComponentActivity() { .padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.End + ) { + TextButton( + onClick = { + sessionManager.logout() + val intent = Intent(context, LoginActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + context.startActivity(intent) + } + ) { + Text("Log Out", color = MaterialTheme.colorScheme.primary) + } + } + + Spacer(modifier = Modifier.height(8.dp)) + PeerIdSection(peerId) // Displays the correct Peer ID Column( diff --git a/app/src/main/java/com/example/neurology_project_android/NIHFormDao.kt b/app/src/main/java/com/example/neurology_project_android/NIHFormDao.kt deleted file mode 100644 index 7ae1158..0000000 --- a/app/src/main/java/com/example/neurology_project_android/NIHFormDao.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.example.neurology_project_android - -import androidx.room.* -import kotlinx.coroutines.flow.Flow - -@Dao -interface NIHFormDao { - @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun insertForm(form: NIHForm) - - @Query("SELECT * FROM nih_forms ORDER BY date DESC") - fun getAllForms(): Flow> - - @Delete - suspend fun deleteForm(form: NIHForm) - - @Query("SELECT * FROM nih_forms WHERE id = :formId") - suspend fun getFormById(formId: Int): NIHForm? -} diff --git a/app/src/main/java/com/example/neurology_project_android/NIHFormDatabase.kt b/app/src/main/java/com/example/neurology_project_android/NIHFormDatabase.kt deleted file mode 100644 index c38aab9..0000000 --- a/app/src/main/java/com/example/neurology_project_android/NIHFormDatabase.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.example.neurology_project_android - -import android.content.Context -import androidx.room.Database -import androidx.room.Room -import androidx.room.RoomDatabase -import androidx.room.migration.Migration -import androidx.sqlite.db.SupportSQLiteDatabase - -@Database(entities = [NIHForm::class], version = 2) -abstract class NIHFormDatabase : RoomDatabase() { - abstract fun nihFormDao(): NIHFormDao - - companion object { - @Volatile - private var INSTANCE: NIHFormDatabase? = null - - val MIGRATION_1_2 = object : Migration(1, 2) { - override fun migrate(database: SupportSQLiteDatabase) { - database.execSQL("ALTER TABLE nih_forms ADD COLUMN username TEXT NOT NULL DEFAULT 'unknown'") - } - } - - fun getDatabase(context: Context): NIHFormDatabase { - return INSTANCE ?: synchronized(this) { - val instance = Room.databaseBuilder( - context.applicationContext, - NIHFormDatabase::class.java, - "nih_form_database" - ) - .addMigrations(MIGRATION_1_2) - .build() - INSTANCE = instance - instance - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/neurology_project_android/NewNIHFormActivity.kt b/app/src/main/java/com/example/neurology_project_android/NewNIHFormActivity.kt index ef62f4a..ad6545f 100644 --- a/app/src/main/java/com/example/neurology_project_android/NewNIHFormActivity.kt +++ b/app/src/main/java/com/example/neurology_project_android/NewNIHFormActivity.kt @@ -27,6 +27,8 @@ import androidx.compose.ui.unit.sp import kotlinx.coroutines.launch import okhttp3.Call import okhttp3.Callback +import okhttp3.HttpUrl +import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.OkHttpClient import okhttp3.Request @@ -40,27 +42,53 @@ import java.util.* class NewNIHFormActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + + val formId = intent.getIntExtra("formId", -1) + val patientName = intent.getStringExtra("patientName") + val dob = intent.getStringExtra("dob") + val date = intent.getStringExtra("date") + val formData = intent.getStringExtra("formData") + val username = intent.getStringExtra("username") + + val existingForm = if (patientName != null && dob != null && date != null && formData != null && username != null) { + NIHForm(formId, patientName, dob, date, formData, username) + } else null + setContent { - NewNIHFormScreen() + NewNIHFormScreen(existingForm) } } } @Composable -fun NewNIHFormScreen() { +fun NewNIHFormScreen(existingForm: NIHForm? = null) { val context = LocalContext.current val sessionManager = remember { SessionManager(context) } - var patientName by remember { mutableStateOf("") } + val client = sessionManager.client + val coroutineScope = rememberCoroutineScope() + var refreshTrigger by remember { mutableStateOf(0) } + + var patientName by remember { mutableStateOf(existingForm?.patientName ?: "") } + var dob by remember { mutableStateOf(existingForm?.dob ?: "") } val questions = remember { StrokeScaleQuestions.questions } - val selectedOptions = remember { mutableStateListOf().apply { repeat(questions.size) { add(null) } } } + val selectedOptions = remember { + mutableStateListOf().apply { repeat(questions.size) { add(null) } } + } + val keyboardController = LocalSoftwareKeyboardController.current val dobCalendar = remember { Calendar.getInstance() } - var dob by remember { mutableStateOf("") } - val coroutineScope = rememberCoroutineScope() - val nihFormDao = NIHFormDatabase.getDatabase(context).nihFormDao() + val username = remember { sessionManager.fetchUsername() ?: "anonymous" } - val username = remember { - sessionManager.fetchUsername() ?: "anonymous" + val date = remember { + existingForm?.date ?: SimpleDateFormat("MM/dd/yyyy", Locale.getDefault()).format(Date()) + } + + // Populate selected options if editing + LaunchedEffect(existingForm) { + existingForm?.formData?.forEachIndexed { index, c -> + val score = c.toString().toIntOrNull() ?: 9 + selectedOptions[index] = if (score != 9) score else null + } } val datePickerDialog = android.app.DatePickerDialog( @@ -74,11 +102,6 @@ fun NewNIHFormScreen() { dobCalendar.get(Calendar.DAY_OF_MONTH) ) - - val date = remember { - SimpleDateFormat("MM/dd/yyyy", Locale.getDefault()).format(Date()) - } - Column( modifier = Modifier .fillMaxSize() @@ -155,8 +178,6 @@ fun NewNIHFormScreen() { ) { Button( onClick = { - Log.d("DEBUG", "Saving form for user: $username") - if (patientName.isBlank()) { Toast.makeText(context, "Please enter a patient name", Toast.LENGTH_SHORT).show() return@Button @@ -171,13 +192,18 @@ fun NewNIHFormScreen() { formData = formData, username = username ) - nihFormDao.insertForm(form) - sendFormToServer(form) - - // Navigate back to the list - val intent = Intent(context, ListNIHFormActivity::class.java) - intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP - context.startActivity(intent) + FormManager.submitFormToServer(form, client) { success -> + (context as? ComponentActivity)?.runOnUiThread { + if (success) { + Toast.makeText(context, "Form saved successfully", Toast.LENGTH_SHORT).show() + val intent = Intent(context, ListNIHFormActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP + context.startActivity(intent) + } else { + Toast.makeText(context, "Failed to save form", Toast.LENGTH_SHORT).show() + } + } + } } }, colors = ButtonDefaults.buttonColors(containerColor = Color.Green), @@ -250,44 +276,6 @@ fun QuestionCard(question: StrokeScaleQuestion, selectedOptions: MutableList(null) } + val sessionManager = remember { SessionManager(context) } val questions = remember { StrokeScaleQuestions.questions } val selectedOptions = remember { mutableStateListOf().apply { repeat(questions.size) { add(null) } } } - LaunchedEffect(formId) { - form = nihFormDao.getFormById(formId) - form?.let { - val values = it.formData.split(",").map { score -> score.toIntOrNull() ?: 9 } - values.forEachIndexed { index, score -> selectedOptions[index] = if (score != 9) score else null } + var isEditing by remember { mutableStateOf(false) } + + LaunchedEffect(form) { + val values = form.formData.map { c -> c.toString().toIntOrNull() ?: 9 } + values.forEachIndexed { index, score -> + selectedOptions[index] = if (score != 9) score else null } } - if (form == null) { - Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - CircularProgressIndicator() + Column( + modifier = Modifier + .fillMaxSize() + .background(Color.White) + .padding(16.dp) + ) { + // Back Arrow + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp), + horizontalArrangement = Arrangement.Start + ) { + Text( + text = "< Back", + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + color = Color.Black, + modifier = Modifier + .clickable { (context as? ComponentActivity)?.finish() } + .padding(8.dp) + ) } - } else { + + // Header Column( - modifier = Modifier - .fillMaxSize() - .background(Color.White) - .padding(16.dp) + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally ) { - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text( - text = "NIH Stroke Scale Form", - fontSize = 24.sp, - fontWeight = FontWeight.Bold, - color = Color.Black - ) - - Text( - text = "Patient Name: ${form?.patientName}", - fontSize = 18.sp, - fontWeight = FontWeight.Bold, - color = Color.Black, - modifier = Modifier.padding(top = 4.dp) - ) - - Text( - text = "DOB: ${form?.dob}", - fontSize = 16.sp, - color = Color.Gray - ) - - Text( - text = "Date: ${form?.date}", - fontSize = 16.sp, - color = Color.Gray - ) - } + Text( + text = "NIH Stroke Scale Form", + fontSize = 24.sp, + fontWeight = FontWeight.Bold, + color = Color.Black + ) + + Text( + text = "Patient Name: ${form.patientName}", + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = Color.Black, + modifier = Modifier.padding(top = 4.dp) + ) + + Text( + text = "DOB: ${form.dob}", + fontSize = 16.sp, + color = Color.Gray + ) - LazyColumn(modifier = Modifier.weight(1f)) { - items(questions) { question -> + Text( + text = "Date: ${form.date}", + fontSize = 16.sp, + color = Color.Gray + ) + } + + // Question list + LazyColumn(modifier = Modifier.weight(1f)) { + items(questions) { question -> + if (isEditing) { + QuestionCard(question, selectedOptions) + } else { ReadOnlyQuestionCard(question, selectedOptions) } } + } - Row( - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 16.dp), - horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterHorizontally) + // Buttons + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp), + horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterHorizontally) + ) { + Button( + onClick = { + if (isEditing) { + val updatedForm = NIHForm( + id = form.id, + patientName = form.patientName, + dob = form.dob, + date = form.date, + formData = selectedOptions.joinToString("") { (it ?: 9).toString() }, + username = form.username + ) + FormManager.updateForm(updatedForm, sessionManager.client) { success -> + (context as? ComponentActivity)?.runOnUiThread { + if (success) { + (context as? ComponentActivity)?.finish() + } else { + Toast.makeText(context, "Failed to update form", Toast.LENGTH_SHORT).show() + } + } + } + } else { + isEditing = true + } + }, + colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFF3E5F5)), + modifier = Modifier.weight(1f) ) { - Button( - onClick = { - // Navigate back - (context as? ComponentActivity)?.finish() - }, - colors = ButtonDefaults.buttonColors(containerColor = Color.White), - modifier = Modifier.weight(1f) - ) { - Text(text = "Done", color = Color.Black) - } + Text(text = if (isEditing) "Done" else "Update", color = Color.Black) + } - Button( - onClick = { - form?.let { - coroutineScope.launch { - nihFormDao.deleteForm(it) + Button( + onClick = { + FormManager.deleteForm(form.id, form.username, sessionManager.client) { success -> + (context as? ComponentActivity)?.runOnUiThread { + if (success) { (context as? ComponentActivity)?.finish() + } else { + Toast.makeText(context, "Failed to delete form", Toast.LENGTH_SHORT).show() } } - }, - colors = ButtonDefaults.buttonColors(containerColor = Color.Red), - modifier = Modifier.weight(1f) - ) { - Text(text = "Delete", color = Color.White) - } + } + }, + colors = ButtonDefaults.buttonColors(containerColor = Color.Red), + modifier = Modifier.weight(1f) + ) { + Text(text = "Delete", color = Color.White) } } } @@ -173,4 +221,3 @@ fun ReadOnlyQuestionCard(question: StrokeScaleQuestion, selectedOptions: List