Skip to content

Commit

Permalink
feat: [ANDROAPP-5794] Implement new InputDate Date and TimePicker fun…
Browse files Browse the repository at this point in the history
…ctionalities
  • Loading branch information
xavimolloy committed Feb 15, 2024
1 parent 5fc8fb9 commit c874fd2
Show file tree
Hide file tree
Showing 18 changed files with 156 additions and 156 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ class EventInitialTest {
EventInputDateUiModel(
eventDate = date,
detailsEnabled = details.enabled,
onDateClick = { viewModel.onDateClick() },
onDateClick = viewModel.showPeriodDialog() ,
onDateSet = { dateValues ->
viewModel.onDateSet(dateValues.year, dateValues.month, dateValues.day)
},
Expand Down Expand Up @@ -257,7 +257,7 @@ class EventInitialTest {
EventInputDateUiModel(
eventDate = date,
detailsEnabled = details.enabled,
onDateClick = { viewModel.onDateClick() },
onDateClick = viewModel.showPeriodDialog(),
onDateSet = { dateValues ->
viewModel.onDateSet(dateValues.year, dateValues.month, dateValues.day)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.DatePicker
import androidx.compose.foundation.layout.Column
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.databinding.DataBindingUtil
import org.dhis2.App
import org.dhis2.R
import org.dhis2.commons.data.EventCreationType
import org.dhis2.commons.dialogs.calendarpicker.CalendarPicker
import org.dhis2.commons.dialogs.calendarpicker.OnDatePickerListener
import org.dhis2.databinding.ActivityEventScheduledBinding
import org.dhis2.usescases.eventsWithoutRegistration.eventCapture.EventCaptureActivity
import org.dhis2.usescases.eventsWithoutRegistration.eventDetails.models.EventDate
Expand All @@ -28,8 +25,6 @@ import org.hisp.dhis.android.core.event.EventStatus
import org.hisp.dhis.android.core.period.PeriodType
import org.hisp.dhis.android.core.program.Program
import org.hisp.dhis.android.core.program.ProgramStage
import java.util.Calendar
import java.util.Date
import javax.inject.Inject

const val EXTRA_EVENT_UID = "EVENT_UID"
Expand Down Expand Up @@ -109,14 +104,17 @@ class ScheduledEventActivity : ActivityGlobalAbstract(), ScheduledEventContract.
dateValue = "",
)

val eventDateAction = if (programStage.periodType() == null) null else showEventDatePeriodDialog(programStage.periodType())

ProvideInputDate(
EventInputDateUiModel(
eventDate = eventDate,
allowsManualInput = false,
detailsEnabled = true,
onDateClick = { setEvenDateListener(programStage.periodType()) },
onDateClick = eventDateAction,
onDateSet = {},
onClear = {},
selectableDates = presenter.getSelectableDates(program, false),
),

)
Expand All @@ -125,13 +123,18 @@ class ScheduledEventActivity : ActivityGlobalAbstract(), ScheduledEventContract.
label = programStage.dueDateLabel() ?: getString(R.string.due_date),
dateValue = DateUtils.uiDateFormat().format(event.dueDate() ?: ""),
)
val dueDateAction = if (programStage.periodType() == null) null else showDueDatePeriodDialog(programStage.periodType())

ProvideInputDate(
EventInputDateUiModel(
eventDate = dueDate,
detailsEnabled = true,
onDateClick = { setDueDateListener(programStage.periodType()) },
onDateSet = {},
onDateClick = dueDateAction,
onDateSet = { date ->
presenter.setEventDate(presenter.formatDateValues(date))
},
onClear = {},
selectableDates = presenter.getSelectableDates(program, true),
),
)
}
Expand All @@ -145,10 +148,8 @@ class ScheduledEventActivity : ActivityGlobalAbstract(), ScheduledEventContract.
binding.name = program.displayName()
}

private fun setEvenDateListener(periodType: PeriodType?) {
if (periodType == null) {
showCustomCalendar(false)
} else {
private fun showEventDatePeriodDialog(periodType: PeriodType?) {
if (periodType != null) {
var minDate =
DateUtils.getInstance().expDate(null, program.expiryDays()!!, periodType)
val lastPeriodDate =
Expand All @@ -174,10 +175,8 @@ class ScheduledEventActivity : ActivityGlobalAbstract(), ScheduledEventContract.
}
}

private fun setDueDateListener(periodType: PeriodType?) {
if (periodType == null) {
showCustomCalendar(true)
} else {
private fun showDueDatePeriodDialog(periodType: PeriodType?) {
if (periodType != null) {
var minDate =
DateUtils.getInstance().expDate(null, program.expiryDays()!!, periodType)
val lastPeriodDate =
Expand All @@ -203,51 +202,6 @@ class ScheduledEventActivity : ActivityGlobalAbstract(), ScheduledEventContract.
}
}

private fun showCustomCalendar(isDueDate: Boolean) {
val dialog = CalendarPicker(this)

if (isDueDate) {
dialog.setInitialDate(event.dueDate())
dialog.setScheduleInterval(stage.standardInterval() ?: 0)
}

if (program.expiryPeriodType() != null) {
val minDate = DateUtils.getInstance().expDate(
null,
program.expiryDays() ?: 0,
program.expiryPeriodType(),
)
dialog.setMinDate(minDate)
}

if (!isDueDate) {
dialog.setMaxDate(Date(System.currentTimeMillis() - 1000))
}
dialog.setListener(object : OnDatePickerListener {
override fun onNegativeClick() {
dialog.dismiss()
}

override fun onPositiveClick(datePicker: DatePicker) {
val date = Calendar.getInstance().apply {
set(Calendar.YEAR, datePicker.year)
set(Calendar.MONTH, datePicker.month)
set(Calendar.DAY_OF_MONTH, datePicker.dayOfMonth)
set(Calendar.HOUR, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.time
if (isDueDate) {
presenter.setDueDate(date)
} else {
presenter.setEventDate(date)
}
}
})
dialog.show()
}

override fun openInitialActivity() {
val bundle = EventInitialActivity.getBundle(
program.uid(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package org.dhis2.usescases.events

import org.dhis2.usescases.eventsWithoutRegistration.eventDetails.providers.InputDateValues
import org.dhis2.usescases.general.AbstractActivityContracts
import org.hisp.dhis.android.core.category.CategoryOption
import org.hisp.dhis.android.core.enrollment.Enrollment
import org.hisp.dhis.android.core.event.Event
import org.hisp.dhis.android.core.program.Program
import org.hisp.dhis.android.core.program.ProgramStage
import org.hisp.dhis.mobile.ui.designsystem.component.SelectableDates
import java.util.Date

class ScheduledEventContract {
Expand All @@ -22,11 +24,14 @@ class ScheduledEventContract {
fun init()
fun finish()
fun setEventDate(date: Date)
fun formatDateValues(date: InputDateValues): Date
fun setDueDate(date: Date)
fun getDateFormatConfiguration(): String?
fun skipEvent()
fun setCatOptionCombo(catComboUid: String, arrayList: ArrayList<CategoryOption>)
fun onBackClick()
fun getEventTei(): String
fun getEnrollment(): Enrollment?
fun getSelectableDates(program: Program, isDueDate: Boolean): SelectableDates?
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@ import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import org.dhis2.data.dhislogic.DhisEventUtils
import org.dhis2.usescases.eventsWithoutRegistration.eventDetails.providers.InputDateValues
import org.dhis2.utils.DateUtils
import org.hisp.dhis.android.core.D2
import org.hisp.dhis.android.core.arch.helpers.UidsHelper
import org.hisp.dhis.android.core.category.CategoryOption
import org.hisp.dhis.android.core.enrollment.Enrollment
import org.hisp.dhis.android.core.event.EventStatus
import org.hisp.dhis.android.core.program.Program
import org.hisp.dhis.mobile.ui.designsystem.component.SelectableDates
import timber.log.Timber
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale

class ScheduledEventPresenterImpl(
val view: ScheduledEventContract.View,
Expand Down Expand Up @@ -82,6 +89,32 @@ class ScheduledEventPresenterImpl(
}
}

override fun formatDateValues(date: InputDateValues): Date {
val calendar = Calendar.getInstance()
calendar[date.year, date.month - 1, date.day, 0, 0] = 0
calendar[Calendar.MILLISECOND] = 0
return calendar.time
}

override fun getDateFormatConfiguration(): String? {
return d2.systemInfoModule().systemInfo().blockingGet()?.dateFormat()
}

override fun getSelectableDates(program: Program, isDueDate: Boolean): SelectableDates? {
val minDate = if (program.expiryPeriodType() != null) {
DateUtils.getInstance().expDate(
null,
program.expiryDays() ?: 0,
program.expiryPeriodType(),
)
} else {
null
}
val minDateString = if (minDate == null) null else SimpleDateFormat("ddMMyyyy", Locale.US).format(minDate)
val maxDateString = if (isDueDate)"12112124" else SimpleDateFormat("ddMMyyyy", Locale.US).format(Date(System.currentTimeMillis() - 1000))
return SelectableDates(minDateString ?: "12111924", maxDateString)
}

override fun setDueDate(date: Date) {
d2.eventModule().events().uid(eventUid).setDueDate(date)
d2.eventModule().events().uid(eventUid).setStatus(EventStatus.SCHEDULE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ class EventDetailsRepository(
.blockingGet()
}

fun getDateFormatConfiguration(): String? {
return d2.systemInfoModule().systemInfo().blockingGet()?.dateFormat()
}

fun getObjectStyle(): ObjectStyle? {
val programStage = getProgramStage()
val program = getProgram()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package org.dhis2.usescases.eventsWithoutRegistration.eventDetails.models

import org.dhis2.usescases.eventsWithoutRegistration.eventDetails.providers.InputDateValues
import org.hisp.dhis.mobile.ui.designsystem.component.SelectableDates

data class EventInputDateUiModel(
val eventDate: EventDate,
val detailsEnabled: Boolean,
val onDateClick: () -> Unit,
val onDateClick: Unit?,
val allowsManualInput: Boolean = true,
val onDateSet: (InputDateValues) -> Unit,
val onClear: () -> Unit,
val required: Boolean = false,
val showField: Boolean = true,
val is24HourFormat: Boolean = true,
val selectableDates: SelectableDates? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,19 @@ import org.hisp.dhis.android.core.common.FeatureType
import org.hisp.dhis.android.core.common.Geometry
import org.hisp.dhis.android.core.common.ValueType
import org.hisp.dhis.mobile.ui.designsystem.component.Coordinates
import org.hisp.dhis.mobile.ui.designsystem.component.DateTimeActionIconType
import org.hisp.dhis.mobile.ui.designsystem.component.DateTimeActionType
import org.hisp.dhis.mobile.ui.designsystem.component.DropdownItem
import org.hisp.dhis.mobile.ui.designsystem.component.InputCoordinate
import org.hisp.dhis.mobile.ui.designsystem.component.InputDateTime
import org.hisp.dhis.mobile.ui.designsystem.component.InputDateTimeModel
import org.hisp.dhis.mobile.ui.designsystem.component.InputDropDown
import org.hisp.dhis.mobile.ui.designsystem.component.InputOrgUnit
import org.hisp.dhis.mobile.ui.designsystem.component.InputPolygon
import org.hisp.dhis.mobile.ui.designsystem.component.InputRadioButton
import org.hisp.dhis.mobile.ui.designsystem.component.InputShellState
import org.hisp.dhis.mobile.ui.designsystem.component.Orientation
import org.hisp.dhis.mobile.ui.designsystem.component.RadioButtonData
import org.hisp.dhis.mobile.ui.designsystem.component.SelectableDates
import org.hisp.dhis.mobile.ui.designsystem.component.internal.DateTransformation
import java.time.LocalDate
import java.time.format.DateTimeFormatter
Expand All @@ -54,7 +56,6 @@ fun ProvideInputDate(
if (uiModel.showField) {
Spacer(modifier = Modifier.height(16.dp))
val textSelection = TextRange(if (uiModel.eventDate.dateValue != null) uiModel.eventDate.dateValue.length else 0)

var value by remember(uiModel.eventDate.dateValue) {
if (uiModel.eventDate.dateValue != null) {
mutableStateOf(TextFieldValue(formatStoredDateToUI(uiModel.eventDate.dateValue) ?: "", textSelection))
Expand All @@ -68,25 +69,36 @@ fun ProvideInputDate(
}

InputDateTime(
title = uiModel.eventDate.label ?: "",
allowsManualInput = uiModel.allowsManualInput,
inputTextFieldValue = value,
actionIconType = DateTimeActionIconType.DATE,
onActionClicked = uiModel.onDateClick,
state = state,
visualTransformation = DateTransformation(),
onValueChanged = {
value = it
state = getInputShellStateBasedOnValue(it.text)
manageActionBasedOnValue(uiModel, it.text)
},
isRequired = uiModel.required,
InputDateTimeModel(
title = uiModel.eventDate.label ?: "",
allowsManualInput = uiModel.allowsManualInput,
inputTextFieldValue = value,
actionType = DateTimeActionType.DATE,
state = state,
visualTransformation = DateTransformation(),
onValueChanged = {
value = it ?: TextFieldValue()
state = getInputShellStateBasedOnValue(it?.text)
it?.let { it1 -> manageActionBasedOnValue(uiModel, it1.text) }
},
isRequired = uiModel.required,
onFocusChanged = { focused ->
if (!focused && !isValid(value.text)) {
state = InputShellState.ERROR
}
},
format = "ddMMyyyy",
is24hourFormat = uiModel.is24HourFormat,
selectableDates = uiModel.selectableDates ?: SelectableDates("01011924", "12312124"),
onDateSelected = { dateString ->
dateString?.let {
formatUIDateToStored(it)?.let { formatedDate ->
uiModel.onDateSet.invoke(formatedDate)
}
}
},
),
modifier = modifier.testTag(INPUT_EVENT_INITIAL_DATE),
onFocusChanged = { focused ->
if (!focused && !isValid(value.text)) {
state = InputShellState.ERROR
}
},
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,18 +236,20 @@ class EventDetailsFragment : FragmentGlobalAbstract() {
coordinates: EventCoordinates,
eventTemp: EventTemp,
) {
val eventDateAction = if (viewModel.getPeriodType() == null) null else viewModel.showPeriodDialog()
Column {
ProvideInputDate(
EventInputDateUiModel(
eventDate = date,
detailsEnabled = details.enabled,
onDateClick = { viewModel.onDateClick() },
onDateClick = eventDateAction,
onDateSet = { dateValues ->
viewModel.onDateSet(dateValues.year, dateValues.month - 1, dateValues.day)
},
onClear = { viewModel.onClearEventReportDate() },
required = true,
showField = date.active,

),
)
ProvideOrgUnit(
Expand Down
Loading

0 comments on commit c874fd2

Please sign in to comment.