Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class AnalyticsHelper(
fun trackNotificationShown(medication: Medication) {
val params = bundleOf(
MEDICATION_TIME to medication.medicationTime.toFormattedDateString(),
MEDICATION_END_DATE to medication.endDate.toFormattedDateString(),
MEDICATION_END_DATE to (medication.endDate?.toFormattedDateString() ?: "ongoing"),
NOTIFICATION_TIME to Date().toFormattedDateString()
)
logEvent(AnalyticsEvents.MEDICATION_NOTIFICATION_SHOWN, params)
Expand All @@ -29,7 +29,7 @@ class AnalyticsHelper(
fun trackNotificationScheduled(medication: Medication) {
val params = bundleOf(
MEDICATION_TIME to medication.medicationTime.toFormattedDateString(),
MEDICATION_END_DATE to medication.endDate.toFormattedDateString(),
MEDICATION_END_DATE to (medication.endDate?.toFormattedDateString() ?: "ongoing"),
NOTIFICATION_TIME to Date().toFormattedDateString()
)
logEvent(AnalyticsEvents.MEDICATION_NOTIFICATION_SCHEDULED, params)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import com.waseefakhtar.doseapp.data.entity.MedicationEntity

@Database(
entities = [MedicationEntity::class],
version = 4,
version = 5,
autoMigrations = [
AutoMigration(from = 3, to = 4, spec = MedicationDatabase.AutoMigration::class)
AutoMigration(from = 3, to = 4, spec = MedicationDatabase.AutoMigration3To4::class),
AutoMigration(from = 4, to = 5)
]
)
@TypeConverters(Converters::class)
Expand All @@ -22,5 +23,5 @@ abstract class MedicationDatabase : RoomDatabase() {
abstract val dao: MedicationDao
@DeleteColumn(tableName = "MedicationEntity", columnName = "timesOfDay")
@RenameColumn(tableName = "MedicationEntity", fromColumnName = "date", toColumnName = "medicationTime")
class AutoMigration : AutoMigrationSpec
class AutoMigration3To4 : AutoMigrationSpec
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ data class MedicationEntity(
val dosage: Int,
val recurrence: String,
val startDate: Date?,
val endDate: Date,
val endDate: Date?,
val medicationTaken: Boolean,
val medicationTime: Date,
@ColumnInfo(defaultValue = "TABLET")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ data class Medication(
val dosage: Int,
val frequency: String,
val startDate: Date,
val endDate: Date,
val endDate: Date?,
val medicationTaken: Boolean,
val medicationTime: Date,
val type: MedicationType = MedicationType.getDefault()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
Expand All @@ -32,6 +33,7 @@ import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.DateRange
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.Button
import androidx.compose.material3.Checkbox
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
Expand Down Expand Up @@ -60,6 +62,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
Expand Down Expand Up @@ -107,6 +110,7 @@ fun AddMedicationScreen(
var frequency by rememberSaveable { mutableStateOf(Frequency.EVERYDAY.name) }
var startDate by rememberSaveable { mutableLongStateOf(0L) }
var endDate by rememberSaveable { mutableLongStateOf(0L) }
var isOngoing by rememberSaveable { mutableStateOf(false) }
var showDatePicker by remember { mutableStateOf(false) }
val selectedTimes =
rememberSaveable(
Expand Down Expand Up @@ -169,6 +173,7 @@ fun AddMedicationScreen(
frequency = frequency,
startDate = startDate,
endDate = endDate,
isOngoing = isOngoing,
selectedTimes = selectedTimes,
type = medicationType,
onInvalidate = {
Expand Down Expand Up @@ -227,39 +232,93 @@ fun AddMedicationScreen(

Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
TextField(
modifier = Modifier.fillMaxWidth(),
readOnly = true,
value = buildDateRangeText(startDate, endDate),
onValueChange = {},
label = { Text(stringResource(R.string.duration)) },
placeholder = { Text(stringResource(R.string.select_duration)) },
trailingIcon = { Icon(Icons.Default.DateRange, contentDescription = null) },
interactionSource = remember { MutableInteractionSource() }.also { interactionSource ->
LaunchedEffect(interactionSource) {
interactionSource.interactions.collect {
if (it is PressInteraction.Release) {
showDatePicker = true
Row(
modifier = Modifier
.fillMaxWidth()
.toggleable(
value = isOngoing,
onValueChange = { isOngoing = it },
role = Role.Checkbox,
)
.padding(vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Checkbox(
checked = isOngoing,
onCheckedChange = null,
)
Text(
text = stringResource(R.string.ongoing_medication),
modifier = Modifier.padding(start = 8.dp),
style = MaterialTheme.typography.bodyMedium,
)
}

if (isOngoing) {
TextField(
modifier = Modifier.fillMaxWidth(),
readOnly = true,
value = buildStartDateText(startDate),
onValueChange = {},
label = { Text(stringResource(R.string.start_date)) },
placeholder = { Text(stringResource(R.string.select_start_date)) },
trailingIcon = { Icon(Icons.Default.DateRange, contentDescription = null) },
interactionSource = remember { MutableInteractionSource() }.also { interactionSource ->
LaunchedEffect(interactionSource) {
interactionSource.interactions.collect {
if (it is PressInteraction.Release) {
showDatePicker = true
}
}
}
}
},
)
} else {
TextField(
modifier = Modifier.fillMaxWidth(),
readOnly = true,
value = buildDateRangeText(startDate, endDate),
onValueChange = {},
label = { Text(stringResource(R.string.duration)) },
placeholder = { Text(stringResource(R.string.select_duration)) },
trailingIcon = { Icon(Icons.Default.DateRange, contentDescription = null) },
interactionSource = remember { MutableInteractionSource() }.also { interactionSource ->
LaunchedEffect(interactionSource) {
interactionSource.interactions.collect {
if (it is PressInteraction.Release) {
showDatePicker = true
}
}
}
},
)
}
}

if (isOngoing) {
StartDatePickerDialog(
showDialog = showDatePicker,
selectedDate = startDate,
onDismiss = { showDatePicker = false },
onDateSelected = { start ->
startDate = start
},
)
} else {
DateRangePickerDialog(
showDialog = showDatePicker,
startDate = startDate,
endDate = endDate,
onDismiss = { showDatePicker = false },
onDateSelected = { start, end ->
startDate = start
endDate = end
},
)
}

DateRangePickerDialog(
showDialog = showDatePicker,
startDate = startDate,
endDate = endDate,
onDismiss = { showDatePicker = false },
onDateSelected = { start, end ->
startDate = start
endDate = end
},
)

Spacer(modifier = Modifier.padding(4.dp))
Text(
text = stringResource(R.string.schedule),
Expand Down Expand Up @@ -358,6 +417,7 @@ private fun validateMedication(
frequency: String,
startDate: Long,
endDate: Long,
isOngoing: Boolean,
selectedTimes: List<CalendarInformation>,
type: MedicationType,
onInvalidate: (Int) -> Unit,
Expand All @@ -374,14 +434,22 @@ private fun validateMedication(
return
}

if (startDate == 0L || endDate == 0L) {
onInvalidate(R.string.duration)
return
}
// For ongoing medications, only startDate is required
if (isOngoing) {
if (startDate == 0L) {
onInvalidate(R.string.start_date)
return
}
} else {
if (startDate == 0L || endDate == 0L) {
onInvalidate(R.string.duration)
return
}

if (startDate >= endDate) {
onInvalidate(R.string.duration)
return
if (startDate >= endDate) {
onInvalidate(R.string.duration)
return
}
}

if (selectedTimes.isEmpty()) {
Expand All @@ -395,7 +463,7 @@ private fun validateMedication(
dosage = dosage,
frequency = frequency,
startDate = Date(startDate),
endDate = Date(endDate),
endDate = if (isOngoing) null else Date(endDate),
medicationTimes = selectedTimes,
type = type
)
Expand Down Expand Up @@ -526,6 +594,16 @@ private fun buildDateRangeText(
"${Date(startDate).toFormattedMonthDateString()} - ${Date(endDate).toFormattedMonthDateString()}"
}

@Composable
private fun buildStartDateText(
startDate: Long,
): String =
if (startDate == 0L) {
""
} else {
Date(startDate).toFormattedMonthDateString()
}

@Composable
private fun MedicationTypeBox(
type: MedicationType,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.waseefakhtar.doseapp.feature.addmedication

import androidx.compose.foundation.layout.padding
import androidx.compose.material3.DatePicker
import androidx.compose.material3.DatePickerDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberDatePickerState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.waseefakhtar.doseapp.R
import com.waseefakhtar.doseapp.extension.toFormattedDateString
import java.util.Calendar

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun StartDatePickerDialog(
showDialog: Boolean,
selectedDate: Long?,
onDismiss: () -> Unit,
onDateSelected: (startDate: Long) -> Unit,
) {
if (showDialog) {
val today = Calendar.getInstance().timeInMillis
val datePickerState = rememberDatePickerState(
initialSelectedDateMillis = if (selectedDate == 0L) today else selectedDate,
)

DatePickerDialog(
onDismissRequest = onDismiss,
confirmButton = {
TextButton(
enabled = datePickerState.selectedDateMillis != null,
onClick = {
datePickerState.selectedDateMillis?.let { start ->
onDateSelected(start)
}
onDismiss()
},
) {
Text(stringResource(R.string.ok))
}
},
dismissButton = {
TextButton(onClick = onDismiss) {
Text(stringResource(R.string.cancel))
}
},
) {
DatePicker(
state = datePickerState,
showModeToggle = false,
title = {
Text(
text = stringResource(R.string.select_start_date),
modifier = Modifier.padding(
start = 24.dp,
end = 12.dp,
top = 16.dp,
),
)
},
headline = {
datePickerState.selectedDateMillis?.toFormattedDateString()?.let {
Text(
modifier = Modifier.padding(
start = 24.dp,
end = 12.dp,
bottom = 12.dp,
),
text = it
)
}
},
)
}
}
}
Loading