Skip to content
This repository was archived by the owner on Sep 22, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
android:usesCleartextTraffic="true"
tools:replace="android:allowBackup,android:label"
tools:targetApi="31"
tools:ignore="ExtraText">
tools:ignore="ExtraText"
android:networkSecurityConfig="@xml/network_security_config">
<activity
android:name=".WelcomeActivity"
android:exported="false" />
Expand Down Expand Up @@ -185,6 +186,7 @@
android:name=".view.general.TasksListActivity"
android:exported="false" />


<activity android:name=".ModulesActivity" />


Expand All @@ -207,6 +209,21 @@
<activity android:name=".view.falldetection.FallAlertActivity" />
<activity android:name="deakin.gopher.guardian.view.caretaker.notifications.confirmincident.CallAmbulanceActivity" />

<activity
android:name=".view.calendar.GuardianCalendarActivity"
android:exported="false"
android:screenOrientation="portrait" />

<activity
android:name=".view.calendar.AddTaskCalendarActivity"
android:exported="false"
android:screenOrientation="portrait" />

<activity
android:name=".view.logbook.PatientLogbookActivity"
android:exported="false"
android:screenOrientation="portrait" />

<activity
android:name=".PatientExerciseModules"
android:exported="false"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package deakin.gopher.guardian.adapter

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.recyclerview.widget.RecyclerView
import deakin.gopher.guardian.R
import java.util.*

class CalendarGridAdapter(
private var weekDays: List<Date>,
private val timeSlots: List<String>,
private val onSlotClick: (Date, String) -> Unit
) : RecyclerView.Adapter<CalendarGridAdapter.CalendarSlotViewHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CalendarSlotViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_calendar_slot, parent, false)
return CalendarSlotViewHolder(view)
}

override fun onBindViewHolder(holder: CalendarSlotViewHolder, position: Int) {
val dayIndex = position % 7
val timeIndex = position / 7

if (dayIndex < weekDays.size && timeIndex < timeSlots.size) {
val date = weekDays[dayIndex]
val time = timeSlots[timeIndex]
holder.bind(date, time, onSlotClick)
}
}

override fun getItemCount() = weekDays.size * timeSlots.size

fun updateWeekDays(newWeekDays: List<Date>) {
weekDays = newWeekDays
notifyDataSetChanged()
}

class CalendarSlotViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(date: Date, time: String, onSlotClick: (Date, String) -> Unit) {
itemView.setOnClickListener {
onSlotClick(date, time)
}
}
}
}
86 changes: 86 additions & 0 deletions app/src/main/java/deakin/gopher/guardian/adapter/LogbookAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package deakin.gopher.guardian.adapter

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.recyclerview.widget.RecyclerView
import deakin.gopher.guardian.R
import deakin.gopher.guardian.model.logbook.LogEntry
import java.text.SimpleDateFormat
import java.util.*

class LogbookAdapter(
private val onLogClick: (LogEntry) -> Unit,
private val onDeleteClick: (LogEntry) -> Unit
) : RecyclerView.Adapter<LogbookAdapter.LogEntryViewHolder>() {

private var logs = mutableListOf<LogEntry>()

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LogEntryViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_log_entry, parent, false)
return LogEntryViewHolder(view)
}

override fun onBindViewHolder(holder: LogEntryViewHolder, position: Int) {
holder.bind(logs[position], onLogClick, onDeleteClick)
}

override fun getItemCount() = logs.size

fun updateLogs(newLogs: List<LogEntry>) {
logs.clear()
logs.addAll(newLogs)
notifyDataSetChanged()
}

class LogEntryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val titleText: TextView = itemView.findViewById(R.id.log_title)
private val descriptionText: TextView = itemView.findViewById(R.id.log_description)
private val createdByText: TextView = itemView.findViewById(R.id.created_by_text)
private val createdAtText: TextView = itemView.findViewById(R.id.created_at_text)
private val deleteButton: ImageButton = itemView.findViewById(R.id.delete_button)
private val roleBadge: TextView = itemView.findViewById(R.id.role_badge)

fun bind(
log: LogEntry,
onLogClick: (LogEntry) -> Unit,
onDeleteClick: (LogEntry) -> Unit
) {
titleText.text = log.title
descriptionText.text = log.description
createdByText.text = log.createdBy.fullname

// Format the creation date
val formattedDate = formatCreatedAt(log.createdAt)
createdAtText.text = formattedDate

// Set role badge
roleBadge.text = log.createdBy.role.uppercase()
val roleBadgeColor = when (log.createdBy.role.lowercase()) {
"nurse" -> itemView.context.getColor(R.color.nurse_role_color)
"admin" -> itemView.context.getColor(R.color.admin_role_color)
"doctor" -> itemView.context.getColor(R.color.doctor_role_color)
else -> itemView.context.getColor(R.color.default_role_color)
}
roleBadge.setBackgroundColor(roleBadgeColor)

// Click listeners
itemView.setOnClickListener { onLogClick(log) }
deleteButton.setOnClickListener { onDeleteClick(log) }
}

private fun formatCreatedAt(createdAt: String): String {
return try {
val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault())
val outputFormat = SimpleDateFormat("MMM dd, yyyy 'at' h:mm a", Locale.getDefault())
val date = inputFormat.parse(createdAt)
date?.let { outputFormat.format(it) } ?: createdAt
} catch (e: Exception) {
// Fallback to original string if parsing fails
createdAt
}
}
}
}
215 changes: 215 additions & 0 deletions app/src/main/java/deakin/gopher/guardian/adapter/TaskEventsAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
package deakin.gopher.guardian.adapter

import deakin.gopher.guardian.util.CalendarUtils


import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.recyclerview.widget.RecyclerView
import deakin.gopher.guardian.R
import deakin.gopher.guardian.model.calendar.TaskResponse

import java.text.SimpleDateFormat
import java.util.*

class TaskEventsAdapter(
private val onTaskClick: (TaskResponse) -> Unit,
private val onTaskComplete: (String) -> Unit,
private val onTaskEdit: (TaskResponse) -> Unit
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

private var displayItems = mutableListOf<DisplayItem>()

companion object {
const val TYPE_DATE_HEADER = 0
const val TYPE_TASK_ITEM = 1
const val TYPE_NO_EVENTS = 2
}

override fun getItemViewType(position: Int): Int {
return when (displayItems[position]) {
is DisplayItem.DateHeader -> TYPE_DATE_HEADER
is DisplayItem.TaskItem -> TYPE_TASK_ITEM
is DisplayItem.NoEvents -> TYPE_NO_EVENTS
}
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
TYPE_DATE_HEADER -> {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_date_header, parent, false)
DateHeaderViewHolder(view)
}
TYPE_TASK_ITEM -> {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_task_event, parent, false)
TaskEventViewHolder(view)
}
TYPE_NO_EVENTS -> {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_no_events, parent, false)
NoEventsViewHolder(view)
}
else -> throw IllegalArgumentException("Unknown view type: $viewType")
}
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = displayItems[position]) {
is DisplayItem.DateHeader -> {
(holder as DateHeaderViewHolder).bind(item.date)
}
is DisplayItem.TaskItem -> {
(holder as TaskEventViewHolder).bind(
item.task,
onTaskClick,
onTaskComplete,
onTaskEdit
)
}
is DisplayItem.NoEvents -> {
// No binding needed
}
}
}

override fun getItemCount() = displayItems.size

fun updateTasks(tasks: List<TaskResponse>) {
displayItems.clear()

if (tasks.isEmpty()) {
displayItems.add(DisplayItem.NoEvents)
notifyDataSetChanged()
return
}

// Group tasks by date and sort
val tasksByDate = tasks.groupBy { task ->
task.dueDate?.let {
val date = CalendarUtils.parseDateString(it)
SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(date)
} ?: "unknown"
}.toSortedMap()

tasksByDate.forEach { (dateString, tasksForDate) ->
if (dateString != "unknown") {
val date = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse(dateString) ?: Date()
displayItems.add(DisplayItem.DateHeader(date))

// Sort tasks by time for the day
val sortedTasks = tasksForDate.sortedBy { task ->
task.dueDate?.let { CalendarUtils.parseDateString(it) } ?: Date(0)
}

sortedTasks.forEach { task ->
displayItems.add(DisplayItem.TaskItem(task))
}
}
}

notifyDataSetChanged()
}

sealed class DisplayItem {
data class DateHeader(val date: Date) : DisplayItem()
data class TaskItem(val task: TaskResponse) : DisplayItem()
object NoEvents : DisplayItem()
}

class DateHeaderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val dateText: TextView = itemView.findViewById(R.id.date_text)

fun bind(date: Date) {
dateText.text = CalendarUtils.formatDateHeader(date)
}
}

class TaskEventViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val timeText: TextView = itemView.findViewById(R.id.time_text)
private val durationText: TextView = itemView.findViewById(R.id.duration_text)
private val titleText: TextView = itemView.findViewById(R.id.title_text)
private val descriptionText: TextView = itemView.findViewById(R.id.description_text)
private val priorityIndicator: View = itemView.findViewById(R.id.priority_indicator)
private val statusIcon: ImageView = itemView.findViewById(R.id.status_icon)
private val patientBadge: TextView = itemView.findViewById(R.id.patient_badge)
private val completeButton: ImageButton = itemView.findViewById(R.id.complete_button)
private val editButton: ImageButton = itemView.findViewById(R.id.edit_button)

fun bind(
task: TaskResponse,
onTaskClick: (TaskResponse) -> Unit,
onTaskComplete: (String) -> Unit,
onTaskEdit: (TaskResponse) -> Unit
) {
// Time formatting
val time = task.dueDate?.let {
val date = CalendarUtils.parseDateString(it)
SimpleDateFormat("h:mm a", Locale.getDefault()).format(date)
} ?: "No time"

timeText.text = time
durationText.text = "1h" // You can calculate or store duration
titleText.text = task.title

// Show description if available and different from title
if (task.description.isNotBlank() && task.description != task.title) {
descriptionText.text = task.description
descriptionText.visibility = View.VISIBLE
} else {
descriptionText.visibility = View.GONE
}

// Priority indicator
val priorityColor = when (task.priority.lowercase()) {
"urgent", "high" -> itemView.context.getColor(R.color.priority_high)
"medium" -> itemView.context.getColor(R.color.priority_medium)
"low" -> itemView.context.getColor(R.color.priority_low)
else -> itemView.context.getColor(R.color.priority_medium)
}
priorityIndicator.setBackgroundColor(priorityColor)

// Status icon and styling
val isCompleted = task.status.lowercase() == "completed"
when (task.status.lowercase()) {
"completed" -> {
statusIcon.setImageResource(R.drawable.ic_check_circle)
statusIcon.setColorFilter(itemView.context.getColor(R.color.success_color))
itemView.alpha = 0.7f
}
"in_progress" -> {
statusIcon.setImageResource(R.drawable.ic_in_progress)
statusIcon.setColorFilter(itemView.context.getColor(R.color.warning_color))
itemView.alpha = 1.0f
}
else -> {
statusIcon.setImageResource(R.drawable.ic_pending)
statusIcon.setColorFilter(itemView.context.getColor(R.color.text_secondary))
itemView.alpha = 1.0f
}
}

// Patient badge
if (task.patientId != null) {
patientBadge.visibility = View.VISIBLE
patientBadge.text = "Patient"
} else {
patientBadge.visibility = View.GONE
}

// Action buttons
completeButton.visibility = if (isCompleted) View.GONE else View.VISIBLE
completeButton.setOnClickListener { onTaskComplete(task.id) }

editButton.setOnClickListener { onTaskEdit(task) }

// Click listeners
itemView.setOnClickListener { onTaskClick(task) }
}
}

class NoEventsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
}
Loading
Loading