From 1be86014ecf6a90e0ce4787d95e88dcd9c700ad3 Mon Sep 17 00:00:00 2001 From: Karanveer Singh Date: Mon, 16 Oct 2023 12:07:54 +0530 Subject: [PATCH 1/4] add-medication-screen-ui-fix --- .../addmedication/AddMedicationRoute.kt | 512 +++++++++--------- 1 file changed, 261 insertions(+), 251 deletions(-) diff --git a/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt b/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt index 65567a1..ee8f894 100644 --- a/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt +++ b/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt @@ -32,8 +32,10 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.FloatingActionButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextField +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -98,280 +100,287 @@ fun AddMedicationScreen( var isAfternoonSelected by rememberSaveable { mutableStateOf(false) } var isEveningSelected by rememberSaveable { mutableStateOf(false) } var isNightSelected by rememberSaveable { mutableStateOf(false) } + val context = LocalContext.current - Column( - modifier = Modifier - .padding(0.dp, 16.dp) - .verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - Row( - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - FloatingActionButton( + Scaffold( + topBar = { + TopAppBar( + modifier = Modifier + .padding(top = 8.dp, bottom = 16.dp), + navigationIcon = { + FloatingActionButton( + onClick = { + analyticsHelper.logEvent(AnalyticsEvents.ADD_MEDICATION_ON_BACK_CLICKED) + onBackClicked() + }, + elevation = FloatingActionButtonDefaults.elevation(0.dp, 0.dp) + ) { + Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "Back") + } + }, title = { + Text( + text = stringResource(id = R.string.add_medication), + fontWeight = FontWeight.Bold, + style = MaterialTheme.typography.displaySmall + ) + }) + }, + bottomBar = { + Button( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp) + .height(56.dp), onClick = { - analyticsHelper.logEvent(AnalyticsEvents.ADD_MEDICATION_ON_BACK_CLICKED) - onBackClicked() + validateMedication( + name = medicationName, + dosage = numberOfDosage.toIntOrNull() ?: 0, + recurrence = recurrence, + endDate = endDate, + morningSelection = isMorningSelected, + afternoonSelection = isAfternoonSelected, + eveningSelection = isEveningSelected, + nightSelection = isNightSelected, + onInvalidate = { + val invalidatedValue = context.getString(it) + Toast.makeText( + context, + context.getString(R.string.value_is_empty, invalidatedValue), + Toast.LENGTH_LONG + ).show() + + val event = String.format( + AnalyticsEvents.ADD_MEDICATION_MEDICATION_VALUE_INVALIDATED, + invalidatedValue + ) + analyticsHelper.logEvent(event) + }, + onValidate = { + navigateToMedicationConfirm(it) + analyticsHelper.logEvent(AnalyticsEvents.ADD_MEDICATION_NAVIGATING_TO_MEDICATION_CONFIRM) + }, + viewModel = viewModel + ) }, - elevation = FloatingActionButtonDefaults.elevation(0.dp, 0.dp) - ) { - Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "Back") - } - Text( - text = stringResource(id = R.string.add_medication), - fontWeight = FontWeight.Bold, - style = MaterialTheme.typography.displaySmall - ) - } - - Spacer(modifier = Modifier.padding(8.dp)) - - Text( - text = stringResource(id = R.string.medication_name), - style = MaterialTheme.typography.bodyLarge - ) - TextField( - modifier = Modifier.fillMaxWidth(), - value = medicationName, - onValueChange = { medicationName = it }, - // label = { Text(text = stringResource(id = R.string.medication_name)) }, - placeholder = { Text(text = "e.g. Risperdal, 4mg") }, - ) - - Spacer(modifier = Modifier.padding(4.dp)) - - var isMaxDoseError by rememberSaveable { mutableStateOf(false) } - Row( - horizontalArrangement = Arrangement.spacedBy(16.dp) - ) { - val maxDose = 3 - - Column( - verticalArrangement = Arrangement.spacedBy(8.dp) + shape = MaterialTheme.shapes.extraLarge ) { Text( - text = stringResource(id = R.string.dose_per_day), + text = stringResource(id = R.string.next), style = MaterialTheme.typography.bodyLarge ) - TextField( - modifier = Modifier.width(128.dp), - value = numberOfDosage, - onValueChange = { - if (it.length < maxDose) { - isMaxDoseError = false - numberOfDosage = it - } else { - isMaxDoseError = true - } - }, - trailingIcon = { - if (isMaxDoseError) { - Icon( - imageVector = Icons.Filled.Info, - contentDescription = "Error", - tint = MaterialTheme.colorScheme.error - ) - } - }, - placeholder = { Text(text = "e.g. 1") }, - isError = isMaxDoseError, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) - ) } - RecurrenceDropdownMenu { recurrence = it } } + ) { innerPadding -> + Column( + modifier = Modifier + .padding(innerPadding) + .verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { - if (isMaxDoseError) { Text( - text = "You cannot have more than 99 dosage per day.", - color = MaterialTheme.colorScheme.error, - style = MaterialTheme.typography.bodySmall, + text = stringResource(id = R.string.medication_name), + style = MaterialTheme.typography.bodyLarge + ) + TextField( + modifier = Modifier.fillMaxWidth(), + value = medicationName, + onValueChange = { medicationName = it }, + placeholder = { Text(text = "e.g. Risperdal, 4mg") }, ) - } - - Spacer(modifier = Modifier.padding(4.dp)) - EndDateTextField { endDate = it } - - Spacer(modifier = Modifier.padding(4.dp)) - Text( - text = stringResource(id = R.string.times_of_day), - style = MaterialTheme.typography.bodyLarge - ) - var selectionCount by rememberSaveable { mutableStateOf(0) } - val scope = rememberCoroutineScope() - val context = LocalContext.current + Spacer(modifier = Modifier.padding(4.dp)) - Row( - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - FilterChip( - modifier = Modifier - .fillMaxWidth() - .weight(1f), - selected = isMorningSelected, - onClick = { - handleSelection( - isSelected = isMorningSelected, - selectionCount = selectionCount, - canSelectMoreTimesOfDay = canSelectMoreTimesOfDay( - selectionCount, - numberOfDosage.toIntOrNull() ?: 0 - ), - onStateChange = { count, selected -> - isMorningSelected = selected - selectionCount = count - }, - onShowMaxSelectionError = { - showMaxSelectionSnackbar(scope, numberOfDosage, context) - } - ) - }, - label = { Text(text = TimesOfDay.Morning.name) }, - leadingIcon = { - Icon( - imageVector = Icons.Default.Done, - contentDescription = "Selected" - ) - } - ) - FilterChip( - modifier = Modifier - .fillMaxWidth() - .weight(1f), - selected = isAfternoonSelected, - onClick = { - handleSelection( - isSelected = isAfternoonSelected, - selectionCount = selectionCount, - canSelectMoreTimesOfDay = canSelectMoreTimesOfDay( - selectionCount, - numberOfDosage.toIntOrNull() ?: 0 - ), - onStateChange = { count, selected -> - isAfternoonSelected = selected - selectionCount = count - }, - onShowMaxSelectionError = { - showMaxSelectionSnackbar(scope, numberOfDosage, context) - } - ) - }, - label = { Text(text = TimesOfDay.Afternoon.name) }, - leadingIcon = { - Icon( - imageVector = Icons.Default.Done, - contentDescription = "Selected" + var isMaxDoseError by rememberSaveable { mutableStateOf(false) } + Row( + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + val maxDose = 3 + + Column( + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text( + text = stringResource(id = R.string.dose_per_day), + style = MaterialTheme.typography.bodyLarge ) - } - ) - } - Row( - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - FilterChip( - modifier = Modifier - .fillMaxWidth() - .weight(1f), - selected = isEveningSelected, - onClick = { - handleSelection( - isSelected = isEveningSelected, - selectionCount = selectionCount, - canSelectMoreTimesOfDay = canSelectMoreTimesOfDay( - selectionCount, - numberOfDosage.toIntOrNull() ?: 0 - ), - onStateChange = { count, selected -> - isEveningSelected = selected - selectionCount = count + TextField( + modifier = Modifier.width(128.dp), + value = numberOfDosage, + onValueChange = { + if (it.length < maxDose) { + isMaxDoseError = false + numberOfDosage = it + } else { + isMaxDoseError = true + } }, - onShowMaxSelectionError = { - showMaxSelectionSnackbar(scope, numberOfDosage, context) - } - ) - }, - label = { Text(text = TimesOfDay.Evening.name) }, - leadingIcon = { - Icon( - imageVector = Icons.Default.Done, - contentDescription = "Selected" - ) - } - ) - FilterChip( - modifier = Modifier - .fillMaxWidth() - .weight(1f), - selected = isNightSelected, - onClick = { - handleSelection( - isSelected = isNightSelected, - selectionCount = selectionCount, - canSelectMoreTimesOfDay = canSelectMoreTimesOfDay( - selectionCount, - numberOfDosage.toIntOrNull() ?: 0 - ), - onStateChange = { count, selected -> - isNightSelected = selected - selectionCount = count + trailingIcon = { + if (isMaxDoseError) { + Icon( + imageVector = Icons.Filled.Info, + contentDescription = "Error", + tint = MaterialTheme.colorScheme.error + ) + } }, - onShowMaxSelectionError = { - showMaxSelectionSnackbar(scope, numberOfDosage, context) - } - ) - }, - label = { Text(text = TimesOfDay.Night.name) }, - leadingIcon = { - Icon( - imageVector = Icons.Default.Done, - contentDescription = "Selected" + placeholder = { Text(text = "e.g. 1") }, + isError = isMaxDoseError, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) ) } - ) - } + RecurrenceDropdownMenu { recurrence = it } + } - Spacer(modifier = Modifier.padding(8.dp)) - Button( - modifier = Modifier - .fillMaxWidth() - .height(56.dp) - .align(Alignment.CenterHorizontally), - onClick = { - validateMedication( - name = medicationName, - dosage = numberOfDosage.toIntOrNull() ?: 0, - recurrence = recurrence, - endDate = endDate, - morningSelection = isMorningSelected, - afternoonSelection = isAfternoonSelected, - eveningSelection = isEveningSelected, - nightSelection = isNightSelected, - onInvalidate = { - val invalidatedValue = context.getString(it) - Toast.makeText( - context, - context.getString(R.string.value_is_empty, invalidatedValue), - Toast.LENGTH_LONG - ).show() - - val event = String.format(AnalyticsEvents.ADD_MEDICATION_MEDICATION_VALUE_INVALIDATED, invalidatedValue) - analyticsHelper.logEvent(event) - }, - onValidate = { - navigateToMedicationConfirm(it) - analyticsHelper.logEvent(AnalyticsEvents.ADD_MEDICATION_NAVIGATING_TO_MEDICATION_CONFIRM) - }, - viewModel = viewModel + if (isMaxDoseError) { + Text( + text = "You cannot have more than 99 dosage per day.", + color = MaterialTheme.colorScheme.error, + style = MaterialTheme.typography.bodySmall, ) - }, - shape = MaterialTheme.shapes.extraLarge - ) { + } + + Spacer(modifier = Modifier.padding(4.dp)) + EndDateTextField { endDate = it } + + Spacer(modifier = Modifier.padding(4.dp)) Text( - text = stringResource(id = R.string.next), + text = stringResource(id = R.string.times_of_day), style = MaterialTheme.typography.bodyLarge ) + + var selectionCount by rememberSaveable { mutableStateOf(0) } + val scope = rememberCoroutineScope() + + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + FilterChip( + modifier = Modifier + .fillMaxWidth() + .weight(1f), + selected = isMorningSelected, + onClick = { + handleSelection( + isSelected = isMorningSelected, + selectionCount = selectionCount, + canSelectMoreTimesOfDay = canSelectMoreTimesOfDay( + selectionCount, + numberOfDosage.toIntOrNull() ?: 0 + ), + onStateChange = { count, selected -> + isMorningSelected = selected + selectionCount = count + }, + onShowMaxSelectionError = { + showMaxSelectionSnackbar(scope, numberOfDosage, context) + } + ) + }, + label = { Text(text = TimesOfDay.Morning.name) }, + leadingIcon = { + Icon( + imageVector = Icons.Default.Done, + contentDescription = "Selected" + ) + } + ) + FilterChip( + modifier = Modifier + .fillMaxWidth() + .weight(1f), + selected = isAfternoonSelected, + onClick = { + handleSelection( + isSelected = isAfternoonSelected, + selectionCount = selectionCount, + canSelectMoreTimesOfDay = canSelectMoreTimesOfDay( + selectionCount, + numberOfDosage.toIntOrNull() ?: 0 + ), + onStateChange = { count, selected -> + isAfternoonSelected = selected + selectionCount = count + }, + onShowMaxSelectionError = { + showMaxSelectionSnackbar(scope, numberOfDosage, context) + } + ) + }, + label = { Text(text = TimesOfDay.Afternoon.name) }, + leadingIcon = { + Icon( + imageVector = Icons.Default.Done, + contentDescription = "Selected" + ) + } + ) + } + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + FilterChip( + modifier = Modifier + .fillMaxWidth() + .weight(1f), + selected = isEveningSelected, + onClick = { + handleSelection( + isSelected = isEveningSelected, + selectionCount = selectionCount, + canSelectMoreTimesOfDay = canSelectMoreTimesOfDay( + selectionCount, + numberOfDosage.toIntOrNull() ?: 0 + ), + onStateChange = { count, selected -> + isEveningSelected = selected + selectionCount = count + }, + onShowMaxSelectionError = { + showMaxSelectionSnackbar(scope, numberOfDosage, context) + } + ) + }, + label = { Text(text = TimesOfDay.Evening.name) }, + leadingIcon = { + Icon( + imageVector = Icons.Default.Done, + contentDescription = "Selected" + ) + } + ) + FilterChip( + modifier = Modifier + .fillMaxWidth() + .weight(1f), + selected = isNightSelected, + onClick = { + handleSelection( + isSelected = isNightSelected, + selectionCount = selectionCount, + canSelectMoreTimesOfDay = canSelectMoreTimesOfDay( + selectionCount, + numberOfDosage.toIntOrNull() ?: 0 + ), + onStateChange = { count, selected -> + isNightSelected = selected + selectionCount = count + }, + onShowMaxSelectionError = { + showMaxSelectionSnackbar(scope, numberOfDosage, context) + } + ) + }, + label = { Text(text = TimesOfDay.Night.name) }, + leadingIcon = { + Icon( + imageVector = Icons.Default.Done, + contentDescription = "Selected" + ) + } + ) + } + } } } @@ -415,7 +424,8 @@ private fun validateMedication( if (eveningSelection) timesOfDay.add(TimesOfDay.Evening) if (nightSelection) timesOfDay.add(TimesOfDay.Night) - val medications = viewModel.createMedications(name, dosage, recurrence, Date(endDate), timesOfDay) + val medications = + viewModel.createMedications(name, dosage, recurrence, Date(endDate), timesOfDay) onValidate(medications) } From d857119b9a749be28f8c817123ef06f24be7fde7 Mon Sep 17 00:00:00 2001 From: Karanveer Singh Date: Mon, 16 Oct 2023 15:57:51 +0530 Subject: [PATCH 2/4] add-medication-screen-ui-fix --- .../doseapp/feature/addmedication/AddMedicationRoute.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt b/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt index ee8f894..20cc803 100644 --- a/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt +++ b/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt @@ -36,6 +36,8 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -106,7 +108,7 @@ fun AddMedicationScreen( topBar = { TopAppBar( modifier = Modifier - .padding(top = 8.dp, bottom = 16.dp), + .padding(vertical = 8.dp), navigationIcon = { FloatingActionButton( onClick = { @@ -123,7 +125,8 @@ fun AddMedicationScreen( fontWeight = FontWeight.Bold, style = MaterialTheme.typography.displaySmall ) - }) + } + ) }, bottomBar = { Button( From a333222564cb15e7e6fec95f6fe35d524b748edb Mon Sep 17 00:00:00 2001 From: Waseef Akhtar Date: Wed, 25 Oct 2023 00:42:17 +0200 Subject: [PATCH 3/4] Fix padding, ktlint --- .../feature/addmedication/AddMedicationRoute.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt b/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt index 2af01a8..263832b 100644 --- a/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt +++ b/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt @@ -34,19 +34,15 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableLongStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester @@ -115,7 +111,7 @@ fun AddMedicationScreen( topBar = { TopAppBar( modifier = Modifier - .padding(vertical = 8.dp), + .padding(vertical = 16.dp), navigationIcon = { FloatingActionButton( onClick = { @@ -128,6 +124,7 @@ fun AddMedicationScreen( } }, title = { Text( + modifier = Modifier.padding(16.dp), text = stringResource(id = R.string.add_medication), fontWeight = FontWeight.Bold, style = MaterialTheme.typography.displaySmall @@ -139,7 +136,7 @@ fun AddMedicationScreen( Button( modifier = Modifier .fillMaxWidth() - .padding(vertical = 8.dp) + .padding(vertical = 16.dp) .height(56.dp), onClick = { validateMedication( @@ -392,7 +389,6 @@ fun AddMedicationScreen( } ) } - } } } From b805a0fce51d6e4c752203838fc7d3782c3bddcf Mon Sep 17 00:00:00 2001 From: Waseef Akhtar Date: Wed, 25 Oct 2023 00:59:11 +0200 Subject: [PATCH 4/4] Fix ktlint --- .../doseapp/feature/addmedication/AddMedicationRoute.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt b/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt index 263832b..aa1374e 100644 --- a/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt +++ b/app/src/main/java/com/waseefakhtar/doseapp/feature/addmedication/AddMedicationRoute.kt @@ -122,7 +122,8 @@ fun AddMedicationScreen( ) { Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "Back") } - }, title = { + }, + title = { Text( modifier = Modifier.padding(16.dp), text = stringResource(id = R.string.add_medication),