diff --git a/.gitignore b/.gitignore index c6cbe56..a80a5ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.iml .gradle +.idea /local.properties /.idea/workspace.xml /.idea/libraries diff --git a/demo/src/main/res/xml/preferences.xml b/demo/src/main/res/xml/preferences.xml index c06437a..cd40fbe 100644 --- a/demo/src/main/res/xml/preferences.xml +++ b/demo/src/main/res/xml/preferences.xml @@ -33,6 +33,16 @@ app:defaultHours="10" app:defaultMins="0" app:timeAsSummary="true"/> + + -1 || defaultYear > -1 && defaultMonthOfYear > -1 && defaultDayOfMonth > -1) { + setDefaultValue(calculateValue(getDefaultDate())); + } + dateFormat = typedArray.getInt(R.styleable.DatePickerPreference_dateFormat, DATE_FORMAT_INHERIT); + if (dateFormat == DATE_FORMAT_CUSTOM) { + String customFormat = typedArray.getString(R.styleable.DatePickerPreference_dateFormatString); + if (customFormat == null || customFormat.isEmpty()) { + throw new IllegalArgumentException("dateFormatString required for custom formats"); + } + customFormatter = DateTimeFormat.forPattern(customFormat); + } + typedArray.recycle(); + } + + public DatePickerPreference(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public DatePickerPreference(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.datePickerPreferenceStyle); + } + + public DatePickerPreference(Context context) { + this(context, null); + } + + public static int calculateValue(LocalDate date) { + return Days.daysBetween(EPOCH, date).getDays(); + } + + private LocalDate getDate() { + return EPOCH.plusDays(value); + } + + public int getYear() { + return getDate().getYear(); + } + + public int getMonthOfYear() { + return getDate().getMonthOfYear(); + } + + public int getDayOfMonth() { + return getDate().getDayOfMonth(); + } + + public void setValue(LocalDate date) { + setValue(calculateValue(date)); + } + + public void setValue(int value) { + this.value = value; + if (dateAsSummary) { + switch (dateFormat) { + case DATE_FORMAT_MONTH_DAY_YEAR: + setSummary(MONTH_DAY_YEAR_FORAMT.print(getDate())); + break; + case DATE_FORMAT_DAY_MONTH_YEAR: + setSummary(DAY_MONTH_YEAR_FORAMT.print(getDate())); + break; + case DATE_FORMAT_CUSTOM: + setSummary(customFormatter.print(getDate())); + case DATE_FORMAT_INHERIT: + default: + Date date = getDate().toDateTimeAtStartOfDay().toDate(); + setSummary(DateFormat.getDateFormat(getContext()).format(date)); + break; + } + } + persistInt(value); + } + + private LocalDate getDefaultDate() { + if (defaultYear > -1 && defaultYearsAgo > -1) { + throw new IllegalArgumentException("Cannot specify both defaultYear and defaultYearsAgo"); + } + if (defaultYearsAgo > -1) { + return LocalDate.now().minusYears(defaultYearsAgo); + } else { + return new LocalDate(defaultYear, defaultMonthOfYear + 1, defaultDayOfMonth); + } + } + + @Override + protected Object onGetDefaultValue(TypedArray a, int index) { + return a.getInt(index, calculateValue(getDefaultDate())); + } + + @Override + protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { + setValue(restorePersistedValue ? getPersistedInt(value) : (Integer) defaultValue); + } + + @Override + protected Parcelable onSaveInstanceState() { + final Parcelable superState = super.onSaveInstanceState(); + if (isPersistent()) { + return superState; + } + final SavedState savedState = new SavedState(superState); + savedState.dateAsSummary = dateAsSummary; + savedState.dateFormat = dateFormat; + savedState.defaultDayOfMonth = defaultDayOfMonth; + savedState.defaultMonthOfYear = defaultMonthOfYear; + savedState.defaultYear = defaultYear; + savedState.defaultYearsAgo = defaultYearsAgo; + savedState.value = value; + return savedState; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state == null || !state.getClass().equals(SavedState.class)) { + super.onRestoreInstanceState(state); + return; + } + SavedState savedState = (SavedState) state; + super.onRestoreInstanceState(savedState.getSuperState()); + dateAsSummary = savedState.dateAsSummary; + dateFormat = savedState.dateFormat; + defaultDayOfMonth = savedState.defaultDayOfMonth; + defaultMonthOfYear = savedState.defaultMonthOfYear; + defaultYear = savedState.defaultYear; + defaultYearsAgo = savedState.defaultYearsAgo; + value = savedState.value; + } + + private static class SavedState extends BaseSavedState { + + private boolean dateAsSummary; + private int dateFormat; + private int defaultDayOfMonth; + private int defaultMonthOfYear; + private int defaultYear; + private int defaultYearsAgo; + private int value; + + @SuppressLint("ParcelClassLoader") + SavedState(Parcel source) { + super(source); + dateAsSummary = (boolean) source.readValue(null); + dateFormat = source.readInt(); + defaultDayOfMonth = source.readInt(); + defaultMonthOfYear = source.readInt(); + defaultYear = source.readInt(); + defaultYearsAgo = source.readInt(); + value = source.readInt(); + } + + SavedState(Parcelable superState) { + super(superState); + } + + @Override public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeValue(dateAsSummary); + dest.writeInt(dateFormat); + dest.writeInt(defaultDayOfMonth); + dest.writeInt(defaultMonthOfYear); + dest.writeInt(defaultYear); + dest.writeInt(defaultYearsAgo); + dest.writeInt(value); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override public SavedState createFromParcel(Parcel source) { + return new SavedState(source); + } + + @Override public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } +} diff --git a/library/src/main/java/android/support/v7/preference/DatePickerPreferenceDialogFragmentCompat.java b/library/src/main/java/android/support/v7/preference/DatePickerPreferenceDialogFragmentCompat.java new file mode 100644 index 0000000..06b2667 --- /dev/null +++ b/library/src/main/java/android/support/v7/preference/DatePickerPreferenceDialogFragmentCompat.java @@ -0,0 +1,46 @@ +package android.support.v7.preference; + +import android.app.DatePickerDialog; +import android.app.Dialog; +import android.app.TimePickerDialog; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.widget.DatePicker; + +import org.joda.time.LocalDate; + +/** + * Created by parkeroth on 1/14/18. + */ + +public class DatePickerPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat implements DatePickerDialog.OnDateSetListener { + + public static DatePickerPreferenceDialogFragmentCompat newInstance(String key) { + DatePickerPreferenceDialogFragmentCompat fragment = new DatePickerPreferenceDialogFragmentCompat(); + Bundle args = new Bundle(1); + args.putString(ARG_KEY, key); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onDateSet(DatePicker datePicker, int year, int monthOfYear, int dayOfMonth) { + DatePickerPreference preference = (DatePickerPreference) getPreference(); + LocalDate date = new LocalDate(year, monthOfYear + 1, dayOfMonth); + if (preference.callChangeListener(DatePickerPreference.calculateValue(date))) { + preference.setValue(date); + } + } + + @Override + public void onDialogClosed(boolean positiveResult) { + // Not needed, as handled by onTimeSet + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + DatePickerPreference preference = (DatePickerPreference) getPreference(); + return new DatePickerDialog(getActivity(), this, preference.getYear(), preference.getMonthOfYear() - 1, preference.getDayOfMonth()); + } +} diff --git a/library/src/main/java/me/philio/preferencecompatextended/PreferenceFragmentCompat.java b/library/src/main/java/me/philio/preferencecompatextended/PreferenceFragmentCompat.java index 3742d16..21233ff 100644 --- a/library/src/main/java/me/philio/preferencecompatextended/PreferenceFragmentCompat.java +++ b/library/src/main/java/me/philio/preferencecompatextended/PreferenceFragmentCompat.java @@ -1,6 +1,8 @@ package me.philio.preferencecompatextended; import android.support.v4.app.DialogFragment; +import android.support.v7.preference.DatePickerPreference; +import android.support.v7.preference.DatePickerPreferenceDialogFragmentCompat; import android.support.v7.preference.NumberPickerPreference; import android.support.v7.preference.NumberPickerPreferenceDialogFragmentCompat; import android.support.v7.preference.Preference; @@ -28,6 +30,14 @@ public abstract class PreferenceFragmentCompat extends android.support.v7.prefer final DialogFragment fragment = TimePickerPreferenceDialogFragmentCompat.newInstance(preference.getKey()); fragment.setTargetFragment(this, 0); fragment.show(getFragmentManager(), DIALOG_FRAGMENT_TAG); + } else if (preference instanceof DatePickerPreference) { + // Inherit the same behaviour as parent + if (getFragmentManager().findFragmentByTag(DIALOG_FRAGMENT_TAG) != null) { + return; + } + final DialogFragment fragment = DatePickerPreferenceDialogFragmentCompat.newInstance(preference.getKey()); + fragment.setTargetFragment(this, 0); + fragment.show(getFragmentManager(), DIALOG_FRAGMENT_TAG); } else { super.onDisplayPreferenceDialog(preference); } diff --git a/library/src/main/res/values-v14/styles.xml b/library/src/main/res/values-v14/styles.xml index e40931d..675b7cd 100644 --- a/library/src/main/res/values-v14/styles.xml +++ b/library/src/main/res/values-v14/styles.xml @@ -4,6 +4,7 @@ + + \ No newline at end of file diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml index 4fced6a..268d863 100644 --- a/library/src/main/res/values/attrs.xml +++ b/library/src/main/res/values/attrs.xml @@ -5,6 +5,8 @@ + + @@ -38,4 +40,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/library/src/main/res/values/styles.xml b/library/src/main/res/values/styles.xml index 6338a38..add6cb6 100644 --- a/library/src/main/res/values/styles.xml +++ b/library/src/main/res/values/styles.xml @@ -12,4 +12,6 @@