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

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

Keep track of recent messages.

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