source: trunk/hiptop/pester/net/sabi/pester/AlarmSetDialog.java@ 270

Last change on this file since 270 was 270, checked in by Nicholas Riley, 18 years ago

Fix auto-day increment (Date.setToday() doesn't set today, it sets _now_). Save/restore the period regardless of the alarm type, so we don't end up with 1-second periods. Read the time from the time editor when the date picker is focused - less consistency, but easier to understand.

File size: 8.6 KB
Line 
1package net.sabi.pester;
2
3import danger.app.Application;
4import danger.app.Event;
5import danger.audio.ToneClass;
6import danger.audio.ToneRights;
7import danger.internal.Date;
8import danger.ui.Button;
9import danger.ui.CheckBox;
10import danger.ui.Color;
11import danger.ui.DateTimeEditor;
12import danger.ui.DatePicker;
13import danger.ui.DialogWindow;
14import danger.ui.Font;
15import danger.ui.Layout;
16import danger.ui.MenuItem;
17import danger.ui.NumberEditor;
18import danger.ui.Pen;
19import danger.ui.PopupMenu;
20import danger.ui.RadioButton;
21import danger.ui.Rect;
22import danger.ui.RingTonePicker;
23import danger.ui.StaticTextBox;
24import danger.ui.TypeAheadTextField;
25import danger.util.DEBUG;
26
27public class AlarmSetDialog extends DialogWindow
28 implements Resources, Commands {
29
30 private TypeAheadTextField mMessageField;
31 private RadioButton mInButton, mAtButton;
32 private NumberEditor mPeriodField;
33 private PopupMenu mPeriodUnitsPopup;
34 // XXX don't allow <5 second repeating alarms
35 private CheckBox mRepeatCheckBox;
36 private DateTimeEditor mTimeEditor, mDateEditor;
37 private DatePicker mDatePicker;
38 private RingTonePicker mAlertPicker;
39 private Button mDiscardAlarmButton, mSetAlarmButton;
40 private StaticTextBox mStatusBox;
41
42 private Alarm mEditingAlarm;
43 private boolean mAlarmIsNew;
44 private boolean mHaveShownWindow = false;
45
46 private danger.app.Alarm mValidateAlarm;
47
48 public static AlarmSetDialog getDialog() {
49 AlarmSetDialog dialog = (AlarmSetDialog)
50 Application.getCurrentApp().getDialog(ID_ALARM_SET_DIALOG, null);
51 return dialog;
52 }
53
54 public void onDecoded() {
55 setCancelButtonEvent(new Event(this, EVENT_CANCEL_ALARM));
56 mMessageField =
57 (TypeAheadTextField)getDescendantWithID(ID_MESSAGE_FIELD);
58 mInButton = (RadioButton)getDescendantWithID(ID_IN_BUTTON);
59 mAtButton = (RadioButton)getDescendantWithID(ID_AT_BUTTON);
60 mPeriodField = (NumberEditor)getDescendantWithID(ID_PERIOD_FIELD);
61 mPeriodUnitsPopup =
62 (PopupMenu)getDescendantWithID(ID_PERIOD_UNITS_POPUP);
63 mRepeatCheckBox =
64 (CheckBox)getDescendantWithID(ID_PERIOD_REPEAT_CHECKBOX);
65 mTimeEditor = (DateTimeEditor)getDescendantWithID(ID_TIME_EDITOR);
66 mDateEditor = (DateTimeEditor)getDescendantWithID(ID_DATE_EDITOR);
67 mDatePicker = (DatePicker)getDescendantWithID(ID_DATE_PICKER);
68 mAlertPicker = (RingTonePicker)getDescendantWithID(ID_ALERT_PICKER);
69 mSetAlarmButton = (Button)getDescendantWithID(ID_SET_ALARM_BUTTON);
70 mDiscardAlarmButton =
71 (Button)getDescendantWithID(ID_DISCARD_ALARM_BUTTON);
72 mInButton.setValue(1);
73 mDateEditor.limitToDangerEpoch();
74 mAlertPicker.setGroupFilter(ToneClass.FOREGROUND | ToneClass.CUSTOM);
75 mAlertPicker.setRights(ToneRights.FULL);
76 // this doesn't work properly yet
77 // mAlertPicker.setCanRecord(true);
78
79 mStatusBox = new StaticTextBox();
80 mStatusBox.setTransparent(true);
81 mStatusBox.setHasBorder(false);
82 mStatusBox.setFont(Font.findSystemFont());
83 mStatusBox.setAutoResize(false);
84
85 mValidateAlarm = new danger.app.Alarm(1, this);
86
87 editAlarm(Alarms.getDefaultAlarm());
88
89 super.onDecoded();
90 }
91
92 protected void editDate(Date date) {
93 // time and date editors must share the same date object
94 mTimeEditor.setDate(date);
95 mDateEditor.setDate(date);
96 mDatePicker.setDate(date);
97 }
98
99 protected void editAlarm(Alarm alarm) {
100 mMessageField.setText(alarm.getMessage());
101
102 int period = alarm.getPeriod();
103 if (period > 0) {
104 for (int i = mPeriodUnitsPopup.itemCount() - 1 ; i >= 0 ; --i) {
105 int unitsPerSec = mPeriodUnitsPopup.getItem(i).getEvent().data;
106 if (period % unitsPerSec == 0) {
107 mPeriodUnitsPopup.setValue(i);
108 mPeriodField.setValue(period / unitsPerSec);
109 break;
110 }
111 }
112 mRepeatCheckBox.setValue(alarm.getRepeating() ? 1 : 0);
113 }
114
115 editDate(new Date(alarm.getDate()));
116
117 boolean usesPeriod = alarm.getUsesPeriod();
118 mInButton.setValue(usesPeriod ? 1 : 0);
119 mAtButton.setValue(usesPeriod ? 0 : 1);
120
121 mAlertPicker.setRingTone(alarm.getAlert());
122 }
123
124 public void editAlarm(Alarm alarm, boolean asNew) {
125 mEditingAlarm = alarm;
126 mAlarmIsNew = asNew;
127 alarm.beginEditing();
128 if (asNew) {
129 mDiscardAlarmButton.hide();
130 // XXX default to now?
131 } else {
132 editAlarm(alarm);
133 mDiscardAlarmButton.show();
134 }
135 validate();
136 Application.registerForEvent(this, Event.EVENT_TIME_CHANGED);
137 show();
138 if (!mHaveShownWindow) {
139 Rect alarmRect = mSetAlarmButton.getFrame();
140 Rect contentRect = getContentRect();
141 mStatusBox.setPosition(contentRect.left + 8, alarmRect.top + 2);
142 mStatusBox.setSize(alarmRect.left - 8, 11);
143 mStatusBox.show();
144 addChild(mStatusBox);
145 mHaveShownWindow = true;
146 setAutoSize(false); // don't resize to contain it next time
147 }
148 }
149
150 protected boolean isIn() {
151 return (mInButton.getValue() == 1);
152 }
153
154 protected int editingInterval() {
155 int itemIndex = mPeriodUnitsPopup.getValue();
156 MenuItem itemAtIndex = mPeriodUnitsPopup.getItem(itemIndex);
157 Event event = itemAtIndex.getEvent();
158 return mPeriodField.getValue() * event.data;
159 }
160
161 protected Date editingDate() {
162 Date date;
163 if (isIn()) {
164 date = new Date();
165 date.addSeconds(editingInterval());
166 } else {
167 date = mDateEditor.getDate();
168 date.setSeconds(0);
169 }
170 return date;
171 }
172
173 protected boolean isValid() {
174 // doesn't redraw properly otherwise
175 invalidate(mStatusBox.getBounds());
176 if (mMessageField.length() == 0) {
177 mStatusBox.setText("Specify a message.");
178 return false;
179 }
180 Date now = new Date();
181 Date editingDate = editingDate();
182 if (isIn()) {
183 mValidateAlarm.resetWake(60 - now.getSeconds());
184 } else {
185 int secondsUntilDate =
186 editingDate.getDangerTimeGMT() - now.getDangerTimeGMT();
187 if (secondsUntilDate <= 0) {
188 mStatusBox.setText("Specify a future date.");
189 return false;
190 }
191 mValidateAlarm.resetWake(secondsUntilDate);
192 }
193 // we read the time from the date editor; if we constrain it to
194 // absolutely now, we won't read an earlier time even if the time
195 // editor sets it
196 now.setTime(0);
197 mDateEditor.min(now);
198 mDatePicker.min(now);
199 mStatusBox.setText(Alarm.dateTimeString(editingDate, true));
200 return true;
201 }
202
203 // XXX make a timer-only version of this which doesn't try to extract
204 // XXX the editing date (it can cause odd behavior by forcing the
205 // XXX NumberEditor to spit out a value)
206 protected void validate() {
207 boolean isValid = isValid();
208 mSetAlarmButton.setEnabled(isValid);
209 if (!isValid)
210 mValidateAlarm.deactivate();
211 }
212
213 protected void stopEditing() {
214 mEditingAlarm = null;
215 mValidateAlarm.deactivate();
216 Application.unregisterForEvent(this, Event.EVENT_TIME_CHANGED);
217 }
218
219 public boolean receiveEvent(Event e) {
220 switch (e.type) {
221 case EVENT_SET_ALARM:
222 if (!isValid())
223 return true;
224 mEditingAlarm.setMessage(mMessageField.toString());
225 // set the period regardless, so it gets saved for future use
226 mEditingAlarm.setPeriod(editingInterval(),
227 mRepeatCheckBox.getValue() == 1);
228 if (!isIn()) { // otherwise, date = current time + period
229 mEditingAlarm.setDate(editingDate());
230 }
231 mEditingAlarm.setAlert(mAlertPicker.getRingTone());
232 // schedule before adding so the tooltip is correct
233 mEditingAlarm.schedule();
234 if (mAlarmIsNew) Alarms.addAlarm(mEditingAlarm);
235 Alarms.setDefaultAlarm(mEditingAlarm);
236 stopEditing();
237 return true;
238 case EVENT_CANCEL_ALARM:
239 if (!mAlarmIsNew) mEditingAlarm.resume();
240 stopEditing();
241 return true;
242 case EVENT_DISCARD_ALARM:
243 Alarms.removeAlarm(mEditingAlarm);
244 stopEditing();
245 return true;
246 case Event.EVENT_TIME_CHANGED: // time on device changed
247 case Event.EVENT_ALARM: // computed time invalid
248 case EVENT_VALIDATE: // something changed
249 validate();
250 return true;
251 case EVENT_IN:
252 mAtButton.setValue(0);
253 validate();
254 return true;
255 case EVENT_AT:
256 mInButton.setValue(0);
257 validate();
258 return true;
259 case EVENT_TIME_EDITOR:
260 validate();
261 return true;
262 case EVENT_DATE_EDITOR_TOOK_FOCUS:
263 {
264 Date date = editingDate();
265 Date now = new Date();
266 if (date.compareTo(now) <= 0) { // XXX do with 1 minute fuzz
267 int time = date.getTime();
268 date.set(now); // idiotically, setToday() sets the time too
269 date.setTime(time);
270 if (date.compareTo(now) <= 0)
271 date.addDays(1); // tomorrow
272 editDate(date);
273 }
274 validate();
275 return true;
276 }
277 case EVENT_DATE_EDITOR:
278 mDatePicker.setDate(mDateEditor.getDate());
279 validate();
280 return true;
281 case EVENT_DATE_PICKER:
282 {
283 Date date = (Date)e.argument;
284 date.setTime(mTimeEditor.getDate().getTime());
285 mTimeEditor.setDate(date);
286 mDateEditor.setDate(date);
287 validate();
288 return true;
289 }
290 }
291 return super.receiveEvent(e);
292 }
293}
Note: See TracBrowser for help on using the repository browser.