Show alarm only on certain days of the week

pull/30/head
Alinson S. Xavier 10 years ago
parent c68176ad09
commit 1a4dbd9cba

@ -21,7 +21,7 @@
<meta-data
android:name="AA_DB_VERSION"
android:value="10"/>
android:value="11"/>
<meta-data
android:name="com.google.android.backup.api_key"

@ -0,0 +1 @@
alter table habits add column reminder_days integer not null default 127;

@ -19,6 +19,8 @@ package org.isoron.helpers;
import android.content.Context;
import android.text.format.DateFormat;
import org.isoron.uhabits.R;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
@ -51,10 +53,22 @@ public class DateHelper
{
GregorianCalendar day = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
day.setTimeInMillis(DateHelper.getStartOfDay(DateHelper.getLocalTime()));
return day;
}
public static GregorianCalendar getCalendar(long timestamp)
{
GregorianCalendar day = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
day.setTimeInMillis(timestamp);
return day;
}
public static int getWeekday(long timestamp)
{
GregorianCalendar day = getCalendar(timestamp);
return day.get(GregorianCalendar.DAY_OF_WEEK) % 7;
}
public static long getStartOfToday()
{
return getStartOfDay(DateHelper.getLocalTime());
@ -87,6 +101,17 @@ public class DateHelper
}
public static String[] getShortDayNames()
{
return getDayNames(GregorianCalendar.SHORT);
}
public static String[] getLongDayNames()
{
return getDayNames(GregorianCalendar.LONG);
}
public static String[] getDayNames(int format)
{
String[] wdays = new String[7];
@ -95,7 +120,7 @@ public class DateHelper
for (int i = 0; i < 7; i++)
{
wdays[i] = day.getDisplayName(GregorianCalendar.DAY_OF_WEEK, GregorianCalendar.SHORT,
wdays[i] = day.getDisplayName(GregorianCalendar.DAY_OF_WEEK, format,
Locale.getDefault());
day.add(GregorianCalendar.DAY_OF_MONTH, 1);
}
@ -103,4 +128,61 @@ public class DateHelper
return wdays;
}
public static String formatWeekdayList(Context context, boolean weekday[])
{
String shortDayNames[] = getShortDayNames();
String longDayNames[] = getLongDayNames();
StringBuilder buffer = new StringBuilder();
int count = 0;
int first = 0;
boolean isFirst = true;
for(int i = 0; i < 7; i++)
{
if(weekday[i])
{
if(isFirst) first = i;
else buffer.append(", ");
buffer.append(shortDayNames[i]);
isFirst = false;
count++;
}
}
if(count == 1) return longDayNames[first];
if(count == 2 && weekday[0] && weekday[1]) return context.getString(R.string.weekends);
if(count == 5 && !weekday[0] && !weekday[1]) return context.getString(R.string.any_weekday);
if(count == 7) return context.getString(R.string.any_day);
return buffer.toString();
}
public static Integer packWeekdayList(boolean weekday[])
{
int list = 0;
int current = 1;
for(int i = 0; i < 7; i++)
{
if(weekday[i]) list |= current;
current = current << 1;
}
return list;
}
public static boolean[] unpackWeekdayList(int list)
{
boolean[] weekday = new boolean[7];
int current = 1;
for(int i = 0; i < 7; i++)
{
if((list & current) != 0) weekday[i] = true;
current = current << 1;
}
return weekday;
}
}

@ -28,6 +28,7 @@ import android.content.SharedPreferences;
import android.graphics.BitmapFactory;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
@ -46,34 +47,44 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
public static final String ACTION_SNOOZE = "org.isoron.uhabits.ACTION_SNOOZE";
@Override
public void onReceive(Context context, Intent intent)
public void onReceive(final Context context, Intent intent)
{
switch (intent.getAction())
{
case ACTION_REMIND:
createNotification(context, intent.getData());
createNotification(context, intent);
createReminderAlarms(context);
break;
case ACTION_DISMISS:
dismissAllHabits();
ReminderHelper.createReminderAlarms(context);
break;
case ACTION_CHECK:
checkHabit(context, intent.getData());
ReminderHelper.createReminderAlarms(context);
checkHabit(context, intent);
break;
case ACTION_SNOOZE:
snoozeHabit(context, intent.getData());
ReminderHelper.createReminderAlarms(context);
snoozeHabit(context, intent);
break;
}
}
private void snoozeHabit(Context context, Uri data)
private void createReminderAlarms(final Context context)
{
new Handler().postDelayed(new Runnable()
{
@Override
public void run()
{
ReminderHelper.createReminderAlarms(context);
}
}, 5000);
}
private void snoozeHabit(Context context, Intent intent)
{
Uri data = intent.getData();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
long delayMinutes = Long.parseLong(prefs.getString("pref_snooze_interval", "15"));
@ -83,8 +94,9 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
dismissNotification(context, habit);
}
private void checkHabit(Context context, Uri data)
private void checkHabit(Context context, Intent intent)
{
Uri data = intent.getData();
Long timestamp = DateHelper.getStartOfToday();
String paramTimestamp = data.getQueryParameter("timestamp");
@ -115,9 +127,9 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
}
private void createNotification(Context context, Uri data)
private void createNotification(Context context, Intent intent)
{
Uri data = intent.getData();
Habit habit = Habit.get(ContentUris.parseId(data));
if (habit.hasImplicitRepToday()) return;
@ -125,6 +137,8 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
habit.highlight = 1;
habit.save();
if (!checkWeekday(intent, habit)) return;
// Check if reminder has been turned off after alarm was scheduled
if (habit.reminderHour == null) return;
@ -149,6 +163,8 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Long reminderTime = intent.getLongExtra("reminderTime", DateHelper.getStartOfToday());
NotificationCompat.WearableExtender wearableExtender =
new NotificationCompat.WearableExtender().setBackground(
BitmapFactory.decodeResource(context.getResources(), R.drawable.stripe));
@ -165,6 +181,8 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
context.getString(R.string.snooze), snoozeIntentPending)
.setSound(soundUri)
.extend(wearableExtender)
.setWhen(reminderTime)
.setShowWhen(true)
.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
@ -176,4 +194,14 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
notificationManager.notify(notificationId, notification);
}
private boolean checkWeekday(Intent intent, Habit habit)
{
Long timestamp = intent.getLongExtra("timestamp", DateHelper.getStartOfToday());
boolean reminderDays[] = DateHelper.unpackWeekdayList(habit.reminderDays);
int weekday = DateHelper.getWeekday(timestamp);
return reminderDays[weekday];
}
}

@ -0,0 +1,63 @@
package org.isoron.uhabits.dialogs;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;
import org.isoron.helpers.DateHelper;
public class WeekdayPickerDialog extends DialogFragment
implements DialogInterface.OnMultiChoiceClickListener, DialogInterface.OnClickListener
{
public interface OnWeekdaysPickedListener
{
void onWeekdaysPicked(boolean[] selectedDays);
}
private boolean[] selectedDays;
private OnWeekdaysPickedListener listener;
public void setListener(OnWeekdaysPickedListener listener)
{
this.listener = listener;
}
public void setSelectedDays(boolean[] selectedDays)
{
this.selectedDays = selectedDays;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Select weekdays")
.setMultiChoiceItems(DateHelper.getLongDayNames(), selectedDays, this)
.setPositiveButton(android.R.string.yes, this)
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
dismiss();
}
});
return builder.create();
}
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked)
{
selectedDays[which] = isChecked;
}
@Override
public void onClick(DialogInterface dialog, int which)
{
if(listener != null) listener.onWeekdaysPicked(selectedDays);
}
}

@ -34,16 +34,18 @@ import com.android.colorpicker.ColorPickerDialog;
import com.android.colorpicker.ColorPickerSwatch;
import com.android.datetimepicker.time.RadialPickerLayout;
import com.android.datetimepicker.time.TimePickerDialog;
import com.android.datetimepicker.time.TimePickerDialog.OnTimeSetListener;
import org.isoron.helpers.ColorHelper;
import org.isoron.helpers.Command;
import org.isoron.helpers.DateHelper;
import org.isoron.helpers.DialogHelper.OnSavedListener;
import org.isoron.uhabits.R;
import org.isoron.uhabits.dialogs.WeekdayPickerDialog;
import org.isoron.uhabits.models.Habit;
public class EditHabitFragment extends DialogFragment implements OnClickListener
public class EditHabitFragment extends DialogFragment
implements OnClickListener, WeekdayPickerDialog.OnWeekdaysPickedListener,
TimePickerDialog.OnTimeSetListener
{
private Integer mode;
static final int EDIT_MODE = 0;
@ -52,7 +54,7 @@ public class EditHabitFragment extends DialogFragment implements OnClickListener
private OnSavedListener onSavedListener;
private Habit originalHabit, modifiedHabit;
private TextView tvName, tvDescription, tvFreqNum, tvFreqDen, tvInputReminder;
private TextView tvName, tvDescription, tvFreqNum, tvFreqDen, tvReminderTime, tvReminderDays;
private SharedPreferences prefs;
private boolean is24HourMode;
@ -85,14 +87,16 @@ public class EditHabitFragment extends DialogFragment implements OnClickListener
tvDescription = (TextView) view.findViewById(R.id.input_description);
tvFreqNum = (TextView) view.findViewById(R.id.input_freq_num);
tvFreqDen = (TextView) view.findViewById(R.id.input_freq_den);
tvInputReminder = (TextView) view.findViewById(R.id.inputReminderTime);
tvReminderTime = (TextView) view.findViewById(R.id.inputReminderTime);
tvReminderDays = (TextView) view.findViewById(R.id.inputReminderDays);
Button buttonSave = (Button) view.findViewById(R.id.buttonSave);
Button buttonDiscard = (Button) view.findViewById(R.id.buttonDiscard);
buttonSave.setOnClickListener(this);
buttonDiscard.setOnClickListener(this);
tvInputReminder.setOnClickListener(this);
tvReminderTime.setOnClickListener(this);
tvReminderDays.setOnClickListener(this);
ImageButton buttonPickColor = (ImageButton) view.findViewById(R.id.buttonPickColor);
@ -151,15 +155,20 @@ public class EditHabitFragment extends DialogFragment implements OnClickListener
{
if (modifiedHabit.reminderHour != null)
{
tvInputReminder.setTextColor(Color.BLACK);
tvInputReminder.setText(DateHelper.formatTime(getActivity(),
modifiedHabit.reminderHour, modifiedHabit.reminderMin));
tvReminderTime.setTextColor(Color.BLACK);
tvReminderTime.setText(DateHelper.formatTime(getActivity(), modifiedHabit.reminderHour,
modifiedHabit.reminderMin));
tvReminderDays.setVisibility(View.VISIBLE);
}
else
{
tvInputReminder.setTextColor(Color.GRAY);
tvInputReminder.setText(R.string.reminder_off);
tvReminderTime.setTextColor(Color.GRAY);
tvReminderTime.setText(R.string.reminder_off);
tvReminderDays.setVisibility(View.GONE);
}
boolean weekdays[] = DateHelper.unpackWeekdayList(modifiedHabit.reminderDays);
tvReminderDays.setText(DateHelper.formatWeekdayList(getActivity(), weekdays));
}
public void setOnSavedListener(OnSavedListener onSavedListener)
@ -176,6 +185,10 @@ public class EditHabitFragment extends DialogFragment implements OnClickListener
onDateSpinnerClick();
break;
case R.id.inputReminderDays:
onWeekdayClick();
break;
case R.id.buttonSave:
onSaveButtonClick();
break;
@ -273,8 +286,19 @@ public class EditHabitFragment extends DialogFragment implements OnClickListener
defaultMin = modifiedHabit.reminderMin;
}
TimePickerDialog timePicker = TimePickerDialog.newInstance(new OnTimeSetListener()
TimePickerDialog timePicker =
TimePickerDialog.newInstance(this, defaultHour, defaultMin, is24HourMode);
timePicker.show(getFragmentManager(), "timePicker");
}
private void onWeekdayClick()
{
WeekdayPickerDialog dialog = new WeekdayPickerDialog();
dialog.setListener(this);
dialog.setSelectedDays(DateHelper.unpackWeekdayList(modifiedHabit.reminderDays));
dialog.show(getFragmentManager(), "weekdayPicker");
}
@Override
public void onTimeSet(RadialPickerLayout view, int hour, int minute)
{
@ -290,8 +314,11 @@ public class EditHabitFragment extends DialogFragment implements OnClickListener
modifiedHabit.reminderMin = null;
updateReminder();
}
}, defaultHour, defaultMin, is24HourMode);
timePicker.show(getFragmentManager(), "timePicker");
@Override
public void onWeekdaysPicked(boolean[] selectedDays)
{
modifiedHabit.reminderDays = DateHelper.packWeekdayList(selectedDays);
updateReminder();
}
}

@ -58,14 +58,13 @@ public class ReminderHelper
long timestamp = DateHelper.getStartOfDay(DateHelper.toLocalTime(reminderTime));
Uri uri = Uri.parse(String.format("content://org.isoron.uhabits/habit/%d?timestamp=%d",
habit.getId(), timestamp));
Log.d("Alarm", uri.toString());
Uri uri = Uri.parse(String.format("content://org.isoron.uhabits/habit/%d", habit.getId()));
Intent alarmIntent = new Intent(context, ReminderAlarmReceiver.class);
alarmIntent.setAction(ReminderAlarmReceiver.ACTION_REMIND);
alarmIntent.setData(uri);
alarmIntent.putExtra("timestamp", timestamp);
alarmIntent.putExtra("reminderTime", reminderTime);
PendingIntent pendingIntent =
PendingIntent.getBroadcast(context, ((int) (habit.getId() % Integer.MAX_VALUE)) + 1,
@ -77,7 +76,7 @@ public class ReminderHelper
else
manager.set(AlarmManager.RTC_WAKEUP, reminderTime, pendingIntent);
Log.d("Alarm", String.format("Setting alarm (%s): %s",
Log.d("ReminderHelper", String.format("Setting alarm (%s): %s",
DateFormat.getDateTimeInstance().format(new Date(reminderTime)), habit.name));
}
}

@ -71,6 +71,9 @@ public class Habit extends Model
@Column(name = "reminder_min")
public Integer reminderMin;
@Column(name = "reminder_days")
public Integer reminderDays;
@Column(name = "highlight")
public Integer highlight;
@ -90,6 +93,7 @@ public class Habit extends Model
this.archived = 0;
this.freqDen = 7;
this.freqNum = 3;
this.reminderDays = 127;
}
public static Habit get(Long id)
@ -189,6 +193,7 @@ public class Habit extends Model
this.position = model.position;
this.reminderHour = model.reminderHour;
this.reminderMin = model.reminderMin;
this.reminderDays = model.reminderDays;
this.highlight = model.highlight;
this.archived = model.archived;
}

@ -75,6 +75,11 @@
android:id="@+id/inputReminderTime"
style="@style/dialogFormTimePicker" />
<TextView
android:id="@+id/inputReminderDays"
android:text="Any weekday"
style="@style/dialogFormTimePicker" />
</LinearLayout>
</LinearLayout>

@ -107,6 +107,9 @@
<string name="hint_landscape">You can see more days by putting your phone in landscape mode.</string>
<string name="delete_habits">Delete Habits</string>
<string name="delete_habits_message">The habits will be permanently deleted. This action cannot be undone.</string>
<string name="weekends">Weekends</string>
<string name="any_weekday">Any weekday</string>
<string name="any_day">Any day</string>
<string-array name="hints">
<item>@string/hint_drag</item>

Loading…
Cancel
Save