mirror of https://github.com/iSoron/uhabits.git
parent
b21eb3f118
commit
8f5f72d9fd
@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.core.reminders;
|
||||
|
||||
import androidx.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.*;
|
||||
|
||||
import javax.inject.*;
|
||||
|
||||
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;
|
||||
|
||||
private SystemScheduler sys;
|
||||
|
||||
@Inject
|
||||
public ReminderScheduler(@NonNull CommandRunner commandRunner,
|
||||
@NonNull HabitList habitList,
|
||||
@NonNull SystemScheduler sys,
|
||||
@NonNull WidgetPreferences widgetPreferences)
|
||||
{
|
||||
this.commandRunner = commandRunner;
|
||||
this.habitList = habitList;
|
||||
this.sys = sys;
|
||||
this.widgetPreferences = widgetPreferences;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onCommandFinished(@Nullable Command command)
|
||||
{
|
||||
if (command instanceof CreateRepetitionCommand) return;
|
||||
if (command instanceof ChangeHabitColorCommand) return;
|
||||
scheduleAll();
|
||||
}
|
||||
|
||||
public synchronized void schedule(@NonNull Habit habit)
|
||||
{
|
||||
if (habit.getId() == null)
|
||||
{
|
||||
sys.log("ReminderScheduler", "Habit has null id. Returning.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!habit.hasReminder())
|
||||
{
|
||||
sys.log("ReminderScheduler", "habit=" + habit.getId() + " has no reminder. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
long reminderTime = Objects.requireNonNull(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 synchronized void scheduleAtTime(@NonNull Habit habit, long reminderTime)
|
||||
{
|
||||
sys.log("ReminderScheduler", "Scheduling alarm for habit=" + habit.getId());
|
||||
|
||||
if (!habit.hasReminder())
|
||||
{
|
||||
sys.log("ReminderScheduler", "habit=" + habit.getId() + " has no reminder. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (habit.isArchived())
|
||||
{
|
||||
sys.log("ReminderScheduler", "habit=" + habit.getId() + " is archived. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
long timestamp = getStartOfDayWithOffset(removeTimezone(reminderTime));
|
||||
sys.log("ReminderScheduler",
|
||||
String.format(
|
||||
Locale.US,
|
||||
"reminderTime=%d removeTimezone=%d timestamp=%d",
|
||||
reminderTime,
|
||||
removeTimezone(reminderTime),
|
||||
timestamp));
|
||||
|
||||
sys.scheduleShowReminder(reminderTime, habit, timestamp);
|
||||
}
|
||||
|
||||
public synchronized void scheduleAll()
|
||||
{
|
||||
sys.log("ReminderScheduler", "Scheduling all alarms");
|
||||
HabitList reminderHabits =
|
||||
habitList.getFiltered(HabitMatcher.WITH_ALARM);
|
||||
for (Habit habit : reminderHabits)
|
||||
schedule(habit);
|
||||
}
|
||||
|
||||
public synchronized void startListening()
|
||||
{
|
||||
commandRunner.addListener(this);
|
||||
}
|
||||
|
||||
public synchronized void stopListening()
|
||||
{
|
||||
commandRunner.removeListener(this);
|
||||
}
|
||||
|
||||
public synchronized void snoozeReminder(Habit habit, long minutes)
|
||||
{
|
||||
long now = applyTimezone(getLocalTime());
|
||||
long snoozedUntil = now + minutes * 60 * 1000;
|
||||
widgetPreferences.setSnoozeTime(habit.getId(), snoozedUntil);
|
||||
schedule(habit);
|
||||
}
|
||||
|
||||
public interface SystemScheduler
|
||||
{
|
||||
SchedulerResult scheduleShowReminder(long reminderTime, Habit habit, long timestamp);
|
||||
|
||||
SchedulerResult scheduleWidgetUpdate(long updateTime);
|
||||
|
||||
void log(String componentName, String msg);
|
||||
}
|
||||
|
||||
public enum SchedulerResult
|
||||
{
|
||||
IGNORED,
|
||||
OK
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.isoron.uhabits.core.reminders
|
||||
|
||||
import org.isoron.uhabits.core.AppScope
|
||||
import org.isoron.uhabits.core.commands.ChangeHabitColorCommand
|
||||
import org.isoron.uhabits.core.commands.Command
|
||||
import org.isoron.uhabits.core.commands.CommandRunner
|
||||
import org.isoron.uhabits.core.commands.CreateRepetitionCommand
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.models.HabitList
|
||||
import org.isoron.uhabits.core.models.HabitMatcher
|
||||
import org.isoron.uhabits.core.preferences.WidgetPreferences
|
||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.applyTimezone
|
||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.getLocalTime
|
||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.getStartOfDayWithOffset
|
||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.removeTimezone
|
||||
import java.util.Locale
|
||||
import java.util.Objects
|
||||
import javax.inject.Inject
|
||||
|
||||
@AppScope
|
||||
class ReminderScheduler @Inject constructor(
|
||||
private val commandRunner: CommandRunner,
|
||||
private val habitList: HabitList,
|
||||
private val sys: SystemScheduler,
|
||||
private val widgetPreferences: WidgetPreferences
|
||||
) : CommandRunner.Listener {
|
||||
@Synchronized
|
||||
override fun onCommandFinished(command: Command) {
|
||||
if (command is CreateRepetitionCommand) return
|
||||
if (command is ChangeHabitColorCommand) return
|
||||
scheduleAll()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun schedule(habit: Habit) {
|
||||
if (habit.id == null) {
|
||||
sys.log("ReminderScheduler", "Habit has null id. Returning.")
|
||||
return
|
||||
}
|
||||
if (!habit.hasReminder()) {
|
||||
sys.log("ReminderScheduler", "habit=" + habit.id + " has no reminder. Skipping.")
|
||||
return
|
||||
}
|
||||
var reminderTime = Objects.requireNonNull(habit.reminder)!!.timeInMillis
|
||||
val snoozeReminderTime = widgetPreferences.getSnoozeTime(habit.id!!)
|
||||
if (snoozeReminderTime != 0L) {
|
||||
val now = applyTimezone(getLocalTime())
|
||||
sys.log(
|
||||
"ReminderScheduler",
|
||||
String.format(
|
||||
Locale.US,
|
||||
"Habit %d has been snoozed until %d",
|
||||
habit.id,
|
||||
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.id!!)
|
||||
}
|
||||
}
|
||||
scheduleAtTime(habit, reminderTime)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun scheduleAtTime(habit: Habit, reminderTime: Long) {
|
||||
sys.log("ReminderScheduler", "Scheduling alarm for habit=" + habit.id)
|
||||
if (!habit.hasReminder()) {
|
||||
sys.log("ReminderScheduler", "habit=" + habit.id + " has no reminder. Skipping.")
|
||||
return
|
||||
}
|
||||
if (habit.isArchived) {
|
||||
sys.log("ReminderScheduler", "habit=" + habit.id + " is archived. Skipping.")
|
||||
return
|
||||
}
|
||||
val timestamp = getStartOfDayWithOffset(removeTimezone(reminderTime))
|
||||
sys.log(
|
||||
"ReminderScheduler",
|
||||
String.format(
|
||||
Locale.US,
|
||||
"reminderTime=%d removeTimezone=%d timestamp=%d",
|
||||
reminderTime,
|
||||
removeTimezone(reminderTime),
|
||||
timestamp
|
||||
)
|
||||
)
|
||||
sys.scheduleShowReminder(reminderTime, habit, timestamp)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun scheduleAll() {
|
||||
sys.log("ReminderScheduler", "Scheduling all alarms")
|
||||
val reminderHabits = habitList.getFiltered(HabitMatcher.WITH_ALARM)
|
||||
for (habit in reminderHabits) schedule(habit)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun startListening() {
|
||||
commandRunner.addListener(this)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun stopListening() {
|
||||
commandRunner.removeListener(this)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun snoozeReminder(habit: Habit, minutes: Long) {
|
||||
val now = applyTimezone(getLocalTime())
|
||||
val snoozedUntil = now + minutes * 60 * 1000
|
||||
widgetPreferences.setSnoozeTime(habit.id, snoozedUntil)
|
||||
schedule(habit)
|
||||
}
|
||||
|
||||
interface SystemScheduler {
|
||||
fun scheduleShowReminder(
|
||||
reminderTime: Long,
|
||||
habit: Habit,
|
||||
timestamp: Long
|
||||
): SchedulerResult
|
||||
|
||||
fun scheduleWidgetUpdate(updateTime: Long): SchedulerResult?
|
||||
fun log(componentName: String?, msg: String?)
|
||||
}
|
||||
|
||||
enum class SchedulerResult {
|
||||
IGNORED, OK
|
||||
}
|
||||
}
|
Loading…
Reference in new issue