Index: trunk/hiptop/pester/locale/en_US/Pester.rsrc
===================================================================
--- trunk/hiptop/pester/locale/en_US/Pester.rsrc	(revision 295)
+++ trunk/hiptop/pester/locale/en_US/Pester.rsrc	(revision 296)
@@ -230,5 +230,8 @@
 endDialog
 
-textInputAlert ID_ALARM_ALERT
+string ID_SNOOZE_LABEL_LEFT "Snooze for"
+string ID_SNOOZE_LABEL_RIGHT "minute(s)"
+
+alert ID_ALARM_ALERT
 	systemDialog
 	title = "Alarm"
@@ -243,22 +246,15 @@
 		shortcut = cancelButton
 	button
+		id = ID_RESCHEDULE_BUTTON
 		event = EVENT_SET_ALARM
 		title = "Reschedule..."
 		position = buttonBottom3
 	button
+		id = ID_DISMISS_BUTTON
 		event = EVENT_DISMISS_ALARM
 		title = okButton
 		position = buttonBottom1
 		shortcut = doneButton
-	textField
-		id = ID_SNOOZE_MINUTES
-		title = "Snooze for minutes:"
-		dontAcceptKeyRepeats
-		initiallySelectAll
-		numericOnly
-		justifyRight
-		maxLength = 2
-		position = top
-endTextInputAlert
+endAlert
 
 alert ID_LIMIT_ALERT
Index: trunk/hiptop/pester/net/sabi/pester/Alarm.java
===================================================================
--- trunk/hiptop/pester/net/sabi/pester/Alarm.java	(revision 295)
+++ trunk/hiptop/pester/net/sabi/pester/Alarm.java	(revision 296)
@@ -31,5 +31,6 @@
     // transient
     private int mState;
-    private int mAbsoluteFireTime; // valid if periodic and modified since reboot
+    private int mAbsoluteFireTime; // valid if periodic or snoozed,
+                                   // and modified since reboot
     private danger.app.Alarm mAlarm;
     private int mUID;
@@ -155,5 +156,5 @@
 	if (mState != STATE_SCHEDULED)
 	    return;
-	if (getUsesPeriod() && mAbsoluteFireTime != -1) {
+	if (mAbsoluteFireTime != -1) {
 	    int realSecondsLeft = mAbsoluteFireTime - Hardware.getAbsoluteTime();
 	    mDate = new Date();
@@ -200,19 +201,21 @@
     public String description() {
 	StringBuffer sb = new StringBuffer();
+	if (mUID != 0) sb.append('(').append(mUID).append(") ");
 	switch (mState) {
-	case STATE_INVALID: sb.append("invalid "); break;
-	case STATE_EDITING: sb.append("editing "); break;
-	case STATE_SCHEDULED: sb.append("scheduled "); break;
+	case STATE_INVALID: sb.append("inv "); break;
+	case STATE_EDITING: sb.append("edi "); break;
+	case STATE_SCHEDULED: sb.append("sch "); break;
 	}
 	switch (mType) {
+	case TYPE_PERIODIC_REPEATING:
+	    sb.append("r-");
 	case TYPE_PERIODIC:
-	    sb.append("periodic (").append(mPeriod).append("s) "); break;
-	case TYPE_PERIODIC_REPEATING:
-	    sb.append("repeating periodic (").append(mPeriod).append("s) ");
-	    break;
+	    sb.append("per(").append(mPeriod).append("s)");
+	    if (mState != STATE_SCHEDULED)
+		break;
 	case TYPE_DATE:
-	    sb.append("date (").append(getDateTimeString()).append(") "); break;
-	}
-	sb.append("alarm: ");
+	    sb.append("(").append(getDateTimeString()).append(")"); break;
+	}
+	sb.append(": ");
 	sb.append('"').append(mMessage).append('"');
 	return sb.toString();
Index: trunk/hiptop/pester/net/sabi/pester/Alarms.java
===================================================================
--- trunk/hiptop/pester/net/sabi/pester/Alarms.java	(revision 295)
+++ trunk/hiptop/pester/net/sabi/pester/Alarms.java	(revision 296)
@@ -30,9 +30,37 @@
     }
 
+    private void dumpAlarms() { // XXX enable via IPC, make validity checking
+	int i;
+	DEBUG.p("== ALARMS ==");
+	for (i = 0 ; i < size() ; ++i) {
+	    DEBUG.p(((Alarm)getItem(i)).description());
+	}
+
+    }
+    private void dumpDatastore() {
+	int i;
+	DEBUG.p("== DATASTORE CONTENTS ==");
+	byte[][] alarmsData = mDataStore.getRecords();
+	for (i = 0 ; i < alarmsData.length ; ++i) {
+	    Alarm alarm = new Alarm();
+	    alarm.fromByteArray(alarmsData[i]);
+	    alarm.setUID(mDataStore.getRecordUID(i));
+	    DEBUG.p(alarm.description());
+	}
+    }
     void refreshFromDataStore(boolean datastoreRestored) {
 	sAlarmList = null;
-	removeAllItems();
+	if (datastoreRestored) {
+	    DEBUG.p("+++ BEFORE RESOLUTION +++");
+	    dumpAlarms();
+	    dumpDatastore();
+	}
+	removeAllItems(); // XXX no, we can't do this because some alarms may be (a) in the process of being edited, (b) sitting at expiry, or (c) are periodic or snoozed and need their absolute time preserved.  Instead, we should just add all the new records - but what about conflicts?
 	if (datastoreRestored)
-	    mDataStore.doneResolvingConflict(); // resolves UID conflicts
+	    mDataStore.doneResolvingConflict(); // renumbers on-device records
+	if (datastoreRestored) {
+	    DEBUG.p("+++ AFTER RESOLUTION +++");
+	    dumpDatastore();
+	}
 	byte[][] alarmsData = mDataStore.getRecords();
 	int i;
@@ -49,4 +77,7 @@
 	    MessageFinder.setDefaultMessageList();
 	}
+	DEBUG.p("+++ AFTER RESTORATION +++");
+	dumpAlarms();
+	dumpDatastore();
 	sAlarmList = this;
     }
@@ -80,9 +111,7 @@
 	    return;
 	Alarm alarm = (Alarm)item;
-	DEBUG.p("adding: " + alarm +
-		" next UID: " + mDataStore.getAutoSyncNextUID());
 	index = mDataStore.addRecord(alarm.toByteArray());
 	alarm.setUID(mDataStore.getRecordUID(index));
-	DEBUG.p("added UID " + alarm.getUID() + " @ " + index);
+	DEBUG.p("ADD" + alarm.description());
     }
 
@@ -95,5 +124,7 @@
 	    return;
 	mDataStore.removeRecordByUID(uid);
-	DEBUG.p("removed UID " + alarm.getUID());
+	if (uid < 0)
+	    mDataStore.removeRecordByUID(-uid);
+	DEBUG.p("DEL" + alarm.description());
     }
 
@@ -103,5 +134,5 @@
 	Alarm alarm = (Alarm)item;
 	mDataStore.setRecordDataByUID(alarm.getUID(), alarm.toByteArray(), true);
-	DEBUG.p("updated: " + alarm + " UID " + alarm.getUID());
+	DEBUG.p("MOD" + alarm.description());
     }
 
@@ -137,6 +168,6 @@
 	    } else if (e.type == Event.EVENT_DATASTORE_RESTORED) {
 		String dbName = (String)e.argument;
-		DEBUG.p("DATASTORE_RESTORED: " + dbName);
-		if (!dbName.endsWith("alarms")) {
+		DEBUG.p("Pester: DATASTORE_RESTORED " + dbName);
+		if (dbName.endsWith("alarms")) {
 		    // because we only get/set the default alarm on demand
 		    // there's no need to handle conflicts with the settings...
Index: trunk/hiptop/pester/net/sabi/pester/Pester.java
===================================================================
--- trunk/hiptop/pester/net/sabi/pester/Pester.java	(revision 295)
+++ trunk/hiptop/pester/net/sabi/pester/Pester.java	(revision 296)
@@ -3,21 +3,62 @@
 import danger.app.Application;
 import danger.app.Event;
-import danger.app.IPCMessage;
+import danger.ui.AlertWindow;
+import danger.ui.Container;
+import danger.ui.Control;
+import danger.ui.Font;
 import danger.ui.Layout;
-import danger.ui.TextField;
-import danger.ui.TextInputAlertWindow;
+import danger.ui.RecordingPen;
 import danger.ui.ScreenWindow;
 import danger.ui.StaticText;
+import danger.ui.TextField;
 import danger.util.DEBUG;
-import java.util.Stack;
+import danger.util.TextInputFilter;
 
 public class Pester extends Application implements Resources, Commands {
     private static ScreenWindow sAlarmListWindow;
-    private static Stack sAlarmStack;
 
     public Pester() {
 	sAlarmListWindow = (ScreenWindow)getResources().getScreen(ID_ALARM_LIST_SCREEN);
 	sAlarmListWindow.show();
-	sAlarmStack = new Stack();
+    }
+
+    private void showAlertForAlarm(Alarm alarm) {
+	AlertWindow alert = (AlertWindow)getAlert(ID_ALARM_ALERT, this);
+	alert.setTitle(alarm.getDateTimeString());
+	alert.setMessage(alarm.getMessage());
+	alert.setShowTone(alarm.getAlert());
+
+	Font font = Font.findBoldSystemFont();
+	StaticText label = new StaticText(getString(ID_SNOOZE_LABEL_LEFT), font);
+	TextField field = new TextField();
+	field.setAlignment(TextField.JUSTIFY_RIGHT);
+	field.attachInputFilter(TextInputFilter.newLengthFilter(2));
+	field.attachInputFilter(TextInputFilter.newNumericFilter());
+	label.setLeft(35); // XXX alert.getMessageView().getLeft()
+	Layout.positionToRight(field, label, 3);
+	Layout.alignBaseline(label, field);
+	alert.addChildBelowMessageArea(label, label.getLeft(), label.getTop());
+	alert.addChildBelowMessageArea(field, field.getLeft(), field.getTop());
+	label = new StaticText(getString(ID_SNOOZE_LABEL_RIGHT), font);
+	Layout.positionToRight(label, field, 3);
+	Layout.alignBaseline(label, field);
+	alert.addChildBelowMessageArea(label, label.getLeft(), label.getTop());
+	
+	alert.setEventArgForControlWithID(ID_RESCHEDULE_BUTTON, alarm);
+	alert.setEventArgForControlWithID(ID_DISMISS_BUTTON, alarm);
+	alert.setDefaultFocus(field);
+
+	alert.paint(new RecordingPen()); // force layout
+	int fieldID = alert.incrementMaxChildID();
+	alert.removeChild(field);
+	alert.addChild(field, fieldID);
+	Control snoozeButton = alert.getControlWithID(ID_SNOOZE_BUTTON);
+	Event event = snoozeButton.getEvent();
+	event.argument = alert;
+	event.data = fieldID;
+	snoozeButton.setEvent(event);
+	alert.disableButtonOnEmptyField(ID_SNOOZE_BUTTON, fieldID);
+
+	alert.show(AlertWindow.SYSTEM_ALERT_TYPE_ALARM);
     }
 
@@ -25,26 +66,19 @@
 	switch (e.type) {
 	case Event.EVENT_ALARM:
-	    Alarm alarm = (Alarm)e.argument;
-	    TextInputAlertWindow alert = getTextInputAlert(ID_ALARM_ALERT, this);
-	    alert.setTitle(alarm.getDateTimeString());
-	    alert.setMessage(alarm.getMessage());
-	    alert.setShowTone(alarm.getAlert());
-	    alert.disableButtonOnEmptyField(ID_SNOOZE_BUTTON, ID_SNOOZE_MINUTES);
-	    alert.setShowCancel(false);
-	    alert.show(TextInputAlertWindow.SYSTEM_ALERT_TYPE_ALARM);
-	    sAlarmStack.push(alarm);
+	    showAlertForAlarm((Alarm)e.argument);
 	    return true;
 	case EVENT_SET_ALARM:
-	    AlarmSetDialog.getDialog().rescheduleAlarm((Alarm)sAlarmStack.pop());
+	    AlarmSetDialog.getDialog().rescheduleAlarm((Alarm)e.argument);
 	    return true;
 	case EVENT_SNOOZE_ALARM:
+	    AlertWindow alert = (AlertWindow)e.argument;
 	    int snoozeMinutes =
-		Integer.parseInt(TextInputAlertWindow.
-				 getTextFieldValue((IPCMessage)e.argument,
-						   ID_SNOOZE_MINUTES));
-	    ((Alarm)sAlarmStack.pop()).snoozeForMinutes(snoozeMinutes);
+		Integer.parseInt(alert.getControlWithID(e.data).toString());
+	    Control dismissButton = alert.getControlWithID(ID_DISMISS_BUTTON);
+	    Alarm alarm = (Alarm)dismissButton.getEvent().argument;
+	    alarm.snoozeForMinutes(snoozeMinutes);
 	    return true;
 	case EVENT_DISMISS_ALARM:
-	    ((Alarm)sAlarmStack.pop()).dismiss();
+	    ((Alarm)e.argument).dismiss();
 	    return true;
 	}
