Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup and moved Date and Time pickers to material #1312

Merged
merged 10 commits into from
Apr 29, 2022
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.android.fhir.datacapture.utilities

import android.content.Context
import android.text.format.DateFormat
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.Date

internal val LocalDateTime.localizedDateString: String
get() = toLocalDate().localizedString

internal fun LocalDateTime.toLocalizedTimeString(context: Context): String {
val date = Date.from(atZone(ZoneId.systemDefault()).toInstant())
return DateFormat.getTimeFormat(context).format(date)
Comment on lines +34 to +35
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should just call the function in MoreLocalTimes.kt?

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ import java.util.Locale
internal val LocalDate.localizedString: String
get() {
val date = Date.from(atStartOfDay(ZoneId.systemDefault())?.toInstant())
return if (isAndroidIcuSupported()) DateFormat.getDateInstance(DateFormat.DEFAULT).format(date)
else SimpleDateFormat.getDateInstance(DateFormat.DEFAULT, Locale.getDefault()).format(date)
return if (isAndroidIcuSupported()) {
DateFormat.getDateInstance(DateFormat.DEFAULT).format(date)
} else {
SimpleDateFormat.getDateInstance(java.text.DateFormat.DEFAULT, Locale.getDefault())
.format(date)
}
}

// Android ICU is supported API level 24 onwards.
private fun isAndroidIcuSupported() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
internal fun isAndroidIcuSupported() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.android.fhir.datacapture.utilities

import android.content.Context
import android.text.format.DateFormat
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.ZoneId
import java.util.Date

// ICU on Android does not observe the user's 24h/12h time format setting (obtained from
// DateFormat.is24HourFormat()). In order to observe the setting, we are using DateFormat as
// suggested in the docs. See
// https://developer.android.com/guide/topics/resources/internationalization#24h-setting for
// details.
internal fun LocalTime.toLocalizedString(context: Context): String {
val today = LocalDateTime.of(LocalDate.now(), this)
val date = Date.from(today.atZone(ZoneId.systemDefault()).toInstant())
return DateFormat.getTimeFormat(context).format(date)
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import com.google.android.material.textfield.TextInputLayout
import java.time.Instant
import java.time.LocalDate
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import org.hl7.fhir.r4.model.DateType
import org.hl7.fhir.r4.model.QuestionnaireResponse

Expand All @@ -57,49 +56,24 @@ internal object QuestionnaireItemDatePickerViewHolderFactory :
// necessary to access the base context twice to retrieve the application object
// from the view's context.
val context = itemView.context.tryUnwrapContext()!!
context.supportFragmentManager.setFragmentResultListener(
aditya-07 marked this conversation as resolved.
Show resolved Hide resolved
DatePickerFragment.RESULT_REQUEST_KEY,
context
) { _, result ->
// java.time APIs can be used with desugaring
val year = result.getInt(DatePickerFragment.RESULT_BUNDLE_KEY_YEAR)
val month = result.getInt(DatePickerFragment.RESULT_BUNDLE_KEY_MONTH)
val dayOfMonth = result.getInt(DatePickerFragment.RESULT_BUNDLE_KEY_DAY_OF_MONTH)
// Month values are 1-12 in java.time but 0-11 in
// DatePickerDialog.
val localDate = LocalDate.of(year, month + 1, dayOfMonth)
textInputEditText.setText(localDate?.localizedString)

val date = DateType(year, month, dayOfMonth)
questionnaireItemViewItem.singleAnswerOrNull =
QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent().apply {
value = date
}
onAnswerChanged(textInputEditText.context)
}
val selectedDate = questionnaireItemViewItem.singleAnswerOrNull?.valueDateType?.localDate
val datePicker =
MaterialDatePicker.Builder.datePicker()
.setTitleText(context.getString(R.string.select_date))
.setSelection(
selectedDate?.atStartOfDay(ZONE_ID_UTC)?.toInstant()?.toEpochMilli()
?: MaterialDatePicker.todayInUtcMilliseconds()
)
.build()
datePicker.addOnPositiveButtonClickListener { epochMilli ->
textInputEditText.setText(
Instant.ofEpochMilli(epochMilli).atZone(ZONE_ID_UTC).toLocalDate().localizedString
)
questionnaireItemViewItem.singleAnswerOrNull =
QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent().apply {
val localDate = Instant.ofEpochMilli(epochMilli).atZone(ZONE_ID_UTC).toLocalDate()
value = DateType(localDate.year, localDate.monthValue - 1, localDate.dayOfMonth)
createMaterialDatePicker()
.apply {
addOnPositiveButtonClickListener { epochMilli ->
textInputEditText.setText(
Instant.ofEpochMilli(epochMilli).atZone(ZONE_ID_UTC).toLocalDate().localizedString
)
questionnaireItemViewItem.singleAnswerOrNull =
QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent().apply {
val localDate =
Instant.ofEpochMilli(epochMilli).atZone(ZONE_ID_UTC).toLocalDate()
value = DateType(localDate.year, localDate.monthValue - 1, localDate.dayOfMonth)
}
// Clear focus so that the user can refocus to open the dialog
textInputEditText.clearFocus()
onAnswerChanged(textInputEditText.context)
}
// Clear focus so that the user can refocus to open the dialog
textInputEditText.clearFocus()
onAnswerChanged(textInputEditText.context)
}
datePicker.show(context.supportFragmentManager, TAG)
}
.show(context.supportFragmentManager, TAG)
}
}

Expand All @@ -125,14 +99,25 @@ internal object QuestionnaireItemDatePickerViewHolderFactory :
textInputEditText.isEnabled = !isReadOnly
textInputLayout.isEnabled = !isReadOnly
}
}

@SuppressLint("NewApi") // java.time APIs can be used due to desugaring
val LOCAL_DATE_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE!!
private fun createMaterialDatePicker(): MaterialDatePicker<Long> {
val selectedDate =
questionnaireItemViewItem
.singleAnswerOrNull
?.valueDateType
?.localDate
?.atStartOfDay(ZONE_ID_UTC)
?.toInstant()
?.toEpochMilli()
?: MaterialDatePicker.todayInUtcMilliseconds()
return MaterialDatePicker.Builder.datePicker()
.setTitleText(R.string.select_date)
.setSelection(selectedDate)
.build()
}
}
}

const val NUMBER_OF_MICROSECONDS_PER_SECOND = 1000000
const val NUMBER_OF_MICROSECONDS_PER_MILLISECOND = 1000
internal const val TAG = "date-picker"
internal val ZONE_ID_UTC = ZoneId.of("UTC")

Expand Down
Loading