diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c925b25..815196f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,5 +46,9 @@ + + + + diff --git a/app/src/main/java/com/example/neurology_project_android/ListSessionActivity.kt b/app/src/main/java/com/example/neurology_project_android/ListSessionActivity.kt new file mode 100644 index 0000000..0bfb0fe --- /dev/null +++ b/app/src/main/java/com/example/neurology_project_android/ListSessionActivity.kt @@ -0,0 +1,244 @@ +package com.example.neurology_project_android + +import android.content.Intent +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +/** + * ListSessionActivity - WITH MOCK DATA FOR TESTING + * + * This version includes sample/test data so you can see how the UI looks + * with actual sessions displayed. + * + */ +class ListSessionActivity : ComponentActivity() { + private var refreshTrigger by mutableStateOf(0) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + ListSessionScreen(refreshTrigger) + } + } + + override fun onResume() { + super.onResume() + refreshTrigger++ + } +} + +@Composable +fun ListSessionScreen(refreshTrigger: Int) { + val context = LocalContext.current + val sessionManager = remember { SessionManager(context) } + val username = sessionManager.fetchUsername() ?: "anonymous" + + // State to hold the list of sessions + var savedSessions by remember { mutableStateOf>(emptyList()) } + + // MOCK DATA - Replace this section when backend is ready + LaunchedEffect(refreshTrigger) { + // Option 1: Try to fetch real data from server + // val fetchedSessions = SessionManagerApi.fetchSessionsForUser(username, sessionManager.client) + + // Option 2: If no data from server, use mock data + val mockSessions = listOf( + Session( + id = 1, + sessionId = "session-001", + date = "10/29/2025", + time = "2:17pm", + attendingDoctors = "Dr. Smith, Dr. Johnson", + patientName = "John Doe", + patientDob = "09/26/1985", + formIds = "1,2", + videoUrl = "https://example.com/video1.mp4", + videoSize = "50MB", + aiFormOutput = "NIHSS Score: 8 - Moderate stroke severity", + username = username + ), + Session( + id = 2, + sessionId = "session-002", + date = "10/28/2025", + time = "3:45pm", + attendingDoctors = "Dr. Williams, Dr. Brown, Dr. Davis", + patientName = "Jane Smith", + patientDob = "03/15/1972", + formIds = "3", + videoUrl = "https://example.com/video2.mp4", + videoSize = "65MB", + aiFormOutput = "NIHSS Score: 3 - Minor stroke severity", + username = username + ), + Session( + id = 3, + sessionId = "session-003", + date = "10/27/2025", + time = "10:30am", + attendingDoctors = "Dr. Miller", + patientName = "Robert Johnson", + patientDob = "11/08/1968", + formIds = "4,5,6", + videoUrl = "https://example.com/video3.mp4", + videoSize = "42MB", + aiFormOutput = "NIHSS Score: 15 - Severe stroke", + username = username + ), + Session( + id = 4, + sessionId = "session-004", + date = "10/26/2025", + time = "9:15am", + attendingDoctors = "Dr. Garcia, Dr. Martinez", + patientName = "Mary Wilson", + patientDob = "07/22/1990", + formIds = "7", + videoUrl = "https://example.com/video4.mp4", + videoSize = "38MB", + aiFormOutput = "NIHSS Score: 1 - Very minor symptoms", + username = username + ), + Session( + id = 5, + sessionId = "session-005", + date = "10/25/2025", + time = "1:00pm", + attendingDoctors = "Dr. Anderson", + patientName = "Michael Brown", + patientDob = "12/30/1956", + formIds = "8,9", + videoUrl = "https://example.com/video5.mp4", + videoSize = "55MB", + aiFormOutput = "NIHSS Score: 12 - Moderate to severe stroke", + username = username + ) + ) + + savedSessions = mockSessions + + // TO USE REAL DATA INSTEAD: + // 1. Comment out the mockSessions lines above + // 2. Uncomment this line: + // savedSessions = SessionManagerApi.fetchSessionsForUser(username, sessionManager.client) + } + + Column( + modifier = Modifier + .fillMaxSize() + .background(Color.White) + .padding(24.dp) + ) { + // Header Row with title and "New Session" button + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 10.dp, bottom = 24.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = "Saved Sessions", + fontSize = 28.sp, + fontWeight = FontWeight.Bold + ) + + TextButton( + onClick = { + val intent = Intent(context, NewSessionActivity::class.java) + context.startActivity(intent) + } + ) { + Text(text = "New Session", fontSize = 16.sp) + } + } + + // Scrollable list of sessions + LazyColumn( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + items(savedSessions) { session -> + SessionItem( + session = session, + onClick = { + // Navigate to session details screen + val intent = Intent(context, SessionDetailsActivity::class.java).apply { + putExtra("sessionId", session.id) + putExtra("sessionIdString", session.sessionId) + putExtra("date", session.date) + putExtra("time", session.time) + putExtra("attendingDoctors", session.attendingDoctors) + putExtra("patientName", session.patientName) + putExtra("patientDob", session.patientDob) + putExtra("formIds", session.formIds) + putExtra("videoUrl", session.videoUrl) + putExtra("videoSize", session.videoSize) + putExtra("aiFormOutput", session.aiFormOutput) + putExtra("username", session.username) + } + context.startActivity(intent) + } + ) + } + } + } +} + +/** + * SessionItem Composable + * + * Displays a single session card in the list. + * Shows the date/time and a "View" button. + */ +@Composable +fun SessionItem(session: Session, onClick: () -> Unit) { + Card( + shape = MaterialTheme.shapes.medium, + elevation = CardDefaults.cardElevation(defaultElevation = 4.dp), + modifier = Modifier + .fillMaxWidth() + .clickable(onClick = onClick) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Column { + // Display date and time + Text( + text = "Date: ${session.date}", + fontSize = 18.sp, + fontWeight = FontWeight.Bold + ) + Text( + text = "Time: ${session.time}", + fontSize = 14.sp, + color = Color.Gray + ) + } + + Button(onClick = onClick) { + Text(text = "View") + } + } + } +} \ No newline at end of file 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 f6f8d2c..860df48 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 @@ -265,7 +265,7 @@ class MainActivity : ComponentActivity() { OnlineNowSection(peers) // No need for additional state } - NIHFormsButton() + SessionsAndFormsButtons() } } } @@ -350,20 +350,42 @@ fun PeerIdSection(peerId: String) { @Composable -fun NIHFormsButton() { +fun SessionsAndFormsButtons() { val context = LocalContext.current - Button( - onClick = { - val intent = Intent(context, ListNIHFormActivity::class.java) - context.startActivity(intent) - }, + Row( modifier = Modifier .fillMaxWidth() .padding(vertical = 16.dp), - shape = RoundedCornerShape(8.dp) + horizontalArrangement = Arrangement.spacedBy(12.dp) ) { - Text(text = "NIH Forms") + // Sessions Button + Button( + onClick = { + val intent = Intent(context, ListSessionActivity::class.java) + context.startActivity(intent) + }, + modifier = Modifier + .weight(1f) + .height(48.dp), + shape = RoundedCornerShape(8.dp) + ) { + Text(text = "Sessions") + } + + // NIH Forms Button + Button( + onClick = { + val intent = Intent(context, ListNIHFormActivity::class.java) + context.startActivity(intent) + }, + modifier = Modifier + .weight(1f) + .height(48.dp), + shape = RoundedCornerShape(8.dp) + ) { + Text(text = "NIH Forms") + } } } diff --git a/app/src/main/java/com/example/neurology_project_android/NewSessionActivity.kt b/app/src/main/java/com/example/neurology_project_android/NewSessionActivity.kt new file mode 100644 index 0000000..8ad6d6f --- /dev/null +++ b/app/src/main/java/com/example/neurology_project_android/NewSessionActivity.kt @@ -0,0 +1,62 @@ +package com.example.neurology_project_android + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +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 + +/** + * NewSessionActivity (PLACEHOLDER) + * + */ +class NewSessionActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + NewSessionPlaceholderScreen() + } + } +} + +@Composable +fun NewSessionPlaceholderScreen() { + Column( + modifier = Modifier + .fillMaxSize() + .background(Color.White) + .padding(24.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Text( + text = "New Session", + fontSize = 28.sp, + fontWeight = FontWeight.Bold + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "This feature is coming soon!", + fontSize = 18.sp, + color = Color.Gray + ) + + Spacer(modifier = Modifier.height(32.dp)) + + Text( + text = "TODO: Implement session creation", + fontSize = 14.sp, + color = Color.Gray + ) + } +} diff --git a/app/src/main/java/com/example/neurology_project_android/Session.kt b/app/src/main/java/com/example/neurology_project_android/Session.kt new file mode 100644 index 0000000..fb17bde --- /dev/null +++ b/app/src/main/java/com/example/neurology_project_android/Session.kt @@ -0,0 +1,29 @@ +package com.example.neurology_project_android + +import androidx.room.Entity +import androidx.room.PrimaryKey + +/** + * Session Data Model + * + * Represents a consultation session that contains: + * - Session metadata (ID, date, time) + * - List of attending doctors + * - Associated stroke scale forms + * - Video recording information + */ +@Entity(tableName = "sessions") +data class Session( + @PrimaryKey(autoGenerate = true) val id: Int = 0, + val sessionId: String, // Unique session identifier + val date: String, // Session date (e.g., "9/30/2025") + val time: String, // Session time (e.g., "2:17pm") + val attendingDoctors: String, // Comma-separated list of doctor names + val patientName: String, // Patient involved in session + val patientDob: String, // Patient date of birth + val formIds: String, // Comma-separated list of form IDs associated with this session + val videoUrl: String, // URL or path to session video recording + val videoSize: String, // Video file size (e.g., "50MB") + val aiFormOutput: String, + val username: String // User who created/owns this session +) diff --git a/app/src/main/java/com/example/neurology_project_android/SessionDetailsActivity.kt b/app/src/main/java/com/example/neurology_project_android/SessionDetailsActivity.kt new file mode 100644 index 0000000..88107e4 --- /dev/null +++ b/app/src/main/java/com/example/neurology_project_android/SessionDetailsActivity.kt @@ -0,0 +1,321 @@ +package com.example.neurology_project_android + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.widget.Toast +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +/** + * SessionDetailsActivity + * + * Shows detailed information about a specific consultation session: + */ +class SessionDetailsActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + // Extract session data from Intent extras + val session = Session( + id = intent.getIntExtra("sessionId", -1), + sessionId = intent.getStringExtra("sessionIdString") ?: "", + date = intent.getStringExtra("date") ?: "", + time = intent.getStringExtra("time") ?: "", + attendingDoctors = intent.getStringExtra("attendingDoctors") ?: "", + patientName = intent.getStringExtra("patientName") ?: "", + patientDob = intent.getStringExtra("patientDob") ?: "", + formIds = intent.getStringExtra("formIds") ?: "", + videoUrl = intent.getStringExtra("videoUrl") ?: "", + videoSize = intent.getStringExtra("videoSize") ?: "", + aiFormOutput = intent.getStringExtra("aiFormOutput") ?: "", + username = intent.getStringExtra("username") ?: "" + ) + + setContent { + SessionDetailsScreen(session) + } + } +} + +@Composable +fun SessionDetailsScreen(session: Session) { + val context = LocalContext.current + val sessionManager = remember { SessionManager(context) } + + 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) + ) + } + + // Header - Session Information + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "Session Details", + fontSize = 24.sp, + fontWeight = FontWeight.Bold, + color = Color.Black + ) + + Text( + text = "${session.date} ${session.time}", + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = Color.Black, + modifier = Modifier.padding(top = 8.dp) + ) + + Text( + text = "Patient: ${session.patientName}", + fontSize = 16.sp, + color = Color.Gray, + modifier = Modifier.padding(top = 4.dp) + ) + + Text( + text = "DOB: ${session.patientDob}", + fontSize = 16.sp, + color = Color.Gray + ) + } + + Spacer(modifier = Modifier.height(16.dp)) + + // Scrollable content + LazyColumn( + modifier = Modifier + .weight(1f) + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + // Attending Doctors Section + item { + SessionDetailCard( + title = "Attending Doctors", + content = session.attendingDoctors.replace(",", ", ") + ) + } + + // Patient Information Card + item { + Card( + modifier = Modifier.fillMaxWidth(), + elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) { + Text( + text = "Patient Name", + fontSize = 16.sp, + fontWeight = FontWeight.Bold + ) + Text( + text = session.patientName, + fontSize = 14.sp, + color = Color.Gray, + modifier = Modifier.padding(top = 4.dp) + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "DOB: ${session.patientDob}", + fontSize = 14.sp, + color = Color.Gray + ) + + Text( + text = "Date: ${session.date}", + fontSize = 14.sp, + color = Color.Gray + ) + + Spacer(modifier = Modifier.height(12.dp)) + + // View Form Button + Button( + onClick = { + // TODO: Navigate to form details + // Parse formIds and open the first form + val formIdsList = session.formIds.split(",") + if (formIdsList.isNotEmpty() && formIdsList[0].isNotEmpty()) { + Toast.makeText( + context, + "Opening form ${formIdsList[0]}", + Toast.LENGTH_SHORT + ).show() + // You can add navigation to SavedNIHFormActivity here + } else { + Toast.makeText( + context, + "No forms associated with this session", + Toast.LENGTH_SHORT + ).show() + } + }, + modifier = Modifier.fillMaxWidth() + ) { + Text(text = "View Form") + } + } + } + } + + // Video File Card + item { + Card( + modifier = Modifier.fillMaxWidth(), + elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) { + Text( + text = "Video File", + fontSize = 16.sp, + fontWeight = FontWeight.Bold + ) + Text( + text = "Size: ${session.videoSize}", + fontSize = 14.sp, + color = Color.Gray, + modifier = Modifier.padding(top = 4.dp) + ) + + Spacer(modifier = Modifier.height(12.dp)) + + // View Video Button + Button( + onClick = { + // Open video player or browser with video URL + if (session.videoUrl.isNotEmpty()) { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(session.videoUrl)) + context.startActivity(intent) + } else { + Toast.makeText( + context, + "No video available", + Toast.LENGTH_SHORT + ).show() + } + }, + modifier = Modifier.fillMaxWidth() + ) { + Text(text = "View Video") + } + } + } + } + + // AI Form Output Section (if available) + if (session.aiFormOutput.isNotEmpty()) { + item { + SessionDetailCard( + title = "AI Assessment", + content = session.aiFormOutput + ) + } + } + } + + // Delete Button at bottom + Button( + onClick = { + SessionManagerApi.deleteSession( + session.id, + session.username, + sessionManager.client + ) { success -> + (context as? ComponentActivity)?.runOnUiThread { + if (success) { + Toast.makeText(context, "Session deleted", Toast.LENGTH_SHORT).show() + (context as? ComponentActivity)?.finish() + } else { + Toast.makeText( + context, + "Failed to delete session", + Toast.LENGTH_SHORT + ).show() + } + } + } + }, + colors = ButtonDefaults.buttonColors(containerColor = Color.Red), + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp) + ) { + Text(text = "Delete Session", color = Color.White) + } + } +} + +/** + * Reusable card component for displaying session detail sections + */ +@Composable +fun SessionDetailCard(title: String, content: String) { + Card( + modifier = Modifier.fillMaxWidth(), + elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) { + Text( + text = title, + fontSize = 16.sp, + fontWeight = FontWeight.Bold + ) + Text( + text = content, + fontSize = 14.sp, + color = Color.Gray, + modifier = Modifier.padding(top = 8.dp) + ) + } + } +} diff --git a/app/src/main/java/com/example/neurology_project_android/SessionManagerApi.kt b/app/src/main/java/com/example/neurology_project_android/SessionManagerApi.kt new file mode 100644 index 0000000..ae321a9 --- /dev/null +++ b/app/src/main/java/com/example/neurology_project_android/SessionManagerApi.kt @@ -0,0 +1,173 @@ +package com.example.neurology_project_android + +import android.util.Log +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okhttp3.* +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import org.json.JSONArray +import org.json.JSONObject +import java.io.IOException + +/** + * SessionManager + * + * Handles all API operations for sessions: + */ +object SessionManagerApi { + + private const val BASE_URL = "https://videochat-signaling-app.ue.r.appspot.com/key=peerjs/post" + + /** + * Fetch all sessions for a specific user + * + * @param username The username to fetch sessions for + * @param client OkHttpClient for making network requests + * @return List of Session objects + */ + suspend fun fetchSessionsForUser( + username: String, + client: OkHttpClient + ): List = withContext(Dispatchers.IO) { + val sessions = 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(BASE_URL) + .post(requestBody) + .addHeader("Content-Type", "application/json") + .addHeader("Action", "getUsersSessions") // Action header for backend to identify request type + .build() + + try { + val response = client.newCall(request).execute() + if (response.isSuccessful) { + val bodyString = response.body?.string() + val jsonArray = JSONArray(bodyString) + + // Parse each session from the JSON array + for (i in 0 until jsonArray.length()) { + val item = jsonArray.getJSONObject(i) + sessions.add( + Session( + id = item.getInt("id"), + sessionId = item.getString("session_id"), + date = item.getString("date"), + time = item.getString("time"), + attendingDoctors = item.getString("attending_doctors"), + patientName = item.getString("patient_name"), + patientDob = item.getString("patient_dob"), + formIds = item.getString("form_ids"), + videoUrl = item.getString("video_url"), + videoSize = item.getString("video_size"), + aiFormOutput = item.getString("ai_form_output"), + username = item.getString("username") + ) + ) + } + } else { + Log.e("SESSION_MANAGER", "Server error: ${response.code}") + } + } catch (e: IOException) { + Log.e("SESSION_MANAGER", "Network error: ${e.message}") + } catch (e: Exception) { + Log.e("SESSION_MANAGER", "Parsing error: ${e.message}") + } + + return@withContext sessions + } + + /** + * Submit a new session to the server + * + * @param session The Session object to submit + * @param client OkHttpClient for making network requests + * @param onResult Callback with success/failure result + */ + fun submitSessionToServer(session: Session, client: OkHttpClient, onResult: (Boolean) -> Unit) { + val json = JSONObject().apply { + put("sessionId", session.sessionId) + put("date", session.date) + put("time", session.time) + put("attendingDoctors", session.attendingDoctors) + put("patientName", session.patientName) + put("patientDob", session.patientDob) + put("formIds", session.formIds) + put("videoUrl", session.videoUrl) + put("videoSize", session.videoSize) + put("aiFormOutput", session.aiFormOutput) + put("username", session.username) + } + + val requestBody = RequestBody.create( + "application/json; charset=utf-8".toMediaTypeOrNull(), + json.toString() + ) + + val request = Request.Builder() + .url(BASE_URL) + .post(requestBody) + .addHeader("Content-Type", "application/json") + .addHeader("Action", "submitSession") + .build() + + client.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + Log.e("SESSION_SUBMIT", "Failed: ${e.message}") + onResult(false) + } + + override fun onResponse(call: Call, response: Response) { + Log.d("SESSION_SUBMIT", "Response code: ${response.code}") + onResult(response.isSuccessful) + } + }) + } + + /** + * Delete a session from the server + * + * @param sessionId The ID of the session to delete + * @param username The username of the session owner + * @param client OkHttpClient for making network requests + * @param callback Callback with success/failure result + */ + fun deleteSession(sessionId: Int, username: String, client: OkHttpClient, callback: (Boolean) -> Unit) { + val json = JSONObject().apply { + put("id", sessionId) + put("username", username) + } + + val requestBody = RequestBody.create( + "application/json; charset=utf-8".toMediaTypeOrNull(), + json.toString() + ) + + val request = Request.Builder() + .url(BASE_URL) + .post(requestBody) + .addHeader("Content-Type", "application/json") + .addHeader("Action", "deleteSession") + .build() + + client.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + Log.e("DELETE_SESSION", "Failed: ${e.message}") + callback(false) + } + + override fun onResponse(call: Call, response: Response) { + Log.d("DELETE_SESSION", "Response code: ${response.code}") + callback(response.isSuccessful) + } + }) + } +}