diff --git a/res/drawable-hdpi/ic_action_snooze.png b/res/drawable-hdpi/ic_action_snooze.png new file mode 100644 index 000000000..257274d8a Binary files /dev/null and b/res/drawable-hdpi/ic_action_snooze.png differ diff --git a/res/drawable-mdpi/ic_action_snooze.png b/res/drawable-mdpi/ic_action_snooze.png new file mode 100644 index 000000000..63b4274f8 Binary files /dev/null and b/res/drawable-mdpi/ic_action_snooze.png differ diff --git a/res/drawable-v21/habits_item_check_normal.xml b/res/drawable-v21/habits_item_check_normal.xml new file mode 100644 index 000000000..0a83d0180 --- /dev/null +++ b/res/drawable-v21/habits_item_check_normal.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable-v21/habits_item_check_pressed.xml b/res/drawable-v21/habits_item_check_pressed.xml new file mode 100644 index 000000000..8fc26c9e2 --- /dev/null +++ b/res/drawable-v21/habits_item_check_pressed.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable-xhdpi/ic_action_snooze.png b/res/drawable-xhdpi/ic_action_snooze.png new file mode 100644 index 000000000..951ebdab8 Binary files /dev/null and b/res/drawable-xhdpi/ic_action_snooze.png differ diff --git a/res/drawable-xxhdpi/ic_action_snooze.png b/res/drawable-xxhdpi/ic_action_snooze.png new file mode 100644 index 000000000..c1b201cea Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_snooze.png differ diff --git a/res/drawable/habits_item_check_normal.xml b/res/drawable/habits_item_check_normal.xml index 0a83d0180..747ab80e6 100644 --- a/res/drawable/habits_item_check_normal.xml +++ b/res/drawable/habits_item_check_normal.xml @@ -4,7 +4,7 @@ diff --git a/res/drawable/habits_item_check_pressed.xml b/res/drawable/habits_item_check_pressed.xml index 8fc26c9e2..887279103 100644 --- a/res/drawable/habits_item_check_pressed.xml +++ b/res/drawable/habits_item_check_pressed.xml @@ -4,7 +4,7 @@ diff --git a/res/values/strings.xml b/res/values/strings.xml index d76b5568b..810e0f446 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -41,5 +41,7 @@ - + + + \ No newline at end of file diff --git a/src/org/isoron/helpers/DateHelper.java b/src/org/isoron/helpers/DateHelper.java index c1bd0624f..8f46a9711 100644 --- a/src/org/isoron/helpers/DateHelper.java +++ b/src/org/isoron/helpers/DateHelper.java @@ -20,6 +20,11 @@ public class DateHelper { return (timestamp / millisecondsInOneDay) * millisecondsInOneDay; } + + public static long getStartOfToday() + { + return getStartOfDay(DateHelper.getLocalTime()); + } // public static Date getStartOfDay(Date date) // { diff --git a/src/org/isoron/uhabits/MainActivity.java b/src/org/isoron/uhabits/MainActivity.java index c00a3f266..f10c095ed 100644 --- a/src/org/isoron/uhabits/MainActivity.java +++ b/src/org/isoron/uhabits/MainActivity.java @@ -15,7 +15,9 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.os.Bundle; +import android.util.DisplayMetrics; import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -43,44 +45,65 @@ public class MainActivity extends Activity setContentView(R.layout.main_activity); showHabitsFragment = (ShowHabitsFragment) getFragmentManager().findFragmentById( R.id.fragment1); + + Log.d("MainActivity", "Creating activity"); undoList = new LinkedList(); redoList = new LinkedList(); - createReminderAlarms(); + createReminderAlarms(MainActivity.this); + } + + @Override + protected void onStart() + { + super.onStart(); + showHabitsFragment.notifyDataSetChanged(); + Log.d("MainActivity", "Starting activity"); } - public void createReminderAlarms() + public static void createReminderAlarms(Context context) { for(Habit habit : Habit.getHabitsWithReminder()) + createReminderAlarm(context, habit, null); + } + + public static void createReminderAlarm(Context context, Habit habit, Long reminderTime) + { + Uri uri = Uri.parse("content://org.isoron.uhabits/habit/" + habit.getId()); + + if(reminderTime == null) { - Uri uri = Uri.parse("content://org.isoron.uhabits/habit/" + habit.getId()); - Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, habit.reminder_hour); calendar.set(Calendar.MINUTE, habit.reminder_min); calendar.set(Calendar.SECOND, 0); - long reminderTime = calendar.getTimeInMillis(); + reminderTime = calendar.getTimeInMillis(); if(System.currentTimeMillis() > reminderTime) { reminderTime += AlarmManager.INTERVAL_DAY; } - - Intent alarmIntent = new Intent(MainActivity.this, ReminderAlarmReceiver.class); - alarmIntent.setData(uri); - - PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, - ((int)(habit.getId() % Integer.MAX_VALUE)) + 1, - alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT); - - AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); + } + + Intent alarmIntent = new Intent(context, ReminderAlarmReceiver.class); + alarmIntent.setAction(ReminderAlarmReceiver.ACTION_REMIND); + alarmIntent.setData(uri); + + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, + ((int)(habit.getId() % Integer.MAX_VALUE)) + 1, + alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT); + + AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + if (Build.VERSION.SDK_INT >= 19) { manager.setExact(AlarmManager.RTC_WAKEUP, reminderTime, pendingIntent); - - Log.d("Alarm", String.format("Setting alarm (%s): %s", DateFormat.getDateTimeInstance() - .format(new Date(reminderTime)), habit.name)); + } else { + manager.set(AlarmManager.RTC_WAKEUP, reminderTime, pendingIntent); } + + Log.d("Alarm", String.format("Setting alarm (%s): %s", DateFormat.getDateTimeInstance() + .format(new Date(reminderTime)), habit.name)); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * diff --git a/src/org/isoron/uhabits/ReminderAlarmReceiver.java b/src/org/isoron/uhabits/ReminderAlarmReceiver.java index acf1578b7..ab0ee593b 100644 --- a/src/org/isoron/uhabits/ReminderAlarmReceiver.java +++ b/src/org/isoron/uhabits/ReminderAlarmReceiver.java @@ -1,11 +1,12 @@ package org.isoron.uhabits; +import java.util.Date; import java.util.List; -import org.isoron.helpers.DateHelper; import org.isoron.uhabits.models.Habit; import android.app.Activity; +import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -20,22 +21,77 @@ import android.util.Log; public class ReminderAlarmReceiver extends BroadcastReceiver { + + public static String ACTION_CHECK = "org.isoron.uhabits.ACTION_CHECK"; + public static String ACTION_DISMISS = "org.isoron.uhabits.ACTION_DISMISS"; + public static String ACTION_REMIND = "org.isoron.uhabits.ACTION_REMIND"; + public static String ACTION_REMOVE_REMINDER = "org.isoron.uhabits.ACTION_REMOVE_REMINDER"; + public static String ACTION_SNOOZE = "org.isoron.uhabits.ACTION_SNOOZE"; + @Override public void onReceive(Context context, Intent intent) { - createNotification(context, intent.getData(), intent.getDataString()); + String action = intent.getAction(); + + if(action.equals(ACTION_REMIND)) + createNotification(context, intent.getData()); + + else if(action.equals(ACTION_DISMISS)) + dismissAllHabits(); + + else if(action.equals(ACTION_CHECK)) + checkHabit(context, intent.getData()); + + else if(action.equals(ACTION_SNOOZE)) + snoozeHabit(context, intent.getData()); + } + + private void snoozeHabit(Context context, Uri data) + { + int delayMinutes = 15; + Habit habit = Habit.get(ContentUris.parseId(data)); + MainActivity.createReminderAlarm(context, habit, new Date().getTime() + delayMinutes * 1000); + dismissNotification(context); + } + + private void checkHabit(Context context, Uri data) + { + Habit habit = Habit.get(ContentUris.parseId(data)); + habit.toggleRepetitionToday(); + habit.save(); + dismissNotification(context); + } + + private void dismissAllHabits() + { + for(Habit h : Habit.getHighlightedHabits()) + { + Log.d("Alarm", String.format("Removing highlight from: %s", h.name)); + h.highlight = 0; + h.save(); + } + } + + private void dismissNotification(Context context) + { + NotificationManager notificationManager = (NotificationManager) context + .getSystemService(Activity.NOTIFICATION_SERVICE); + + notificationManager.cancel(1); } - private void createNotification(Context context, Uri data, String text) + private void createNotification(Context context, Uri data) { Log.d("Alarm", "Alarm received!"); Habit habit = Habit.get(ContentUris.parseId(data)); - // Check if user already did the habit repetition - if(habit.hasRep(DateHelper.getStartOfDay(DateHelper.getLocalTime()))) + if(habit.hasImplicitRepToday()) + { + Log.d("Alarm", String.format("(%s) has implicit rep today", habit.name)); return; + } Log.d("Alarm", String.format("Applying highlight: %s", habit.name)); habit.highlight = 1; @@ -49,27 +105,38 @@ public class ReminderAlarmReceiver extends BroadcastReceiver contentIntent.setData(data); PendingIntent contentPendingIntent = PendingIntent.getActivity(context, 0, contentIntent, 0); - Intent deleteIntent = new Intent(context, ReminderAlarmDismissReceiver.class); + Intent deleteIntent = new Intent(context, ReminderAlarmReceiver.class); + deleteIntent.setAction(ACTION_DISMISS); PendingIntent deletePendingIntent = PendingIntent.getBroadcast(context, 0, deleteIntent, 0); + Intent checkIntent = new Intent(context, ReminderAlarmReceiver.class); + checkIntent.setData(data); + checkIntent.setAction(ACTION_CHECK); + PendingIntent checkIntentPending = PendingIntent.getBroadcast(context, 0, checkIntent, 0); + + Intent snoozeIntent = new Intent(context, ReminderAlarmReceiver.class); + snoozeIntent.setData(data); + snoozeIntent.setAction(ACTION_SNOOZE); + PendingIntent snoozeIntentPending = PendingIntent.getBroadcast(context, 0, snoozeIntent, 0); + Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(); inboxStyle.setBigContentTitle("Habit Reminder:"); List pendingHabits = Habit.getHighlightedHabits(); + StringBuffer contentText = new StringBuffer(); for(Habit h : pendingHabits) { - if(h.hasRep(DateHelper.getStartOfDay(DateHelper.getLocalTime()))) + if(h.hasImplicitRepToday()) continue; + inboxStyle.addLine(h.name); + if(contentText.length() > 0) + contentText.append(", "); + contentText.append(h.name); Log.d("Alarm", String.format("Found highlighted: %s", h.name)); } - String contentText = habit.name; - if(pendingHabits.size() > 1) { - contentText = String.format("%d pending habits.", pendingHabits.size()); - } - Notification notification = new NotificationCompat.Builder(context) .setSmallIcon(R.drawable.ic_notification) @@ -77,6 +144,8 @@ public class ReminderAlarmReceiver extends BroadcastReceiver .setContentText(contentText) .setContentIntent(contentPendingIntent) .setDeleteIntent(deletePendingIntent) + .addAction(R.drawable.ic_action_check, "Check", checkIntentPending) + .addAction(R.drawable.ic_action_snooze, "Later", snoozeIntentPending) .setSound(soundUri) .setStyle(inboxStyle) .build(); diff --git a/src/org/isoron/uhabits/dialogs/ShowHabitsFragment.java b/src/org/isoron/uhabits/dialogs/ShowHabitsFragment.java index ca6eadc6c..36dbed355 100644 --- a/src/org/isoron/uhabits/dialogs/ShowHabitsFragment.java +++ b/src/org/isoron/uhabits/dialogs/ShowHabitsFragment.java @@ -46,7 +46,7 @@ import com.mobeta.android.dslv.DragSortListView.DropListener; public class ShowHabitsFragment extends Fragment implements OnSavedListener, OnItemClickListener, OnLongClickListener, DropListener { - + private int tvNameWidth; private int button_count; ShowHabitsAdapter adapter; @@ -102,8 +102,8 @@ public class ShowHabitsFragment extends Fragment implements OnSavedListener, OnI public View getView(int position, View view, ViewGroup parent) { final Habit habit = (Habit) getItem(position); - - if(view == null) + + if(view == null || (Long) view.getTag(R.id.KEY_TIMESTAMP) != DateHelper.getStartOfToday()) { view = inflater.inflate(R.layout.show_habits_item, null); ((TextView) view.findViewById(R.id.tvStar)).setTypeface(fontawesome); @@ -125,6 +125,8 @@ public class ShowHabitsFragment extends Fragment implements OnSavedListener, OnI btCheck.setOnLongClickListener(ShowHabitsFragment.this); ((LinearLayout) view.findViewById(R.id.llButtons)).addView(check); } + + view.setTag(R.id.KEY_TIMESTAMP, DateHelper.getStartOfToday()); } TextView tvStar = (TextView) view.findViewById(R.id.tvStar); @@ -312,7 +314,7 @@ public class ShowHabitsFragment extends Fragment implements OnSavedListener, OnI public void onSaved(Command command) { executeCommand(command); - mainActivity.createReminderAlarms(); + MainActivity.createReminderAlarms(mainActivity); } public void notifyDataSetChanged() diff --git a/src/org/isoron/uhabits/models/Habit.java b/src/org/isoron/uhabits/models/Habit.java index 8b9d1006f..227ee88a7 100644 --- a/src/org/isoron/uhabits/models/Habit.java +++ b/src/org/isoron/uhabits/models/Habit.java @@ -276,6 +276,11 @@ public class Habit extends Model int count = selectReps().where("timestamp = ?", timestamp).count(); return (count > 0); } + + public boolean hasRepToday() + { + return hasRep(DateHelper.getStartOfToday()); + } public void deleteReps(long timestamp) { @@ -318,6 +323,13 @@ public class Habit extends Model return check; } + + public boolean hasImplicitRepToday() + { + long today = DateHelper.getStartOfToday(); + int reps[] = getReps(today - DateHelper.millisecondsInOneDay, today); + return (reps[0] > 0); + } public Repetition getOldestRep() { @@ -340,6 +352,11 @@ public class Habit extends Model deleteScoresNewerThan(timestamp); } + + public void toggleRepetitionToday() + { + toggleRepetition(DateHelper.getStartOfToday()); + } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Scoring *