package com.github.jjobes.slidedatetimepicker; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.text.format.DateFormat; import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; /** * <p>The {@code DialogFragment} that contains the {@link SlidingTabLayout} * and {@link CustomViewPager}.</p> * * <p>The {@code CustomViewPager} contains the {@link DateFragment} and {@link TimeFragment}.</p> * * <p>This {@code DialogFragment} is managed by {@link SlideDateTimePicker}.</p> * * @author jjobes * */ public class SlideDateTimeDialogFragment extends DialogFragment implements DateFragment.DateChangedListener, TimeFragment.TimeChangedListener { public static final String TAG_SLIDE_DATE_TIME_DIALOG_FRAGMENT = "tagSlideDateTimeDialogFragment"; private static SlideDateTimeListener mListener; private Context mContext; private CustomViewPager mViewPager; private ViewPagerAdapter mViewPagerAdapter; private SlidingTabLayout mSlidingTabLayout; private View mButtonHorizontalDivider; private View mButtonVerticalDivider; private Button mOkButton; private Button mCancelButton; private Date mInitialDate; private int mTheme; private int mIndicatorColor; private Date mMinDate; private Date mMaxDate; private boolean mIsClientSpecified24HourTime; private boolean mIs24HourTime; private Calendar mCalendar; private int mDateFlags = DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL; public SlideDateTimeDialogFragment() { // Required empty public constructor } /** * <p>Return a new instance of {@code SlideDateTimeDialogFragment} with its bundle * filled with the incoming arguments.</p> * * <p>Called by {@link SlideDateTimePicker#show()}.</p> * * @param listener * @param initialDate * @param minDate * @param maxDate * @param isClientSpecified24HourTime * @param is24HourTime * @param theme * @param indicatorColor * @return */ public static SlideDateTimeDialogFragment newInstance(SlideDateTimeListener listener, Date initialDate, Date minDate, Date maxDate, boolean isClientSpecified24HourTime, boolean is24HourTime, int theme, int indicatorColor) { mListener = listener; // Create a new instance of SlideDateTimeDialogFragment SlideDateTimeDialogFragment dialogFragment = new SlideDateTimeDialogFragment(); // Store the arguments and attach the bundle to the fragment Bundle bundle = new Bundle(); bundle.putSerializable("initialDate", initialDate); bundle.putSerializable("minDate", minDate); bundle.putSerializable("maxDate", maxDate); bundle.putBoolean("isClientSpecified24HourTime", isClientSpecified24HourTime); bundle.putBoolean("is24HourTime", is24HourTime); bundle.putInt("theme", theme); bundle.putInt("indicatorColor", indicatorColor); dialogFragment.setArguments(bundle); // Return the fragment with its bundle return dialogFragment; } @Override public void onAttach(Activity activity) { super.onAttach(activity); mContext = activity; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); unpackBundle(); mCalendar = Calendar.getInstance(); mCalendar.setTime(mInitialDate); switch (mTheme) { case SlideDateTimePicker.HOLO_DARK: setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_Holo_Dialog_NoActionBar); break; case SlideDateTimePicker.HOLO_LIGHT: setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_Holo_Light_Dialog_NoActionBar); break; default: // if no theme was specified, default to holo light setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_Holo_Light_Dialog_NoActionBar); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.slide_date_time_picker, container); setupViews(view); customizeViews(); initViewPager(); initTabs(); initButtons(); return view; } @Override public void onDestroyView() { // Workaround for a bug in the compatibility library where calling // setRetainInstance(true) does not retain the instance across // orientation changes. if (getDialog() != null && getRetainInstance()) { getDialog().setDismissMessage(null); } super.onDestroyView(); } private void unpackBundle() { Bundle args = getArguments(); mInitialDate = (Date) args.getSerializable("initialDate"); mMinDate = (Date) args.getSerializable("minDate"); mMaxDate = (Date) args.getSerializable("maxDate"); mIsClientSpecified24HourTime = args.getBoolean("isClientSpecified24HourTime"); mIs24HourTime = args.getBoolean("is24HourTime"); mTheme = args.getInt("theme"); mIndicatorColor = args.getInt("indicatorColor"); } private void setupViews(View v) { mViewPager = (CustomViewPager) v.findViewById(R.id.viewPager); mSlidingTabLayout = (SlidingTabLayout) v.findViewById(R.id.slidingTabLayout); mButtonHorizontalDivider = v.findViewById(R.id.buttonHorizontalDivider); mButtonVerticalDivider = v.findViewById(R.id.buttonVerticalDivider); mOkButton = (Button) v.findViewById(R.id.okButton); mCancelButton = (Button) v.findViewById(R.id.cancelButton); } private void customizeViews() { int lineColor = mTheme == SlideDateTimePicker.HOLO_DARK ? getResources().getColor(R.color.gray_holo_dark) : getResources().getColor(R.color.gray_holo_light); // Set the colors of the horizontal and vertical lines for the // bottom buttons depending on the theme. switch (mTheme) { case SlideDateTimePicker.HOLO_LIGHT: case SlideDateTimePicker.HOLO_DARK: mButtonHorizontalDivider.setBackgroundColor(lineColor); mButtonVerticalDivider.setBackgroundColor(lineColor); break; default: // if no theme was specified, default to holo light mButtonHorizontalDivider.setBackgroundColor(getResources().getColor(R.color.gray_holo_light)); mButtonVerticalDivider.setBackgroundColor(getResources().getColor(R.color.gray_holo_light)); } // Set the color of the selected tab underline if one was specified. if (mIndicatorColor != 0) mSlidingTabLayout.setSelectedIndicatorColors(mIndicatorColor); } private void initViewPager() { mViewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager()); mViewPager.setAdapter(mViewPagerAdapter); // Setting this custom layout for each tab ensures that the tabs will // fill all available horizontal space. mSlidingTabLayout.setCustomTabView(R.layout.custom_tab, R.id.tabText); mSlidingTabLayout.setViewPager(mViewPager); } private void initTabs() { // Set intial date on date tab updateDateTab(); // Set initial time on time tab updateTimeTab(); } private void initButtons() { mOkButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mListener == null) { throw new NullPointerException( "Listener no longer exists for mOkButton"); } mListener.onDateTimeSet(new Date(mCalendar.getTimeInMillis())); dismiss(); } }); mCancelButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mListener == null) { throw new NullPointerException( "Listener no longer exists for mCancelButton"); } mListener.onDateTimeCancel(); dismiss(); } }); } /** * <p>The callback used by the DatePicker to update {@code mCalendar} as * the user changes the date. Each time this is called, we also update * the text on the date tab to reflect the date the user has currenly * selected.</p> * * <p>Implements the {@link DateFragment.DateChangedListener} * interface.</p> */ @Override public void onDateChanged(int year, int month, int day) { mCalendar.set(year, month, day); updateDateTab(); } /** * <p>The callback used by the TimePicker to update {@code mCalendar} as * the user changes the time. Each time this is called, we also update * the text on the time tab to reflect the time the user has currenly * selected.</p> * * <p>Implements the {@link TimeFragment.TimeChangedListener} * interface.</p> */ @Override public void onTimeChanged(int hour, int minute) { mCalendar.set(Calendar.HOUR_OF_DAY, hour); mCalendar.set(Calendar.MINUTE, minute); updateTimeTab(); } private void updateDateTab() { mSlidingTabLayout.setTabText(0, DateUtils.formatDateTime( mContext, mCalendar.getTimeInMillis(), mDateFlags)); } @SuppressLint("SimpleDateFormat") private void updateTimeTab() { if (mIsClientSpecified24HourTime) { SimpleDateFormat formatter; if (mIs24HourTime) { formatter = new SimpleDateFormat("HH:mm"); mSlidingTabLayout.setTabText(1, formatter.format(mCalendar.getTime())); } else { formatter = new SimpleDateFormat("h:mm aa"); mSlidingTabLayout.setTabText(1, formatter.format(mCalendar.getTime())); } } else // display time using the device's default 12/24 hour format preference { mSlidingTabLayout.setTabText(1, DateFormat.getTimeFormat( mContext).format(mCalendar.getTimeInMillis())); } } /** * <p>Called when the user clicks outside the dialog or presses the <b>Back</b> * button.</p> * * <p><b>Note:</b> Actual <b>Cancel</b> button clicks are handled by {@code mCancelButton}'s * event handler.</p> */ @Override public void onCancel(DialogInterface dialog) { super.onCancel(dialog); if (mListener == null) { throw new NullPointerException( "Listener no longer exists in onCancel()"); } mListener.onDateTimeCancel(); } private class ViewPagerAdapter extends FragmentPagerAdapter { public ViewPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { switch (position) { case 0: DateFragment dateFragment = DateFragment.newInstance( mTheme, mCalendar.get(Calendar.YEAR), mCalendar.get(Calendar.MONTH), mCalendar.get(Calendar.DAY_OF_MONTH), mMinDate, mMaxDate); dateFragment.setTargetFragment(SlideDateTimeDialogFragment.this, 100); return dateFragment; case 1: TimeFragment timeFragment = TimeFragment.newInstance( mTheme, mCalendar.get(Calendar.HOUR_OF_DAY), mCalendar.get(Calendar.MINUTE), mIsClientSpecified24HourTime, mIs24HourTime); timeFragment.setTargetFragment(SlideDateTimeDialogFragment.this, 200); return timeFragment; default: return null; } } @Override public int getCount() { return 2; } } }