am 33322052: Merge "DatePicker is picking the wrong date" into honeycomb
* commit '33322052edd6c77b4378e69b66f746f241a80764': DatePicker is picking the wrong date
This commit is contained in:
@@ -440,11 +440,18 @@ public class CalendarView extends FrameLayout {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mMinDate.setTimeInMillis(minDate);
|
mMinDate.setTimeInMillis(minDate);
|
||||||
// reinitialize the adapter since its range depends on min date
|
// make sure the current date is not earlier than
|
||||||
mAdapter.init();
|
// the new min date since the latter is used for
|
||||||
|
// calculating the indices in the adapter thus
|
||||||
|
// avoiding out of bounds error
|
||||||
Calendar date = mAdapter.mSelectedDate;
|
Calendar date = mAdapter.mSelectedDate;
|
||||||
if (date.before(mMinDate)) {
|
if (date.before(mMinDate)) {
|
||||||
setDate(mMinDate.getTimeInMillis());
|
mAdapter.setSelectedDay(mMinDate);
|
||||||
|
}
|
||||||
|
// reinitialize the adapter since its range depends on min date
|
||||||
|
mAdapter.init();
|
||||||
|
if (date.before(mMinDate)) {
|
||||||
|
setDate(mTempDate.getTimeInMillis());
|
||||||
} else {
|
} else {
|
||||||
// we go to the current date to force the ListView to query its
|
// we go to the current date to force the ListView to query its
|
||||||
// adapter for the shown views since we have changed the adapter
|
// adapter for the shown views since we have changed the adapter
|
||||||
@@ -753,7 +760,13 @@ public class CalendarView extends FrameLayout {
|
|||||||
mFirstDayOfMonth.set(Calendar.DAY_OF_MONTH, 1);
|
mFirstDayOfMonth.set(Calendar.DAY_OF_MONTH, 1);
|
||||||
|
|
||||||
setMonthDisplayed(mFirstDayOfMonth);
|
setMonthDisplayed(mFirstDayOfMonth);
|
||||||
position = getWeeksSinceMinDate(mFirstDayOfMonth);
|
|
||||||
|
// the earliest time we can scroll to is the min date
|
||||||
|
if (mFirstDayOfMonth.before(mMinDate)) {
|
||||||
|
position = 0;
|
||||||
|
} else {
|
||||||
|
position = getWeeksSinceMinDate(mFirstDayOfMonth);
|
||||||
|
}
|
||||||
|
|
||||||
mPreviousScrollState = OnScrollListener.SCROLL_STATE_FLING;
|
mPreviousScrollState = OnScrollListener.SCROLL_STATE_FLING;
|
||||||
if (animate) {
|
if (animate) {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import android.widget.NumberPicker.OnValueChangeListener;
|
|||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
@@ -156,8 +157,34 @@ public class DatePicker extends FrameLayout {
|
|||||||
|
|
||||||
OnValueChangeListener onChangeListener = new OnValueChangeListener() {
|
OnValueChangeListener onChangeListener = new OnValueChangeListener() {
|
||||||
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
|
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
|
||||||
updateDate(mYearSpinner.getValue(), mMonthSpinner.getValue(), mDaySpinner
|
mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
|
||||||
.getValue());
|
// take care of wrapping of days and months to update greater fields
|
||||||
|
if (picker == mDaySpinner) {
|
||||||
|
int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||||
|
if (oldVal == maxDayOfMonth && newVal == 1) {
|
||||||
|
mTempDate.add(Calendar.DAY_OF_MONTH, 1);
|
||||||
|
} else if (oldVal == 1 && newVal == maxDayOfMonth) {
|
||||||
|
mTempDate.add(Calendar.DAY_OF_MONTH, -1);
|
||||||
|
} else {
|
||||||
|
mTempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal);
|
||||||
|
}
|
||||||
|
} else if (picker == mMonthSpinner) {
|
||||||
|
if (oldVal == 11 && newVal == 0) {
|
||||||
|
mTempDate.add(Calendar.MONTH, 1);
|
||||||
|
} else if (oldVal == 0 && newVal == 11) {
|
||||||
|
mTempDate.add(Calendar.MONTH, -1);
|
||||||
|
} else {
|
||||||
|
mTempDate.add(Calendar.MONTH, newVal - oldVal);
|
||||||
|
}
|
||||||
|
} else if (picker == mYearSpinner) {
|
||||||
|
mTempDate.set(Calendar.YEAR, newVal);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
// now set the date to the adjusted one
|
||||||
|
setDate(mTempDate.get(Calendar.YEAR), mTempDate.get(Calendar.MONTH),
|
||||||
|
mTempDate.get(Calendar.DAY_OF_MONTH));
|
||||||
|
notifyDateChanged();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -167,7 +194,8 @@ public class DatePicker extends FrameLayout {
|
|||||||
mCalendarView = (CalendarView) findViewById(R.id.calendar_view);
|
mCalendarView = (CalendarView) findViewById(R.id.calendar_view);
|
||||||
mCalendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() {
|
mCalendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() {
|
||||||
public void onSelectedDayChange(CalendarView view, int year, int month, int monthDay) {
|
public void onSelectedDayChange(CalendarView view, int year, int month, int monthDay) {
|
||||||
updateDate(year, month, monthDay);
|
setDate(year, month, monthDay);
|
||||||
|
notifyDateChanged();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -260,10 +288,12 @@ public class DatePicker extends FrameLayout {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mMinDate.setTimeInMillis(minDate);
|
mMinDate.setTimeInMillis(minDate);
|
||||||
mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR));
|
|
||||||
mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR));
|
|
||||||
mCalendarView.setMinDate(minDate);
|
mCalendarView.setMinDate(minDate);
|
||||||
updateSpinners(mYearSpinner.getValue(), mMonthSpinner.getValue(), mDaySpinner.getValue());
|
if (mCurrentDate.before(mMinDate)) {
|
||||||
|
mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
|
||||||
|
updateCalendarView();
|
||||||
|
}
|
||||||
|
updateSpinners();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -294,10 +324,12 @@ public class DatePicker extends FrameLayout {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mMaxDate.setTimeInMillis(maxDate);
|
mMaxDate.setTimeInMillis(maxDate);
|
||||||
mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR));
|
|
||||||
mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR));
|
|
||||||
mCalendarView.setMaxDate(maxDate);
|
mCalendarView.setMaxDate(maxDate);
|
||||||
updateSpinners(mYearSpinner.getValue(), mMonthSpinner.getValue(), mDaySpinner.getValue());
|
if (mCurrentDate.after(mMaxDate)) {
|
||||||
|
mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
|
||||||
|
updateCalendarView();
|
||||||
|
}
|
||||||
|
updateSpinners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -433,13 +465,11 @@ public class DatePicker extends FrameLayout {
|
|||||||
* @param dayOfMonth The day of the month.
|
* @param dayOfMonth The day of the month.
|
||||||
*/
|
*/
|
||||||
public void updateDate(int year, int month, int dayOfMonth) {
|
public void updateDate(int year, int month, int dayOfMonth) {
|
||||||
if (mCurrentDate.get(Calendar.YEAR) != year
|
if (!isNewDate(year, month, dayOfMonth)) {
|
||||||
|| mCurrentDate.get(Calendar.MONTH) != dayOfMonth
|
return;
|
||||||
|| mCurrentDate.get(Calendar.DAY_OF_MONTH) != month) {
|
|
||||||
updateSpinners(year, month, dayOfMonth);
|
|
||||||
updateCalendarView();
|
|
||||||
notifyDateChanged();
|
|
||||||
}
|
}
|
||||||
|
setDate(year, month, dayOfMonth);
|
||||||
|
notifyDateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override so we are in complete control of save / restore for this widget.
|
// Override so we are in complete control of save / restore for this widget.
|
||||||
@@ -451,15 +481,14 @@ public class DatePicker extends FrameLayout {
|
|||||||
@Override
|
@Override
|
||||||
protected Parcelable onSaveInstanceState() {
|
protected Parcelable onSaveInstanceState() {
|
||||||
Parcelable superState = super.onSaveInstanceState();
|
Parcelable superState = super.onSaveInstanceState();
|
||||||
return new SavedState(superState, mYearSpinner.getValue(), mMonthSpinner.getValue(),
|
return new SavedState(superState, getYear(), getMonth(), getDayOfMonth());
|
||||||
mDaySpinner.getValue());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(Parcelable state) {
|
protected void onRestoreInstanceState(Parcelable state) {
|
||||||
SavedState ss = (SavedState) state;
|
SavedState ss = (SavedState) state;
|
||||||
super.onRestoreInstanceState(ss.getSuperState());
|
super.onRestoreInstanceState(ss.getSuperState());
|
||||||
updateSpinners(ss.mYear, ss.mMonth, ss.mDay);
|
setDate(ss.mYear, ss.mMonth, ss.mDay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -474,10 +503,7 @@ public class DatePicker extends FrameLayout {
|
|||||||
*/
|
*/
|
||||||
public void init(int year, int monthOfYear, int dayOfMonth,
|
public void init(int year, int monthOfYear, int dayOfMonth,
|
||||||
OnDateChangedListener onDateChangedListener) {
|
OnDateChangedListener onDateChangedListener) {
|
||||||
// make sure there is no callback
|
setDate(year, monthOfYear, dayOfMonth);
|
||||||
mOnDateChangedListener = null;
|
|
||||||
updateDate(year, monthOfYear, dayOfMonth);
|
|
||||||
// register the callback after updating the date
|
|
||||||
mOnDateChangedListener = onDateChangedListener;
|
mOnDateChangedListener = onDateChangedListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,104 +540,94 @@ public class DatePicker extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private boolean isNewDate(int year, int month, int dayOfMonth) {
|
||||||
* Updates the spinners with the given <code>year</code>, <code>month</code>
|
return (mCurrentDate.get(Calendar.YEAR) != year
|
||||||
* , and <code>dayOfMonth</code>. If the provided values designate an
|
|| mCurrentDate.get(Calendar.MONTH) != dayOfMonth
|
||||||
* inconsistent date the values are normalized before updating the spinners.
|
|| mCurrentDate.get(Calendar.DAY_OF_MONTH) != month);
|
||||||
*/
|
}
|
||||||
private void updateSpinners(int year, int month, int dayOfMonth) {
|
|
||||||
// compute the deltas before modifying the current date
|
|
||||||
int deltaMonths = getDelataMonth(month);
|
|
||||||
int deltaDays = getDelataDayOfMonth(dayOfMonth);
|
|
||||||
mCurrentDate.set(Calendar.YEAR, year);
|
|
||||||
mCurrentDate.add(Calendar.MONTH, deltaMonths);
|
|
||||||
mCurrentDate.add(Calendar.DAY_OF_MONTH, deltaDays);
|
|
||||||
|
|
||||||
|
private void setDate(int year, int month, int dayOfMonth) {
|
||||||
|
mCurrentDate.set(year, month, dayOfMonth);
|
||||||
if (mCurrentDate.before(mMinDate)) {
|
if (mCurrentDate.before(mMinDate)) {
|
||||||
mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
|
mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
|
||||||
} else if (mCurrentDate.after(mMaxDate)) {
|
} else if (mCurrentDate.after(mMaxDate)) {
|
||||||
mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
|
mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
|
||||||
}
|
}
|
||||||
|
updateSpinners();
|
||||||
|
updateCalendarView();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSpinners() {
|
||||||
|
// set the spinner ranges respecting the min and max dates
|
||||||
|
if (mCurrentDate.equals(mMinDate)) {
|
||||||
|
mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
|
||||||
|
mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||||
|
mDaySpinner.setWrapSelectorWheel(false);
|
||||||
|
mMonthSpinner.setDisplayedValues(null);
|
||||||
|
mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH));
|
||||||
|
mMonthSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.MONTH));
|
||||||
|
mMonthSpinner.setWrapSelectorWheel(false);
|
||||||
|
} else if (mCurrentDate.equals(mMaxDate)) {
|
||||||
|
mDaySpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.DAY_OF_MONTH));
|
||||||
|
mDaySpinner.setMaxValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
|
||||||
|
mDaySpinner.setWrapSelectorWheel(false);
|
||||||
|
mMonthSpinner.setDisplayedValues(null);
|
||||||
|
mMonthSpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.MONTH));
|
||||||
|
mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH));
|
||||||
|
mMonthSpinner.setWrapSelectorWheel(false);
|
||||||
|
} else {
|
||||||
|
mDaySpinner.setMinValue(1);
|
||||||
|
mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||||
|
mDaySpinner.setWrapSelectorWheel(true);
|
||||||
|
mMonthSpinner.setDisplayedValues(null);
|
||||||
|
mMonthSpinner.setMinValue(0);
|
||||||
|
mMonthSpinner.setMaxValue(11);
|
||||||
|
mMonthSpinner.setWrapSelectorWheel(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure the month names are a zero based array
|
||||||
|
// with the months in the month spinner
|
||||||
|
String[] displayedValues = Arrays.copyOfRange(getShortMonths(),
|
||||||
|
mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1);
|
||||||
|
mMonthSpinner.setDisplayedValues(displayedValues);
|
||||||
|
|
||||||
|
// year spinner range does not change based on the current date
|
||||||
|
mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR));
|
||||||
|
mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR));
|
||||||
|
mYearSpinner.setWrapSelectorWheel(false);
|
||||||
|
|
||||||
|
// set the spinner values
|
||||||
mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR));
|
mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR));
|
||||||
mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH));
|
mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH));
|
||||||
mDaySpinner.setMinValue(1);
|
|
||||||
mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
|
|
||||||
mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
|
mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The delta days of moth from the current date and the given
|
* Updates the calendar view with the current date.
|
||||||
* <code>dayOfMonth</code>.
|
|
||||||
*/
|
|
||||||
private int getDelataDayOfMonth(int dayOfMonth) {
|
|
||||||
int prevDayOfMonth = mCurrentDate.get(Calendar.DAY_OF_MONTH);
|
|
||||||
if (prevDayOfMonth == dayOfMonth) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int maxDayOfMonth = mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH);
|
|
||||||
if (dayOfMonth == 1 && prevDayOfMonth == maxDayOfMonth) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (dayOfMonth == maxDayOfMonth && prevDayOfMonth == 1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return dayOfMonth - prevDayOfMonth;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The delta months from the current date and the given
|
|
||||||
* <code>month</code>.
|
|
||||||
*/
|
|
||||||
private int getDelataMonth(int month) {
|
|
||||||
int prevMonth = mCurrentDate.get(Calendar.MONTH);
|
|
||||||
if (prevMonth == month) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (month == 0 && prevMonth == 11) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (month == 11 && prevMonth == 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return month - prevMonth;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the calendar view with the given year, month, and day selected by
|
|
||||||
* the number spinners.
|
|
||||||
*/
|
*/
|
||||||
private void updateCalendarView() {
|
private void updateCalendarView() {
|
||||||
mTempDate.setTimeInMillis(mCalendarView.getDate());
|
mCalendarView.setDate(mCurrentDate.getTimeInMillis(), false, false);
|
||||||
if (mTempDate.get(Calendar.YEAR) != mYearSpinner.getValue()
|
|
||||||
|| mTempDate.get(Calendar.MONTH) != mMonthSpinner.getValue()
|
|
||||||
|| mTempDate.get(Calendar.DAY_OF_MONTH) != mDaySpinner.getValue()) {
|
|
||||||
mTempDate.clear();
|
|
||||||
mTempDate.set(mYearSpinner.getValue(), mMonthSpinner.getValue(),
|
|
||||||
mDaySpinner.getValue());
|
|
||||||
mCalendarView.setDate(mTempDate.getTimeInMillis(), false, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The selected year.
|
* @return The selected year.
|
||||||
*/
|
*/
|
||||||
public int getYear() {
|
public int getYear() {
|
||||||
return mYearSpinner.getValue();
|
return mCurrentDate.get(Calendar.YEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The selected month.
|
* @return The selected month.
|
||||||
*/
|
*/
|
||||||
public int getMonth() {
|
public int getMonth() {
|
||||||
return mMonthSpinner.getValue();
|
return mCurrentDate.get(Calendar.MONTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The selected day of month.
|
* @return The selected day of month.
|
||||||
*/
|
*/
|
||||||
public int getDayOfMonth() {
|
public int getDayOfMonth() {
|
||||||
return mDaySpinner.getValue();
|
return mCurrentDate.get(Calendar.DAY_OF_MONTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -619,8 +635,7 @@ public class DatePicker extends FrameLayout {
|
|||||||
*/
|
*/
|
||||||
private void notifyDateChanged() {
|
private void notifyDateChanged() {
|
||||||
if (mOnDateChangedListener != null) {
|
if (mOnDateChangedListener != null) {
|
||||||
mOnDateChangedListener.onDateChanged(DatePicker.this, mYearSpinner.getValue(),
|
mOnDateChangedListener.onDateChanged(this, getYear(), getMonth(), getDayOfMonth());
|
||||||
mMonthSpinner.getValue(), mDaySpinner.getValue());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -917,6 +917,8 @@ public class NumberPicker extends LinearLayout {
|
|||||||
// force the selector indices array to be reinitialized
|
// force the selector indices array to be reinitialized
|
||||||
mSelectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] = Integer.MAX_VALUE;
|
mSelectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] = Integer.MAX_VALUE;
|
||||||
mWrapSelectorWheel = wrapSelector;
|
mWrapSelectorWheel = wrapSelector;
|
||||||
|
// force redraw since we might look different
|
||||||
|
updateIncrementAndDecrementButtonsVisibilityState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -972,7 +974,6 @@ public class NumberPicker extends LinearLayout {
|
|||||||
setWrapSelectorWheel(wrapSelectorWheel);
|
setWrapSelectorWheel(wrapSelectorWheel);
|
||||||
resetSelectorWheelIndices();
|
resetSelectorWheelIndices();
|
||||||
updateInputTextView();
|
updateInputTextView();
|
||||||
updateIncrementAndDecrementButtonsVisibilityState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1004,7 +1005,6 @@ public class NumberPicker extends LinearLayout {
|
|||||||
setWrapSelectorWheel(wrapSelectorWheel);
|
setWrapSelectorWheel(wrapSelectorWheel);
|
||||||
resetSelectorWheelIndices();
|
resetSelectorWheelIndices();
|
||||||
updateInputTextView();
|
updateInputTextView();
|
||||||
updateIncrementAndDecrementButtonsVisibilityState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user