From 0bfde0a2c262442e36c5d21be9ffbc4a66e4764c Mon Sep 17 00:00:00 2001 From: Tim Su Date: Tue, 13 Jul 2010 01:43:29 -0700 Subject: [PATCH] Custom time picker dialog for setting specific date --- astrid/res/drawable/ic_dialog_time.png | Bin 0 -> 2038 bytes astrid/res/layout/task_edit_activity.xml | 7 + astrid/res/layout/time_picker_dialog.xml | 33 ++++ astrid/res/values/arrays.xml | 11 +- astrid/res/values/strings-3.0.xml | 6 + .../astrid/activity/TaskEditActivity.java | 43 ++-- .../widget/DeadlineTimePickerDialog.java | 187 ++++++++++++++++++ 7 files changed, 259 insertions(+), 28 deletions(-) create mode 100644 astrid/res/drawable/ic_dialog_time.png create mode 100644 astrid/res/layout/time_picker_dialog.xml create mode 100644 astrid/src/com/todoroo/astrid/widget/DeadlineTimePickerDialog.java diff --git a/astrid/res/drawable/ic_dialog_time.png b/astrid/res/drawable/ic_dialog_time.png new file mode 100644 index 0000000000000000000000000000000000000000..337a43acc23ae7527cd17cd496916fe6bf867f91 GIT binary patch literal 2038 zcmVg2N#wPC=0U6E<)^HWbAoOq34G#$<#2^3TT9*rFf|3&IdAih{H@ zwot?qfQC-t_=Jva9z?SYr%-kkfs&wI{$-me?SxpU`)-Qn?gL~(Jk z@caEFKW?oAm4Qm-XFyI(f)b#I^7GQu4@30y^oVpiZ5xBbjsiZPPgGV`iYZg35adSC zdeAzHY??s-fKESq_AC*L#YA6U-^eO3ZrnHxcpwm1ip#^G&qZOzzo6a8Wb!H%dHwoz z;T0h8va+&})9E~j%dKK$M&#YQceRN`qKk^;GMr`;#*7&w7A;!jnmKc39l*DbAb5_g zltEdPN!fWRK$BU#cyVb_QPFu^?%}x=BR?o(4`os|G1yW-f)C;IA}*`N=#Og1zAP~q zPI4Q$$8b0t!WLfCxkBZD?FzcZCr_S;moHz6{{H^K!$<&bw_8k@FhNY6I#qMKFqK@` z28m(e!iB3^TU)!bx!bIV81`2t%_d|ffgt1YxOnvFQR@Bs_hfb&6b1Eyy5uzSDFTJ* zb{!5!O-V_KHy8{GGZT>`*4x{=`r5T?2~!2&ZFpeMo0$z){O;Ym;{N^naR5JnTgO1D z9L>WE+6G1T!?Oiv&6<_VjxSZgF{e`9U-ATy?BQ>fXJ3djb9v+&XFj zypVH`@>zh|O2E>gUH#*+Fefxz>$~4b1e*E}Cxy^^<-GM<_DpQhJKbnx&>*WsY zS3Lz!)A#DttFL5csU>tPR;(ymwrp8=$&w{v?AWn|P$HR1r8ZHPY7(&$^PmY$n>K9@ zKC6wkjt2~f?GV0qWbRF$K7A={vK!yqaIjk7tIOyT3tltr0}In@&LhaEt0*{;&~ z&Ye36xXoYm_plq^NO#Cl#fXjg5#r9|J1C1XRdX_!ozjjs7-`Gs_xSPST6|CI@56<5 zK6vmzKbKMS0(PQGf5>c7nldTdXbv$GyA!86fE!_>i7cD2B9SbMP=E90%|DR(>gSgt zAYGV0fBqV#40-NCgt8S%hKbz?O_V_k)l!qf*MEEK)~(-RvqK6tC~zP*Q?(uA#nmv2=_8Bu~*fu3I*~IR4xm+P$DAIUTMI|=r^hYR#4aw|W!`iQDX5nG7O~NF!4)^NIPLCgK7oL;RoIB#iCVKmQnm^kvGWWxvx{Jq z*CXFpkF>y>OeRyKsX%dYv6r%qb^ysF&p10n&PgJ3)AKqkRCg6+)aZn~@8_kiJ zlUh2B)jea9bL=ZADRGU~>QfeFDk~p}Su1F;9e=@|RI4%%(RD|G3Kn6K->|&hL758M z*D&jA;!foE%__!-l!xbFFb5y0LEe->St=~VnsK{>T?wSFhfH?ChdT5W(&PXI6?)~# zle{T|vQ(>2tb+@y`>_dWaWgw^DpNxJdo~;nm(pt$3Osp{CwZ$(huDabShFd>{Cg+z zm;n=kOFbUXTM(XR8k!Cr_Rw(;QKYm8Ni~k zjakcL-_)Z;A`vSxco^$^KHp|`9wttlSPti@Uf}D;A>FOX3#pg+ZuMJ>9P2Roy6C*TGJ<; zX7QmBJqr&g+#_8sTZfG@me{M@jvqf>C==HI-A4bH8zF}N)kgcf4TEbTg#IVM00Ijn Um%?atR{#J207*qoM6N<$f-WfJ?*IS* literal 0 HcmV?d00001 diff --git a/astrid/res/layout/task_edit_activity.xml b/astrid/res/layout/task_edit_activity.xml index af3df49b3..ac25a283a 100644 --- a/astrid/res/layout/task_edit_activity.xml +++ b/astrid/res/layout/task_edit_activity.xml @@ -69,6 +69,13 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" /> + + + + + + + + + + diff --git a/astrid/res/values/arrays.xml b/astrid/res/values/arrays.xml index 19b46080c..a620e3995 100644 --- a/astrid/res/values/arrays.xml +++ b/astrid/res/values/arrays.xml @@ -30,14 +30,12 @@ - No Urgency + Specific Day/Time Today Tomorrow - + (day after) Next Week - Next Month - Specific Day - Specific Day & Time + No Deadline @@ -61,12 +59,11 @@ - No Urgency + No Deadline Today Tomorrow Day After Tomorrow Next Week - Next Month diff --git a/astrid/res/values/strings-3.0.xml b/astrid/res/values/strings-3.0.xml index 9c547fe22..4234ef431 100644 --- a/astrid/res/values/strings-3.0.xml +++ b/astrid/res/values/strings-3.0.xml @@ -268,6 +268,12 @@ to the plugin creator for fastest service. Deadline + + Due at specific time? + + + No Due Time + Hide Until diff --git a/astrid/src/com/todoroo/astrid/activity/TaskEditActivity.java b/astrid/src/com/todoroo/astrid/activity/TaskEditActivity.java index ab2680461..cae1f799a 100644 --- a/astrid/src/com/todoroo/astrid/activity/TaskEditActivity.java +++ b/astrid/src/com/todoroo/astrid/activity/TaskEditActivity.java @@ -27,10 +27,8 @@ import java.util.List; import android.app.AlertDialog; import android.app.DatePickerDialog; -import android.app.DatePickerDialog.OnDateSetListener; import android.app.TabActivity; -import android.app.TimePickerDialog; -import android.app.TimePickerDialog.OnTimeSetListener; +import android.app.DatePickerDialog.OnDateSetListener; import android.content.BroadcastReceiver; import android.content.ContentValues; import android.content.Context; @@ -45,7 +43,6 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; @@ -60,6 +57,7 @@ import android.widget.TabHost; import android.widget.TimePicker; import android.widget.Toast; import android.widget.ToggleButton; +import android.widget.AdapterView.OnItemSelectedListener; import com.flurry.android.FlurryAgent; import com.timsu.astrid.R; @@ -81,6 +79,8 @@ import com.todoroo.astrid.service.StartupService; import com.todoroo.astrid.service.TaskService; import com.todoroo.astrid.tags.TagsControlSet; import com.todoroo.astrid.utility.Constants; +import com.todoroo.astrid.widget.DeadlineTimePickerDialog; +import com.todoroo.astrid.widget.DeadlineTimePickerDialog.OnDeadlineTimeSetListener; /** * This activity is responsible for creating new tasks and editing existing @@ -693,7 +693,7 @@ public final class TaskEditActivity extends TabActivity { // --- UrgencyControlSet private class UrgencyControlSet implements TaskEditControlSet, - OnItemSelectedListener, OnTimeSetListener, OnDateSetListener { + OnItemSelectedListener, OnDeadlineTimeSetListener, OnDateSetListener { private static final long SPECIFIC_DATE = -1; @@ -742,24 +742,20 @@ public final class TaskEditActivity extends TabActivity { // set up base urgency list String[] labels = getResources().getStringArray(R.array.TEA_urgency); UrgencyValue[] urgencyValues = new UrgencyValue[labels.length]; - urgencyValues[0] = new UrgencyValue(labels[Task.URGENCY_NONE], - Task.URGENCY_NONE); - urgencyValues[1] = new UrgencyValue(labels[Task.URGENCY_TODAY], + urgencyValues[0] = new UrgencyValue(labels[0], + Task.URGENCY_SPECIFIC_DAY_TIME, SPECIFIC_DATE); + urgencyValues[1] = new UrgencyValue(labels[1], Task.URGENCY_TODAY); - urgencyValues[2] = new UrgencyValue(labels[Task.URGENCY_TOMORROW], + urgencyValues[2] = new UrgencyValue(labels[2], Task.URGENCY_TOMORROW); String dayAfterTomorrow = new SimpleDateFormat("EEEE").format( //$NON-NLS-1$ new Date(DateUtilities.now() + 2 * DateUtilities.ONE_DAY)); urgencyValues[3] = new UrgencyValue(dayAfterTomorrow, Task.URGENCY_DAY_AFTER); - urgencyValues[4] = new UrgencyValue(labels[Task.URGENCY_NEXT_WEEK], + urgencyValues[4] = new UrgencyValue(labels[4], Task.URGENCY_NEXT_WEEK); - urgencyValues[5] = new UrgencyValue(labels[Task.URGENCY_NEXT_MONTH], - Task.URGENCY_NEXT_MONTH); - urgencyValues[6] = new UrgencyValue(labels[Task.URGENCY_SPECIFIC_DAY], - Task.URGENCY_SPECIFIC_DAY, SPECIFIC_DATE); - urgencyValues[7] = new UrgencyValue(labels[Task.URGENCY_SPECIFIC_DAY_TIME], - Task.URGENCY_SPECIFIC_DAY_TIME, SPECIFIC_DATE); + urgencyValues[5] = new UrgencyValue(labels[5], + Task.URGENCY_NONE); // search for setting int selection = -1; @@ -830,14 +826,18 @@ public final class TaskEditActivity extends TabActivity { return; } - new TimePickerDialog(TaskEditActivity.this, this, + new DeadlineTimePickerDialog(TaskEditActivity.this, this, customDate.getHours(), customDate.getMinutes(), DateUtilities.is24HourFormat(TaskEditActivity.this)).show(); } - public void onTimeSet(TimePicker view, int hourOfDay, int minute) { - customDate.setHours(hourOfDay); - customDate.setMinutes(minute); + public void onTimeSet(TimePicker view, boolean hasTime, int hourOfDay, int minute) { + if(!hasTime) + customSetting = Task.URGENCY_SPECIFIC_DAY; + else { + customDate.setHours(hourOfDay); + customDate.setMinutes(minute); + } customDateFinished(); } @@ -857,7 +857,8 @@ public final class TaskEditActivity extends TabActivity { @Override public void writeToModel(Task task) { UrgencyValue item = urgencyAdapter.getItem(urgency.getSelectedItemPosition()); - task.setValue(Task.DUE_DATE, item.dueDate); + if(item.dueDate != SPECIFIC_DATE) // user cancelled specific date + task.setValue(Task.DUE_DATE, item.dueDate); } } diff --git a/astrid/src/com/todoroo/astrid/widget/DeadlineTimePickerDialog.java b/astrid/src/com/todoroo/astrid/widget/DeadlineTimePickerDialog.java new file mode 100644 index 000000000..78b03b911 --- /dev/null +++ b/astrid/src/com/todoroo/astrid/widget/DeadlineTimePickerDialog.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.todoroo.astrid.widget; + +import java.util.Calendar; + +import android.app.AlertDialog; +import android.app.TimePickerDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.os.Bundle; +import android.text.format.DateFormat; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.TimePicker; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.TimePicker.OnTimeChangedListener; + +import com.timsu.astrid.R; + +/** + * A dialog that prompts the user for the time of day using a {@link TimePicker}. + * This is similar to the Android {@link TimePickerDialog} class + * except allows users to specify "no specific time". + */ +@SuppressWarnings("nls") +public class DeadlineTimePickerDialog extends AlertDialog implements OnClickListener, + OnTimeChangedListener { + + /** + * The callback interface used to indicate the user is done filling in + * the time (they clicked on the 'Set' button). + */ + public interface OnDeadlineTimeSetListener { + + /** + * @param view The view associated with this listener. + * @param hasTime whether time is set + * @param hourOfDay The hour that was set. + * @param minute The minute that was set. + */ + void onTimeSet(TimePicker view, boolean hasTime, int hourOfDay, int minute); + } + + private static final String HOUR = "hour"; + private static final String MINUTE = "minute"; + private static final String IS_24_HOUR = "is24hour"; + + private final TimePicker mTimePicker; + private final CheckBox mHasTime; + private final OnDeadlineTimeSetListener mCallback; + private final Calendar mCalendar; + private final java.text.DateFormat mDateFormat; + + int mInitialHourOfDay; + int mInitialMinute; + boolean mIs24HourView; + + /** + * @param context Parent. + * @param callBack How parent is notified. + * @param hourOfDay The initial hour. + * @param minute The initial minute. + * @param is24HourView Whether this is a 24 hour view, or AM/PM. + */ + public DeadlineTimePickerDialog(Context context, + OnDeadlineTimeSetListener callBack, + int hourOfDay, int minute, boolean is24HourView) { + this(context, android.R.style.Theme_Dialog, + callBack, hourOfDay, minute, is24HourView); + } + + /** + * @param context Parent. + * @param theme the theme to apply to this dialog + * @param callBack How parent is notified. + * @param hourOfDay The initial hour. + * @param minute The initial minute. + * @param is24HourView Whether this is a 24 hour view, or AM/PM. + */ + public DeadlineTimePickerDialog(Context context, + int theme, + OnDeadlineTimeSetListener callBack, + int hourOfDay, int minute, boolean is24HourView) { + super(context, theme); + mCallback = callBack; + mInitialHourOfDay = hourOfDay; + mInitialMinute = minute; + mIs24HourView = is24HourView; + + mDateFormat = DateFormat.getTimeFormat(context); + mCalendar = Calendar.getInstance(); + updateTitle(mInitialHourOfDay, mInitialMinute); + + setButton(context.getText(android.R.string.ok), this); + setButton2(context.getText(android.R.string.cancel), (OnClickListener) null); + setIcon(R.drawable.ic_dialog_time); + + LayoutInflater inflater = + (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View view = inflater.inflate(R.layout.time_picker_dialog, null); + setView(view); + mTimePicker = (TimePicker) view.findViewById(R.id.timePicker); + mHasTime = (CheckBox) view.findViewById(R.id.hasTime); + mHasTime.setOnCheckedChangeListener(new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, + boolean isChecked) { + mTimePicker.setEnabled(isChecked); + if(isChecked) + updateTitle(mTimePicker.getCurrentHour(), mTimePicker.getCurrentMinute()); + else + setTitle(R.string.TEA_urgency_time_none); + } + }); + mHasTime.setChecked(true); + + // initialize state + mTimePicker.setCurrentHour(mInitialHourOfDay); + mTimePicker.setCurrentMinute(mInitialMinute); + mTimePicker.setIs24HourView(mIs24HourView); + mTimePicker.setOnTimeChangedListener(this); + } + + public void onClick(DialogInterface dialog, int which) { + if (mCallback != null) { + mTimePicker.clearFocus(); + mCallback.onTimeSet(mTimePicker, + mHasTime.isChecked(), + mTimePicker.getCurrentHour(), + mTimePicker.getCurrentMinute()); + } + } + + public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { + updateTitle(hourOfDay, minute); + } + + public void updateTime(int hourOfDay, int minutOfHour) { + mTimePicker.setCurrentHour(hourOfDay); + mTimePicker.setCurrentMinute(minutOfHour); + } + + private void updateTitle(int hour, int minute) { + mCalendar.set(Calendar.HOUR_OF_DAY, hour); + mCalendar.set(Calendar.MINUTE, minute); + setTitle(mDateFormat.format(mCalendar.getTime())); + } + + @Override + public Bundle onSaveInstanceState() { + Bundle state = super.onSaveInstanceState(); + state.putInt(HOUR, mTimePicker.getCurrentHour()); + state.putInt(MINUTE, mTimePicker.getCurrentMinute()); + state.putBoolean(IS_24_HOUR, mTimePicker.is24HourView()); + return state; + } + + @Override + public void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + int hour = savedInstanceState.getInt(HOUR); + int minute = savedInstanceState.getInt(MINUTE); + mTimePicker.setCurrentHour(hour); + mTimePicker.setCurrentMinute(minute); + mTimePicker.setIs24HourView(savedInstanceState.getBoolean(IS_24_HOUR)); + mTimePicker.setOnTimeChangedListener(this); + updateTitle(hour, minute); + } +}