// Implements android.widget.RadioGroup.OnCheckedChangeListener interface // Month repeat by radio buttons @Override public void onCheckedChanged(RadioGroup group, int checkedId) { if (checkedId == R.id.repeatMonthlyByNthDayOfMonth) { mModel.monthlyRepeat = RecurrenceModel.MONTHLY_BY_DATE; } else if (checkedId == R.id.repeatMonthlyByNthDayOfTheWeek) { mModel.monthlyRepeat = RecurrenceModel.MONTHLY_BY_NTH_DAY_OF_WEEK; } updateDialog(); }
// Implements OnItemSelectedListener interface // Freq spinner // End spinner @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { if (parent == mFreqSpinner) { mModel.freq = position; } else if (parent == mEndSpinner) { switch (position) { case RecurrenceModel.END_NEVER: mModel.end = RecurrenceModel.END_NEVER; break; case RecurrenceModel.END_BY_DATE: mModel.end = RecurrenceModel.END_BY_DATE; break; case RecurrenceModel.END_BY_COUNT: mModel.end = RecurrenceModel.END_BY_COUNT; if (mModel.endCount <= 1) { mModel.endCount = 1; } else if (mModel.endCount > COUNT_MAX) { mModel.endCount = COUNT_MAX; } updateEndCountText(); break; } mEndCount.setVisibility( mModel.end == RecurrenceModel.END_BY_COUNT ? View.VISIBLE : View.GONE); mEndDateTextView.setVisibility( mModel.end == RecurrenceModel.END_BY_DATE ? View.VISIBLE : View.GONE); mPostEndCount.setVisibility( mModel.end == RecurrenceModel.END_BY_COUNT && !mHidePostEndCount ? View.VISIBLE : View.GONE); } updateDialog(); }
@Override public void onDateSet( CalendarDatePickerDialogFragment view, int year, int monthOfYear, int dayOfMonth) { if (mModel.endDate == null) { mModel.endDate = new Time(mTime.timezone); mModel.endDate.hour = mModel.endDate.minute = mModel.endDate.second = 0; } mModel.endDate.year = year; mModel.endDate.month = monthOfYear; mModel.endDate.monthDay = dayOfMonth; mModel.endDate.normalize(false); updateDialog(); }
private void doToast() { Log.e(TAG, "Model = " + mModel.toString()); String rrule; if (mModel.recurrenceState == RecurrenceModel.STATE_NO_RECURRENCE) { rrule = "Not repeating"; } else { copyModelToEventRecurrence(mModel, mRecurrence); rrule = mRecurrence.toString(); } if (mToast != null) { mToast.cancel(); } mToast = Toast.makeText(getActivity(), rrule, Toast.LENGTH_LONG); mToast.show(); }
@Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mRecurrence.wkst = EventRecurrence.timeDay2Day(Utils.getFirstDayOfWeek(getActivity())); getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE); boolean endCountHasFocus = false; if (savedInstanceState != null) { RecurrenceModel m = (RecurrenceModel) savedInstanceState.get(BUNDLE_MODEL); if (m != null) { mModel = m; } endCountHasFocus = savedInstanceState.getBoolean(BUNDLE_END_COUNT_HAS_FOCUS); } else { Bundle bundle = getArguments(); if (bundle != null) { mTime.set(bundle.getLong(BUNDLE_START_TIME_MILLIS)); String tz = bundle.getString(BUNDLE_TIME_ZONE); if (!TextUtils.isEmpty(tz)) { mTime.timezone = tz; } mTime.normalize(false); // Time days of week: Sun=0, Mon=1, etc mModel.weeklyByDayOfWeek[mTime.weekDay] = true; String rrule = bundle.getString(BUNDLE_RRULE); if (!TextUtils.isEmpty(rrule)) { mModel.recurrenceState = RecurrenceModel.STATE_RECURRENCE; mRecurrence.parse(rrule); copyEventRecurrenceToModel(mRecurrence, mModel); // Leave today's day of week as checked by default in weekly view. if (mRecurrence.bydayCount == 0) { mModel.weeklyByDayOfWeek[mTime.weekDay] = true; } } mModel.forceHideSwitchButton = bundle.getBoolean(BUNDLE_HIDE_SWITCH_BUTTON, false); } else { mTime.setToNow(); } } mResources = getResources(); mView = inflater.inflate(R.layout.recurrencepicker, container, true); final Activity activity = getActivity(); final Configuration config = activity.getResources().getConfiguration(); mRepeatSwitch = (SwitchCompat) mView.findViewById(R.id.repeat_switch); if (mModel.forceHideSwitchButton) { mRepeatSwitch.setChecked(true); mRepeatSwitch.setVisibility(View.GONE); mModel.recurrenceState = RecurrenceModel.STATE_RECURRENCE; } else { mRepeatSwitch.setChecked(mModel.recurrenceState == RecurrenceModel.STATE_RECURRENCE); mRepeatSwitch.setOnCheckedChangeListener( new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { mModel.recurrenceState = isChecked ? RecurrenceModel.STATE_RECURRENCE : RecurrenceModel.STATE_NO_RECURRENCE; togglePickerOptions(); } }); } mFreqSpinner = (Spinner) mView.findViewById(R.id.freqSpinner); mFreqSpinner.setOnItemSelectedListener(this); ArrayAdapter<CharSequence> freqAdapter = ArrayAdapter.createFromResource( getActivity(), R.array.recurrence_freq, R.layout.recurrencepicker_freq_item); freqAdapter.setDropDownViewResource(R.layout.recurrencepicker_freq_item); mFreqSpinner.setAdapter(freqAdapter); mInterval = (EditText) mView.findViewById(R.id.interval); mInterval.addTextChangedListener( new minMaxTextWatcher(1, INTERVAL_DEFAULT, INTERVAL_MAX) { @Override void onChange(int v) { if (mIntervalResId != -1 && mInterval.getText().toString().length() > 0) { mModel.interval = v; updateIntervalText(); mInterval.requestLayout(); } } }); mIntervalPreText = (TextView) mView.findViewById(R.id.intervalPreText); mIntervalPostText = (TextView) mView.findViewById(R.id.intervalPostText); mEndNeverStr = mResources.getString(R.string.recurrence_end_continously); mEndDateLabel = mResources.getString(R.string.recurrence_end_date_label); mEndCountLabel = mResources.getString(R.string.recurrence_end_count_label); mEndSpinnerArray.add(mEndNeverStr); mEndSpinnerArray.add(mEndDateLabel); mEndSpinnerArray.add(mEndCountLabel); mEndSpinner = (Spinner) mView.findViewById(R.id.endSpinner); mEndSpinner.setOnItemSelectedListener(this); mEndSpinnerAdapter = new EndSpinnerAdapter( getActivity(), mEndSpinnerArray, R.layout.recurrencepicker_freq_item, R.layout.recurrencepicker_end_text); mEndSpinnerAdapter.setDropDownViewResource(R.layout.recurrencepicker_freq_item); mEndSpinner.setAdapter(mEndSpinnerAdapter); mEndCount = (EditText) mView.findViewById(R.id.endCount); mEndCount.addTextChangedListener( new minMaxTextWatcher(1, COUNT_DEFAULT, COUNT_MAX) { @Override void onChange(int v) { if (mModel.endCount != v) { mModel.endCount = v; updateEndCountText(); mEndCount.requestLayout(); } } }); mPostEndCount = (TextView) mView.findViewById(R.id.postEndCount); mEndDateTextView = (TextView) mView.findViewById(R.id.endDate); mEndDateTextView.setOnClickListener(this); if (mModel.endDate == null) { mModel.endDate = new Time(mTime); switch (mModel.freq) { case RecurrenceModel.FREQ_HOURLY: case RecurrenceModel.FREQ_DAILY: case RecurrenceModel.FREQ_WEEKLY: mModel.endDate.month += 1; break; case RecurrenceModel.FREQ_MONTHLY: mModel.endDate.month += 3; break; case RecurrenceModel.FREQ_YEARLY: mModel.endDate.year += 3; break; } mModel.endDate.normalize(false); } mWeekGroup = (LinearLayout) mView.findViewById(R.id.weekGroup); mWeekGroup2 = (LinearLayout) mView.findViewById(R.id.weekGroup2); // In Calendar.java day of week order e.g Sun = 1 ... Sat = 7 String[] dayOfWeekString = new DateFormatSymbols().getWeekdays(); mMonthRepeatByDayOfWeekStrs = new String[7][]; // from Time.SUNDAY as 0 through Time.SATURDAY as 6 mMonthRepeatByDayOfWeekStrs[0] = mResources.getStringArray(R.array.repeat_by_nth_sun); mMonthRepeatByDayOfWeekStrs[1] = mResources.getStringArray(R.array.repeat_by_nth_mon); mMonthRepeatByDayOfWeekStrs[2] = mResources.getStringArray(R.array.repeat_by_nth_tues); mMonthRepeatByDayOfWeekStrs[3] = mResources.getStringArray(R.array.repeat_by_nth_wed); mMonthRepeatByDayOfWeekStrs[4] = mResources.getStringArray(R.array.repeat_by_nth_thurs); mMonthRepeatByDayOfWeekStrs[5] = mResources.getStringArray(R.array.repeat_by_nth_fri); mMonthRepeatByDayOfWeekStrs[6] = mResources.getStringArray(R.array.repeat_by_nth_sat); // In Time.java day of week order e.g. Sun = 0 int idx = Utils.getFirstDayOfWeek(getActivity()); // In Calendar.java day of week order e.g Sun = 1 ... Sat = 7 dayOfWeekString = new DateFormatSymbols().getShortWeekdays(); int numOfButtonsInRow1; int numOfButtonsInRow2; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR2) { // Get screen width in dp first Display display = getActivity().getWindowManager().getDefaultDisplay(); DisplayMetrics outMetrics = new DisplayMetrics(); display.getMetrics(outMetrics); float density = getResources().getDisplayMetrics().density; float dpWidth = outMetrics.widthPixels / density; if (dpWidth > MIN_SCREEN_WIDTH_FOR_SINGLE_ROW_WEEK) { numOfButtonsInRow1 = 7; numOfButtonsInRow2 = 0; mWeekGroup2.setVisibility(View.GONE); mWeekGroup2.getChildAt(3).setVisibility(View.GONE); } else { numOfButtonsInRow1 = 4; numOfButtonsInRow2 = 3; mWeekGroup2.setVisibility(View.VISIBLE); // Set rightmost button on the second row invisible so it takes up // space and everything centers properly mWeekGroup2.getChildAt(3).setVisibility(View.INVISIBLE); } } else if (mResources.getConfiguration().screenWidthDp > MIN_SCREEN_WIDTH_FOR_SINGLE_ROW_WEEK) { numOfButtonsInRow1 = 7; numOfButtonsInRow2 = 0; mWeekGroup2.setVisibility(View.GONE); mWeekGroup2.getChildAt(3).setVisibility(View.GONE); } else { numOfButtonsInRow1 = 4; numOfButtonsInRow2 = 3; mWeekGroup2.setVisibility(View.VISIBLE); // Set rightmost button on the second row invisible so it takes up // space and everything centers properly mWeekGroup2.getChildAt(3).setVisibility(View.INVISIBLE); } /* First row */ for (int i = 0; i < 7; i++) { if (i >= numOfButtonsInRow1) { mWeekGroup.getChildAt(i).setVisibility(View.GONE); continue; } mWeekByDayButtons[idx] = (ToggleButton) mWeekGroup.getChildAt(i); mWeekByDayButtons[idx].setTextOff(dayOfWeekString[TIME_DAY_TO_CALENDAR_DAY[idx]]); mWeekByDayButtons[idx].setTextOn(dayOfWeekString[TIME_DAY_TO_CALENDAR_DAY[idx]]); mWeekByDayButtons[idx].setOnCheckedChangeListener(this); if (++idx >= 7) { idx = 0; } } /* 2nd Row */ for (int i = 0; i < 3; i++) { if (i >= numOfButtonsInRow2) { mWeekGroup2.getChildAt(i).setVisibility(View.GONE); continue; } mWeekByDayButtons[idx] = (ToggleButton) mWeekGroup2.getChildAt(i); mWeekByDayButtons[idx].setTextOff(dayOfWeekString[TIME_DAY_TO_CALENDAR_DAY[idx]]); mWeekByDayButtons[idx].setTextOn(dayOfWeekString[TIME_DAY_TO_CALENDAR_DAY[idx]]); mWeekByDayButtons[idx].setOnCheckedChangeListener(this); if (++idx >= 7) { idx = 0; } } mMonthGroup = (LinearLayout) mView.findViewById(R.id.monthGroup); mMonthRepeatByRadioGroup = (RadioGroup) mView.findViewById(R.id.monthGroup); mMonthRepeatByRadioGroup.setOnCheckedChangeListener(this); mRepeatMonthlyByNthDayOfWeek = (RadioButton) mView.findViewById(R.id.repeatMonthlyByNthDayOfTheWeek); mRepeatMonthlyByNthDayOfMonth = (RadioButton) mView.findViewById(R.id.repeatMonthlyByNthDayOfMonth); mDoneButton = (Button) mView.findViewById(R.id.done_button); mDoneButton.setOnClickListener(this); Button cancelButton = (Button) mView.findViewById(R.id.cancel_button); // FIXME no text color for this one ? cancelButton.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { dismiss(); } }); togglePickerOptions(); updateDialog(); if (endCountHasFocus) { mEndCount.requestFocus(); } return mView; }
private static void copyModelToEventRecurrence(final RecurrenceModel model, EventRecurrence er) { if (model.recurrenceState == RecurrenceModel.STATE_NO_RECURRENCE) { throw new IllegalStateException("There's no recurrence"); } // Freq er.freq = mFreqModelToEventRecurrence[model.freq]; // Interval if (model.interval <= 1) { er.interval = 0; } else { er.interval = model.interval; } // End switch (model.end) { case RecurrenceModel.END_BY_DATE: if (model.endDate != null) { model.endDate.switchTimezone(Time.TIMEZONE_UTC); model.endDate.normalize(false); er.until = model.endDate.format2445(); er.count = 0; } else { throw new IllegalStateException("end = END_BY_DATE but endDate is null"); } break; case RecurrenceModel.END_BY_COUNT: er.count = model.endCount; er.until = null; if (er.count <= 0) { throw new IllegalStateException("count is " + er.count); } break; default: er.count = 0; er.until = null; break; } // Weekly && monthly repeat patterns er.bydayCount = 0; er.bymonthdayCount = 0; switch (model.freq) { case RecurrenceModel.FREQ_MONTHLY: if (model.monthlyRepeat == RecurrenceModel.MONTHLY_BY_DATE) { if (model.monthlyByMonthDay > 0) { if (er.bymonthday == null || er.bymonthdayCount < 1) { er.bymonthday = new int[1]; } er.bymonthday[0] = model.monthlyByMonthDay; er.bymonthdayCount = 1; } } else if (model.monthlyRepeat == RecurrenceModel.MONTHLY_BY_NTH_DAY_OF_WEEK) { if (!isSupportedMonthlyByNthDayOfWeek(model.monthlyByNthDayOfWeek)) { throw new IllegalStateException( "month repeat by nth week but n is " + model.monthlyByNthDayOfWeek); } int count = 1; if (er.bydayCount < count || er.byday == null || er.bydayNum == null) { er.byday = new int[count]; er.bydayNum = new int[count]; } er.bydayCount = count; er.byday[0] = EventRecurrence.timeDay2Day(model.monthlyByDayOfWeek); er.bydayNum[0] = model.monthlyByNthDayOfWeek; } break; case RecurrenceModel.FREQ_WEEKLY: int count = 0; for (int i = 0; i < 7; i++) { if (model.weeklyByDayOfWeek[i]) { count++; } } if (er.bydayCount < count || er.byday == null || er.bydayNum == null) { er.byday = new int[count]; er.bydayNum = new int[count]; } er.bydayCount = count; for (int i = 6; i >= 0; i--) { if (model.weeklyByDayOfWeek[i]) { er.bydayNum[--count] = 0; er.byday[count] = EventRecurrence.timeDay2Day(i); } } break; } if (!canHandleRecurrenceRule(er)) { throw new IllegalStateException( "UI generated recurrence that it can't handle. ER:" + er.toString() + " Model: " + model.toString()); } }
// TODO don't lose data when getting data that our UI can't handle private static void copyEventRecurrenceToModel(final EventRecurrence er, RecurrenceModel model) { // Freq: switch (er.freq) { case EventRecurrence.HOURLY: model.freq = RecurrenceModel.FREQ_HOURLY; break; case EventRecurrence.DAILY: model.freq = RecurrenceModel.FREQ_DAILY; break; case EventRecurrence.MONTHLY: model.freq = RecurrenceModel.FREQ_MONTHLY; break; case EventRecurrence.YEARLY: model.freq = RecurrenceModel.FREQ_YEARLY; break; case EventRecurrence.WEEKLY: model.freq = RecurrenceModel.FREQ_WEEKLY; break; default: throw new IllegalStateException("freq=" + er.freq); } // Interval: if (er.interval > 0) { model.interval = er.interval; } // End: // End by count: model.endCount = er.count; if (model.endCount > 0) { model.end = RecurrenceModel.END_BY_COUNT; } // End by date: if (!TextUtils.isEmpty(er.until)) { if (model.endDate == null) { model.endDate = new Time(); } try { model.endDate.parse(er.until); } catch (TimeFormatException e) { model.endDate = null; } // LIMITATION: The UI can only handle END_BY_DATE or END_BY_COUNT if (model.end == RecurrenceModel.END_BY_COUNT && model.endDate != null) { throw new IllegalStateException("freq=" + er.freq); } model.end = RecurrenceModel.END_BY_DATE; } // Weekly: repeat by day of week or Monthly: repeat by nth day of week // in the month Arrays.fill(model.weeklyByDayOfWeek, false); if (er.bydayCount > 0) { int count = 0; for (int i = 0; i < er.bydayCount; i++) { int dayOfWeek = EventRecurrence.day2TimeDay(er.byday[i]); model.weeklyByDayOfWeek[dayOfWeek] = true; if (model.freq == RecurrenceModel.FREQ_MONTHLY && isSupportedMonthlyByNthDayOfWeek(er.bydayNum[i])) { // LIMITATION: Can handle only (one) weekDayNum in nth or last and only // when // monthly model.monthlyByDayOfWeek = dayOfWeek; model.monthlyByNthDayOfWeek = er.bydayNum[i]; model.monthlyRepeat = RecurrenceModel.MONTHLY_BY_NTH_DAY_OF_WEEK; count++; } } if (model.freq == RecurrenceModel.FREQ_MONTHLY) { if (er.bydayCount != 1) { // Can't handle 1st Monday and 2nd Wed throw new IllegalStateException("Can handle only 1 byDayOfWeek in monthly"); } if (count != 1) { throw new IllegalStateException( "Didn't specify which nth day of week to repeat for a monthly"); } } } // Monthly by day of month if (model.freq == RecurrenceModel.FREQ_MONTHLY) { if (er.bymonthdayCount == 1) { if (model.monthlyRepeat == RecurrenceModel.MONTHLY_BY_NTH_DAY_OF_WEEK) { throw new IllegalStateException( "Can handle only by monthday or by nth day of week, not both"); } model.monthlyByMonthDay = er.bymonthday[0]; model.monthlyRepeat = RecurrenceModel.MONTHLY_BY_DATE; } else if (er.bymonthCount > 1) { // LIMITATION: Can handle only one month day throw new IllegalStateException("Can handle only one bymonthday"); } } }
public void updateDialog() { // Interval // Checking before setting because this causes infinite recursion // in afterTextWatcher final String intervalStr = Integer.toString(mModel.interval); if (!intervalStr.equals(mInterval.getText().toString())) { mInterval.setText(intervalStr); } mFreqSpinner.setSelection(mModel.freq); mWeekGroup.setVisibility(mModel.freq == RecurrenceModel.FREQ_WEEKLY ? View.VISIBLE : View.GONE); mWeekGroup2.setVisibility( mModel.freq == RecurrenceModel.FREQ_WEEKLY ? View.VISIBLE : View.GONE); mMonthGroup.setVisibility( mModel.freq == RecurrenceModel.FREQ_MONTHLY ? View.VISIBLE : View.GONE); switch (mModel.freq) { case RecurrenceModel.FREQ_HOURLY: mIntervalResId = R.plurals.recurrence_interval_hourly; break; case RecurrenceModel.FREQ_DAILY: mIntervalResId = R.plurals.recurrence_interval_daily; break; case RecurrenceModel.FREQ_WEEKLY: mIntervalResId = R.plurals.recurrence_interval_weekly; for (int i = 0; i < 7; i++) { mWeekByDayButtons[i].setChecked(mModel.weeklyByDayOfWeek[i]); } break; case RecurrenceModel.FREQ_MONTHLY: mIntervalResId = R.plurals.recurrence_interval_monthly; if (mModel.monthlyRepeat == RecurrenceModel.MONTHLY_BY_DATE) { mMonthRepeatByRadioGroup.check(R.id.repeatMonthlyByNthDayOfMonth); } else if (mModel.monthlyRepeat == RecurrenceModel.MONTHLY_BY_NTH_DAY_OF_WEEK) { mMonthRepeatByRadioGroup.check(R.id.repeatMonthlyByNthDayOfTheWeek); } if (mMonthRepeatByDayOfWeekStr == null) { if (mModel.monthlyByNthDayOfWeek == 0) { mModel.monthlyByNthDayOfWeek = (mTime.monthDay + 6) / 7; // Since not all months have 5 weeks, we convert 5th NthDayOfWeek to // -1 for last monthly day of the week if (mModel.monthlyByNthDayOfWeek >= FIFTH_WEEK_IN_A_MONTH) { mModel.monthlyByNthDayOfWeek = LAST_NTH_DAY_OF_WEEK; } mModel.monthlyByDayOfWeek = mTime.weekDay; } String[] monthlyByNthDayOfWeekStrs = mMonthRepeatByDayOfWeekStrs[mModel.monthlyByDayOfWeek]; // TODO(psliwowski): Find a better way handle -1 indexes int msgIndex = mModel.monthlyByNthDayOfWeek < 0 ? FIFTH_WEEK_IN_A_MONTH : mModel.monthlyByNthDayOfWeek; mMonthRepeatByDayOfWeekStr = monthlyByNthDayOfWeekStrs[msgIndex - 1]; mRepeatMonthlyByNthDayOfWeek.setText(mMonthRepeatByDayOfWeekStr); } break; case RecurrenceModel.FREQ_YEARLY: mIntervalResId = R.plurals.recurrence_interval_yearly; break; } updateIntervalText(); updateDoneButtonState(); mEndSpinner.setSelection(mModel.end); if (mModel.end == RecurrenceModel.END_BY_DATE) { final String dateStr = DateUtils.formatDateTime( getActivity(), mModel.endDate.toMillis(false), DateUtils.FORMAT_NUMERIC_DATE); mEndDateTextView.setText(dateStr); } else { if (mModel.end == RecurrenceModel.END_BY_COUNT) { // Checking before setting because this causes infinite // recursion // in afterTextWatcher final String countStr = Integer.toString(mModel.endCount); if (!countStr.equals(mEndCount.getText().toString())) { mEndCount.setText(countStr); } } } }