package com.github.jjobes.slidedaytimepicker;
import java.text.SimpleDateFormat;
import java.util.Calendar;
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.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 DayFragment} and {@link TimeFragment}.</p>
*
* <p>This {@code DialogFragment} is managed by {@link SlideDayTimePicker}.</p>
*
* @author jjobes
*
*/
public class SlideDayTimeDialogFragment extends DialogFragment implements DayFragment.DayChangedListener,
TimeFragment.TimeChangedListener
{
public static final String TAG_SLIDE_DAY_TIME_DIALOG_FRAGMENT = "tagSlideDayTimeDialogFragment";
private static SlideDayTimeListener 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 boolean mIsCustomDaysArraySpecified;
private String[] mCustomDaysArray;
private String[] mDaysArray;
private int mDayIndex;
private int mHour;
private int mMinute;
private int mTheme;
private int mIndicatorColor;
private boolean mIsClientSpecified24HourTime;
private boolean mIs24HourTime;
private Calendar mCalendar;
public SlideDayTimeDialogFragment()
{
// Required empty public constructor
}
/**
* <p>Return a new instance of {@code SlideDayTimeDialogFragment} with its bundle
* filled with the incoming arguments.</p>
*
* <p>Called by {@link SlideDayTimePicker#show()}.</p>
*
* @param listener
* @param isCustomDaysArraySpecified
* @param initialDay
* @param initialHour
* @param initialMinute
* @param isClientSpecified24HourTime
* @param is24HourTime
* @param theme
* @param indicatorColor
* @return
*/
public static SlideDayTimeDialogFragment newInstance(SlideDayTimeListener listener,
boolean isCustomDaysArraySpecified, String[] customDaysArray, int initialDay,
int initialHour, int initialMinute, boolean isClientSpecified24HourTime,
boolean is24HourTime, int theme, int indicatorColor)
{
// Set listener to a static member variable in order to avoid the
// NotSerializableException on rotation.
mListener = listener;
// Create a new instance of SlideDayTimeDialogFragment
SlideDayTimeDialogFragment dialogFragment = new SlideDayTimeDialogFragment();
// Store the arguments and attach the bundle to the fragment
Bundle bundle = new Bundle();
bundle.putBoolean("isCustomDaysArraySpecified", isCustomDaysArraySpecified);
bundle.putStringArray("customDaysArray", customDaysArray);
bundle.putInt("initialDay", initialDay);
bundle.putInt("initialHour", initialHour);
bundle.putInt("initialMinute", initialMinute);
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);
mDaysArray = getResources().getStringArray(R.array.days_array);
unpackBundle();
if (!mIsCustomDaysArraySpecified)
mDayIndex--;
mCalendar = Calendar.getInstance();
mCalendar.set(Calendar.HOUR_OF_DAY, mHour);
mCalendar.set(Calendar.MINUTE, mMinute);
switch (mTheme)
{
case SlideDayTimePicker.HOLO_DARK:
setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_Holo_Dialog_NoActionBar);
break;
case SlideDayTimePicker.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_day_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();
mIsCustomDaysArraySpecified = args.getBoolean("isCustomDaysArraySpecified");
mCustomDaysArray = args.getStringArray("customDaysArray");
mDayIndex = args.getInt("initialDay");
mHour = args.getInt("initialHour");
mMinute = args.getInt("initialMinute");
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 == SlideDayTimePicker.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 SlideDayTimePicker.HOLO_LIGHT:
case SlideDayTimePicker.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
updateDayTab();
// 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");
}
// mDayIndex currenly holds the index of the day in days_array,
// but we want to return a day integer that is compliant with
// the java.util.Calendar API, so we increment it by 1 if they're
// using the built-in days array. If the user specifies their
// own custom array, return the raw index.
int returnDay;
if (!mIsCustomDaysArraySpecified)
{
returnDay = mDayIndex + 1;
}
else
{
returnDay = mDayIndex;
}
mListener.onDayTimeSet(returnDay, mHour, mMinute);
dismiss();
}
});
mCancelButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v)
{
if (mListener == null)
{
throw new NullPointerException(
"Listener no longer exists for mCancelButton");
}
mListener.onDayTimeCancel();
dismiss();
}
});
}
/**
* <p>The callback used by the day picker to update {@code mCalendar} as
* the user changes the date. Each time this is called, we update the
* day tab to reflect the day the user has currenly selected.</p>
*
* <p>Implements the {@link DayFragment.DayChangedListener} interface.</p>
*/
@Override
public void onDayChanged(int day)
{
mDayIndex = day; // Sunday 0, Monday 1, ... Saturday 6
updateDayTab();
}
/**
* <p>The callback used by the time picker to update {@code mCalendar}
* as the user changes the time. Each time this is called, we update
* 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)
{
mHour = hour;
mMinute = minute;
mCalendar.set(Calendar.HOUR_OF_DAY, mHour);
mCalendar.set(Calendar.MINUTE, mMinute);
updateTimeTab();
}
private void updateDayTab()
{
if (mIsCustomDaysArraySpecified)
mSlidingTabLayout.setTabText(0, mCustomDaysArray[mDayIndex]);
else
mSlidingTabLayout.setTabText(0, mDaysArray[mDayIndex]);
}
@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 device's
* <b>Back</b> button.</p>
*
* <p><b>Note:</b> Actual Cancel 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.onDayTimeCancel();
}
private class ViewPagerAdapter extends FragmentPagerAdapter
{
public ViewPagerAdapter(FragmentManager fm)
{
super(fm);
}
@Override
public Fragment getItem(int position)
{
switch (position)
{
case 0:
Fragment dayFragment = DayFragment.newInstance(
mTheme,
mDayIndex,
mIsCustomDaysArraySpecified,
mCustomDaysArray);
dayFragment.setTargetFragment(SlideDayTimeDialogFragment.this, 100);
return dayFragment;
case 1:
Fragment timeFragment = TimeFragment.newInstance(
mTheme,
mCalendar.get(Calendar.HOUR_OF_DAY),
mCalendar.get(Calendar.MINUTE),
mIsClientSpecified24HourTime,
mIs24HourTime);
timeFragment.setTargetFragment(SlideDayTimeDialogFragment.this, 200);
return timeFragment;
}
return null;
}
@Override
public int getCount()
{
return 2;
}
}
}