mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 01:08:50 -06:00
Add notification actions (check, snooze)
This commit is contained in:
BIN
res/drawable-hdpi/ic_action_snooze.png
Normal file
BIN
res/drawable-hdpi/ic_action_snooze.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
res/drawable-mdpi/ic_action_snooze.png
Normal file
BIN
res/drawable-mdpi/ic_action_snooze.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 694 B |
22
res/drawable-v21/habits_item_check_normal.xml
Normal file
22
res/drawable-v21/habits_item_check_normal.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item>
|
||||
<shape android:shape="oval" >
|
||||
<gradient
|
||||
android:endColor="#00000000"
|
||||
android:gradientRadius="50%p"
|
||||
android:startColor="#50000000"
|
||||
android:type="radial" />
|
||||
</shape>
|
||||
</item>
|
||||
<item
|
||||
android:bottom="6dp"
|
||||
android:left="4dp"
|
||||
android:right="4dp"
|
||||
android:top="2dp">
|
||||
<shape android:shape="oval" >
|
||||
<solid android:color="#ffffff" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
</layer-list>
|
||||
22
res/drawable-v21/habits_item_check_pressed.xml
Normal file
22
res/drawable-v21/habits_item_check_pressed.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item>
|
||||
<shape android:shape="oval" >
|
||||
<gradient
|
||||
android:endColor="#00000000"
|
||||
android:gradientRadius="50%p"
|
||||
android:startColor="#50000000"
|
||||
android:type="radial" />
|
||||
</shape>
|
||||
</item>
|
||||
<item
|
||||
android:bottom="6dp"
|
||||
android:left="4dp"
|
||||
android:right="4dp"
|
||||
android:top="2dp">
|
||||
<shape android:shape="oval" >
|
||||
<solid android:color="#20000000" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
</layer-list>
|
||||
BIN
res/drawable-xhdpi/ic_action_snooze.png
Normal file
BIN
res/drawable-xhdpi/ic_action_snooze.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
res/drawable-xxhdpi/ic_action_snooze.png
Normal file
BIN
res/drawable-xxhdpi/ic_action_snooze.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
@@ -4,7 +4,7 @@
|
||||
<shape android:shape="oval" >
|
||||
<gradient
|
||||
android:endColor="#00000000"
|
||||
android:gradientRadius="50%p"
|
||||
android:gradientRadius="@dimen/radius"
|
||||
android:startColor="#50000000"
|
||||
android:type="radial" />
|
||||
</shape>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<shape android:shape="oval" >
|
||||
<gradient
|
||||
android:endColor="#00000000"
|
||||
android:gradientRadius="50%p"
|
||||
android:gradientRadius="@dimen/radius"
|
||||
android:startColor="#50000000"
|
||||
android:type="radial" />
|
||||
</shape>
|
||||
|
||||
@@ -42,4 +42,6 @@
|
||||
<string name="habit_key"></string>
|
||||
<string name="offset_key"></string>
|
||||
|
||||
<item type="id" name="KEY_TIMESTAMP"/>
|
||||
|
||||
</resources>
|
||||
@@ -21,6 +21,11 @@ public class DateHelper
|
||||
return (timestamp / millisecondsInOneDay) * millisecondsInOneDay;
|
||||
}
|
||||
|
||||
public static long getStartOfToday()
|
||||
{
|
||||
return getStartOfDay(DateHelper.getLocalTime());
|
||||
}
|
||||
|
||||
// public static Date getStartOfDay(Date date)
|
||||
// {
|
||||
// Calendar calendar = Calendar.getInstance();
|
||||
|
||||
@@ -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;
|
||||
@@ -44,43 +46,64 @@ public class MainActivity extends Activity
|
||||
showHabitsFragment = (ShowHabitsFragment) getFragmentManager().findFragmentById(
|
||||
R.id.fragment1);
|
||||
|
||||
Log.d("MainActivity", "Creating activity");
|
||||
|
||||
undoList = new LinkedList<Command>();
|
||||
redoList = new LinkedList<Command>();
|
||||
|
||||
createReminderAlarms();
|
||||
createReminderAlarms(MainActivity.this);
|
||||
}
|
||||
|
||||
public void createReminderAlarms()
|
||||
@Override
|
||||
protected void onStart()
|
||||
{
|
||||
super.onStart();
|
||||
showHabitsFragment.notifyDataSetChanged();
|
||||
Log.d("MainActivity", "Starting activity");
|
||||
}
|
||||
|
||||
public static void createReminderAlarms(Context context)
|
||||
{
|
||||
for(Habit habit : Habit.getHabitsWithReminder())
|
||||
{
|
||||
Uri uri = Uri.parse("content://org.isoron.uhabits/habit/" + habit.getId());
|
||||
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)
|
||||
{
|
||||
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);
|
||||
manager.setExact(AlarmManager.RTC_WAKEUP, reminderTime, pendingIntent);
|
||||
|
||||
Log.d("Alarm", String.format("Setting alarm (%s): %s", DateFormat.getDateTimeInstance()
|
||||
.format(new Date(reminderTime)), habit.name));
|
||||
}
|
||||
|
||||
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);
|
||||
} 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));
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
|
||||
@@ -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,25 +105,36 @@ 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<Habit> 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);
|
||||
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());
|
||||
inboxStyle.addLine(h.name);
|
||||
if(contentText.length() > 0)
|
||||
contentText.append(", ");
|
||||
contentText.append(h.name);
|
||||
Log.d("Alarm", String.format("Found highlighted: %s", h.name));
|
||||
}
|
||||
|
||||
Notification 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();
|
||||
|
||||
@@ -103,7 +103,7 @@ public class ShowHabitsFragment extends Fragment implements OnSavedListener, OnI
|
||||
{
|
||||
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()
|
||||
|
||||
@@ -277,6 +277,11 @@ public class Habit extends Model
|
||||
return (count > 0);
|
||||
}
|
||||
|
||||
public boolean hasRepToday()
|
||||
{
|
||||
return hasRep(DateHelper.getStartOfToday());
|
||||
}
|
||||
|
||||
public void deleteReps(long timestamp)
|
||||
{
|
||||
new Delete().from(Repetition.class).where("habit = ?", getId())
|
||||
@@ -319,6 +324,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()
|
||||
{
|
||||
return (Repetition) selectReps().limit(1).executeSingle();
|
||||
@@ -341,6 +353,11 @@ public class Habit extends Model
|
||||
deleteScoresNewerThan(timestamp);
|
||||
}
|
||||
|
||||
public void toggleRepetitionToday()
|
||||
{
|
||||
toggleRepetition(DateHelper.getStartOfToday());
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Scoring *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
Reference in New Issue
Block a user