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)
+ }
+ })
+ }
+}