Refactor tasks; break progress bars

pull/151/head
Alinson S. Xavier 9 years ago
parent 94a5db2208
commit d54de9df89

@ -60,6 +60,9 @@ public class BaseAndroidTest
@Inject
protected CommandRunner commandRunner;
@Inject
protected TaskRunner taskRunner;
@Inject
protected HabitLogger logger;
@ -139,7 +142,7 @@ public class BaseAndroidTest
return;
}
BaseTask.waitForTasks(10000);
taskRunner.waitForTasks(10000);
}
catch (Exception e)
{

@ -40,6 +40,7 @@ import static org.hamcrest.core.IsNot.not;
public class ExportCSVTaskTest extends BaseAndroidTest
{
@Before
@Override
public void setUp()
{
super.setUp();
@ -48,20 +49,20 @@ public class ExportCSVTaskTest extends BaseAndroidTest
@Test
public void testExportCSV() throws Throwable
{
fixtures.purgeHabits(habitList);
fixtures.createShortHabit();
List<Habit> selected = new LinkedList<>();
for(Habit h : habitList) selected.add(h);
for (Habit h : habitList) selected.add(h);
ExportCSVTask task = new ExportCSVTask(habitList, selected, null);
task.setListener(archiveFilename -> {
taskRunner.execute(
new ExportCSVTask(habitList, selected, archiveFilename -> {
assertThat(archiveFilename, is(not(nullValue())));
File f = new File(archiveFilename);
assertTrue(f.exists());
assertTrue(f.canRead());
});
}));
task.execute();
waitForAsyncTasks();
}
}

@ -19,20 +19,18 @@
package org.isoron.uhabits.tasks;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.runner.*;
import android.test.suitebuilder.annotation.*;
import org.isoron.uhabits.BaseAndroidTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.isoron.uhabits.*;
import org.junit.*;
import org.junit.runner.*;
import java.io.File;
import java.io.*;
import static junit.framework.Assert.assertTrue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static junit.framework.Assert.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.core.IsNot.not;
@RunWith(AndroidJUnit4.class)
@ -48,21 +46,15 @@ public class ExportDBTaskTest extends BaseAndroidTest
@Test
public void testExportCSV() throws Throwable
{
ExportDBTask task = new ExportDBTask(null);
task.setListener(new ExportDBTask.Listener()
{
@Override
public void onExportDBFinished(String filename)
{
ExportDBTask task = new ExportDBTask(filename -> {
assertThat(filename, is(not(nullValue())));
File f = new File(filename);
assertTrue(f.exists());
assertTrue(f.canRead());
}
});
task.execute();
taskRunner.execute(task);
waitForAsyncTasks();
}
}

@ -19,23 +19,18 @@
package org.isoron.uhabits.tasks;
import android.support.annotation.NonNull;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.runner.*;
import android.test.suitebuilder.annotation.*;
import org.isoron.uhabits.BaseAndroidTest;
import org.isoron.uhabits.utils.FileUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.isoron.uhabits.*;
import org.isoron.uhabits.utils.*;
import org.junit.*;
import org.junit.runner.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.fail;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
@RunWith(AndroidJUnit4.class)
@MediumTest
@ -49,49 +44,36 @@ public class ImportDataTaskTest extends BaseAndroidTest
super.setUp();
baseDir = FileUtils.getFilesDir("Backups");
if(baseDir == null) fail("baseDir should not be null");
if (baseDir == null) fail("baseDir should not be null");
}
private void copyAssetToFile(String assetPath, File dst) throws IOException
@Test
public void testImportInvalidData() throws Throwable
{
InputStream in = testContext.getAssets().open(assetPath);
FileUtils.copy(in, dst);
assertTaskResult(ImportDataTask.NOT_RECOGNIZED, "icon.png");
}
private void assertTaskResult(final int expectedResult, String assetFilename) throws Throwable
{
ImportDataTask task = createTask(assetFilename);
task.setListener(new ImportDataTask.Listener()
{
@Override
public void onImportDataFinished(int result)
@Test
public void testImportValidData() throws Throwable
{
assertThat(result, equalTo(expectedResult));
}
});
task.execute();
waitForAsyncTasks();
assertTaskResult(ImportDataTask.SUCCESS, "loop.db");
}
@NonNull
private ImportDataTask createTask(String assetFilename) throws IOException
private void assertTaskResult(final int expectedResult,
String assetFilename) throws Throwable
{
File file = new File(String.format("%s/%s", baseDir.getPath(), assetFilename));
File file = new File(baseDir.getPath() + "/" + assetFilename);
copyAssetToFile(assetFilename, file);
return new ImportDataTask(habitList, file, null);
}
@Test
public void testImportInvalidData() throws Throwable
{
assertTaskResult(ImportDataTask.NOT_RECOGNIZED, "icon.png");
taskRunner.execute(new ImportDataTask(habitList, file,
(result) -> assertThat(result, equalTo(expectedResult))));
waitForAsyncTasks();
}
@Test
public void testImportValidData() throws Throwable
private void copyAssetToFile(String assetPath, File dst) throws IOException
{
assertTaskResult(ImportDataTask.SUCCESS, "loop.db");
InputStream in = testContext.getAssets().open(assetPath);
FileUtils.copy(in, dst);
}
}

@ -42,18 +42,22 @@ import org.isoron.uhabits.widgets.*;
*/
public interface BaseComponent
{
CommandRunner getCommandRunner();
HabitList getHabitList();
IntentFactory getIntentFactory();
ReminderScheduler getReminderScheduler();
TaskRunner getTaskRunner();
void inject(CheckmarkButtonController checkmarkButtonController);
void inject(ListHabitsController listHabitsController);
void inject(CheckmarkPanelView checkmarkPanelView);
void inject(ToggleRepetitionTask toggleRepetitionTask);
void inject(HabitCardListCache habitCardListCache);
void inject(WidgetReceiver widgetReceiver);
void inject(ListHabitsSelectionMenu listHabitsSelectionMenu);
@ -84,8 +88,6 @@ public interface BaseComponent
void inject(BaseSystem baseSystem);
void inject(HistoryEditorDialog historyEditorDialog);
void inject(HabitsApplication application);
void inject(Habit habit);
@ -110,8 +112,6 @@ public interface BaseComponent
void inject(ReceiverActions receiverActions);
void inject(ReminderReceiver reminderReceiver);
void inject(ReminderScheduler reminderScheduler);
void inject(ListHabitsScreen listHabitsScreen);

@ -19,12 +19,12 @@
package org.isoron.uhabits.commands;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.*;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.*;
import org.isoron.uhabits.tasks.*;
import java.util.LinkedList;
import java.util.*;
import javax.inject.*;
@ -37,19 +37,17 @@ import javax.inject.*;
@Singleton
public class CommandRunner
{
private TaskRunner taskRunner;
private LinkedList<Listener> listeners;
@Inject
public CommandRunner()
{
taskRunner = HabitsApplication.getComponent().getTaskRunner();
listeners = new LinkedList<>();
}
private static CommandRunner getInstance()
{
return null;
}
public void addListener(Listener l)
{
listeners.add(l);
@ -57,23 +55,21 @@ public class CommandRunner
public void execute(final Command command, final Long refreshKey)
{
new BaseTask()
taskRunner.execute(new Task()
{
@Override
protected void doInBackground()
public void doInBackground()
{
command.execute();
}
@Override
protected void onPostExecute(Void aVoid)
public void onPostExecute()
{
for (Listener l : listeners)
l.onCommandExecuted(command, refreshKey);
super.onPostExecute(null);
}
}.execute();
});
}
public void removeListener(Listener l)

@ -46,7 +46,10 @@ public class PebbleReceiver extends PebbleDataReceiver
protected HabitList allHabits;
@Inject
protected CommandRunner runner;
protected CommandRunner commandRunner;
@Inject
protected TaskRunner taskRunner;
protected HabitList filteredHabits;
@ -74,7 +77,7 @@ public class PebbleReceiver extends PebbleDataReceiver
PebbleKit.sendAckToPebble(context, transactionId);
Log.d("PebbleReceiver", "<-- " + data.getString(0));
new SimpleTask(() -> {
taskRunner.execute(() -> {
switch (data.getString(0))
{
case "COUNT":
@ -89,7 +92,7 @@ public class PebbleReceiver extends PebbleDataReceiver
processToggle(data);
break;
}
}).execute();
});
}
private void processFetch(@NonNull PebbleDictionary dict)
@ -113,7 +116,8 @@ public class PebbleReceiver extends PebbleDataReceiver
if (habit == null) return;
long today = DateUtils.getStartOfToday();
runner.execute(new ToggleRepetitionCommand(habit, today), habitId);
commandRunner.execute(new ToggleRepetitionCommand(habit, today),
habitId);
sendOK();
}

@ -24,7 +24,6 @@ import android.support.annotation.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.commands.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import javax.inject.*;
@ -54,9 +53,7 @@ public class ReceiverActions
public void toggle_repetition(@NonNull Habit habit, long timestamp)
{
new SimpleTask(() -> {
commandRunner.execute(new ToggleRepetitionCommand(habit, timestamp),
habit.getId());
}).execute();
commandRunner.execute(
new ToggleRepetitionCommand(habit, timestamp), habit.getId());
}
}

@ -36,8 +36,6 @@ import org.isoron.uhabits.utils.*;
import java.util.*;
import javax.inject.*;
/**
* The Android BroadcastReceiver for Loop Habit Tracker.
* <p>
@ -56,16 +54,20 @@ public class ReminderReceiver extends BroadcastReceiver
private static final String TAG = "ReminderReceiver";
@Inject
HabitList habits;
private final HabitList habits;
private final TaskRunner taskRunner;
@Inject
ReminderScheduler reminderScheduler;
private final ReminderScheduler reminderScheduler;
public ReminderReceiver()
{
super();
HabitsApplication.getComponent().inject(this);
BaseComponent component = HabitsApplication.getComponent();
habits = component.getHabitList();
taskRunner = component.getTaskRunner();
reminderScheduler = component.getReminderScheduler();
}
@Override
@ -115,25 +117,25 @@ public class ReminderReceiver extends BroadcastReceiver
{
final Uri data = intent.getData();
final Habit habit = habits.getById(ContentUris.parseId(data));
final Long timestamp = intent.getLongExtra("timestamp",
DateUtils.getStartOfToday());
final Long reminderTime = intent.getLongExtra("reminderTime",
DateUtils.getStartOfToday());
final Long timestamp =
intent.getLongExtra("timestamp", DateUtils.getStartOfToday());
final Long reminderTime =
intent.getLongExtra("reminderTime", DateUtils.getStartOfToday());
if (habit == null) return;
new BaseTask()
taskRunner.execute(new Task()
{
int todayValue;
@Override
protected void doInBackground()
public void doInBackground()
{
todayValue = habit.getCheckmarks().getTodayValue();
}
@Override
protected void onPostExecute(Void aVoid)
public void onPostExecute()
{
if (todayValue != Checkmark.UNCHECKED) return;
if (!shouldShowReminderToday(intent, habit)) return;
@ -141,15 +143,16 @@ public class ReminderReceiver extends BroadcastReceiver
Intent contentIntent = new Intent(context, MainActivity.class);
contentIntent.setData(data);
PendingIntent contentPendingIntent = PendingIntent.getActivity(
context, 0, contentIntent,
PendingIntent contentPendingIntent =
PendingIntent.getActivity(context, 0, contentIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
PendingIntentFactory
pendingIntentFactory = new PendingIntentFactory(context);
PendingIntentFactory pendingIntentFactory =
new PendingIntentFactory(context);
PendingIntent dismissPendingIntent;
dismissPendingIntent = pendingIntentFactory.dismissNotification();
dismissPendingIntent =
pendingIntentFactory.dismissNotification();
PendingIntent checkIntentPending =
pendingIntentFactory.addCheckmark(habit, timestamp);
PendingIntent snoozeIntentPending =
@ -159,12 +162,11 @@ public class ReminderReceiver extends BroadcastReceiver
NotificationCompat.WearableExtender wearableExtender =
new NotificationCompat.WearableExtender().setBackground(
BitmapFactory.decodeResource(
context.getResources(),
BitmapFactory.decodeResource(context.getResources(),
R.drawable.stripe));
Notification notification = new NotificationCompat.Builder(
context)
Notification notification =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(habit.getName())
.setContentText(habit.getDescription())
@ -190,10 +192,8 @@ public class ReminderReceiver extends BroadcastReceiver
int notificationId = (int) (habit.getId() % Integer.MAX_VALUE);
notificationManager.notify(notificationId, notification);
super.onPostExecute(aVoid);
}
}.execute();
});
}
private void createReminderAlarmsDelayed()
@ -216,10 +216,10 @@ public class ReminderReceiver extends BroadcastReceiver
private void onActionSnoozeReminder(Context context, Intent intent)
{
Uri data = intent.getData();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
context);
long delayMinutes = Long.parseLong(
prefs.getString("pref_snooze_interval", "15"));
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(context);
long delayMinutes =
Long.parseLong(prefs.getString("pref_snooze_interval", "15"));
long habitId = ContentUris.parseId(data);
Habit habit = habits.getById(habitId);
@ -238,11 +238,11 @@ public class ReminderReceiver extends BroadcastReceiver
if (!habit.hasReminder()) return false;
Reminder reminder = habit.getReminder();
Long timestamp = intent.getLongExtra("timestamp",
DateUtils.getStartOfToday());
Long timestamp =
intent.getLongExtra("timestamp", DateUtils.getStartOfToday());
boolean reminderDays[] = DateUtils.unpackWeekdayList(
reminder.getDays());
boolean reminderDays[] =
DateUtils.unpackWeekdayList(reminder.getDays());
int weekday = DateUtils.getWeekday(timestamp);
return reminderDays[weekday];

@ -1,75 +0,0 @@
/*
* Copyright (C) 2016 Á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.tasks;
import android.os.AsyncTask;
import android.os.Build;
import android.support.annotation.*;
import java.util.concurrent.TimeoutException;
public abstract class BaseTask extends AsyncTask<Void, Integer, Void>
{
private static int activeTaskCount;
@CallSuper
@Override
protected void onPreExecute()
{
super.onPreExecute();
activeTaskCount++;
}
@CallSuper
@Override
protected void onPostExecute(Void aVoid)
{
activeTaskCount--;
super.onPostExecute(null);
}
@Override
protected final Void doInBackground(Void... params)
{
doInBackground();
return null;
}
protected abstract void doInBackground();
public static void waitForTasks(long timeout)
throws TimeoutException, InterruptedException
{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
throw new UnsupportedOperationException("waitForTasks requires API 16+");
int poolInterval = 100;
while(timeout > 0)
{
if(activeTaskCount == 0) return;
timeout -= poolInterval;
Thread.sleep(poolInterval);
}
throw new TimeoutException();
}
}

@ -28,43 +28,38 @@ import org.isoron.uhabits.utils.*;
import java.io.*;
import java.util.*;
public class ExportCSVTask extends BaseTask
public class ExportCSVTask implements Task
{
private ProgressBar progressBar;
private String archiveFilename;
@NonNull
private final List<Habit> selectedHabits;
private String archiveFilename;
private ExportCSVTask.Listener listener;
@NonNull
private final ExportCSVTask.Listener listener;
@NonNull
private final HabitList habitList;
public ExportCSVTask(HabitList habitList,
List<Habit> selectedHabits,
ProgressBar progressBar)
public ExportCSVTask(@NonNull HabitList habitList,
@NonNull List<Habit> selectedHabits,
@NonNull Listener listener)
{
this.listener = listener;
this.habitList = habitList;
this.selectedHabits = selectedHabits;
this.progressBar = progressBar;
}
public void setListener(Listener listener)
{
this.listener = listener;
}
@Override
protected void doInBackground()
public void doInBackground()
{
try
{
File dir = FileUtils.getFilesDir("CSV");
if (dir == null) return;
HabitsCSVExporter exporter =
new HabitsCSVExporter(habitList, selectedHabits, dir);
HabitsCSVExporter exporter;
exporter = new HabitsCSVExporter(habitList, selectedHabits, dir);
archiveFilename = exporter.writeArchive();
}
catch (IOException e)
@ -74,19 +69,9 @@ public class ExportCSVTask extends BaseTask
}
@Override
protected void onPostExecute(Void aVoid)
{
if (listener != null) listener.onExportCSVFinished(archiveFilename);
if (progressBar != null) progressBar.hide();
super.onPostExecute(null);
}
@Override
protected void onPreExecute()
public void onPostExecute()
{
super.onPreExecute();
if (progressBar != null) progressBar.show();
listener.onExportCSVFinished(archiveFilename);
}
public interface Listener

@ -19,65 +19,50 @@
package org.isoron.uhabits.tasks;
import android.support.annotation.Nullable;
import android.support.annotation.*;
import org.isoron.uhabits.utils.DatabaseUtils;
import org.isoron.uhabits.utils.FileUtils;
import org.isoron.uhabits.utils.*;
import java.io.File;
import java.io.IOException;
import java.io.*;
public class ExportDBTask extends BaseTask
public class ExportDBTask implements Task
{
public interface Listener
{
void onExportDBFinished(@Nullable String filename);
}
private ProgressBar progressBar;
private String filename;
private Listener listener;
public ExportDBTask(ProgressBar progressBar)
{
this.progressBar = progressBar;
}
@NonNull
private final Listener listener;
public void setListener(Listener listener)
public ExportDBTask(@NonNull Listener listener)
{
this.listener = listener;
}
@Override
protected void onPreExecute()
{
super.onPreExecute();
if(progressBar != null) progressBar.show();
}
@Override
protected void onPostExecute(Void aVoid)
{
if(listener != null) listener.onExportDBFinished(filename);
if(progressBar != null) progressBar.hide();
super.onPostExecute(null);
}
@Override
protected void doInBackground()
public void doInBackground()
{
filename = null;
try
{
File dir = FileUtils.getFilesDir("Backups");
if(dir == null) return;
if (dir == null) return;
filename = DatabaseUtils.saveDatabaseCopy(dir);
}
catch(IOException e)
catch (IOException e)
{
e.printStackTrace();
}
}
@Override
public void onPostExecute()
{
listener.onExportDBFinished(filename);
}
public interface Listener
{
void onExportDBFinished(@Nullable String filename);
}
}

@ -26,7 +26,7 @@ import org.isoron.uhabits.models.*;
import java.io.*;
public class ImportDataTask extends BaseTask
public class ImportDataTask implements Task
{
public static final int FAILED = 3;
@ -34,36 +34,28 @@ public class ImportDataTask extends BaseTask
public static final int SUCCESS = 1;
@Nullable
private final ProgressBar progressBar;
int result;
@NonNull
private final File file;
@Nullable
private Listener listener;
int result;
@NonNull
private final Listener listener;
@NonNull
private HabitList habits;
private final HabitList habits;
public ImportDataTask(@NonNull HabitList habits,
@NonNull File file,
@Nullable ProgressBar progressBar)
@NonNull Listener listener)
{
this.listener = listener;
this.habits = habits;
this.file = file;
this.progressBar = progressBar;
}
public void setListener(@Nullable Listener listener)
{
this.listener = listener;
}
@Override
protected void doInBackground()
public void doInBackground()
{
try
{
@ -86,19 +78,9 @@ public class ImportDataTask extends BaseTask
}
@Override
protected void onPostExecute(Void aVoid)
public void onPostExecute()
{
if (progressBar != null) progressBar.hide();
if (listener != null) listener.onImportDataFinished(result);
super.onPostExecute(null);
}
@Override
protected void onPreExecute()
{
super.onPreExecute();
if (progressBar != null) progressBar.show();
listener.onImportDataFinished(result);
}
public interface Listener

@ -19,24 +19,19 @@
package org.isoron.uhabits.tasks;
public class SimpleTask
import android.support.annotation.*;
public interface Task
{
private final BaseTask baseTask;
public SimpleTask(Runnable runnable)
{
this.baseTask = new BaseTask()
{
@Override
protected void doInBackground()
{
runnable.run();
}
};
}
public void execute()
{
baseTask.execute();
}
default void cancel() {}
void doInBackground();
default void onAttached(@NonNull TaskRunner runner) {}
default void onPostExecute() {}
default void onPreExecute() {}
default void onProgressUpdate(int value) {}
}

@ -0,0 +1,117 @@
/*
* Copyright (C) 2016 Á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.tasks;
import android.os.*;
import java.util.*;
import java.util.concurrent.*;
import javax.inject.*;
@Singleton
public class TaskRunner
{
private final LinkedList<CustomAsyncTask> activeTasks;
@Inject
public TaskRunner()
{
activeTasks = new LinkedList<>();
}
public void execute(Task task)
{
task.onAttached(this);
new CustomAsyncTask(task).execute();
}
public void setCurrentProgress(Task task, int progress)
{
for (CustomAsyncTask asyncTask : activeTasks)
if (asyncTask.getTask() == task) asyncTask.publish(progress);
}
public void waitForTasks(long timeout)
throws TimeoutException, InterruptedException
{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
throw new UnsupportedOperationException("waitForTasks requires API 16+");
int poolInterval = 100;
while(timeout > 0)
{
if(activeTasks.isEmpty()) return;
timeout -= poolInterval;
Thread.sleep(poolInterval);
}
throw new TimeoutException();
}
private class CustomAsyncTask extends AsyncTask<Void, Integer, Void>
{
private final Task task;
public CustomAsyncTask(Task task)
{
this.task = task;
}
public Task getTask()
{
return task;
}
public void publish(int progress)
{
publishProgress(progress);
}
@Override
protected Void doInBackground(Void... params)
{
task.doInBackground();
return null;
}
@Override
protected void onPostExecute(Void aVoid)
{
task.onPostExecute();
activeTasks.remove(this);
}
@Override
protected void onProgressUpdate(Integer... values)
{
task.onProgressUpdate(values[0]);
}
@Override
protected void onPreExecute()
{
activeTasks.add(this);
task.onPreExecute();
}
}
}

@ -19,49 +19,51 @@
package org.isoron.uhabits.tasks;
import org.isoron.uhabits.HabitsApplication;
import org.isoron.uhabits.commands.CommandRunner;
import org.isoron.uhabits.commands.ToggleRepetitionCommand;
import org.isoron.uhabits.models.Habit;
import android.support.annotation.*;
import javax.inject.Inject;
import org.isoron.uhabits.*;
import org.isoron.uhabits.commands.*;
import org.isoron.uhabits.models.*;
public class ToggleRepetitionTask extends BaseTask
public class ToggleRepetitionTask implements Task
{
@Inject
CommandRunner commandRunner;
@NonNull
private final CommandRunner commandRunner;
public interface Listener {
void onToggleRepetitionFinished();
}
@NonNull
private final Listener listener;
private Listener listener;
@NonNull
private final Habit habit;
private final Long timestamp;
public ToggleRepetitionTask(Habit habit, Long timestamp)
private final long timestamp;
public ToggleRepetitionTask(@NonNull Habit habit,
long timestamp,
@NonNull Listener listener)
{
this.timestamp = timestamp;
this.habit = habit;
HabitsApplication.getComponent().inject(this);
this.timestamp = timestamp;
this.listener = listener;
commandRunner = HabitsApplication.getComponent().getCommandRunner();
}
@Override
protected void doInBackground()
public void doInBackground()
{
ToggleRepetitionCommand command = new ToggleRepetitionCommand(habit, timestamp);
commandRunner.execute(command, habit.getId());
commandRunner.execute(new ToggleRepetitionCommand(habit, timestamp),
habit.getId());
}
@Override
protected void onPostExecute(Void aVoid)
public void onPostExecute()
{
if(listener != null) listener.onToggleRepetitionFinished();
super.onPostExecute(null);
listener.onToggleRepetitionFinished();
}
public void setListener(Listener listener)
public interface Listener
{
this.listener = listener;
void onToggleRepetitionFinished();
}
}

@ -134,14 +134,6 @@ public class BaseSystem
return builder.toString();
}
/**
* Recreates all application reminders.
*/
public void scheduleReminders()
{
new SimpleTask(() -> reminderScheduler.schedule(habitList)).execute();
}
private String getDeviceInfo()
{
if (context == null) return "null context\n";

@ -33,8 +33,6 @@ import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.ui.common.views.*;
import org.isoron.uhabits.utils.*;
import javax.inject.*;
public class HistoryEditorDialog extends AppCompatDialogFragment
implements DialogInterface.OnClickListener, ModelObservable.Listener
{
@ -44,15 +42,18 @@ public class HistoryEditorDialog extends AppCompatDialogFragment
@Nullable
HistoryChart historyChart;
@Inject
HabitList habitList;
@NonNull
private Controller controller;
private HabitList habitList;
private TaskRunner taskRunner;
public HistoryEditorDialog()
{
this.controller = new Controller() {};
habitList = HabitsApplication.getComponent().getHabitList();
taskRunner = HabitsApplication.getComponent().getTaskRunner();
}
@Override
@ -66,7 +67,6 @@ public class HistoryEditorDialog extends AppCompatDialogFragment
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState)
{
Context context = getActivity();
HabitsApplication.getComponent().inject(this);
historyChart = new HistoryChart(context);
historyChart.setController(controller);
@ -141,28 +141,27 @@ public class HistoryEditorDialog extends AppCompatDialogFragment
private void refreshData()
{
if (habit == null) return;
new RefreshTask().execute();
taskRunner.execute(new RefreshTask());
}
public interface Controller extends HistoryChart.Controller {}
private class RefreshTask extends BaseTask
private class RefreshTask implements Task
{
public int[] checkmarks;
@Override
protected void doInBackground()
public void doInBackground()
{
checkmarks = habit.getCheckmarks().getAllValues();
}
@Override
protected void onPostExecute(Void aVoid)
public void onPostExecute()
{
int color = ColorUtils.getColor(getContext(), habit.getColor());
historyChart.setColor(color);
historyChart.setCheckmarks(checkmarks);
super.onPostExecute(aVoid);
}
}
}

@ -37,7 +37,7 @@ import java.util.*;
import javax.inject.*;
public class ListHabitsController
implements ImportDataTask.Listener, HabitCardListController.HabitListener
implements HabitCardListController.HabitListener
{
@NonNull
private final ListHabitsScreen screen;
@ -57,6 +57,12 @@ public class ListHabitsController
@Inject
CommandRunner commandRunner;
@Inject
ReminderScheduler reminderScheduler;
@Inject
TaskRunner taskRuner;
public ListHabitsController(@NonNull HabitList habitList,
@NonNull ListHabitsScreen screen,
@NonNull BaseSystem system,
@ -74,26 +80,18 @@ public class ListHabitsController
List<Habit> selected = new LinkedList<>();
for (Habit h : habitList) selected.add(h);
ProgressBar progressBar = screen.getProgressBar();
ExportCSVTask task =
new ExportCSVTask(habitList, selected, progressBar);
task.setListener(filename -> {
taskRuner.execute(new ExportCSVTask(habitList, selected, filename -> {
if (filename != null) screen.showSendFileScreen(filename);
else screen.showMessage(R.string.could_not_export);
});
task.execute();
}));
}
public void onExportDB()
{
ExportDBTask task = new ExportDBTask(screen.getProgressBar());
task.setListener(filename -> {
taskRuner.execute(new ExportDBTask(filename -> {
if (filename != null) screen.showSendFileScreen(filename);
else screen.showMessage(R.string.could_not_export);
});
task.execute();
}));
}
@Override
@ -105,20 +103,12 @@ public class ListHabitsController
@Override
public void onHabitReorder(@NonNull Habit from, @NonNull Habit to)
{
new SimpleTask(() -> habitList.reorder(from, to)).execute();
taskRuner.execute(() -> habitList.reorder(from, to));
}
public void onImportData(@NonNull File file)
{
ProgressBar bar = screen.getProgressBar();
ImportDataTask task = new ImportDataTask(habitList, file, bar);
task.setListener(this);
task.execute();
}
@Override
public void onImportDataFinished(int result)
{
taskRuner.execute(new ImportDataTask(habitList, file, result -> {
switch (result)
{
case ImportDataTask.SUCCESS:
@ -134,8 +124,10 @@ public class ListHabitsController
screen.showMessage(R.string.could_not_import);
break;
}
}));
}
@Override
public void onInvalidToggle()
{
@ -177,7 +169,7 @@ public class ListHabitsController
if (prefs.isFirstRun()) onFirstRun();
new Handler().postDelayed(() -> {
system.scheduleReminders();
taskRuner.execute(() -> reminderScheduler.schedule(habitList));
HabitsApplication.getWidgetUpdater().updateWidgets();
}, 1000);
}

@ -19,7 +19,6 @@
package org.isoron.uhabits.ui.habits.list.model;
import android.os.*;
import android.support.annotation.*;
import org.isoron.uhabits.*;
@ -30,8 +29,6 @@ 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.
@ -44,7 +41,7 @@ public class HabitCardListCache implements CommandRunner.Listener
{
private int checkmarkCount;
private BaseTask currentFetchTask;
private Task currentFetchTask;
@Nullable
private Listener listener;
@ -52,30 +49,30 @@ public class HabitCardListCache implements CommandRunner.Listener
@NonNull
private CacheData data;
@Inject
CommandRunner commandRunner;
@NonNull
private HabitList allHabits;
@NonNull
private HabitList filteredHabits;
@NonNull
private ProgressBar progressBar;
private final TaskRunner taskRunner;
private final CommandRunner commandRunner;
public HabitCardListCache(@NonNull HabitList allHabits)
{
this.allHabits = allHabits;
this.filteredHabits = allHabits;
this.progressBar = new ProgressBar() {};
data = new CacheData();
HabitsApplication.getComponent().inject(this);
BaseComponent component = HabitsApplication.getComponent();
commandRunner = component.getCommandRunner();
taskRunner = component.getTaskRunner();
}
public void cancelTasks()
{
if (currentFetchTask != null) currentFetchTask.cancel(true);
if (currentFetchTask != null) currentFetchTask.cancel();
}
public int[] getCheckmarks(long habitId)
@ -127,14 +124,28 @@ public class HabitCardListCache implements CommandRunner.Listener
public void refreshAllHabits()
{
if (currentFetchTask != null) currentFetchTask.cancel(true);
if (currentFetchTask != null) currentFetchTask.cancel();
currentFetchTask = new RefreshTask();
currentFetchTask.execute();
taskRunner.execute(currentFetchTask);
}
public void refreshHabit(long id)
{
new RefreshTask(id).execute();
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);
if (listener != null) listener.onItemRemoved(position);
}
public void reorder(int from, int to)
@ -162,21 +173,7 @@ public class HabitCardListCache implements CommandRunner.Listener
public void setProgressBar(@NonNull ProgressBar progressBar)
{
this.progressBar = progressBar;
}
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);
if (listener != null) listener.onItemRemoved(position);
}
/**
@ -251,7 +248,7 @@ public class HabitCardListCache implements CommandRunner.Listener
}
}
private class RefreshTask extends BaseTask
private class RefreshTask implements Task
{
@NonNull
private CacheData newData;
@ -259,10 +256,15 @@ public class HabitCardListCache implements CommandRunner.Listener
@Nullable
private Long targetId;
private boolean isCancelled;
private TaskRunner runner;
public RefreshTask()
{
newData = new CacheData();
targetId = null;
isCancelled = false;
}
public RefreshTask(Long targetId)
@ -272,7 +274,13 @@ public class HabitCardListCache implements CommandRunner.Listener
}
@Override
protected void doInBackground()
public void cancel()
{
isCancelled = true;
}
@Override
public void doInBackground()
{
newData.fetchHabits();
newData.copyScoresFrom(data);
@ -282,11 +290,11 @@ public class HabitCardListCache implements CommandRunner.Listener
long day = DateUtils.millisecondsInOneDay;
long dateFrom = dateTo - (checkmarkCount - 1) * day;
publishProgress(-1);
runner.setCurrentProgress(this, -1);
for (int position = 0; position < newData.habits.size(); position++)
{
if (isCancelled()) return;
if (isCancelled) return;
Habit habit = newData.habits.get(position);
Long id = habit.getId();
@ -296,44 +304,27 @@ public class HabitCardListCache implements CommandRunner.Listener
newData.checkmarks.put(id,
habit.getCheckmarks().getValues(dateFrom, dateTo));
publishProgress(position);
runner.setCurrentProgress(this, position);
}
}
@Override
protected void onPostExecute(Void aVoid)
public void onAttached(@NonNull TaskRunner runner)
{
currentFetchTask = null;
progressBar.hide();
super.onPostExecute(null);
this.runner = runner;
}
@Override
protected void onPreExecute()
public void onPostExecute()
{
super.onPreExecute();
progressBar.setTotal(0);
new Handler().postDelayed(() -> {
if (getStatus() == Status.RUNNING) progressBar.show();
}, 1000);
currentFetchTask = null;
}
@Override
protected void onProgressUpdate(Integer... values)
public void onProgressUpdate(int currentPosition)
{
int currentPosition = values[0];
if (currentPosition < 0)
{
progressBar.setTotal(newData.habits.size() - 1);
processRemovedHabits();
}
else
{
progressBar.setCurrent(currentPosition);
processPosition(currentPosition);
}
if (currentPosition < 0) processRemovedHabits();
else processPosition(currentPosition);
}
private void performInsert(Habit habit, int position)
@ -358,8 +349,7 @@ public class HabitCardListCache implements CommandRunner.Listener
{
data.scores.put(id, newData.scores.get(id));
data.checkmarks.put(id, newData.checkmarks.get(id));
if(listener != null)
listener.onItemChanged(position);
if (listener != null) listener.onItemChanged(position);
}
private void processPosition(int currentPosition)

@ -24,13 +24,12 @@ 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.ui.common.dialogs.*;
import javax.inject.*;
public class ShowHabitController implements ShowHabitRootView.Controller,
HistoryEditorDialog.Controller
public class ShowHabitController
implements ShowHabitRootView.Controller, HistoryEditorDialog.Controller
{
@NonNull
private final ShowHabitScreen screen;
@ -50,24 +49,21 @@ public class ShowHabitController implements ShowHabitRootView.Controller,
}
@Override
public void onToolbarChanged()
public void onEditHistoryButtonClick()
{
screen.invalidateToolbar();
screen.showEditHistoryDialog(this);
}
@Override
public void onEditHistoryButtonClick()
public void onToggleCheckmark(long timestamp)
{
screen.showEditHistoryDialog(this);
commandRunner.execute(new ToggleRepetitionCommand(habit, timestamp),
null);
}
@Override
public void onToggleCheckmark(long timestamp)
public void onToolbarChanged()
{
new SimpleTask(() -> {
ToggleRepetitionCommand command;
command = new ToggleRepetitionCommand(habit, timestamp);
commandRunner.execute(command, null);
}).execute();
screen.invalidateToolbar();
}
}

@ -41,6 +41,8 @@ public class FrequencyCard extends HabitCard
@BindView(R.id.frequencyChart)
FrequencyChart chart;
private TaskRunner taskRunner;
public FrequencyCard(Context context)
{
super(context);
@ -56,13 +58,14 @@ public class FrequencyCard extends HabitCard
@Override
protected void refreshData()
{
new RefreshTask().execute();
taskRunner.execute(new RefreshTask());
}
private void init()
{
inflate(getContext(), R.layout.show_habit_frequency, this);
ButterKnife.bind(this);
taskRunner = HabitsApplication.getComponent().getTaskRunner();
if (isInEditMode()) initEditMode();
}
@ -75,10 +78,10 @@ public class FrequencyCard extends HabitCard
chart.populateWithRandomData();
}
private class RefreshTask extends BaseTask
private class RefreshTask implements Task
{
@Override
protected void doInBackground()
public void doInBackground()
{
RepetitionList reps = getHabit().getRepetitions();
HashMap<Long, Integer[]> frequency = reps.getWeekdayFrequency();
@ -86,11 +89,10 @@ public class FrequencyCard extends HabitCard
}
@Override
protected void onPreExecute()
public void onPreExecute()
{
super.onPreExecute();
int color =
ColorUtils.getColor(getContext(), getHabit().getColor());
int paletteColor = getHabit().getColor();
int color = ColorUtils.getColor(getContext(), paletteColor);
title.setTextColor(color);
chart.setColor(color);
}

@ -43,6 +43,8 @@ public class HistoryCard extends HabitCard
@NonNull
private Controller controller;
private TaskRunner taskRunner;
public HistoryCard(Context context)
{
super(context);
@ -70,32 +72,14 @@ public class HistoryCard extends HabitCard
@Override
protected void refreshData()
{
Habit habit = getHabit();
new BaseTask()
{
@Override
protected void doInBackground()
{
int checkmarks[] = habit.getCheckmarks().getAllValues();
chart.setCheckmarks(checkmarks);
}
@Override
protected void onPreExecute()
{
super.onPreExecute();
int color = ColorUtils.getColor(getContext(), habit.getColor());
title.setTextColor(color);
chart.setColor(color);
}
}.execute();
taskRunner.execute(new RefreshTask(getHabit()));
}
private void init()
{
inflate(getContext(), R.layout.show_habit_history, this);
ButterKnife.bind(this);
taskRunner = HabitsApplication.getComponent().getTaskRunner();
controller = new Controller() {};
if (isInEditMode()) initEditMode();
}
@ -112,4 +96,26 @@ public class HistoryCard extends HabitCard
{
default void onEditHistoryButtonClick() {}
}
private class RefreshTask implements Task
{
private final Habit habit;
public RefreshTask(Habit habit) {this.habit = habit;}
@Override
public void doInBackground()
{
int checkmarks[] = habit.getCheckmarks().getAllValues();
chart.setCheckmarks(checkmarks);
}
@Override
public void onPreExecute()
{
int color = ColorUtils.getColor(getContext(), habit.getColor());
title.setTextColor(color);
chart.setColor(color);
}
}
}

@ -54,6 +54,8 @@ public class OverviewCard extends HabitCard
private int color;
private TaskRunner taskRunner;
public OverviewCard(Context context)
{
super(context);
@ -69,7 +71,7 @@ public class OverviewCard extends HabitCard
@Override
protected void refreshData()
{
new RefreshTask().execute();
taskRunner.execute(new RefreshTask());
}
private String formatPercentageDiff(float percentageDiff)
@ -80,6 +82,7 @@ public class OverviewCard extends HabitCard
private void init()
{
taskRunner = HabitsApplication.getComponent().getTaskRunner();
inflate(getContext(), R.layout.show_habit_overview, this);
ButterKnife.bind(this);
cache = new Cache();
@ -136,10 +139,10 @@ public class OverviewCard extends HabitCard
public float lastYearScore;
}
private class RefreshTask extends BaseTask
private class RefreshTask implements Task
{
@Override
protected void doInBackground()
public void doInBackground()
{
ScoreList scores = getHabit().getScores();
@ -153,16 +156,14 @@ public class OverviewCard extends HabitCard
}
@Override
protected void onPostExecute(Void aVoid)
public void onPostExecute()
{
refreshScore();
super.onPostExecute(aVoid);
}
@Override
protected void onPreExecute()
public void onPreExecute()
{
super.onPreExecute();
color = ColorUtils.getColor(getContext(), getHabit().getColor());
refreshColors();
}

@ -49,6 +49,8 @@ public class ScoreCard extends HabitCard
private int bucketSize;
private TaskRunner taskRunner;
public ScoreCard(Context context)
{
super(context);
@ -86,7 +88,7 @@ public class ScoreCard extends HabitCard
@Override
protected void refreshData()
{
new RefreshTask().execute();
taskRunner.execute(new RefreshTask());
}
private int getDefaultSpinnerPosition()
@ -97,6 +99,8 @@ public class ScoreCard extends HabitCard
private void init()
{
taskRunner = HabitsApplication.getComponent().getTaskRunner();
inflate(getContext(), R.layout.show_habit_score, this);
ButterKnife.bind(this);
@ -121,10 +125,10 @@ public class ScoreCard extends HabitCard
bucketSize = BUCKET_SIZES[position];
}
private class RefreshTask extends BaseTask
private class RefreshTask implements Task
{
@Override
protected void doInBackground()
public void doInBackground()
{
List<Score> scores;
ScoreList scoreList = getHabit().getScores();
@ -137,9 +141,8 @@ public class ScoreCard extends HabitCard
}
@Override
protected void onPreExecute()
public void onPreExecute()
{
super.onPreExecute();
int color =
ColorUtils.getColor(getContext(), getHabit().getColor());
title.setTextColor(color);

@ -43,6 +43,8 @@ public class StreakCard extends HabitCard
@BindView(R.id.streakChart)
StreakChart streakChart;
private TaskRunner taskRunner;
public StreakCard(Context context)
{
super(context);
@ -58,11 +60,12 @@ public class StreakCard extends HabitCard
@Override
protected void refreshData()
{
new RefreshTask().execute();
taskRunner.execute(new RefreshTask());
}
private void init()
{
taskRunner = HabitsApplication.getComponent().getTaskRunner();
inflate(getContext(), R.layout.show_habit_streak, this);
ButterKnife.bind(this);
setOrientation(VERTICAL);
@ -77,28 +80,26 @@ public class StreakCard extends HabitCard
streakChart.populateWithRandomData();
}
private class RefreshTask extends BaseTask
private class RefreshTask implements Task
{
public List<Streak> bestStreaks;
@Override
protected void doInBackground()
public void doInBackground()
{
StreakList streaks = getHabit().getStreaks();
bestStreaks = streaks.getBest(NUM_STREAKS);
}
@Override
protected void onPostExecute(Void aVoid)
public void onPostExecute()
{
streakChart.setStreaks(bestStreaks);
super.onPostExecute(aVoid);
}
@Override
protected void onPreExecute()
public void onPreExecute()
{
super.onPreExecute();
int color =
ColorUtils.getColor(getContext(), getHabit().getColor());
title.setTextColor(color);

Loading…
Cancel
Save