Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Added min max limits to RadialTimePickers #272

Merged
merged 3 commits into from
Apr 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import com.codetroopers.betterpickers.HapticFeedbackController;
import com.codetroopers.betterpickers.R;
import com.codetroopers.betterpickers.Utils;
import com.codetroopers.betterpickers.numberpicker.NumberPickerErrorTextView;
import com.codetroopers.betterpickers.radialtimepicker.RadialPickerLayout.OnValueSelectedListener;
import com.nineoldandroids.animation.ObjectAnimator;

Expand All @@ -62,6 +63,10 @@ public class RadialTimePickerDialogFragment extends DialogFragment implements On
private static final String KEY_IN_KB_MODE = "in_kb_mode";
private static final String KEY_TYPED_TIMES = "typed_times";
private static final String KEY_STYLE = "theme";
private static final String KEY_FUTURE_MINUTES_LIMIT = "future_minutes_limit";
private static final String KEY_PAST_MINUTES_LIMIT = "past_minutes_limit";
private static final String KEY_CURRENT_DATE = "current_date";
private static final String KEY_PICKER_DATE = "picker_date";

public static final int HOUR_INDEX = 0;
public static final int MINUTE_INDEX = 1;
Expand All @@ -88,19 +93,26 @@ public class RadialTimePickerDialogFragment extends DialogFragment implements On
private TextView mAmPmTextView;
private View mAmPmHitspace;
private RadialPickerLayout mTimePicker;
private TextView mTitleTextView;
private NumberPickerErrorTextView mError;

private int mSelectedColor;
private int mUnselectedColor;
private String mAmText;
private String mPmText;
private String mDoneText;
private String mCancelText;
private String mTitleText;

private boolean mAllowAutoAdvance;
private int mInitialHourOfDay;
private int mInitialMinute;
private Boolean mIs24HourMode;
private int mStyleResId;
private Integer mFutureMinutesLimit;
private Integer mPastMinutesLimit;
private Calendar mValidateDateTime;
private Calendar mPickerDate;

// For hardware IME input.
private char mPlaceholderText;
Expand Down Expand Up @@ -222,11 +234,36 @@ public RadialTimePickerDialogFragment setStartTime(int hourOfDay, int minute) {
return this;
}

public RadialTimePickerDialogFragment setTitleText(String text) {
mTitleText = text;
return this;
}

public RadialTimePickerDialogFragment setDoneText(String text) {
mDoneText = text;
return this;
}

public RadialTimePickerDialogFragment setFutureMinutesLimit(Integer futureMinutesLimit) {
this.mFutureMinutesLimit = futureMinutesLimit;
return this;
}

public RadialTimePickerDialogFragment setPastMinutesLimit(Integer pastMinutesLimit) {
this.mPastMinutesLimit = pastMinutesLimit;
return this;
}

public RadialTimePickerDialogFragment setValidateDateTime(Calendar validateDateTime) {
this.mValidateDateTime = validateDateTime;
return this;
}

public RadialTimePickerDialogFragment setPickerDate(Calendar pickerDate) {
this.mPickerDate = pickerDate;
return this;
}

public RadialTimePickerDialogFragment setCancelText(String text) {
mCancelText = text;
return this;
Expand Down Expand Up @@ -270,9 +307,13 @@ public void onCreate(Bundle savedInstanceState) {
mIs24HourMode = savedInstanceState.getBoolean(KEY_IS_24_HOUR_VIEW);
mInKbMode = savedInstanceState.getBoolean(KEY_IN_KB_MODE);
mStyleResId = savedInstanceState.getInt(KEY_STYLE);
if(savedInstanceState.containsKey(KEY_FUTURE_MINUTES_LIMIT)) mFutureMinutesLimit = savedInstanceState.getInt(KEY_FUTURE_MINUTES_LIMIT);
if(savedInstanceState.containsKey(KEY_PAST_MINUTES_LIMIT)) mPastMinutesLimit = savedInstanceState.getInt(KEY_PAST_MINUTES_LIMIT);
if(savedInstanceState.containsKey(KEY_CURRENT_DATE)) mValidateDateTime = (Calendar) savedInstanceState.getSerializable(KEY_CURRENT_DATE);
if(savedInstanceState.containsKey(KEY_PICKER_DATE)) mPickerDate = (Calendar) savedInstanceState.getSerializable(KEY_PICKER_DATE);
} else {
if (mIs24HourMode == null) {
mIs24HourMode = DateFormat.is24HourFormat(getContext());
mIs24HourMode = DateFormat.is24HourFormat(getContext());;
}
}
}
Expand Down Expand Up @@ -338,6 +379,17 @@ public void onClick(View v) {
}
});

mTitleTextView = (TextView) view.findViewById(R.id.time_picker_header);
if (mTitleText != null) {
mTitleTextView.setVisibility(View.VISIBLE);
mTitleTextView.setText(mTitleText);
}
else {
mTitleTextView.setVisibility(View.GONE);
}

mError = (NumberPickerErrorTextView) view.findViewById(R.id.error);

mDoneButton = (Button) view.findViewById(R.id.done_button);
if (mDoneText != null) {
mDoneButton.setText(mDoneText);
Expand All @@ -351,11 +403,7 @@ public void onClick(View v) {
} else {
tryVibrate();
}
if (mCallback != null) {
mCallback.onTimeSet(RadialTimePickerDialogFragment.this,
mTimePicker.getHours(), mTimePicker.getMinutes());
}
dismiss();
doneClickValidateAndCallback();
}
});
mDoneButton.setOnKeyListener(keyboardListener);
Expand Down Expand Up @@ -478,18 +526,83 @@ public void onSaveInstanceState(Bundle outState) {
outState.putBoolean(KEY_IS_24_HOUR_VIEW, mIs24HourMode);
outState.putInt(KEY_CURRENT_ITEM_SHOWING, mTimePicker.getCurrentItemShowing());
outState.putBoolean(KEY_IN_KB_MODE, mInKbMode);
if (mInKbMode) {
outState.putIntegerArrayList(KEY_TYPED_TIMES, mTypedTimes);
}
if(mFutureMinutesLimit != null) outState.putInt(KEY_FUTURE_MINUTES_LIMIT, mFutureMinutesLimit);
if(mPastMinutesLimit != null) outState.putInt(KEY_PAST_MINUTES_LIMIT, mPastMinutesLimit);
outState.putSerializable(KEY_CURRENT_DATE, mValidateDateTime);
outState.putSerializable(KEY_PICKER_DATE, mPickerDate);
if (mInKbMode) outState.putIntegerArrayList(KEY_TYPED_TIMES, mTypedTimes);
outState.putInt(KEY_STYLE, mStyleResId);
}
}

/**
* Checks if the selected time lays too far in the future
* @return true if too far in the future, false if not
*/
public boolean isSelectionTooFarInTheFuture() {
if(this.mPickerDate != null && this.mValidateDateTime != null && this.mFutureMinutesLimit != null) {
Calendar selectedDate = Calendar.getInstance();
selectedDate.setTime(this.mPickerDate.getTime());
selectedDate.set(Calendar.HOUR_OF_DAY, mTimePicker.getHours());
selectedDate.set(Calendar.MINUTE, mTimePicker.getMinutes());

Calendar futureLimit = Calendar.getInstance();
futureLimit.setTime(this.mValidateDateTime.getTime());
futureLimit.add(Calendar.MINUTE, this.mFutureMinutesLimit);
return selectedDate.compareTo(futureLimit) > 0;
}
return false;
}

/**
* Checks if the selected time lays too far in the past
* @return true if too far in the past, false if not
*/
public boolean isSelectionTooFarInPast() {
if(this.mPickerDate != null && this.mValidateDateTime != null && this.mPastMinutesLimit != null) {
Calendar selectedDate = Calendar.getInstance();
selectedDate.setTime(this.mPickerDate.getTime());
selectedDate.set(Calendar.HOUR_OF_DAY, mTimePicker.getHours());
selectedDate.set(Calendar.MINUTE, mTimePicker.getMinutes());

Calendar pastLimit = Calendar.getInstance();
pastLimit.setTime(this.mValidateDateTime.getTime());
pastLimit.add(Calendar.MINUTE, -this.mPastMinutesLimit);
return selectedDate.compareTo(pastLimit) < 0;
}
return false;
}

/**
* Called when the done button is pressed. Validates the input and performs a callback if valid.
*/
public void doneClickValidateAndCallback() {
if(isSelectionTooFarInTheFuture()) {
if(mError != null) {
mError.setText(getString(R.string.max_time_error));
mError.show();
}
}
else if(isSelectionTooFarInPast()) {
if(mError != null) {
mError.setText(getString(R.string.min_time_error));
mError.show();
}
}
else {
if (mCallback != null) {
mCallback.onTimeSet(RadialTimePickerDialogFragment.this, mTimePicker.getHours(), mTimePicker.getMinutes());
}
dismiss();
}
}

/**
* Called by the picker for updating the header display.
*/
@Override
public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) {
mError.hideImmediately();
if (pickerIndex == HOUR_INDEX) {
setHour(newValue, false);
String announcement = String.format("%d", newValue);
Expand Down Expand Up @@ -604,11 +717,7 @@ private boolean processKeyUp(int keyCode) {
}
finishKbMode(false);
}
if (mCallback != null) {
mCallback.onTimeSet(RadialTimePickerDialogFragment.this,
mTimePicker.getHours(), mTimePicker.getMinutes());
}
dismiss();
doneClickValidateAndCallback();
return true;
} else if (keyCode == KeyEvent.KEYCODE_DEL) {
if (mInKbMode) {
Expand Down
21 changes: 20 additions & 1 deletion library/src/main/res/layout-land/radial_time_picker_dialog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,26 @@
<LinearLayout
android:layout_width="@dimen/left_side_width"
android:layout_height="match_parent"
android:orientation="vertical">
android:orientation="vertical"
android:background="@color/bpWhite">

<include layout="@layout/calendar_date_picker_header_view"
android:id="@+id/time_picker_header"
android:layout_width="match_parent"
android:layout_height="@dimen/date_picker_header_height"/>

<com.codetroopers.betterpickers.numberpicker.NumberPickerErrorTextView
android:id="@+id/error"
android:visibility="invisible"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:background="#ffff4444"
android:textColor="#ffffffff"
android:textStyle="bold"/>

<FrameLayout
android:id="@+id/time_display_background"
android:layout_width="match_parent"
Expand Down
17 changes: 17 additions & 0 deletions library/src/main/res/layout/radial_time_picker_dialog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@
android:focusable="true"
android:orientation="vertical">

<include layout="@layout/calendar_date_picker_header_view"
android:id="@+id/time_picker_header"
android:layout_width="match_parent"
android:layout_height="@dimen/date_picker_header_height" />

<com.codetroopers.betterpickers.numberpicker.NumberPickerErrorTextView
android:id="@+id/error"
android:visibility="invisible"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:background="#ffff4444"
android:textColor="#ffffffff"
android:textStyle="bold"/>

<FrameLayout
android:id="@+id/time_display_background"
android:layout_width="match_parent"
Expand Down
3 changes: 3 additions & 0 deletions library/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
<string name="min_error">Bitte eine Zahl größer oder gleich %1$s eingeben</string>
<string name="max_error">Bitte eine Zahl kleiner oder gleich %1$s eingeben</string>
<string name="min_max_error">Bitte eine Zahl zwischen %1$s und %2$s eingeben</string>
<!-- Time validation -->
<string name="max_time_error">Die eingegebene Zeit liegt zu weit in der Zukunft</string>
<string name="min_time_error">Die eingegebene Zeit liegt zu weit in der Vergangenheit</string>

<!-- From AOSP -->
<!-- Label for button to confirm chosen date or time [CHAR LIMIT=30] -->
Expand Down
3 changes: 3 additions & 0 deletions library/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
<string name="min_error">Please input a number greater than or equal to %1$s</string>
<string name="max_error">Please input a number less than or equal to %1$s</string>
<string name="min_max_error">Please input a number between %1$s and %2$s</string>
<!-- Time validation -->
<string name="max_time_error">The time entered lays too far in the future</string>
<string name="min_time_error">The time entered lays too far in the past</string>

<!-- From AOSP -->
<!-- Label for button to confirm chosen date or time [CHAR LIMIT=30] -->
Expand Down
8 changes: 8 additions & 0 deletions sample/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,14 @@
<category android:name="com.doomonafireball.betterpickers.sample.SAMPLE" />
</intent-filter>
</activity>
<activity
android:name=".activity.radialtimepicker.SampleRadialTimeMinMax"
android:label="Radial Time/Limit +-1 hour">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.doomonafireball.betterpickers.sample.SAMPLE" />
</intent-filter>
</activity>
<activity
android:name=".activity.recurrencepicker.SampleRecurrenceBasicUsage"
android:label="Recurrence/Basic Usage">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.codetroopers.betterpickers.sample.activity.radialtimepicker;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.codetroopers.betterpickers.radialtimepicker.RadialTimePickerDialogFragment;
import com.codetroopers.betterpickers.sample.R;
import com.codetroopers.betterpickers.sample.activity.BaseSampleActivity;

import java.util.Calendar;

public class SampleRadialTimeMinMax extends BaseSampleActivity
implements RadialTimePickerDialogFragment.OnTimeSetListener {

private static final String FRAG_TAG_TIME_PICKER = "timePickerDialogFragment";

private TextView mResultTextView;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.text_and_button);

mResultTextView = (TextView) findViewById(R.id.text);
Button button = (Button) findViewById(R.id.button);

mResultTextView.setText(R.string.no_value);
button.setText(R.string.radial_time_picker);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
RadialTimePickerDialogFragment rtpd = new RadialTimePickerDialogFragment()
.setOnTimeSetListener(SampleRadialTimeMinMax.this)
.setFutureMinutesLimit(60)
.setPastMinutesLimit(60)
.setValidateDateTime(Calendar.getInstance())
.setPickerDate(Calendar.getInstance())
.setForced12hFormat();
rtpd.show(getSupportFragmentManager(), FRAG_TAG_TIME_PICKER);
}
});
}

@Override
public void onTimeSet(RadialTimePickerDialogFragment dialog, int hourOfDay, int minute) {
mResultTextView.setText(getString(R.string.radial_time_picker_result_value, hourOfDay, minute));
}

@Override
public void onResume() {
// Example of reattaching to the fragment
super.onResume();
RadialTimePickerDialogFragment rtpd = (RadialTimePickerDialogFragment) getSupportFragmentManager().findFragmentByTag(FRAG_TAG_TIME_PICKER);
if (rtpd != null) {
rtpd.setOnTimeSetListener(this);
}
}
}