Skip to content

Commit cc1cfd7

Browse files
ldjcmudsn5ft
authored andcommitted
Separate date format string from date hint string in MaterialDatePicker for better hints.
Resolves #695 PiperOrigin-RevId: 279095896 (cherry picked from commit c097d3d)
1 parent 1f338fe commit cc1cfd7

File tree

5 files changed

+52
-21
lines changed

5 files changed

+52
-21
lines changed

lib/java/com/google/android/material/datepicker/DateFormatTextWatcher.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,21 @@
2929

3030
abstract class DateFormatTextWatcher implements TextWatcher {
3131

32-
private final String pattern;
32+
private final String formatHint;
3333
private final DateFormat dateFormat;
3434
@NonNull private final TextInputLayout textInputLayout;
3535
private final CalendarConstraints constraints;
36-
private final String invalidFormat;
3736
private final String outOfRange;
3837

3938
DateFormatTextWatcher(
40-
String pattern,
39+
String formatHint,
4140
DateFormat dateFormat,
4241
@NonNull TextInputLayout textInputLayout,
4342
CalendarConstraints constraints) {
44-
this.pattern = pattern;
43+
this.formatHint = formatHint;
4544
this.dateFormat = dateFormat;
4645
this.textInputLayout = textInputLayout;
4746
this.constraints = constraints;
48-
this.invalidFormat =
49-
textInputLayout.getContext().getString(R.string.mtrl_picker_invalid_format);
5047
this.outOfRange = textInputLayout.getContext().getString(R.string.mtrl_picker_out_of_range);
5148
}
5249

@@ -79,7 +76,17 @@ public void onTextChanged(@NonNull CharSequence s, int start, int before, int co
7976
onInvalidDate();
8077
}
8178
} catch (ParseException e) {
82-
textInputLayout.setError(String.format(invalidFormat, pattern));
79+
String invalidFormat =
80+
textInputLayout.getContext().getString(R.string.mtrl_picker_invalid_format);
81+
String useLine =
82+
String.format(
83+
textInputLayout.getContext().getString(R.string.mtrl_picker_invalid_format_use),
84+
formatHint);
85+
String exampleLine =
86+
String.format(
87+
textInputLayout.getContext().getString(R.string.mtrl_picker_invalid_format_example),
88+
dateFormat.format(new Date(UtcDates.getTodayCalendar().getTimeInMillis())));
89+
textInputLayout.setError(invalidFormat + "\n" + useLine + "\n" + exampleLine);
8390
onInvalidDate();
8491
}
8592
}

lib/java/com/google/android/material/datepicker/RangeDateSelector.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,9 @@ public View onCreateTextInputView(
179179
EditText startEditText = startTextInput.getEditText();
180180
EditText endEditText = endTextInput.getEditText();
181181

182-
String pattern = root.getResources().getString(R.string.mtrl_picker_text_input_date_format);
183182
invalidRangeStartError = root.getResources().getString(R.string.mtrl_picker_invalid_range);
184183

185-
SimpleDateFormat format = UtcDates.getSimpleFormat(pattern);
186-
format.setLenient(false);
184+
SimpleDateFormat format = UtcDates.getTextInputFormat();
187185

188186
if (selectedStartItem != null) {
189187
startEditText.setText(format.format(selectedStartItem));
@@ -194,8 +192,10 @@ public View onCreateTextInputView(
194192
proposedTextEnd = selectedEndItem;
195193
}
196194

195+
String formatHint = UtcDates.getTextInputHint(root.getResources(), format);
196+
197197
startEditText.addTextChangedListener(
198-
new DateFormatTextWatcher(pattern, format, startTextInput, constraints) {
198+
new DateFormatTextWatcher(formatHint, format, startTextInput, constraints) {
199199

200200
@Override
201201
void onValidDate(@Nullable Long day) {
@@ -211,7 +211,7 @@ void onInvalidDate() {
211211
});
212212

213213
endEditText.addTextChangedListener(
214-
new DateFormatTextWatcher(pattern, format, endTextInput, constraints) {
214+
new DateFormatTextWatcher(formatHint, format, endTextInput, constraints) {
215215
void onValidDate(@Nullable Long day) {
216216
proposedTextEnd = day;
217217
updateIfValidTextProposal(startTextInput, endTextInput, listener);

lib/java/com/google/android/material/datepicker/SingleDateSelector.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,15 @@ public View onCreateTextInputView(
100100

101101
TextInputLayout dateTextInput = root.findViewById(R.id.mtrl_picker_text_input_date);
102102
EditText dateEditText = dateTextInput.getEditText();
103-
104-
String pattern = root.getResources().getString(R.string.mtrl_picker_text_input_date_format);
105-
SimpleDateFormat format = UtcDates.getSimpleFormat(pattern);
106-
format.setLenient(false);
103+
SimpleDateFormat format = UtcDates.getTextInputFormat();
104+
String formatHint = UtcDates.getTextInputHint(root.getResources(), format);
107105

108106
if (selectedItem != null) {
109107
dateEditText.setText(format.format(selectedItem));
110108
}
111109

112110
dateEditText.addTextChangedListener(
113-
new DateFormatTextWatcher(pattern, format, dateTextInput, constraints) {
111+
new DateFormatTextWatcher(formatHint, format, dateTextInput, constraints) {
114112

115113
@Override
116114
void onValidDate(@Nullable Long day) {

lib/java/com/google/android/material/datepicker/UtcDates.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
*/
1616
package com.google.android.material.datepicker;
1717

18+
import com.google.android.material.R;
19+
1820
import android.annotation.TargetApi;
21+
import android.content.res.Resources;
1922
import android.os.Build.VERSION_CODES;
2023
import androidx.annotation.NonNull;
2124
import java.text.DateFormat;
@@ -90,6 +93,26 @@ private static DateFormat getFormat(int style, Locale locale) {
9093
return format;
9194
}
9295

96+
static SimpleDateFormat getTextInputFormat() {
97+
String pattern =
98+
((SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()))
99+
.toLocalizedPattern()
100+
.replaceAll("\\s+", "");
101+
SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.getDefault());
102+
format.setTimeZone(UtcDates.getTimeZone());
103+
format.setLenient(false);
104+
return format;
105+
}
106+
107+
static String getTextInputHint(Resources res, SimpleDateFormat format) {
108+
String formatHint = format.toLocalizedPattern();
109+
String yearChar = res.getString(R.string.mtrl_picker_text_input_year_abbr);
110+
String monthChar = res.getString(R.string.mtrl_picker_text_input_month_abbr);
111+
String dayChar = res.getString(R.string.mtrl_picker_text_input_day_abbr);
112+
113+
return formatHint.replaceAll("d", dayChar).replaceAll("M", monthChar).replaceAll("y", yearChar);
114+
}
115+
93116
static SimpleDateFormat getSimpleFormat(String pattern) {
94117
return getSimpleFormat(pattern, Locale.getDefault());
95118
}

lib/java/com/google/android/material/datepicker/res/values/strings.xml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,16 @@
2929
<string name="mtrl_picker_text_input_date_range_start_hint" description="Label for the start date in a range selected by the user [CHAR_LIMIT=60]">Start date</string>
3030
<string name="mtrl_picker_text_input_date_range_end_hint" description="Label for the end date in a range selected by the user [CHAR_LIMIT=60]">End date</string>
3131
<!-- TODO(b/134174653): internationalize date format strings -->
32-
<string name="mtrl_picker_date_format" description="The format for how a date will be shown to the user, with the year included [CHAR_LIMIT=16]">MMM dd, yyyy</string>
33-
<string name="mtrl_picker_date_format_without_year" description="The format for how a date will be shown to the user, without the year included [CHAR_LIMIT=16]">MMM dd</string>
34-
<string name="mtrl_picker_text_input_date_format" description="The format for how the user should enter a date via text input [CHAR_LIMIT=16]">MM/dd/yyyy</string>
32+
<string name="mtrl_picker_text_input_year_abbr" description="A 1 character abbreviation for year. It will be part of a string such as dd/mm/yyyy or mm/dd/yyyy or y.mm.dd. [CHAR_LIMIT=1]">y</string>
33+
<string name="mtrl_picker_text_input_month_abbr" description="A 1 character abbreviation for month. It will be part of a string such as dd/mm/yyyy or mm/dd/yyyy or y.mm.dd. [CHAR_LIMIT=1]">m</string>
34+
<string name="mtrl_picker_text_input_day_abbr" description="A 1 character abbreviation for day. It will be part of a string such as dd/mm/yyyy or mm/dd/yyyy or y.mm.dd. [CHAR_LIMIT=1]">d</string>
3535
<string name="mtrl_picker_save" description="Confirms the selection [CHAR_LIMIT=12]">Save</string>
3636
<string name="mtrl_picker_invalid_range" description="Notifies the user that the two entered dates do not represent a valid range of dates [CHAR_LIMIT=36]">Invalid range.</string>
3737
<string name="mtrl_picker_out_of_range" description="Notifies the user that the entered date is outside the allowed range [CHAR_LIMIT=36]">Out of range: %1$s</string>
38-
<string name="mtrl_picker_invalid_format" description="Indicates that the user entered date cannot be parsed because its format is wrong. The user should instead use the format after the colon. Includes a line break [CHAR_LIMIT=54]">Invalid format.\nUse: %1$s</string>
38+
39+
<string name="mtrl_picker_invalid_format" description="Indicates that the user entered date cannot be parsed because its format is wrong. [CHAR_LIMIT=36]">Invalid format.</string>
40+
<string name="mtrl_picker_invalid_format_use" description="Tells a user what format is expected for their date entry. [CHAR_LIMIT=18]">Use: %1$s</string>
41+
<string name="mtrl_picker_invalid_format_example" description="Tells a user what an example valid entry looks like. [CHAR_LIMIT=18]">Example: %1$s</string>
3942

4043
<string name="mtrl_picker_toggle_to_calendar_input_mode" description="a11y string to indicate this button changes the input mode to a calendar [CHAR_LIMIT=NONE]">Switch to calendar input mode</string>
4144
<string name="mtrl_picker_toggle_to_text_input_mode" description="a11y string to indicate this button changes the input mode to a text field [CHAR_LIMIT=NONE]">Switch to text input mode</string>

0 commit comments

Comments
 (0)