diff --git a/build.gradle b/build.gradle
index b21b92ae7..6692adb1e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.0.0-beta6'
+ classpath 'com.android.tools.build:gradle:3.0.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.6.4'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
diff --git a/gradle.properties b/gradle.properties
index bc47317b6..9e3278641 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,7 +6,7 @@ TARGET_SDK_VERSION = 25
COMPILE_SDK_VERSION = 25
DAGGER_VERSION = 2.9
-BUILD_TOOLS_VERSION = 26.0.0
+BUILD_TOOLS_VERSION = 26.0.2
KOTLIN_VERSION = 1.1.2-4
SUPPORT_LIBRARY_VERSION = 25.3.1
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt b/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt
index 2758ba934..b60904840 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt
@@ -54,6 +54,15 @@ class PendingIntentFactory
},
FLAG_UPDATE_CURRENT)
+ fun removeRepetition(habit: Habit): PendingIntent =
+ PendingIntent.getBroadcast(
+ context, 3,
+ Intent(context, WidgetReceiver::class.java).apply {
+ action = WidgetReceiver.ACTION_REMOVE_REPETITION
+ data = Uri.parse(habit.uriString)
+ },
+ FLAG_UPDATE_CURRENT)
+
fun showHabit(habit: Habit): PendingIntent =
android.support.v4.app.TaskStackBuilder
.create(context)
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt
index 6a25300d0..15abc403f 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt
@@ -23,6 +23,7 @@ import android.app.*
import android.content.*
import android.graphics.*
import android.graphics.BitmapFactory.*
+import android.support.annotation.*
import android.support.v4.app.*
import android.support.v4.app.NotificationCompat.*
import org.isoron.androidbase.*
@@ -50,11 +51,24 @@ class AndroidNotificationTray
override fun showNotification(habit: Habit,
notificationId: Int,
timestamp: Timestamp,
- reminderTime: Long) {
+ reminderTime: Long)
+ {
+ val notificationManager = NotificationManagerCompat.from(context)
+ val summary = buildSummary(reminderTime)
+ notificationManager.notify(Int.MAX_VALUE, summary)
+ val notification = buildNotification(habit, reminderTime, timestamp)
+ notificationManager.notify(notificationId, notification)
+ }
+
+ @NonNull
+ fun buildNotification(@NonNull habit: Habit,
+ @NonNull reminderTime: Long,
+ @NonNull timestamp: Timestamp) : Notification
+ {
- val checkAction = Action(
+ val addRepetitionAction = Action(
R.drawable.ic_action_check,
- context.getString(R.string.check),
+ context.getString(R.string.yes),
pendingIntents.addCheckmark(habit, timestamp))
val snoozeAction = Action(
@@ -62,6 +76,12 @@ class AndroidNotificationTray
context.getString(R.string.snooze),
pendingIntents.snoozeNotification(habit))
+ val removeRepetitionAction = Action(
+ R.drawable.ic_action_cancel,
+ context.getString(R.string.no),
+ pendingIntents.removeRepetition(habit)
+ )
+
val wearableBg = decodeResource(context.resources, R.drawable.stripe)
// Even though the set of actions is the same on the phone and
@@ -69,7 +89,8 @@ class AndroidNotificationTray
// WearableExtender.
val wearableExtender = WearableExtender()
.setBackground(wearableBg)
- .addAction(checkAction)
+ .addAction(addRepetitionAction)
+ .addAction(removeRepetitionAction)
.addAction(snoozeAction)
val builder = NotificationCompat.Builder(context)
@@ -78,20 +99,32 @@ class AndroidNotificationTray
.setContentText(habit.description)
.setContentIntent(pendingIntents.showHabit(habit))
.setDeleteIntent(pendingIntents.dismissNotification(habit))
- .addAction(checkAction)
+ .addAction(addRepetitionAction)
+ .addAction(removeRepetitionAction)
.addAction(snoozeAction)
.setSound(ringtoneManager.getURI())
.extend(wearableExtender)
.setWhen(reminderTime)
.setShowWhen(true)
.setOngoing(preferences.shouldMakeNotificationsSticky())
+ .setGroup("default")
if (preferences.shouldMakeNotificationsLed())
builder.setLights(Color.RED, 1000, 1000)
- val notificationManager = context.getSystemService(
- Activity.NOTIFICATION_SERVICE) as NotificationManager
+ return builder.build()
+ }
- notificationManager.notify(notificationId, builder.build())
+ @NonNull
+ private fun buildSummary(@NonNull reminderTime: Long) : Notification
+ {
+ return NotificationCompat.Builder(context)
+ .setSmallIcon(R.drawable.ic_notification)
+ .setContentTitle(context.getString(R.string.app_name))
+ .setWhen(reminderTime)
+ .setShowWhen(true)
+ .setGroup("default")
+ .setGroupSummary(true)
+ .build()
}
}
diff --git a/uhabits-android/src/main/res/drawable-hdpi/ic_action_cancel.png b/uhabits-android/src/main/res/drawable-hdpi/ic_action_cancel.png
new file mode 100644
index 000000000..374fc6fc0
Binary files /dev/null and b/uhabits-android/src/main/res/drawable-hdpi/ic_action_cancel.png differ
diff --git a/uhabits-android/src/main/res/drawable-mdpi/ic_action_cancel.png b/uhabits-android/src/main/res/drawable-mdpi/ic_action_cancel.png
new file mode 100644
index 000000000..e7de03a06
Binary files /dev/null and b/uhabits-android/src/main/res/drawable-mdpi/ic_action_cancel.png differ
diff --git a/uhabits-android/src/main/res/drawable-xhdpi/ic_action_cancel.png b/uhabits-android/src/main/res/drawable-xhdpi/ic_action_cancel.png
new file mode 100644
index 000000000..dbd10906c
Binary files /dev/null and b/uhabits-android/src/main/res/drawable-xhdpi/ic_action_cancel.png differ
diff --git a/uhabits-android/src/main/res/drawable-xxhdpi/ic_action_cancel.png b/uhabits-android/src/main/res/drawable-xxhdpi/ic_action_cancel.png
new file mode 100644
index 000000000..20591def4
Binary files /dev/null and b/uhabits-android/src/main/res/drawable-xxhdpi/ic_action_cancel.png differ
diff --git a/uhabits-android/src/main/res/values/strings.xml b/uhabits-android/src/main/res/values/strings.xml
index a78c873cb..5c043b111 100644
--- a/uhabits-android/src/main/res/values/strings.xml
+++ b/uhabits-android/src/main/res/values/strings.xml
@@ -220,4 +220,6 @@
e.g. Did you exercise today?
Question
Target
+ Yes
+ No
\ No newline at end of file
diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryHabitList.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryHabitList.java
index 5e2727114..c1d05f517 100644
--- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryHabitList.java
+++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryHabitList.java
@@ -155,14 +155,14 @@ public class MemoryHabitList extends HabitList
}
@Override
- public int indexOf(@NonNull Habit h)
+ public synchronized int indexOf(@NonNull Habit h)
{
return list.indexOf(h);
}
@NonNull
@Override
- public Iterator iterator()
+ public synchronized Iterator iterator()
{
return Collections.unmodifiableCollection(list).iterator();
}
@@ -200,13 +200,13 @@ public class MemoryHabitList extends HabitList
}
@Override
- public int size()
+ public synchronized int size()
{
return list.size();
}
@Override
- public void update(List habits)
+ public synchronized void update(List habits)
{
resort();
getObservable().notifyListeners();
diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitList.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitList.java
index bb16e1f49..ab086cff5 100644
--- a/uhabits-core/src/main/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitList.java
+++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitList.java
@@ -91,7 +91,7 @@ public class SQLiteHabitList extends HabitList
@Override
@Nullable
- public Habit getById(long id)
+ public synchronized Habit getById(long id)
{
loadRecords();
return list.getById(id);
@@ -99,7 +99,7 @@ public class SQLiteHabitList extends HabitList
@Override
@NonNull
- public Habit getByPosition(int position)
+ public synchronized Habit getByPosition(int position)
{
loadRecords();
return list.getByPosition(position);
@@ -107,7 +107,7 @@ public class SQLiteHabitList extends HabitList
@NonNull
@Override
- public HabitList getFiltered(HabitMatcher filter)
+ public synchronized HabitList getFiltered(HabitMatcher filter)
{
loadRecords();
return list.getFiltered(filter);
@@ -121,21 +121,21 @@ public class SQLiteHabitList extends HabitList
}
@Override
- public void setOrder(@NonNull Order order)
+ public synchronized void setOrder(@NonNull Order order)
{
list.setOrder(order);
getObservable().notifyListeners();
}
@Override
- public int indexOf(@NonNull Habit h)
+ public synchronized int indexOf(@NonNull Habit h)
{
loadRecords();
return list.indexOf(h);
}
@Override
- public Iterator iterator()
+ public synchronized Iterator iterator()
{
loadRecords();
return list.iterator();
@@ -214,7 +214,7 @@ public class SQLiteHabitList extends HabitList
}
@Override
- public void repair()
+ public synchronized void repair()
{
loadRecords();
rebuildOrder();
@@ -222,7 +222,7 @@ public class SQLiteHabitList extends HabitList
}
@Override
- public int size()
+ public synchronized int size()
{
loadRecords();
return list.size();
@@ -245,7 +245,7 @@ public class SQLiteHabitList extends HabitList
getObservable().notifyListeners();
}
- public void reload()
+ public synchronized void reload()
{
loaded = false;
}
diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java
index 1f9500123..d3aa800af 100644
--- a/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java
+++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java
@@ -48,14 +48,15 @@ public class WidgetBehavior
public void onAddRepetition(@NonNull Habit habit, Timestamp timestamp)
{
+ notificationTray.cancel(habit);
Repetition rep = habit.getRepetitions().getByTimestamp(timestamp);
if (rep != null) return;
performToggle(habit, timestamp);
- notificationTray.cancel(habit);
}
public void onRemoveRepetition(@NonNull Habit habit, Timestamp timestamp)
{
+ notificationTray.cancel(habit);
Repetition rep = habit.getRepetitions().getByTimestamp(timestamp);
if (rep == null) return;
performToggle(habit, timestamp);