source: trunk/hiptop/pester/net/sabi/pester/Alarm.java@ 249

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

Better (informative, not yet pretty) date display.

File size: 6.3 KB
RevLine 
[237]1package net.sabi.pester;
2
3import java.io.ByteArrayInputStream;
4import java.io.ByteArrayOutputStream;
5import java.io.DataInputStream;
6import java.io.DataOutputStream;
[242]7import danger.app.Application;
[244]8import danger.audio.RingToneObject;
[237]9import danger.internal.Date;
[243]10import danger.util.LocaleUtils;
[242]11import danger.util.StdActiveList;
[237]12import danger.util.StdActiveObject;
[240]13import danger.util.DEBUG;
[243]14import danger.util.format.DateFormat;
15import danger.util.format.StringFormat;
[237]16
17public class Alarm extends StdActiveObject {
18 private static final int VERSION_1 = 1;
19
20 // persisted
21 private String mMessage;
[239]22 private int mType;
[249]23 private int mInterval; // XXX rename to 'interval'
[237]24 private Date mDate;
[244]25 private RingToneObject mAlert;
[237]26
27 // transient
[241]28 private int mState;
[242]29 private danger.app.Alarm mAlarm;
[237]30
31 public Alarm() {
[241]32 mState = STATE_INVALID;
[242]33 mAlarm = new danger.app.Alarm(0, Application.getCurrentApp(), this);
[237]34 }
35
36 public String getMessage() {
37 return mMessage;
38 }
[240]39 public int getPeriod() {
[249]40 return mInterval;
[237]41 }
42 public boolean getUsesPeriod() {
[239]43 return mType != TYPE_DATE;
[237]44 }
[240]45 public boolean getRepeating() {
46 return mType == TYPE_PERIODIC_REPEATING;
47 }
[237]48 public Date getDate() {
49 return mDate;
50 }
[244]51 public RingToneObject getAlert() {
52 return mAlert;
53 }
[237]54
55 public void setMessage(String message) {
56 mMessage = message;
57 }
[240]58 public void setPeriod(int period, boolean repeating) {
[239]59 mType = repeating ? TYPE_PERIODIC_REPEATING : TYPE_PERIODIC;
[249]60 mInterval = period;
[237]61 }
62 public void setDate(Date date) {
[239]63 mType = TYPE_DATE;
[237]64 mDate = date;
65 }
[244]66 public void setAlert(RingToneObject alert) {
67 mAlert = alert.isValid() ? alert : null;
68 }
[237]69
70 public byte[] toByteArray() {
71 try {
72 ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
73 DataOutputStream dataStream = new DataOutputStream(byteStream);
74
75 dataStream.writeByte(VERSION_1);
76 dataStream.writeUTF(mMessage);
[249]77 dataStream.writeInt(mInterval);
[237]78 dataStream.writeInt(mDate.getUnixTimeGMT());
[239]79 dataStream.writeInt(mType);
[237]80 dataStream.flush();
81 return byteStream.toByteArray();
82 } catch (Exception e) {
83 // XXX do something
84 }
85 return null;
86 }
87
88 public void fromByteArray(byte[] data) {
89 try {
90 ByteArrayInputStream byteStream = new ByteArrayInputStream(data);
91 DataInputStream dataStream = new DataInputStream(byteStream);
92
93 byte version = dataStream.readByte();
94 if (version != VERSION_1) {
95 // XXX barf
96 }
97 mMessage = dataStream.readUTF();
[249]98 mInterval = dataStream.readInt();
[239]99 mType = dataStream.readInt();
[237]100 } catch (Exception e) {
101 // XXX do something
102 }
103 }
104
105 void beginEditing() {
[241]106 mState = STATE_EDITING;
[242]107 mAlarm.deactivate();
[237]108 }
109
[249]110 public static int secondsFromNow(Date date) {
111 return date.getDangerTimeGMT() - new Date().getDangerTimeGMT();
112 }
113
114 protected int remainingInterval() {
115 return secondsFromNow(mDate);
116 }
117
[243]118 void resume() {
119 mState = STATE_SCHEDULED;
[249]120 int interval = remainingInterval();
121 if (interval < 0) interval = 0;
122 mAlarm.resetWake(interval);
123 DEBUG.p("resetWake: " + description() + " - " + interval + "s left");
[243]124 update();
125 }
126
127 void schedule() {
128 if (getUsesPeriod()) {
129 mDate = new Date();
[249]130 mDate.addSeconds(mInterval);
[243]131 }
132 resume();
133 }
134
[242]135 void dismiss() {
136 if (getRepeating())
137 schedule();
138 else
139 ((StdActiveList)getDelegate()).removeItem(this);
140 }
141
142 void cancel() {
143 mState = STATE_INVALID;
144 mAlarm.deactivate();
145 }
146
[243]147 public String description() {
148 StringBuffer sb = new StringBuffer();
149 switch (mState) {
150 case STATE_INVALID: sb.append("invalid "); break;
151 case STATE_EDITING: sb.append("editing "); break;
152 case STATE_SCHEDULED: sb.append("scheduled "); break;
153 }
[240]154 switch (mType) {
155 case TYPE_PERIODIC:
[249]156 sb.append("periodic (").append(mInterval).append("s) "); break;
[240]157 case TYPE_PERIODIC_REPEATING:
[249]158 sb.append("repeating periodic (").append(mInterval).append("s) ");
[243]159 break;
[240]160 case TYPE_DATE:
[243]161 sb.append("date (").append(getDateTimeString()).append(") "); break;
[240]162 }
[243]163 sb.append("alarm: ");
164 sb.append('"').append(mMessage).append('"');
165 return sb.toString();
[237]166 }
[243]167
[249]168 public static String dateTimeString(Date date, boolean relative) {
[243]169 if (date == null)
170 return null;
171 String layout = LocaleUtils.getDateTimePattern();
172 String timeFormat = LocaleUtils.getMediumTimeFormat();
[247]173 String dateFormat = LocaleUtils.getMediumDateFormat();
[249]174 String timeString = DateFormat.withFormat(timeFormat, date);
175 String dateString = DateFormat.withFormat(dateFormat, date);
176 if (relative) {
177 int daysFromToday = date.getDaysBetween(new Date());
178 if (daysFromToday == 0)
179 dateString = "Today"; // XXX localize
180 else if (daysFromToday == 1)
181 dateString = "Tomorrow"; // XXX localize
182 else if (daysFromToday < 7)
183 dateString = date.getDayString();
184 }
185 return StringFormat.withFormat(layout, timeString, dateString);
[243]186 }
187
[249]188 protected static void addUnit(StringBuffer sb, int n, String unit) {
189 if (n == 0) return;
190 if (sb.length() > 0) sb.append(", ");
191 if (n == 1) sb.append("one ").append(unit);
192 else sb.append(n).append(' ').append(unit).append("s");
193 }
194
195 public static String intervalString(int i) { // XXX localize
196 if (i < 0)
197 return "expired";
198 StringBuffer sb = new StringBuffer();
199 if (i < 60) {
200 addUnit(sb, i, "second");
201 } else {
202 i /= 60; // minutes
203 if (i < 24 * 60) {
204 addUnit(sb, i / 60, "hour");
205 addUnit(sb, i % 60, "minute");
206 } else {
207 i /= 60; // hours
208 if (i < 365) {
209 addUnit(sb, i / 24, "day");
210 addUnit(sb, i % 24, "hour");
211 } else {
212 i /= 24; // days
213 addUnit(sb, i / 365, "year"); // XXX actually 365.242199
214 addUnit(sb, i % 365, "day");
215 }
216 }
217 }
218 return sb.toString();
219 }
220
221 public String getDateTimeString(boolean relative) {
222 return dateTimeString(mDate, relative);
223 }
224
[243]225 public String getDateTimeString() {
[249]226 return getDateTimeString(false);
[243]227 }
[249]228
229 public String getIntervalString() {
230 return intervalString(remainingInterval());
231 }
[243]232
[237]233 public String toString() {
[249]234 return getDateTimeString(true) + " - " + mMessage;
[237]235 }
236
[239]237 public static final int TYPE_PERIODIC = 0;
238 public static final int TYPE_PERIODIC_REPEATING = 1;
239 public static final int TYPE_DATE = 2;
240
[241]241 public static final int STATE_INVALID = 0;
242 public static final int STATE_EDITING = 1;
243 public static final int STATE_SCHEDULED = 2;
[237]244}
Note: See TracBrowser for help on using the repository browser.