mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Move ListHabits controllers to uhabits-core
This commit is contained in:
@@ -21,14 +21,31 @@ package org.isoron.uhabits.preferences;
|
||||
|
||||
public interface Preferences
|
||||
{
|
||||
int getLastHintNumber();
|
||||
|
||||
long getLastHintTimestamp();
|
||||
|
||||
boolean getShowArchived();
|
||||
|
||||
boolean getShowCompleted();
|
||||
|
||||
int getTheme();
|
||||
|
||||
void incrementLaunchCount();
|
||||
|
||||
boolean isFirstRun();
|
||||
|
||||
boolean isPureBlackEnabled();
|
||||
|
||||
void setDeveloper(boolean isDeveloper);
|
||||
|
||||
void setFirstRun(boolean b);
|
||||
|
||||
void setShowArchived(boolean showArchived);
|
||||
|
||||
void setShowCompleted(boolean showCompleted);
|
||||
|
||||
void setTheme(int theme);
|
||||
|
||||
void updateLastHint(int i, long startOfToday);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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.ui;
|
||||
|
||||
import org.isoron.uhabits.models.*;
|
||||
|
||||
public interface NotificationTray
|
||||
{
|
||||
void cancel(Habit habit);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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.ui;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.preferences.*;
|
||||
|
||||
public abstract class ThemeSwitcher
|
||||
{
|
||||
public static final int THEME_DARK = 1;
|
||||
|
||||
public static final int THEME_LIGHT = 0;
|
||||
|
||||
private final Preferences preferences;
|
||||
|
||||
public ThemeSwitcher(@NonNull Preferences preferences)
|
||||
{
|
||||
this.preferences = preferences;
|
||||
}
|
||||
|
||||
public void apply()
|
||||
{
|
||||
if (preferences.getTheme() == THEME_DARK)
|
||||
{
|
||||
if (preferences.isPureBlackEnabled()) applyPureBlackTheme();
|
||||
else applyDarkTheme();
|
||||
}
|
||||
else
|
||||
{
|
||||
applyLightTheme();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void applyDarkTheme();
|
||||
|
||||
public abstract void applyLightTheme();
|
||||
|
||||
public abstract void applyPureBlackTheme();
|
||||
|
||||
public boolean isNightMode()
|
||||
{
|
||||
return preferences.getTheme() == THEME_DARK;
|
||||
}
|
||||
|
||||
public void setTheme(int theme)
|
||||
{
|
||||
preferences.setTheme(theme);
|
||||
}
|
||||
|
||||
public void toggleNightMode()
|
||||
{
|
||||
if (isNightMode()) setTheme(THEME_LIGHT);
|
||||
else setTheme(THEME_DARK);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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.ui.callbacks;
|
||||
|
||||
public interface OnColorPickedCallback
|
||||
{
|
||||
void onColorPicked(int color);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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.ui.callbacks;
|
||||
|
||||
public interface OnConfirmedCallback
|
||||
{
|
||||
void onConfirmed();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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.ui.callbacks;
|
||||
|
||||
public interface OnFinishedCallback
|
||||
{
|
||||
void onFinish();
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.ui.about;
|
||||
package org.isoron.uhabits.ui.screens.about;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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.ui.screens.habits.list;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.commands.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.tasks.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import javax.inject.*;
|
||||
|
||||
/**
|
||||
* A HabitCardListCache fetches and keeps a cache of all the data necessary to
|
||||
* render a HabitCardListView.
|
||||
* <p>
|
||||
* This is needed since performing database lookups during scrolling can make
|
||||
* the ListView very slow. It also registers itself as an observer of the
|
||||
* models, in order to update itself automatically.
|
||||
* <p>
|
||||
* Note that this class is singleton-scoped, therefore it is shared among all
|
||||
* activities.
|
||||
*/
|
||||
@AppScope
|
||||
public class HabitCardListCache implements CommandRunner.Listener
|
||||
{
|
||||
private int checkmarkCount;
|
||||
|
||||
private Task currentFetchTask;
|
||||
|
||||
@NonNull
|
||||
private Listener listener;
|
||||
|
||||
@NonNull
|
||||
private CacheData data;
|
||||
|
||||
@NonNull
|
||||
private HabitList allHabits;
|
||||
|
||||
@NonNull
|
||||
private HabitList filteredHabits;
|
||||
|
||||
private final TaskRunner taskRunner;
|
||||
|
||||
private final CommandRunner commandRunner;
|
||||
|
||||
@Inject
|
||||
public HabitCardListCache(@NonNull HabitList allHabits,
|
||||
@NonNull CommandRunner commandRunner,
|
||||
@NonNull TaskRunner taskRunner)
|
||||
{
|
||||
this.allHabits = allHabits;
|
||||
this.commandRunner = commandRunner;
|
||||
this.filteredHabits = allHabits;
|
||||
this.taskRunner = taskRunner;
|
||||
|
||||
this.listener = new Listener() {};
|
||||
data = new CacheData();
|
||||
}
|
||||
|
||||
public void cancelTasks()
|
||||
{
|
||||
if (currentFetchTask != null) currentFetchTask.cancel();
|
||||
}
|
||||
|
||||
public int[] getCheckmarks(long habitId)
|
||||
{
|
||||
return data.checkmarks.get(habitId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the habits that occupies a certain position on the list.
|
||||
*
|
||||
* @param position the position of the habit
|
||||
* @return the habit at given position
|
||||
* @throws IndexOutOfBoundsException if position is not valid
|
||||
*/
|
||||
@NonNull
|
||||
public Habit getHabitByPosition(int position)
|
||||
{
|
||||
return data.habits.get(position);
|
||||
}
|
||||
|
||||
public int getHabitCount()
|
||||
{
|
||||
return data.habits.size();
|
||||
}
|
||||
|
||||
public HabitList.Order getOrder()
|
||||
{
|
||||
return filteredHabits.getOrder();
|
||||
}
|
||||
|
||||
public double getScore(long habitId)
|
||||
{
|
||||
return data.scores.get(habitId);
|
||||
}
|
||||
|
||||
public void onAttached()
|
||||
{
|
||||
refreshAllHabits();
|
||||
commandRunner.addListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommandExecuted(@NonNull Command command,
|
||||
@Nullable Long refreshKey)
|
||||
{
|
||||
if (refreshKey == null) refreshAllHabits();
|
||||
else refreshHabit(refreshKey);
|
||||
}
|
||||
|
||||
public void onDetached()
|
||||
{
|
||||
commandRunner.removeListener(this);
|
||||
}
|
||||
|
||||
public void refreshAllHabits()
|
||||
{
|
||||
if (currentFetchTask != null) currentFetchTask.cancel();
|
||||
currentFetchTask = new RefreshTask();
|
||||
taskRunner.execute(currentFetchTask);
|
||||
}
|
||||
|
||||
public void refreshHabit(long id)
|
||||
{
|
||||
taskRunner.execute(new RefreshTask(id));
|
||||
}
|
||||
|
||||
public void remove(@NonNull Long id)
|
||||
{
|
||||
Habit h = data.id_to_habit.get(id);
|
||||
if (h == null) return;
|
||||
|
||||
int position = data.habits.indexOf(h);
|
||||
data.habits.remove(position);
|
||||
data.id_to_habit.remove(id);
|
||||
data.checkmarks.remove(id);
|
||||
data.scores.remove(id);
|
||||
|
||||
listener.onItemRemoved(position);
|
||||
}
|
||||
|
||||
public void reorder(int from, int to)
|
||||
{
|
||||
Habit fromHabit = data.habits.get(from);
|
||||
data.habits.remove(from);
|
||||
data.habits.add(to, fromHabit);
|
||||
listener.onItemMoved(from, to);
|
||||
}
|
||||
|
||||
public void setCheckmarkCount(int checkmarkCount)
|
||||
{
|
||||
this.checkmarkCount = checkmarkCount;
|
||||
}
|
||||
|
||||
public void setFilter(HabitMatcher matcher)
|
||||
{
|
||||
filteredHabits = allHabits.getFiltered(matcher);
|
||||
}
|
||||
|
||||
public void setListener(@NonNull Listener listener)
|
||||
{
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void setOrder(HabitList.Order order)
|
||||
{
|
||||
allHabits.setOrder(order);
|
||||
filteredHabits.setOrder(order);
|
||||
refreshAllHabits();
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface definition for a callback to be invoked when the data on the
|
||||
* cache has been modified.
|
||||
*/
|
||||
public interface Listener
|
||||
{
|
||||
default void onItemChanged(int position) {}
|
||||
|
||||
default void onItemInserted(int position) {}
|
||||
|
||||
default void onItemMoved(int oldPosition, int newPosition) {}
|
||||
|
||||
default void onItemRemoved(int position) {}
|
||||
|
||||
default void onRefreshFinished() {}
|
||||
}
|
||||
|
||||
private class CacheData
|
||||
{
|
||||
@NonNull
|
||||
public HashMap<Long, Habit> id_to_habit;
|
||||
|
||||
@NonNull
|
||||
public List<Habit> habits;
|
||||
|
||||
@NonNull
|
||||
public HashMap<Long, int[]> checkmarks;
|
||||
|
||||
@NonNull
|
||||
public HashMap<Long, Double> scores;
|
||||
|
||||
/**
|
||||
* Creates a new CacheData without any content.
|
||||
*/
|
||||
public CacheData()
|
||||
{
|
||||
id_to_habit = new HashMap<>();
|
||||
habits = new LinkedList<>();
|
||||
checkmarks = new HashMap<>();
|
||||
scores = new HashMap<>();
|
||||
}
|
||||
|
||||
public void copyCheckmarksFrom(@NonNull CacheData oldData)
|
||||
{
|
||||
int[] empty = new int[checkmarkCount];
|
||||
|
||||
for (Long id : id_to_habit.keySet())
|
||||
{
|
||||
if (oldData.checkmarks.containsKey(id))
|
||||
checkmarks.put(id, oldData.checkmarks.get(id));
|
||||
else checkmarks.put(id, empty);
|
||||
}
|
||||
}
|
||||
|
||||
public void copyScoresFrom(@NonNull CacheData oldData)
|
||||
{
|
||||
for (Long id : id_to_habit.keySet())
|
||||
{
|
||||
if (oldData.scores.containsKey(id))
|
||||
scores.put(id, oldData.scores.get(id));
|
||||
else scores.put(id, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
public void fetchHabits()
|
||||
{
|
||||
for (Habit h : filteredHabits)
|
||||
{
|
||||
habits.add(h);
|
||||
id_to_habit.put(h.getId(), h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class RefreshTask implements Task
|
||||
{
|
||||
@NonNull
|
||||
private CacheData newData;
|
||||
|
||||
@Nullable
|
||||
private Long targetId;
|
||||
|
||||
private boolean isCancelled;
|
||||
|
||||
private TaskRunner runner;
|
||||
|
||||
public RefreshTask()
|
||||
{
|
||||
newData = new CacheData();
|
||||
targetId = null;
|
||||
isCancelled = false;
|
||||
}
|
||||
|
||||
public RefreshTask(long targetId)
|
||||
{
|
||||
newData = new CacheData();
|
||||
this.targetId = targetId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel()
|
||||
{
|
||||
isCancelled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doInBackground()
|
||||
{
|
||||
newData.fetchHabits();
|
||||
newData.copyScoresFrom(data);
|
||||
newData.copyCheckmarksFrom(data);
|
||||
|
||||
long day = DateUtils.millisecondsInOneDay;
|
||||
long dateTo = DateUtils.getStartOfDay(DateUtils.getLocalTime());
|
||||
long dateFrom = dateTo - (checkmarkCount - 1) * day;
|
||||
|
||||
runner.publishProgress(this, -1);
|
||||
|
||||
for (int position = 0; position < newData.habits.size(); position++)
|
||||
{
|
||||
if (isCancelled) return;
|
||||
|
||||
Habit habit = newData.habits.get(position);
|
||||
Long id = habit.getId();
|
||||
if (targetId != null && !targetId.equals(id)) continue;
|
||||
|
||||
newData.scores.put(id, habit.getScores().getTodayValue());
|
||||
newData.checkmarks.put(id,
|
||||
habit.getCheckmarks().getValues(dateFrom, dateTo));
|
||||
|
||||
runner.publishProgress(this, position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttached(@NonNull TaskRunner runner)
|
||||
{
|
||||
this.runner = runner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostExecute()
|
||||
{
|
||||
currentFetchTask = null;
|
||||
listener.onRefreshFinished();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressUpdate(int currentPosition)
|
||||
{
|
||||
if (currentPosition < 0) processRemovedHabits();
|
||||
else processPosition(currentPosition);
|
||||
}
|
||||
|
||||
private void performInsert(Habit habit, int position)
|
||||
{
|
||||
Long id = habit.getId();
|
||||
data.habits.add(position, habit);
|
||||
data.id_to_habit.put(id, habit);
|
||||
data.scores.put(id, newData.scores.get(id));
|
||||
data.checkmarks.put(id, newData.checkmarks.get(id));
|
||||
listener.onItemInserted(position);
|
||||
}
|
||||
|
||||
private void performMove(Habit habit, int fromPosition, int toPosition)
|
||||
{
|
||||
data.habits.remove(fromPosition);
|
||||
data.habits.add(toPosition, habit);
|
||||
listener.onItemMoved(fromPosition, toPosition);
|
||||
}
|
||||
|
||||
private void performUpdate(Long id, int position)
|
||||
{
|
||||
double oldScore = data.scores.get(id);
|
||||
int[] oldCheckmarks = data.checkmarks.get(id);
|
||||
|
||||
double newScore = newData.scores.get(id);
|
||||
int[] newCheckmarks = newData.checkmarks.get(id);
|
||||
|
||||
boolean unchanged = true;
|
||||
if (oldScore != newScore) unchanged = false;
|
||||
if (!Arrays.equals(oldCheckmarks, newCheckmarks)) unchanged = false;
|
||||
if (unchanged) return;
|
||||
|
||||
data.scores.put(id, newScore);
|
||||
data.checkmarks.put(id, newCheckmarks);
|
||||
listener.onItemChanged(position);
|
||||
}
|
||||
|
||||
private void processPosition(int currentPosition)
|
||||
{
|
||||
Habit habit = newData.habits.get(currentPosition);
|
||||
Long id = habit.getId();
|
||||
|
||||
int prevPosition = data.habits.indexOf(habit);
|
||||
|
||||
if (prevPosition < 0) performInsert(habit, currentPosition);
|
||||
else if (prevPosition == currentPosition)
|
||||
performUpdate(id, currentPosition);
|
||||
else performMove(habit, prevPosition, currentPosition);
|
||||
}
|
||||
|
||||
private void processRemovedHabits()
|
||||
{
|
||||
Set<Long> before = data.id_to_habit.keySet();
|
||||
Set<Long> after = newData.id_to_habit.keySet();
|
||||
|
||||
Set<Long> removed = new TreeSet<>(before);
|
||||
removed.removeAll(after);
|
||||
|
||||
for (Long id : removed) remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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.ui.screens.habits.list;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
import com.google.auto.factory.*;
|
||||
|
||||
import org.isoron.uhabits.preferences.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
|
||||
/**
|
||||
* Provides a list of hints to be shown at the application startup, and takes
|
||||
* care of deciding when a new hint should be shown.
|
||||
*/
|
||||
@AutoFactory
|
||||
public class HintList
|
||||
{
|
||||
private final Preferences prefs;
|
||||
|
||||
@NonNull
|
||||
private final String[] hints;
|
||||
|
||||
/**
|
||||
* Constructs a new list containing the provided hints.
|
||||
*
|
||||
* @param hints initial list of hints
|
||||
*/
|
||||
public HintList(@Provided @NonNull Preferences prefs,
|
||||
@NonNull String hints[])
|
||||
{
|
||||
this.prefs = prefs;
|
||||
this.hints = hints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new hint to be shown to the user.
|
||||
* <p>
|
||||
* The hint returned is marked as read on the list, and will not be returned
|
||||
* again. In case all hints have already been read, and there is nothing
|
||||
* left, returns null.
|
||||
*
|
||||
* @return the next hint to be shown, or null if none
|
||||
*/
|
||||
public String pop()
|
||||
{
|
||||
int next = prefs.getLastHintNumber() + 1;
|
||||
if (next >= hints.length) return null;
|
||||
|
||||
prefs.updateLastHint(next, DateUtils.getStartOfToday());
|
||||
return hints[next];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether it is time to show a new hint or not.
|
||||
*
|
||||
* @return true if hint should be shown, false otherwise
|
||||
*/
|
||||
public boolean shouldShow()
|
||||
{
|
||||
long lastHintTimestamp = prefs.getLastHintTimestamp();
|
||||
return (DateUtils.getStartOfToday() > lastHintTimestamp);
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.ui.habits.list;
|
||||
package org.isoron.uhabits.ui.screens.habits.list;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
@@ -187,11 +187,6 @@ public class ListHabitsBehavior
|
||||
void onNumberPicked(double newValue);
|
||||
}
|
||||
|
||||
public interface OnFinishedListener
|
||||
{
|
||||
void onFinish();
|
||||
}
|
||||
|
||||
public interface Screen
|
||||
{
|
||||
void showHabitScreen(@NonNull Habit h);
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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.ui.screens.habits.list;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.preferences.*;
|
||||
import org.isoron.uhabits.ui.*;
|
||||
|
||||
import javax.inject.*;
|
||||
|
||||
public class ListHabitsMenuBehavior
|
||||
{
|
||||
@NonNull
|
||||
private final Screen screen;
|
||||
|
||||
@NonNull
|
||||
private final Adapter adapter;
|
||||
|
||||
@NonNull
|
||||
private final Preferences preferences;
|
||||
|
||||
@NonNull
|
||||
private final ThemeSwitcher themeSwitcher;
|
||||
|
||||
private boolean showCompleted;
|
||||
|
||||
private boolean showArchived;
|
||||
|
||||
@Inject
|
||||
public ListHabitsMenuBehavior(@NonNull Screen screen,
|
||||
@NonNull Adapter adapter,
|
||||
@NonNull Preferences preferences,
|
||||
@NonNull ThemeSwitcher themeSwitcher)
|
||||
{
|
||||
this.screen = screen;
|
||||
this.adapter = adapter;
|
||||
this.preferences = preferences;
|
||||
this.themeSwitcher = themeSwitcher;
|
||||
|
||||
showCompleted = preferences.getShowCompleted();
|
||||
showArchived = preferences.getShowArchived();
|
||||
updateAdapterFilter();
|
||||
}
|
||||
|
||||
public void onCreateHabit()
|
||||
{
|
||||
screen.showCreateHabitScreen();
|
||||
}
|
||||
|
||||
public void onViewFAQ()
|
||||
{
|
||||
screen.showFAQScreen();
|
||||
}
|
||||
|
||||
public void onViewAbout()
|
||||
{
|
||||
screen.showAboutScreen();
|
||||
}
|
||||
|
||||
public void onViewSettings()
|
||||
{
|
||||
screen.showSettingsScreen();
|
||||
}
|
||||
|
||||
public void onToggleShowArchived()
|
||||
{
|
||||
showArchived = !showArchived;
|
||||
preferences.setShowArchived(showArchived);
|
||||
updateAdapterFilter();
|
||||
}
|
||||
|
||||
public void onToggleShowCompleted()
|
||||
{
|
||||
showCompleted = !showCompleted;
|
||||
preferences.setShowCompleted(showCompleted);
|
||||
updateAdapterFilter();
|
||||
}
|
||||
|
||||
public void onSortByColor()
|
||||
{
|
||||
adapter.setOrder(HabitList.Order.BY_COLOR);
|
||||
}
|
||||
|
||||
public void onSortByManually()
|
||||
{
|
||||
adapter.setOrder(HabitList.Order.BY_POSITION);
|
||||
}
|
||||
|
||||
public void onSortByScore()
|
||||
{
|
||||
adapter.setOrder(HabitList.Order.BY_SCORE);
|
||||
}
|
||||
|
||||
public void onSortByName()
|
||||
{
|
||||
adapter.setOrder(HabitList.Order.BY_NAME);
|
||||
}
|
||||
|
||||
public void onToggleNightMode()
|
||||
{
|
||||
themeSwitcher.toggleNightMode();
|
||||
screen.applyTheme();
|
||||
}
|
||||
|
||||
private void toggleShowArchived()
|
||||
{
|
||||
showArchived = !showArchived;
|
||||
preferences.setShowArchived(showArchived);
|
||||
updateAdapterFilter();
|
||||
}
|
||||
|
||||
private void toggleShowCompleted()
|
||||
{
|
||||
showCompleted = !showCompleted;
|
||||
preferences.setShowCompleted(showCompleted);
|
||||
updateAdapterFilter();
|
||||
}
|
||||
|
||||
private void updateAdapterFilter()
|
||||
{
|
||||
adapter.setFilter(new HabitMatcherBuilder()
|
||||
.setArchivedAllowed(showArchived)
|
||||
.setCompletedAllowed(showCompleted)
|
||||
.build());
|
||||
adapter.refresh();
|
||||
}
|
||||
|
||||
public interface Adapter
|
||||
{
|
||||
void refresh();
|
||||
|
||||
void setFilter(HabitMatcher build);
|
||||
|
||||
void setOrder(HabitList.Order order);
|
||||
}
|
||||
|
||||
public interface Screen
|
||||
{
|
||||
void applyTheme();
|
||||
|
||||
void showAboutScreen();
|
||||
|
||||
void showCreateHabitScreen();
|
||||
|
||||
void showFAQScreen();
|
||||
|
||||
void showSettingsScreen();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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.ui.screens.habits.list;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.commands.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.ui.callbacks.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import javax.inject.*;
|
||||
|
||||
public class ListHabitsSelectionMenuBehavior
|
||||
{
|
||||
@NonNull
|
||||
private final Screen screen;
|
||||
|
||||
@NonNull
|
||||
CommandRunner commandRunner;
|
||||
|
||||
@NonNull
|
||||
private final Adapter adapter;
|
||||
|
||||
@NonNull
|
||||
private final HabitList habitList;
|
||||
|
||||
@Inject
|
||||
public ListHabitsSelectionMenuBehavior(@NonNull HabitList habitList,
|
||||
@NonNull Screen screen,
|
||||
@NonNull Adapter adapter,
|
||||
@NonNull CommandRunner commandRunner)
|
||||
{
|
||||
this.habitList = habitList;
|
||||
this.screen = screen;
|
||||
this.adapter = adapter;
|
||||
this.commandRunner = commandRunner;
|
||||
}
|
||||
|
||||
public boolean canArchive()
|
||||
{
|
||||
for (Habit h : adapter.getSelected())
|
||||
if (h.isArchived()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean canEdit()
|
||||
{
|
||||
return (adapter.getSelected().size() == 1);
|
||||
}
|
||||
|
||||
public boolean canUnarchive()
|
||||
{
|
||||
for (Habit h : adapter.getSelected())
|
||||
if (!h.isArchived()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onArchiveHabits()
|
||||
{
|
||||
commandRunner.execute(
|
||||
new ArchiveHabitsCommand(habitList, adapter.getSelected()), null);
|
||||
adapter.clearSelection();
|
||||
}
|
||||
|
||||
public void onChangeColor()
|
||||
{
|
||||
List<Habit> selected = adapter.getSelected();
|
||||
Habit first = selected.get(0);
|
||||
|
||||
screen.showColorPicker(first.getColor(), selectedColor ->
|
||||
{
|
||||
commandRunner.execute(
|
||||
new ChangeHabitColorCommand(habitList, selected, selectedColor),
|
||||
null);
|
||||
adapter.clearSelection();
|
||||
});
|
||||
}
|
||||
|
||||
public void onDeleteHabits()
|
||||
{
|
||||
List<Habit> selected = adapter.getSelected();
|
||||
screen.showDeleteConfirmationScreen(() ->
|
||||
{
|
||||
adapter.performRemove(selected);
|
||||
commandRunner.execute(new DeleteHabitsCommand(habitList, selected),
|
||||
null);
|
||||
adapter.clearSelection();
|
||||
});
|
||||
}
|
||||
|
||||
public void onEditHabits()
|
||||
{
|
||||
screen.showEditHabitsScreen(adapter.getSelected());
|
||||
}
|
||||
|
||||
public void onUnarchiveHabits()
|
||||
{
|
||||
commandRunner.execute(
|
||||
new UnarchiveHabitsCommand(habitList, adapter.getSelected()), null);
|
||||
adapter.clearSelection();
|
||||
}
|
||||
|
||||
public interface Adapter
|
||||
{
|
||||
void clearSelection();
|
||||
|
||||
List<Habit> getSelected();
|
||||
|
||||
void performRemove(List<Habit> selected);
|
||||
}
|
||||
|
||||
public interface Screen
|
||||
{
|
||||
void showColorPicker(int defaultColor,
|
||||
@NonNull OnColorPickedCallback callback);
|
||||
|
||||
void showDeleteConfirmationScreen(
|
||||
@NonNull OnConfirmedCallback callback);
|
||||
|
||||
void showEditHabitsScreen(@NonNull List<Habit> selected);
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.ui.habits.show;
|
||||
package org.isoron.uhabits.ui.screens.habits.show;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.ui.habits.show;
|
||||
package org.isoron.uhabits.ui.screens.habits.show;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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.ui.widgets;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.commands.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.ui.*;
|
||||
|
||||
import javax.inject.*;
|
||||
|
||||
public class WidgetBehavior
|
||||
{
|
||||
@NonNull
|
||||
private final CommandRunner commandRunner;
|
||||
|
||||
private NotificationTray notificationTray;
|
||||
|
||||
@Inject
|
||||
public WidgetBehavior(@NonNull CommandRunner commandRunner,
|
||||
@NonNull NotificationTray notificationTray)
|
||||
{
|
||||
this.commandRunner = commandRunner;
|
||||
this.notificationTray = notificationTray;
|
||||
}
|
||||
|
||||
public void onAddRepetition(@NonNull Habit habit, long timestamp)
|
||||
{
|
||||
Repetition rep = habit.getRepetitions().getByTimestamp(timestamp);
|
||||
if (rep != null) return;
|
||||
performToggle(habit, timestamp);
|
||||
notificationTray.cancel(habit);
|
||||
}
|
||||
|
||||
public void onRemoveRepetition(@NonNull Habit habit, long timestamp)
|
||||
{
|
||||
Repetition rep = habit.getRepetitions().getByTimestamp(timestamp);
|
||||
if (rep == null) return;
|
||||
performToggle(habit, timestamp);
|
||||
}
|
||||
|
||||
public void onToggleRepetition(@NonNull Habit habit, long timestamp)
|
||||
{
|
||||
performToggle(habit, timestamp);
|
||||
}
|
||||
|
||||
private void performToggle(@NonNull Habit habit, long timestamp)
|
||||
{
|
||||
commandRunner.execute(new ToggleRepetitionCommand(habit, timestamp),
|
||||
habit.getId());
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.ui.habits.list;
|
||||
package org.isoron.uhabits.ui.screens.habits.list;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
@@ -30,7 +30,7 @@ import org.mockito.junit.*;
|
||||
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.isoron.uhabits.ui.habits.list.ListHabitsBehavior.Message.*;
|
||||
import static org.isoron.uhabits.ui.screens.habits.list.ListHabitsBehavior.Message.*;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
@@ -17,7 +17,7 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.ui.habits.show;
|
||||
package org.isoron.uhabits.ui.screens.habits.show;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
Reference in New Issue
Block a user