mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 01:08:50 -06:00
Merge branch 'dev'
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
VERSION_CODE = 47
|
||||
VERSION_NAME = 1.8.4
|
||||
VERSION_CODE = 48
|
||||
VERSION_NAME = 1.8.5
|
||||
|
||||
MIN_SDK_VERSION = 21
|
||||
TARGET_SDK_VERSION = 29
|
||||
|
||||
@@ -61,7 +61,6 @@ class CheckmarkPanelViewTest : BaseViewTest() {
|
||||
|
||||
@After
|
||||
public override fun tearDown() {
|
||||
// view.onDetachedFromWindow()
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
@@ -70,11 +69,12 @@ class CheckmarkPanelViewTest : BaseViewTest() {
|
||||
assertRenders(view, "$PATH/render.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender_withDifferentColor() {
|
||||
view.color = PaletteUtils.getAndroidTestColor(1)
|
||||
assertRenders(view, "$PATH/render_different_color.png")
|
||||
}
|
||||
// // Flaky test
|
||||
// @Test
|
||||
// fun testRender_withDifferentColor() {
|
||||
// view.color = PaletteUtils.getAndroidTestColor(1)
|
||||
// assertRenders(view, "$PATH/render_different_color.png")
|
||||
// }
|
||||
|
||||
// // Flaky test
|
||||
// @Test
|
||||
|
||||
@@ -65,17 +65,19 @@ class NumberPanelViewTest : BaseViewTest() {
|
||||
assertRenders(view, "$PATH/render.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender_withDifferentColor() {
|
||||
view.color = PaletteUtils.getAndroidTestColor(1)
|
||||
assertRenders(view, "$PATH/render_different_color.png")
|
||||
}
|
||||
// // Flaky test
|
||||
// @Test
|
||||
// fun testRender_withDifferentColor() {
|
||||
// view.color = PaletteUtils.getAndroidTestColor(1)
|
||||
// assertRenders(view, "$PATH/render_different_color.png")
|
||||
// }
|
||||
|
||||
@Test
|
||||
fun testRender_Reversed() {
|
||||
prefs.isCheckmarkSequenceReversed = true
|
||||
assertRenders(view, "$PATH/render_reversed.png")
|
||||
}
|
||||
// // Flaky test
|
||||
// @Test
|
||||
// fun testRender_Reversed() {
|
||||
// prefs.isCheckmarkSequenceReversed = true
|
||||
// assertRenders(view, "$PATH/render_reversed.png")
|
||||
// }
|
||||
|
||||
// // Flaky test
|
||||
// @Test
|
||||
|
||||
@@ -48,9 +48,10 @@ class HabitsModule {
|
||||
fun getReminderScheduler(
|
||||
sys: IntentScheduler,
|
||||
commandRunner: CommandRunner,
|
||||
habitList: HabitList
|
||||
habitList: HabitList,
|
||||
widgetPreferences: WidgetPreferences
|
||||
): ReminderScheduler {
|
||||
return ReminderScheduler(commandRunner, habitList, sys)
|
||||
return ReminderScheduler(commandRunner, habitList, sys, widgetPreferences)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -148,13 +148,9 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
|
||||
updateWeekdayPreference();
|
||||
|
||||
if (SDK_INT < Build.VERSION_CODES.O)
|
||||
findPreference("reminderCustomize").setVisible(false);
|
||||
else
|
||||
{
|
||||
findPreference("reminderSound").setVisible(false);
|
||||
findPreference("pref_snooze_interval").setVisible(false);
|
||||
}
|
||||
// Temporarily disable this; we now always ask
|
||||
findPreference("reminderSound").setVisible(false);
|
||||
findPreference("pref_snooze_interval").setVisible(false);
|
||||
|
||||
updateSync();
|
||||
}
|
||||
|
||||
@@ -66,8 +66,8 @@ class AndroidNotificationTray
|
||||
timestamp: Timestamp,
|
||||
reminderTime: Long) {
|
||||
val notificationManager = NotificationManagerCompat.from(context)
|
||||
val summary = buildSummary(habit, reminderTime)
|
||||
notificationManager.notify(Int.MAX_VALUE, summary)
|
||||
//val summary = buildSummary(habit, reminderTime)
|
||||
//notificationManager.notify(Int.MAX_VALUE, summary)
|
||||
val notification = buildNotification(habit, reminderTime, timestamp)
|
||||
createAndroidNotificationChannel(context)
|
||||
try {
|
||||
@@ -132,13 +132,11 @@ class AndroidNotificationTray
|
||||
if (preferences.shouldMakeNotificationsLed())
|
||||
builder.setLights(Color.RED, 1000, 1000)
|
||||
|
||||
if (SDK_INT < Build.VERSION_CODES.O) {
|
||||
val snoozeAction = Action(R.drawable.ic_action_snooze,
|
||||
context.getString(R.string.snooze),
|
||||
pendingIntents.snoozeNotification(habit))
|
||||
wearableExtender.addAction(snoozeAction)
|
||||
builder.addAction(snoozeAction)
|
||||
}
|
||||
val snoozeAction = Action(R.drawable.ic_action_snooze,
|
||||
context.getString(R.string.snooze),
|
||||
pendingIntents.snoozeNotification(habit))
|
||||
wearableExtender.addAction(snoozeAction)
|
||||
builder.addAction(snoozeAction)
|
||||
|
||||
builder.extend(wearableExtender)
|
||||
return builder.build()
|
||||
|
||||
@@ -26,6 +26,9 @@ public class SnoozeDelayPickerActivity extends FragmentActivity
|
||||
|
||||
private ReminderController reminderController;
|
||||
|
||||
@Nullable
|
||||
private AlertDialog dialog;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle bundle)
|
||||
{
|
||||
@@ -40,7 +43,7 @@ public class SnoozeDelayPickerActivity extends FragmentActivity
|
||||
if (habit == null) finish();
|
||||
|
||||
int theme = R.style.Theme_AppCompat_Light_Dialog_Alert;
|
||||
AlertDialog dialog = new AlertDialog.Builder(new ContextThemeWrapper(this, theme))
|
||||
dialog = new AlertDialog.Builder(new ContextThemeWrapper(this, theme))
|
||||
.setTitle(R.string.select_snooze_delay)
|
||||
.setItems(R.array.snooze_picker_names, null)
|
||||
.create();
|
||||
@@ -82,4 +85,11 @@ public class SnoozeDelayPickerActivity extends FragmentActivity
|
||||
super.finish();
|
||||
overridePendingTransition(0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause()
|
||||
{
|
||||
if (dialog != null) dialog.dismiss();
|
||||
super.onPause();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,17 +70,13 @@ public class ReminderController
|
||||
|
||||
public void onSnoozePressed(@NonNull Habit habit, final Context context)
|
||||
{
|
||||
long delay = preferences.getSnoozeInterval();
|
||||
|
||||
if (delay < 0)
|
||||
showSnoozeDelayPicker(habit, context);
|
||||
else
|
||||
scheduleReminderMinutesFromNow(habit, delay);
|
||||
showSnoozeDelayPicker(habit, context);
|
||||
}
|
||||
|
||||
public void onSnoozeDelayPicked(Habit habit, int delay)
|
||||
public void onSnoozeDelayPicked(Habit habit, int delayInMinutes)
|
||||
{
|
||||
scheduleReminderMinutesFromNow(habit, delay);
|
||||
reminderScheduler.snoozeReminder(habit, delayInMinutes);
|
||||
notificationTray.cancel(habit);
|
||||
}
|
||||
|
||||
public void onSnoozeTimePicked(Habit habit, int hour, int minute)
|
||||
@@ -95,12 +91,6 @@ public class ReminderController
|
||||
notificationTray.cancel(habit);
|
||||
}
|
||||
|
||||
private void scheduleReminderMinutesFromNow(Habit habit, long minutes)
|
||||
{
|
||||
reminderScheduler.scheduleMinutesFromNow(habit, minutes);
|
||||
notificationTray.cancel(habit);
|
||||
}
|
||||
|
||||
private void showSnoozeDelayPicker(@NonNull Habit habit, Context context)
|
||||
{
|
||||
context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
1.8.4
|
||||
1.8.5
|
||||
* Bugfixes
|
||||
1.8:
|
||||
* New bar chart showing number of repetitions performed each week, month or year
|
||||
|
||||
@@ -61,21 +61,6 @@ public class ReminderControllerTest extends BaseAndroidJVMTest
|
||||
verifyNoMoreInteractions(preferences);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnSnooze() throws Exception
|
||||
{
|
||||
Habit habit = mock(Habit.class);
|
||||
long now = timestamp(2015, 1, 1);
|
||||
long nowTz = DateUtils.applyTimezone(now);
|
||||
DateUtils.setFixedLocalTime(now);
|
||||
when(preferences.getSnoozeInterval()).thenReturn(15L);
|
||||
|
||||
controller.onSnoozePressed(habit,null);
|
||||
|
||||
verify(reminderScheduler).scheduleMinutesFromNow(habit, 15L);
|
||||
verify(notificationTray).cancel(habit);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnShowReminder() throws Exception
|
||||
{
|
||||
|
||||
@@ -57,7 +57,27 @@ public class WidgetPreferences {
|
||||
storage.remove(habitIdKey);
|
||||
}
|
||||
|
||||
public long getSnoozeTime(long id)
|
||||
{
|
||||
return storage.getLong(getSnoozeKey(id), 0);
|
||||
}
|
||||
|
||||
private String getHabitIdKey(int id) {
|
||||
return String.format("widget-%06d-habit", id);
|
||||
}
|
||||
|
||||
private String getSnoozeKey(long id)
|
||||
{
|
||||
return String.format("snooze-%06d", id);
|
||||
}
|
||||
|
||||
public void removeSnoozeTime(long id)
|
||||
{
|
||||
storage.putLong(getSnoozeKey(id), 0);
|
||||
}
|
||||
|
||||
public void setSnoozeTime(Long id, long time)
|
||||
{
|
||||
storage.putLong(getSnoozeKey(id), time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.support.annotation.*;
|
||||
import org.isoron.uhabits.core.*;
|
||||
import org.isoron.uhabits.core.commands.*;
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.core.preferences.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -34,6 +35,8 @@ import static org.isoron.uhabits.core.utils.DateUtils.*;
|
||||
@AppScope
|
||||
public class ReminderScheduler implements CommandRunner.Listener
|
||||
{
|
||||
private final WidgetPreferences widgetPreferences;
|
||||
|
||||
private CommandRunner commandRunner;
|
||||
|
||||
private HabitList habitList;
|
||||
@@ -43,43 +46,77 @@ public class ReminderScheduler implements CommandRunner.Listener
|
||||
@Inject
|
||||
public ReminderScheduler(@NonNull CommandRunner commandRunner,
|
||||
@NonNull HabitList habitList,
|
||||
@NonNull SystemScheduler sys)
|
||||
@NonNull SystemScheduler sys,
|
||||
@NonNull WidgetPreferences widgetPreferences)
|
||||
{
|
||||
this.commandRunner = commandRunner;
|
||||
this.habitList = habitList;
|
||||
this.sys = sys;
|
||||
this.widgetPreferences = widgetPreferences;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommandExecuted(@NonNull Command command,
|
||||
@Nullable Long refreshKey)
|
||||
public synchronized void onCommandExecuted(@NonNull Command command,
|
||||
@Nullable Long refreshKey)
|
||||
{
|
||||
if (command instanceof ToggleRepetitionCommand) return;
|
||||
if (command instanceof ChangeHabitColorCommand) return;
|
||||
scheduleAll();
|
||||
}
|
||||
|
||||
public void schedule(@NonNull Habit habit)
|
||||
public synchronized void schedule(@NonNull Habit habit)
|
||||
{
|
||||
if (!habit.hasReminder()) {
|
||||
if (habit.getId() == null)
|
||||
{
|
||||
sys.log("ReminderScheduler", "Habit has null id. Returning.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!habit.hasReminder())
|
||||
{
|
||||
sys.log("ReminderScheduler", "habit=" + habit.id + " has no reminder. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
long reminderTime = habit.getReminder().getTimeInMillis();
|
||||
long snoozeReminderTime = widgetPreferences.getSnoozeTime(habit.getId());
|
||||
|
||||
if (snoozeReminderTime != 0)
|
||||
{
|
||||
long now = applyTimezone(getLocalTime());
|
||||
sys.log("ReminderScheduler", String.format(
|
||||
Locale.US,
|
||||
"Habit %d has been snoozed until %d",
|
||||
habit.getId(),
|
||||
snoozeReminderTime));
|
||||
|
||||
if (snoozeReminderTime > now)
|
||||
{
|
||||
sys.log("ReminderScheduler", "Snooze time is in the future. Accepting.");
|
||||
reminderTime = snoozeReminderTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
sys.log("ReminderScheduler", "Snooze time is in the past. Discarding.");
|
||||
widgetPreferences.removeSnoozeTime(habit.getId());
|
||||
}
|
||||
}
|
||||
scheduleAtTime(habit, reminderTime);
|
||||
|
||||
}
|
||||
|
||||
public void scheduleAtTime(@NonNull Habit habit, long reminderTime)
|
||||
public synchronized void scheduleAtTime(@NonNull Habit habit, long reminderTime)
|
||||
{
|
||||
sys.log("ReminderScheduler", "Scheduling alarm for habit=" + habit.id);
|
||||
|
||||
if (!habit.hasReminder()) {
|
||||
if (!habit.hasReminder())
|
||||
{
|
||||
sys.log("ReminderScheduler", "habit=" + habit.id + " has no reminder. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (habit.isArchived()) {
|
||||
if (habit.isArchived())
|
||||
{
|
||||
sys.log("ReminderScheduler", "habit=" + habit.id + " is archived. Skipping.");
|
||||
return;
|
||||
}
|
||||
@@ -100,26 +137,27 @@ public class ReminderScheduler implements CommandRunner.Listener
|
||||
{
|
||||
sys.log("ReminderScheduler", "Scheduling all alarms");
|
||||
HabitList reminderHabits =
|
||||
habitList.getFiltered(HabitMatcher.WITH_ALARM);
|
||||
habitList.getFiltered(HabitMatcher.WITH_ALARM);
|
||||
for (Habit habit : reminderHabits)
|
||||
schedule(habit);
|
||||
}
|
||||
|
||||
public void startListening()
|
||||
public synchronized void startListening()
|
||||
{
|
||||
commandRunner.addListener(this);
|
||||
}
|
||||
|
||||
public void stopListening()
|
||||
public synchronized void stopListening()
|
||||
{
|
||||
commandRunner.removeListener(this);
|
||||
}
|
||||
|
||||
public void scheduleMinutesFromNow(Habit habit, long minutes)
|
||||
public synchronized void snoozeReminder(Habit habit, long minutes)
|
||||
{
|
||||
long now = applyTimezone(getLocalTime());
|
||||
long reminderTime = now + minutes * 60 * 1000;
|
||||
scheduleAtTime(habit, reminderTime);
|
||||
long snoozedUntil = now + minutes * 60 * 1000;
|
||||
widgetPreferences.setSnoozeTime(habit.getId(), snoozedUntil);
|
||||
schedule(habit);
|
||||
}
|
||||
|
||||
public interface SystemScheduler
|
||||
|
||||
@@ -21,6 +21,7 @@ package org.isoron.uhabits.core.reminders;
|
||||
|
||||
import org.isoron.uhabits.core.*;
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.core.preferences.*;
|
||||
import org.isoron.uhabits.core.utils.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
@@ -29,11 +30,16 @@ import org.mockito.junit.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.isoron.uhabits.core.utils.DateUtils.applyTimezone;
|
||||
import static org.isoron.uhabits.core.utils.DateUtils.removeTimezone;
|
||||
import static org.isoron.uhabits.core.utils.DateUtils.setFixedLocalTime;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ReminderSchedulerTest extends BaseUnitTest
|
||||
{
|
||||
private final long habitId = 10L;
|
||||
|
||||
private Habit habit;
|
||||
|
||||
private ReminderScheduler reminderScheduler;
|
||||
@@ -41,15 +47,19 @@ public class ReminderSchedulerTest extends BaseUnitTest
|
||||
@Mock
|
||||
private ReminderScheduler.SystemScheduler sys;
|
||||
|
||||
@Mock
|
||||
private WidgetPreferences widgetPreferences;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
habit = fixtures.createEmptyHabit();
|
||||
habit.id = habitId;
|
||||
|
||||
reminderScheduler =
|
||||
new ReminderScheduler(commandRunner, habitList, sys);
|
||||
new ReminderScheduler(commandRunner, habitList, sys, widgetPreferences);
|
||||
|
||||
DateUtils.setFixedTimeZone(TimeZone.getTimeZone("GMT-4"));
|
||||
}
|
||||
@@ -58,7 +68,7 @@ public class ReminderSchedulerTest extends BaseUnitTest
|
||||
public void testScheduleAll()
|
||||
{
|
||||
long now = unixTime(2015, 1, 26, 13, 0);
|
||||
DateUtils.setFixedLocalTime(now);
|
||||
setFixedLocalTime(now);
|
||||
|
||||
Habit h1 = fixtures.createEmptyHabit();
|
||||
Habit h2 = fixtures.createEmptyHabit();
|
||||
@@ -88,11 +98,33 @@ public class ReminderSchedulerTest extends BaseUnitTest
|
||||
scheduleAndVerify(atTime, expectedCheckmarkTime, atTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchedule_withSnooze()
|
||||
{
|
||||
long now = removeTimezone(unixTime(2015, 1, 1, 15, 0));
|
||||
setFixedLocalTime(now);
|
||||
|
||||
long snoozeTimeInFuture = unixTime(2015, 1, 1, 21, 0);
|
||||
long snoozeTimeInPast = unixTime(2015, 1, 1, 7, 0);
|
||||
long regularReminderTime = applyTimezone(unixTime(2015, 1, 2, 8, 30));
|
||||
long todayCheckmarkTime = unixTime(2015, 1, 1, 0, 0);
|
||||
long tomorrowCheckmarkTime = unixTime(2015, 1, 2, 0, 0);
|
||||
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
|
||||
|
||||
when(widgetPreferences.getSnoozeTime(habitId)).thenReturn(snoozeTimeInFuture);
|
||||
reminderScheduler.schedule(habit);
|
||||
verify(sys).scheduleShowReminder(snoozeTimeInFuture, habit, todayCheckmarkTime);
|
||||
|
||||
when(widgetPreferences.getSnoozeTime(habitId)).thenReturn(snoozeTimeInPast);
|
||||
reminderScheduler.schedule(habit);
|
||||
verify(sys).scheduleShowReminder(regularReminderTime, habit, tomorrowCheckmarkTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchedule_laterToday()
|
||||
{
|
||||
long now = unixTime(2015, 1, 26, 6, 30);
|
||||
DateUtils.setFixedLocalTime(now);
|
||||
setFixedLocalTime(now);
|
||||
|
||||
long expectedCheckmarkTime = unixTime(2015, 1, 26, 0, 0);
|
||||
long expectedReminderTime = unixTime(2015, 1, 26, 12, 30);
|
||||
@@ -105,7 +137,7 @@ public class ReminderSchedulerTest extends BaseUnitTest
|
||||
public void testSchedule_tomorrow()
|
||||
{
|
||||
long now = unixTime(2015, 1, 26, 13, 0);
|
||||
DateUtils.setFixedLocalTime(now);
|
||||
setFixedLocalTime(now);
|
||||
|
||||
long expectedCheckmarkTime = unixTime(2015, 1, 27, 0, 0);
|
||||
long expectedReminderTime = unixTime(2015, 1, 27, 12, 30);
|
||||
|
||||
Reference in New Issue
Block a user