package com.novachevskyi.datepicker;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.novachevskyi.datepicker.base.CalendarDatePickerController;
import com.novachevskyi.datepicker.base.adapters.MonthAdapter;
import com.novachevskyi.datepicker.base.animators.AccessibleDateAnimator;
import com.novachevskyi.datepicker.base.views.DayPickerView;
import com.novachevskyi.datepicker.base.views.SimpleDayPickerView;
import com.novachevskyi.datepicker.utils.Utils;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Locale;
public class CalendarDatePickerDialog extends DialogFragment implements
OnClickListener, CalendarDatePickerController {
private static final String KEY_SELECTED_YEAR = "year";
private static final String KEY_SELECTED_MONTH = "month";
private static final String KEY_SELECTED_DAY = "day";
private static final String KEY_LIST_POSITION = "list_position";
private static final String KEY_WEEK_START = "week_start";
private static final String KEY_YEAR_START = "year_start";
private static final String KEY_YEAR_END = "year_end";
private static final int DEFAULT_START_YEAR = 1900;
private static final int DEFAULT_END_YEAR = 2100;
private static final int ANIMATION_DURATION = 300;
private static final int ANIMATION_DELAY = 500;
private static final SimpleDateFormat DAY_FORMAT =
new SimpleDateFormat("dd", Locale.getDefault());
private final Calendar mCalendar = Calendar.getInstance();
private OnDateSetListener mCallBack;
private HashSet<OnDateChangedListener> mListeners = new HashSet<>();
private AccessibleDateAnimator mAnimator;
private TextView mDayOfWeekView;
private LinearLayout mMonthAndDayView;
private TextView mSelectedMonthTextView;
private TextView mSelectedDayTextView;
private DayPickerView mDayPickerView;
private int mWeekStart = mCalendar.getFirstDayOfWeek();
private int mMinYear = DEFAULT_START_YEAR;
private int mMaxYear = DEFAULT_END_YEAR;
private boolean mDelayAnimation = true;
private String mDayPickerDescription;
private String mSelectDay;
public interface OnDateSetListener {
void onDateSet(
CalendarDatePickerDialog dialog,
int year, int monthOfYear, int dayOfMonth);
}
public interface OnDateChangedListener {
void onDateChanged();
}
public CalendarDatePickerDialog() {
}
public static CalendarDatePickerDialog newInstance(
OnDateSetListener callBack, int year,
int monthOfYear,
int dayOfMonth) {
CalendarDatePickerDialog
ret = new CalendarDatePickerDialog();
ret.initialize(callBack, year, monthOfYear, dayOfMonth);
return ret;
}
public void initialize(OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) {
mCallBack = callBack;
mCalendar.set(Calendar.YEAR, year);
mCalendar.set(Calendar.MONTH, monthOfYear);
mCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Activity activity = getActivity();
activity.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
if (savedInstanceState != null) {
mCalendar.set(Calendar.YEAR, savedInstanceState.getInt(KEY_SELECTED_YEAR));
mCalendar.set(Calendar.MONTH, savedInstanceState.getInt(KEY_SELECTED_MONTH));
mCalendar.set(Calendar.DAY_OF_MONTH, savedInstanceState.getInt(KEY_SELECTED_DAY));
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(KEY_SELECTED_YEAR, mCalendar.get(Calendar.YEAR));
outState.putInt(KEY_SELECTED_MONTH, mCalendar.get(Calendar.MONTH));
outState.putInt(KEY_SELECTED_DAY, mCalendar.get(Calendar.DAY_OF_MONTH));
outState.putInt(KEY_WEEK_START, mWeekStart);
outState.putInt(KEY_YEAR_START, mMinYear);
outState.putInt(KEY_YEAR_END, mMaxYear);
int listPosition = mDayPickerView.getMostVisiblePosition();
outState.putInt(KEY_LIST_POSITION, listPosition);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
View view =
inflater.inflate(R.layout.calendar_date_picker_dialog,
null);
mDayOfWeekView =
(TextView) view.findViewById(R.id.date_picker_header);
mMonthAndDayView = (LinearLayout) view.findViewById(R.id.date_picker_month_and_day);
mMonthAndDayView.setOnClickListener(this);
mSelectedMonthTextView =
(TextView) view.findViewById(R.id.date_picker_month);
mSelectedDayTextView =
(TextView) view.findViewById(R.id.date_picker_day);
int listPosition = -1;
if (savedInstanceState != null) {
mWeekStart = savedInstanceState.getInt(KEY_WEEK_START);
mMinYear = savedInstanceState.getInt(KEY_YEAR_START);
mMaxYear = savedInstanceState.getInt(KEY_YEAR_END);
listPosition = savedInstanceState.getInt(KEY_LIST_POSITION);
}
final Activity activity = getActivity();
mDayPickerView = new SimpleDayPickerView(activity, this);
Resources res = getResources();
mDayPickerDescription =
res.getString(R.string.day_picker_description);
mSelectDay = res.getString(R.string.select_day);
mAnimator =
(AccessibleDateAnimator) view.findViewById(R.id.animator);
mAnimator.addView(mDayPickerView);
mAnimator.setDateMillis(mCalendar.getTimeInMillis());
Animation animation = new AlphaAnimation(0.0f, 1.0f);
animation.setDuration(ANIMATION_DURATION);
mAnimator.setInAnimation(animation);
Animation animation2 = new AlphaAnimation(1.0f, 0.0f);
animation2.setDuration(ANIMATION_DURATION);
mAnimator.setOutAnimation(animation2);
Button mDoneButton = (Button) view.findViewById(R.id.done);
mDoneButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mCallBack != null) {
mCallBack.onDateSet(
CalendarDatePickerDialog.this,
mCalendar.get(Calendar.YEAR),
mCalendar.get(Calendar.MONTH), mCalendar.get(Calendar.DAY_OF_MONTH));
}
dismiss();
}
});
updateDisplay(false);
setCurrentView();
if (listPosition != -1) {
mDayPickerView.postSetSelection(listPosition);
}
return view;
}
private void setCurrentView() {
long millis = mCalendar.getTimeInMillis();
ObjectAnimator pulseAnimator = Utils.getPulseAnimator(
mMonthAndDayView, 0.9f,
1.05f);
if (mDelayAnimation) {
pulseAnimator.setStartDelay(ANIMATION_DELAY);
mDelayAnimation = false;
}
mDayPickerView.onDateChanged();
mMonthAndDayView.setSelected(true);
pulseAnimator.start();
int flags = DateUtils.FORMAT_SHOW_DATE;
String dayString = DateUtils.formatDateTime(getActivity(), millis, flags);
mAnimator.setContentDescription(mDayPickerDescription + ": " + dayString);
Utils.tryAccessibilityAnnounce(mAnimator, mSelectDay);
}
private void updateDisplay(boolean announce) {
if (mDayOfWeekView != null) {
mDayOfWeekView.setText(mCalendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG,
Locale.getDefault()).toUpperCase(Locale.getDefault()));
}
mSelectedMonthTextView.setText(mCalendar.getDisplayName(Calendar.MONTH, Calendar.SHORT,
Locale.getDefault()).toUpperCase(Locale.getDefault()));
mSelectedDayTextView.setText(DAY_FORMAT.format(mCalendar.getTime()));
long millis = mCalendar.getTimeInMillis();
mAnimator.setDateMillis(millis);
int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR;
String monthAndDayText = DateUtils.formatDateTime(getActivity(), millis, flags);
mMonthAndDayView.setContentDescription(monthAndDayText);
if (announce) {
flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
String fullDateText = DateUtils.formatDateTime(getActivity(), millis, flags);
Utils.tryAccessibilityAnnounce(mAnimator, fullDateText);
}
}
public void setFirstDayOfWeek(int startOfWeek) {
if (startOfWeek < Calendar.SUNDAY || startOfWeek > Calendar.SATURDAY) {
throw new IllegalArgumentException("Value must be between Calendar.SUNDAY and " +
"Calendar.SATURDAY");
}
mWeekStart = startOfWeek;
if (mDayPickerView != null) {
mDayPickerView.onChange();
}
}
public void setYearRange(int startYear, int endYear) {
if (endYear <= startYear) {
throw new IllegalArgumentException("Year end must be larger than year start");
}
mMinYear = startYear;
mMaxYear = endYear;
if (mDayPickerView != null) {
mDayPickerView.onChange();
}
}
public void setOnDateSetListener(OnDateSetListener listener) {
mCallBack = listener;
}
private void adjustDayInMonthIfNeeded(int month, int year) {
int day = mCalendar.get(Calendar.DAY_OF_MONTH);
int daysInMonth = Utils.getDaysInMonth(month, year);
if (day > daysInMonth) {
mCalendar.set(Calendar.DAY_OF_MONTH, daysInMonth);
}
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.date_picker_month_and_day) {
setCurrentView();
}
}
@Override
public void onYearSelected(int year) {
adjustDayInMonthIfNeeded(mCalendar.get(Calendar.MONTH), year);
mCalendar.set(Calendar.YEAR, year);
updatePickers();
setCurrentView();
updateDisplay(true);
}
@Override
public void onDayOfMonthSelected(int year, int month, int day) {
mCalendar.set(Calendar.YEAR, year);
mCalendar.set(Calendar.MONTH, month);
mCalendar.set(Calendar.DAY_OF_MONTH, day);
updatePickers();
updateDisplay(true);
}
private void updatePickers() {
for (OnDateChangedListener mListener : mListeners) {
mListener.onDateChanged();
}
}
@Override
public MonthAdapter.CalendarDay getSelectedDay() {
return new MonthAdapter.CalendarDay(mCalendar);
}
@Override
public int getMinYear() {
return mMinYear;
}
@Override
public int getMaxYear() {
return mMaxYear;
}
@Override
public int getFirstDayOfWeek() {
return mWeekStart;
}
@Override
public void registerOnDateChangedListener(OnDateChangedListener listener) {
mListeners.add(listener);
}
@Override
public void unregisterOnDateChangedListener(OnDateChangedListener listener) {
mListeners.remove(listener);
}
}