Move ListHabitsBehavior to uhabits-core

pull/87/merge
Alinson S. Xavier 8 years ago
parent 95385fa8f4
commit 3e558be4d4

@ -26,6 +26,18 @@ import org.isoron.uhabits.tasks.*;
import dagger.*; import dagger.*;
@AppScope
@Component(modules = {
AppModule.class,
HabitsModule.class,
SingleThreadModule.class,
SQLModelFactory.class
})
public interface AndroidTestComponent extends HabitsComponent
{
}
@Module @Module
class SingleThreadModule class SingleThreadModule
{ {
@ -36,11 +48,3 @@ class SingleThreadModule
return new SingleThreadTaskRunner(); return new SingleThreadTaskRunner();
} }
} }
@AppScope
@Component(modules = {
AppModule.class, SingleThreadModule.class, SQLModelFactory.class
})
public interface AndroidTestComponent extends AppComponent
{
}

@ -1,129 +0,0 @@
/*
* 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.activities.habits.list;
import org.isoron.androidbase.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.habits.list.model.*;
import org.isoron.uhabits.commands.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.preferences.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.tasks.android.*;
import org.isoron.uhabits.utils.*;
import org.isoron.uhabits.widgets.*;
import org.junit.*;
import static org.mockito.Mockito.*;
public class ListHabitsControllerTest extends BaseAndroidTest
{
private ListHabitsController controller;
private ImportDataTaskFactory importTaskFactory;
private BaseSystem system;
private CommandRunner commandRunner;
private HabitCardListAdapter adapter;
private ListHabitsScreen screen;
private AndroidPreferences prefs;
private ReminderScheduler reminderScheduler;
private SingleThreadTaskRunner taskRunner;
private WidgetUpdater widgetUpdater;
private ExportCSVTaskFactory exportCSVFactory;
private ExportDBTaskFactory exportDBFactory;
@Override
public void setUp()
{
super.setUp();
habitList = mock(HabitList.class);
system = mock(BaseSystem.class);
commandRunner = mock(CommandRunner.class);
adapter = mock(HabitCardListAdapter.class);
screen = mock(ListHabitsScreen.class);
prefs = mock(AndroidPreferences.class);
reminderScheduler = mock(ReminderScheduler.class);
taskRunner = new SingleThreadTaskRunner();
widgetUpdater = mock(WidgetUpdater.class);
importTaskFactory = mock(ImportDataTaskFactory.class);
exportCSVFactory = mock(ExportCSVTaskFactory.class);
exportDBFactory = mock(ExportDBTaskFactory.class);
controller =
spy(new ListHabitsController(system, commandRunner, habitList,
adapter, screen, prefs, reminderScheduler, taskRunner,
widgetUpdater, importTaskFactory, exportCSVFactory, exportDBFactory));
}
@Test
public void testOnHabitClick()
{
Habit h = mock(Habit.class);
controller.onHabitClick(h);
verify(screen).showHabitScreen(h);
}
@Test
public void testOnHabitReorder()
{
Habit from = mock(Habit.class);
Habit to = mock(Habit.class);
controller.onHabitReorder(from, to);
verify(habitList).reorder(from, to);
}
@Test
public void onInvalidToggle()
{
controller.onInvalidToggle();
verify(screen).showMessage(R.string.long_press_to_toggle);
}
@Test
public void onStartup_notFirstLaunch()
{
when(prefs.isFirstRun()).thenReturn(false);
controller.onStartup();
verify(prefs).incrementLaunchCount();
}
@Test
public void onStartup_firstLaunch()
{
long today = DateUtils.getStartOfToday();
when(prefs.isFirstRun()).thenReturn(true);
controller.onStartup();
verify(prefs).setFirstRun(false);
verify(prefs).updateLastHint(-1, today);
verify(screen).showIntroScreen();
}
}

@ -28,6 +28,8 @@ import android.view.*;
import org.isoron.androidbase.utils.*; import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.ui.habits.list.*;
import org.isoron.uhabits.ui.habits.show.*;
import org.isoron.uhabits.utils.*; import org.isoron.uhabits.utils.*;
import java.io.*; import java.io.*;
@ -45,7 +47,9 @@ import javax.inject.*;
* permissions. * permissions.
*/ */
@AppScope @AppScope
public class BaseSystem implements CACertSSLContextProvider public class BaseSystem implements CACertSSLContextProvider,
ListHabitsBehavior.System,
ShowHabitMenuBehavior.System
{ {
private Context context; private Context context;
@ -84,24 +88,32 @@ public class BaseSystem implements CACertSSLContextProvider
* @return the generated file. * @return the generated file.
* @throws IOException when I/O errors occur. * @throws IOException when I/O errors occur.
*/ */
@Override
@NonNull @NonNull
public File dumpBugReportToFile() throws IOException public void dumpBugReportToFile()
{ {
String date = try
DateFormats.getBackupDateFormat().format(DateUtils.getLocalTime()); {
String date = DateFormats
.getBackupDateFormat()
.format(DateUtils.getLocalTime());
if (context == null) throw new RuntimeException( if (context == null) throw new IllegalStateException();
"application context should not be null");
File dir = getFilesDir("Logs");
if (dir == null) throw new IOException("log dir should not be null");
File logFile = File dir = getFilesDir("Logs");
new File(String.format("%s/Log %s.txt", dir.getPath(), date)); if (dir == null)
FileWriter output = new FileWriter(logFile); throw new IOException("log dir should not be null");
output.write(getBugReport());
output.close();
return logFile; File logFile =
new File(String.format("%s/Log %s.txt", dir.getPath(), date));
FileWriter output = new FileWriter(logFile);
output.write(getBugReport());
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
} }
/** /**
@ -112,6 +124,7 @@ public class BaseSystem implements CACertSSLContextProvider
* @return a String containing the bug report. * @return a String containing the bug report.
* @throws IOException when any I/O error occur. * @throws IOException when any I/O error occur.
*/ */
@Override
@NonNull @NonNull
public String getBugReport() throws IOException public String getBugReport() throws IOException
{ {
@ -125,6 +138,12 @@ public class BaseSystem implements CACertSSLContextProvider
return log; return log;
} }
@Override
public File getCSVOutputDir()
{
return getFilesDir("CSV");
}
public String getLogcat() throws IOException public String getLogcat() throws IOException
{ {
int maxLineCount = 250; int maxLineCount = 250;

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com> * Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
* *
* This file is part of Loop Habit Tracker. * This file is part of Loop Habit Tracker.
* *
@ -17,17 +17,17 @@
* with this program. If not, see <http://www.gnu.org/licenses/>. * with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.isoron.uhabits.activities; package org.isoron.androidbase.activities;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.*;
import org.isoron.uhabits.activities.common.dialogs.*; import org.isoron.uhabits.activities.common.dialogs.*;
import dagger.*; import dagger.*;
@ActivityScope @ActivityScope
@Component(modules = { ActivityModule.class }, @Component(modules = { ActivityModule.class },
dependencies = { AppComponent.class }) dependencies = { HabitsComponent.class })
public interface ActivityComponent public interface ActivityComponent
{ {
BaseActivity getActivity(); BaseActivity getActivity();

@ -126,7 +126,7 @@ abstract public class BaseActivity extends AppCompatActivity
component = DaggerActivityComponent component = DaggerActivityComponent
.builder() .builder()
.activityModule(new ActivityModule(this)) .activityModule(new ActivityModule(this))
.appComponent(app.getComponent()) .habitsComponent(app.getComponent())
.build(); .build();
component.getThemeSwitcher().apply(); component.getThemeSwitcher().apply();

@ -41,7 +41,7 @@ public class HabitsApplication extends Application
{ {
private Context context; private Context context;
private static AppComponent component; private static HabitsComponent component;
private WidgetUpdater widgetUpdater; private WidgetUpdater widgetUpdater;
@ -49,12 +49,12 @@ public class HabitsApplication extends Application
private NotificationTray notificationTray; private NotificationTray notificationTray;
public AppComponent getComponent() public HabitsComponent getComponent()
{ {
return component; return component;
} }
public static void setComponent(AppComponent component) public static void setComponent(HabitsComponent component)
{ {
HabitsApplication.component = component; HabitsApplication.component = component;
} }
@ -78,7 +78,7 @@ public class HabitsApplication extends Application
super.onCreate(); super.onCreate();
context = this; context = this;
component = DaggerAppComponent component = DaggerHabitsComponent
.builder() .builder()
.appModule(new AppModule(context)) .appModule(new AppModule(context))
.build(); .build();

@ -40,10 +40,15 @@ import dagger.*;
@AppScope @AppScope
@Component(modules = { @Component(modules = {
AppModule.class, AndroidTaskRunner.class, SQLModelFactory.class AppModule.class,
HabitsModule.class,
AndroidTaskRunner.class,
SQLModelFactory.class
}) })
public interface AppComponent public interface HabitsComponent
{ {
AndroidPreferences getPreferences();
BaseSystem getBaseSystem(); BaseSystem getBaseSystem();
CommandRunner getCommandRunner(); CommandRunner getCommandRunner();
@ -67,13 +72,15 @@ public interface AppComponent
IntentParser getIntentParser(); IntentParser getIntentParser();
MidnightTimer getMidnightTimer();
ModelFactory getModelFactory(); ModelFactory getModelFactory();
NotificationTray getNotificationTray(); NotificationTray getNotificationTray();
PendingIntentFactory getPendingIntentFactory(); PendingIntentFactory getPendingIntentFactory();
AndroidPreferences getPreferences(); Preferences getCorePreferences();
ReminderScheduler getReminderScheduler(); ReminderScheduler getReminderScheduler();
@ -86,6 +93,4 @@ public interface AppComponent
WidgetPreferences getWidgetPreferences(); WidgetPreferences getWidgetPreferences();
WidgetUpdater getWidgetUpdater(); WidgetUpdater getWidgetUpdater();
MidnightTimer getMidnightTimer();
} }

@ -0,0 +1,35 @@
/*
* 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;
import org.isoron.uhabits.preferences.*;
import dagger.*;
@Module
public class HabitsModule
{
@Provides
@AppScope
public static Preferences getPreferences(AndroidPreferences preferences)
{
return preferences;
}
}

@ -36,7 +36,7 @@ public class AboutActivity extends BaseActivity
{ {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
HabitsApplication app = (HabitsApplication) getApplication(); HabitsApplication app = (HabitsApplication) getApplication();
AppComponent cmp = app.getComponent(); HabitsComponent cmp = app.getComponent();
AboutScreen screen = new AboutScreen(this, cmp.getIntentFactory()); AboutScreen screen = new AboutScreen(this, cmp.getIntentFactory());
AboutBehavior behavior = new AboutBehavior(cmp.getPreferences(), screen); AboutBehavior behavior = new AboutBehavior(cmp.getPreferences(), screen);
AboutRootView rootView = new AboutRootView(this, behavior); AboutRootView rootView = new AboutRootView(this, behavior);

@ -55,7 +55,7 @@ public class EditHabitDialog extends AppCompatDialogFragment
protected HabitList habitList; protected HabitList habitList;
protected AppComponent component; protected HabitsComponent component;
protected ModelFactory modelFactory; protected ModelFactory modelFactory;

@ -64,8 +64,8 @@ public class ListHabitsActivity extends BaseActivity
component = DaggerListHabitsComponent component = DaggerListHabitsComponent
.builder() .builder()
.appComponent(app.getComponent()) .habitsComponent(app.getComponent())
.activityModule(new ActivityModule(this)) .listHabitsModule(new ListHabitsModule(this))
.build(); .build();
ListHabitsMenu menu = component.getMenu(); ListHabitsMenu menu = component.getMenu();

@ -23,13 +23,12 @@ import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.habits.list.controllers.*; import org.isoron.uhabits.activities.habits.list.controllers.*;
import org.isoron.uhabits.activities.habits.list.model.*; import org.isoron.uhabits.activities.habits.list.model.*;
import org.isoron.uhabits.utils.*;
import dagger.*; import dagger.*;
@ActivityScope @ActivityScope
@Component(modules = { ActivityModule.class }, @Component(modules = { ListHabitsModule.class },
dependencies = { AppComponent.class }) dependencies = { HabitsComponent.class })
public interface ListHabitsComponent public interface ListHabitsComponent
{ {
HabitCardListAdapter getAdapter(); HabitCardListAdapter getAdapter();

@ -21,21 +21,16 @@ package org.isoron.uhabits.activities.habits.list;
import android.support.annotation.*; import android.support.annotation.*;
import org.isoron.androidbase.*;
import org.isoron.androidbase.activities.*; import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.habits.list.controllers.*; import org.isoron.uhabits.activities.habits.list.controllers.*;
import org.isoron.uhabits.activities.habits.list.model.*; import org.isoron.uhabits.activities.habits.list.model.*;
import org.isoron.uhabits.commands.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.preferences.*;
import org.isoron.uhabits.tasks.*; import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.tasks.android.*; import org.isoron.uhabits.tasks.android.*;
import org.isoron.uhabits.utils.*; import org.isoron.uhabits.ui.habits.list.*;
import org.isoron.uhabits.widgets.*;
import java.io.*; import java.io.*;
import java.util.*;
import javax.inject.*; import javax.inject.*;
@ -43,82 +38,53 @@ import javax.inject.*;
public class ListHabitsController public class ListHabitsController
implements HabitCardListController.HabitListener implements HabitCardListController.HabitListener
{ {
@NonNull @NonNull
private final ListHabitsScreen screen; private final ListHabitsBehavior behavior;
@NonNull @NonNull
private final BaseSystem system; private final ListHabitsScreen screen;
@NonNull
private final HabitList habitList;
@NonNull @NonNull
private final HabitCardListAdapter adapter; private final HabitCardListAdapter adapter;
@NonNull
private final AndroidPreferences prefs;
@NonNull
private final CommandRunner commandRunner;
@NonNull @NonNull
private final TaskRunner taskRunner; private final TaskRunner taskRunner;
private ReminderScheduler reminderScheduler;
private WidgetUpdater widgetUpdater;
private ImportDataTaskFactory importTaskFactory; private ImportDataTaskFactory importTaskFactory;
private ExportCSVTaskFactory exportCSVFactory;
private ExportDBTaskFactory exportDBFactory; private ExportDBTaskFactory exportDBFactory;
@Inject @Inject
public ListHabitsController(@NonNull BaseSystem system, public ListHabitsController(@NonNull ListHabitsBehavior behavior,
@NonNull CommandRunner commandRunner,
@NonNull HabitList habitList,
@NonNull HabitCardListAdapter adapter, @NonNull HabitCardListAdapter adapter,
@NonNull ListHabitsScreen screen, @NonNull ListHabitsScreen screen,
@NonNull AndroidPreferences prefs,
@NonNull ReminderScheduler reminderScheduler,
@NonNull TaskRunner taskRunner, @NonNull TaskRunner taskRunner,
@NonNull WidgetUpdater widgetUpdater,
@NonNull ImportDataTaskFactory importTaskFactory, @NonNull ImportDataTaskFactory importTaskFactory,
@NonNull ExportCSVTaskFactory exportCSVFactory,
@NonNull ExportDBTaskFactory exportDBFactory) @NonNull ExportDBTaskFactory exportDBFactory)
{ {
this.behavior = behavior;
this.adapter = adapter; this.adapter = adapter;
this.commandRunner = commandRunner;
this.habitList = habitList;
this.prefs = prefs;
this.screen = screen; this.screen = screen;
this.system = system;
this.taskRunner = taskRunner; this.taskRunner = taskRunner;
this.reminderScheduler = reminderScheduler;
this.widgetUpdater = widgetUpdater;
this.importTaskFactory = importTaskFactory; this.importTaskFactory = importTaskFactory;
this.exportCSVFactory = exportCSVFactory;
this.exportDBFactory = exportDBFactory; this.exportDBFactory = exportDBFactory;
} }
@Override
public void onEdit(@NonNull Habit habit, long timestamp)
{
behavior.onEdit(habit, timestamp);
}
public void onExportCSV() public void onExportCSV()
{ {
List<Habit> selected = new LinkedList<>(); behavior.onExportCSV();
for (Habit h : habitList) selected.add(h);
File outputDir = system.getFilesDir("CSV");
taskRunner.execute(
exportCSVFactory.create(selected, outputDir, filename -> {
if (filename != null) screen.showSendFileScreen(filename);
else screen.showMessage(R.string.could_not_export);
}));
} }
public void onExportDB() public void onExportDB()
{ {
taskRunner.execute(exportDBFactory.create(filename -> { taskRunner.execute(exportDBFactory.create(filename ->
{
if (filename != null) screen.showSendFileScreen(filename); if (filename != null) screen.showSendFileScreen(filename);
else screen.showMessage(R.string.could_not_export); else screen.showMessage(R.string.could_not_export);
})); }));
@ -127,19 +93,20 @@ public class ListHabitsController
@Override @Override
public void onHabitClick(@NonNull Habit h) public void onHabitClick(@NonNull Habit h)
{ {
screen.showHabitScreen(h); behavior.onClickHabit(h);
} }
@Override @Override
public void onHabitReorder(@NonNull Habit from, @NonNull Habit to) public void onHabitReorder(@NonNull Habit from, @NonNull Habit to)
{ {
taskRunner.execute(() -> habitList.reorder(from, to)); behavior.onReorderHabit(from, to);
} }
public void onImportData(@NonNull File file, public void onImportData(@NonNull File file,
@NonNull OnFinishedListener finishedListener) @NonNull OnFinishedListener finishedListener)
{ {
taskRunner.execute(importTaskFactory.create(file, result -> { taskRunner.execute(importTaskFactory.create(file, result ->
{
switch (result) switch (result)
{ {
case ImportDataTask.SUCCESS: case ImportDataTask.SUCCESS:
@ -166,21 +133,6 @@ public class ListHabitsController
screen.showMessage(R.string.long_press_to_edit); screen.showMessage(R.string.long_press_to_edit);
} }
@Override
public void onEdit(@NonNull Habit habit, long timestamp)
{
CheckmarkList checkmarks = habit.getCheckmarks();
double oldValue = checkmarks.getValues(timestamp, timestamp)[0];
screen.showNumberPicker(oldValue / 1000, habit.getUnit(), newValue -> {
newValue = Math.round(newValue * 1000);
commandRunner.execute(
new CreateRepetitionCommand(habit, timestamp, (int) newValue),
habit.getId());
});
}
@Override @Override
public void onInvalidToggle() public void onInvalidToggle()
{ {
@ -189,55 +141,23 @@ public class ListHabitsController
public void onRepairDB() public void onRepairDB()
{ {
taskRunner.execute(() -> { behavior.onRepairDB();
habitList.repair();
screen.showMessage(R.string.database_repaired);
});
} }
public void onSendBugReport() public void onSendBugReport()
{ {
try behavior.onSendBugReport();
{
system.dumpBugReportToFile();
}
catch (IOException e)
{
// ignored
}
try
{
String log = system.getBugReport();
int to = R.string.bugReportTo;
int subject = R.string.bugReportSubject;
screen.showSendEmailScreen(to, subject, log);
}
catch (IOException e)
{
e.printStackTrace();
screen.showMessage(R.string.bug_report_failed);
}
} }
public void onStartup() public void onStartup()
{ {
prefs.incrementLaunchCount(); behavior.onStartup();
if (prefs.isFirstRun()) onFirstRun();
} }
@Override @Override
public void onToggle(@NonNull Habit habit, long timestamp) public void onToggle(@NonNull Habit habit, long timestamp)
{ {
commandRunner.execute(new ToggleRepetitionCommand(habit, timestamp), behavior.onToggle(habit, timestamp);
habit.getId());
}
private void onFirstRun()
{
prefs.setFirstRun(false);
prefs.updateLastHint(-1, DateUtils.getStartOfToday());
screen.showIntroScreen();
} }
public interface OnFinishedListener public interface OnFinishedListener

@ -0,0 +1,48 @@
/*
* 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.activities.habits.list;
import org.isoron.androidbase.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.ui.habits.list.*;
import dagger.*;
@Module
public class ListHabitsModule extends ActivityModule
{
public ListHabitsModule(BaseActivity activity)
{
super(activity);
}
@Provides
ListHabitsBehavior.Screen getScreen(ListHabitsScreen screen)
{
return screen;
}
@Provides
ListHabitsBehavior.System getSystem(BaseSystem system)
{
return system;
}
}

@ -39,6 +39,7 @@ import org.isoron.uhabits.commands.*;
import org.isoron.uhabits.intents.*; import org.isoron.uhabits.intents.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.preferences.*; import org.isoron.uhabits.preferences.*;
import org.isoron.uhabits.ui.habits.list.*;
import org.isoron.uhabits.utils.*; import org.isoron.uhabits.utils.*;
import java.io.*; import java.io.*;
@ -51,7 +52,7 @@ import static android.view.inputmethod.EditorInfo.*;
@ActivityScope @ActivityScope
public class ListHabitsScreen extends BaseScreen public class ListHabitsScreen extends BaseScreen
implements CommandRunner.Listener implements CommandRunner.Listener, ListHabitsBehavior.Screen
{ {
public static final int REQUEST_OPEN_DOCUMENT = 6; public static final int REQUEST_OPEN_DOCUMENT = 6;
@ -100,9 +101,12 @@ public class ListHabitsScreen extends BaseScreen
@NonNull ListHabitsRootView rootView, @NonNull ListHabitsRootView rootView,
@NonNull IntentFactory intentFactory, @NonNull IntentFactory intentFactory,
@NonNull ThemeSwitcher themeSwitcher, @NonNull ThemeSwitcher themeSwitcher,
@NonNull ConfirmDeleteDialogFactory confirmDeleteDialogFactory, @NonNull
@NonNull ColorPickerDialogFactory colorPickerFactory, ConfirmDeleteDialogFactory confirmDeleteDialogFactory,
@NonNull EditHabitDialogFactory editHabitDialogFactory, @NonNull
ColorPickerDialogFactory colorPickerFactory,
@NonNull
EditHabitDialogFactory editHabitDialogFactory,
@NonNull AndroidPreferences prefs, @NonNull AndroidPreferences prefs,
@NonNull CommandParser commandParser) @NonNull CommandParser commandParser)
{ {
@ -127,7 +131,7 @@ public class ListHabitsScreen extends BaseScreen
public void onCommandExecuted(@NonNull Command command, public void onCommandExecuted(@NonNull Command command,
@Nullable Long refreshKey) @Nullable Long refreshKey)
{ {
if(command.isRemote()) return; if (command.isRemote()) return;
showMessage(commandParser.getExecuteString(command)); showMessage(commandParser.getExecuteString(command));
} }
@ -172,9 +176,16 @@ public class ListHabitsScreen extends BaseScreen
activity.showDialog(picker, "picker"); activity.showDialog(picker, "picker");
} }
public void showCreateBooleanHabitScreen()
{
EditHabitDialog dialog;
dialog = editHabitDialogFactory.createBoolean();
activity.showDialog(dialog, "editHabit");
}
public void showCreateHabitScreen() public void showCreateHabitScreen()
{ {
if(!prefs.isNumericalHabitsFeatureEnabled()) if (!prefs.isNumericalHabitsFeatureEnabled())
{ {
showCreateBooleanHabitScreen(); showCreateBooleanHabitScreen();
return; return;
@ -182,8 +193,9 @@ public class ListHabitsScreen extends BaseScreen
Dialog dialog = new AlertDialog.Builder(activity) Dialog dialog = new AlertDialog.Builder(activity)
.setTitle("Type of habit") .setTitle("Type of habit")
.setItems(R.array.habitTypes, (d, which) -> { .setItems(R.array.habitTypes, (d, which) ->
if(which == 0) showCreateBooleanHabitScreen(); {
if (which == 0) showCreateBooleanHabitScreen();
else showCreateNumericalHabitScreen(); else showCreateNumericalHabitScreen();
}) })
.create(); .create();
@ -191,20 +203,6 @@ public class ListHabitsScreen extends BaseScreen
dialog.show(); dialog.show();
} }
private void showCreateNumericalHabitScreen()
{
EditHabitDialog dialog;
dialog = editHabitDialogFactory.createNumerical();
activity.showDialog(dialog, "editHabit");
}
public void showCreateBooleanHabitScreen()
{
EditHabitDialog dialog;
dialog = editHabitDialogFactory.createBoolean();
activity.showDialog(dialog, "editHabit");
}
public void showDeleteConfirmationScreen(ConfirmDeleteDialog.Callback callback) public void showDeleteConfirmationScreen(ConfirmDeleteDialog.Callback callback)
{ {
activity.showDialog(confirmDeleteDialogFactory.create(callback)); activity.showDialog(confirmDeleteDialogFactory.create(callback));
@ -223,6 +221,7 @@ public class ListHabitsScreen extends BaseScreen
activity.startActivity(intent); activity.startActivity(intent);
} }
@Override
public void showHabitScreen(@NonNull Habit habit) public void showHabitScreen(@NonNull Habit habit)
{ {
Intent intent = intentFactory.startShowHabitActivity(activity, habit); Intent intent = intentFactory.startShowHabitActivity(activity, habit);
@ -235,15 +234,48 @@ public class ListHabitsScreen extends BaseScreen
activity.startActivityForResult(intent, REQUEST_OPEN_DOCUMENT); activity.startActivityForResult(intent, REQUEST_OPEN_DOCUMENT);
} }
@Override
public void showIntroScreen() public void showIntroScreen()
{ {
Intent intent = intentFactory.startIntroActivity(activity); Intent intent = intentFactory.startIntroActivity(activity);
activity.startActivity(intent); activity.startActivity(intent);
} }
@Override
public void showMessage(@NonNull ListHabitsBehavior.Message m)
{
switch (m)
{
case COULD_NOT_EXPORT:
showMessage(R.string.could_not_export);
break;
case IMPORT_SUCCESSFUL:
showMessage(R.string.habits_imported);
break;
case IMPORT_FAILED:
showMessage(R.string.could_not_import);
break;
case DATABASE_REPAIRED:
showMessage(R.string.database_repaired);
break;
case COULD_NOT_GENERATE_BUG_REPORT:
showMessage(R.string.bug_report_failed);
break;
case FILE_NOT_RECOGNIZED:
showMessage(R.string.file_not_recognized);
break;
}
}
@Override
public void showNumberPicker(double value, public void showNumberPicker(double value,
@NonNull String unit, @NonNull String unit,
@NonNull NumberPickerCallback callback) @NonNull ListHabitsBehavior.NumberPickerCallback callback)
{ {
LayoutInflater inflater = activity.getLayoutInflater(); LayoutInflater inflater = activity.getLayoutInflater();
View view = inflater.inflate(R.layout.number_picker_dialog, null); View view = inflater.inflate(R.layout.number_picker_dialog, null);
@ -292,21 +324,12 @@ public class ListHabitsScreen extends BaseScreen
dialog.show(); dialog.show();
} }
private void refreshInitialValue(NumberPicker picker2) @Override
public void showSendBugReportToDeveloperScreen(String log)
{ {
// Workaround for a bug on Android: int to = R.string.bugReportTo;
// https://code.google.com/p/android/issues/detail?id=35482 int subject = R.string.bugReportSubject;
try showSendEmailScreen(to, subject, log);
{
Field f = NumberPicker.class.getDeclaredField("mInputText");
f.setAccessible(true);
EditText inputText = (EditText) f.get(picker2);
inputText.setFilters(new InputFilter[0]);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
} }
public void showSettingsScreen() public void showSettingsScreen()
@ -373,8 +396,27 @@ public class ListHabitsScreen extends BaseScreen
} }
} }
public interface NumberPickerCallback private void refreshInitialValue(NumberPicker picker2)
{ {
void onNumberPicked(double newValue); // Workaround for a bug on Android:
// https://code.google.com/p/android/issues/detail?id=35482
try
{
Field f = NumberPicker.class.getDeclaredField("mInputText");
f.setAccessible(true);
EditText inputText = (EditText) f.get(picker2);
inputText.setFilters(new InputFilter[0]);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
private void showCreateNumericalHabitScreen()
{
EditHabitDialog dialog;
dialog = editHabitDialogFactory.createNumerical();
activity.showDialog(dialog, "editHabit");
} }
} }

@ -27,9 +27,6 @@ import android.support.annotation.*;
import org.isoron.androidbase.activities.*; import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.habits.show.*;
import java.io.*;
/** /**
* Activity that allows the user to see more information about a single habit. * Activity that allows the user to see more information about a single habit.
@ -37,25 +34,16 @@ import java.io.*;
* Shows all the metadata for the habit, in addition to several charts. * Shows all the metadata for the habit, in addition to several charts.
*/ */
public class ShowHabitActivity extends BaseActivity public class ShowHabitActivity extends BaseActivity
implements ShowHabitMenuBehavior.System
{ {
@Nullable @Nullable
private HabitList habitList; private HabitList habitList;
@Nullable @Nullable
private AppComponent appComponent; private HabitsComponent appComponent;
@Nullable @Nullable
private ShowHabitScreen screen; private ShowHabitScreen screen;
@Override
public File getCSVOutputDir()
{
if(appComponent == null) throw new IllegalStateException();
return appComponent.getBaseSystem().getFilesDir("CSV");
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) protected void onCreate(Bundle savedInstanceState)
{ {
@ -68,7 +56,7 @@ public class ShowHabitActivity extends BaseActivity
ShowHabitComponent component = DaggerShowHabitComponent ShowHabitComponent component = DaggerShowHabitComponent
.builder() .builder()
.appComponent(app.getComponent()) .habitsComponent(app.getComponent())
.showHabitModule(new ShowHabitModule(this, habit)) .showHabitModule(new ShowHabitModule(this, habit))
.build(); .build();

@ -28,7 +28,7 @@ import dagger.*;
@ActivityScope @ActivityScope
@Component(modules = { ShowHabitModule.class }, @Component(modules = { ShowHabitModule.class },
dependencies = { AppComponent.class }) dependencies = { HabitsComponent.class })
public interface ShowHabitComponent public interface ShowHabitComponent
{ {
@NonNull @NonNull

@ -21,6 +21,7 @@ package org.isoron.uhabits.activities.habits.show;
import android.support.annotation.*; import android.support.annotation.*;
import org.isoron.androidbase.*;
import org.isoron.androidbase.activities.*; import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.habits.show.*; import org.isoron.uhabits.ui.habits.show.*;
@ -57,8 +58,8 @@ public class ShowHabitModule extends ActivityModule
} }
@Provides @Provides
public ShowHabitMenuBehavior.System getSystem(BaseActivity activity) public ShowHabitMenuBehavior.System getSystem(BaseSystem system)
{ {
return (ShowHabitActivity) activity; return system;
} }
} }

@ -54,7 +54,7 @@ public class FireSettingReceiver extends BroadcastReceiver
ReceiverComponent component = ReceiverComponent component =
DaggerFireSettingReceiver_ReceiverComponent DaggerFireSettingReceiver_ReceiverComponent
.builder() .builder()
.appComponent(app.getComponent()) .habitsComponent(app.getComponent())
.build(); .build();
allHabits = app.getComponent().getHabitList(); allHabits = app.getComponent().getHabitList();
@ -99,7 +99,7 @@ public class FireSettingReceiver extends BroadcastReceiver
} }
@ReceiverScope @ReceiverScope
@Component(dependencies = AppComponent.class) @Component(dependencies = HabitsComponent.class)
interface ReceiverComponent interface ReceiverComponent
{ {
WidgetController getWidgetController(); WidgetController getWidgetController();

@ -31,6 +31,8 @@ import java.util.*;
import javax.inject.*; import javax.inject.*;
import dagger.*;
@AppScope @AppScope
public class AndroidPreferences public class AndroidPreferences
implements SharedPreferences.OnSharedPreferenceChangeListener, Preferences implements SharedPreferences.OnSharedPreferenceChangeListener, Preferences

@ -36,7 +36,7 @@ public class ConnectivityReceiver extends BroadcastReceiver
if (context == null) return; if (context == null) return;
if (intent == null) return; if (intent == null) return;
AppComponent component = HabitsComponent component =
((HabitsApplication) context.getApplicationContext()).getComponent(); ((HabitsApplication) context.getApplicationContext()).getComponent();
NetworkInfo networkInfo = NetworkInfo networkInfo =

@ -73,7 +73,7 @@ public class PebbleReceiver extends PebbleDataReceiver
HabitsApplication app = HabitsApplication app =
(HabitsApplication) context.getApplicationContext(); (HabitsApplication) context.getApplicationContext();
AppComponent component = app.getComponent(); HabitsComponent component = app.getComponent();
commandRunner = component.getCommandRunner(); commandRunner = component.getCommandRunner();
taskRunner = component.getTaskRunner(); taskRunner = component.getTaskRunner();
allHabits = component.getHabitList(); allHabits = component.getHabitList();

@ -56,7 +56,7 @@ public class ReminderReceiver extends BroadcastReceiver
ReminderComponent component = DaggerReminderReceiver_ReminderComponent ReminderComponent component = DaggerReminderReceiver_ReminderComponent
.builder() .builder()
.appComponent(app.getComponent()) .habitsComponent(app.getComponent())
.build(); .build();
HabitList habits = app.getComponent().getHabitList(); HabitList habits = app.getComponent().getHabitList();
@ -105,7 +105,7 @@ public class ReminderReceiver extends BroadcastReceiver
} }
@ReceiverScope @ReceiverScope
@Component(dependencies = AppComponent.class) @Component(dependencies = HabitsComponent.class)
interface ReminderComponent interface ReminderComponent
{ {
ReminderController getReminderController(); ReminderController getReminderController();

@ -56,7 +56,7 @@ public class WidgetReceiver extends BroadcastReceiver
WidgetComponent component = DaggerWidgetReceiver_WidgetComponent WidgetComponent component = DaggerWidgetReceiver_WidgetComponent
.builder() .builder()
.appComponent(app.getComponent()) .habitsComponent(app.getComponent())
.build(); .build();
IntentParser parser = app.getComponent().getIntentParser(); IntentParser parser = app.getComponent().getIntentParser();
@ -93,7 +93,7 @@ public class WidgetReceiver extends BroadcastReceiver
} }
@ReceiverScope @ReceiverScope
@Component(dependencies = AppComponent.class) @Component(dependencies = HabitsComponent.class)
interface WidgetComponent interface WidgetComponent
{ {
WidgetController getWidgetController(); WidgetController getWidgetController();

@ -69,7 +69,7 @@ public class HabitPickerDialog extends Activity
setContentView(R.layout.widget_configure_activity); setContentView(R.layout.widget_configure_activity);
HabitsApplication app = (HabitsApplication) getApplicationContext(); HabitsApplication app = (HabitsApplication) getApplicationContext();
AppComponent component = app.getComponent(); HabitsComponent component = app.getComponent();
habitList = component.getHabitList(); habitList = component.getHabitList();
preferences = component.getWidgetPreferences(); preferences = component.getWidgetPreferences();

@ -28,7 +28,6 @@ import android.view.*;
import android.widget.*; import android.widget.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.*;
import org.isoron.uhabits.activities.common.dialogs.*; import org.isoron.uhabits.activities.common.dialogs.*;
import org.junit.*; import org.junit.*;
import org.junit.runner.*; import org.junit.runner.*;

@ -22,5 +22,13 @@ package org.isoron.uhabits.preferences;
public interface Preferences public interface Preferences
{ {
void incrementLaunchCount();
boolean isFirstRun();
void setDeveloper(boolean isDeveloper); void setDeveloper(boolean isDeveloper);
void setFirstRun(boolean b);
void updateLastHint(int i, long startOfToday);
} }

@ -0,0 +1,220 @@
/*
* 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.habits.list;
import android.support.annotation.*;
import org.isoron.uhabits.commands.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.preferences.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.utils.*;
import java.io.*;
import java.util.*;
import javax.inject.*;
public class ListHabitsBehavior
{
private HabitList habitList;
private System system;
private TaskRunner taskRunner;
private Screen screen;
private CommandRunner commandRunner;
private Preferences prefs;
@Inject
public ListHabitsBehavior(@NonNull HabitList habitList,
@NonNull System system,
@NonNull TaskRunner taskRunner,
@NonNull Screen screen,
@NonNull CommandRunner commandRunner,
@NonNull Preferences prefs)
{
this.habitList = habitList;
this.system = system;
this.taskRunner = taskRunner;
this.screen = screen;
this.commandRunner = commandRunner;
this.prefs = prefs;
}
public void onClickHabit(@NonNull Habit h)
{
screen.showHabitScreen(h);
}
// public void onExportDB()
// {
// taskRunner.execute(exportDBFactory.create(filename -> {
// if (filename != null) screen.showSendFileScreen(filename);
// else screen.showMessage(R.string.could_not_export);
// }));
// }
public void onEdit(@NonNull Habit habit, long timestamp)
{
CheckmarkList checkmarks = habit.getCheckmarks();
double oldValue = checkmarks.getValues(timestamp, timestamp)[0];
screen.showNumberPicker(oldValue / 1000, habit.getUnit(), newValue ->
{
newValue = Math.round(newValue * 1000);
commandRunner.execute(
new CreateRepetitionCommand(habit, timestamp, (int) newValue),
habit.getId());
});
}
public void onExportCSV()
{
List<Habit> selected = new LinkedList<>();
for (Habit h : habitList) selected.add(h);
File outputDir = system.getCSVOutputDir();
taskRunner.execute(
new ExportCSVTask(habitList, selected, outputDir, filename ->
{
if (filename != null) screen.showSendFileScreen(filename);
else screen.showMessage(Message.COULD_NOT_EXPORT);
}));
}
// public void onImportData(@NonNull File file,
// @NonNull OnFinishedListener finishedListener)
// {
// taskRunner.execute(importTaskFactory.create(file, result -> {
// switch (result)
// {
// case ImportDataTask.SUCCESS:
// adapter.refresh();
// screen.showMessage(R.string.habits_imported);
// break;
//
// case ImportDataTask.NOT_RECOGNIZED:
// screen.showMessage(R.string.file_not_recognized);
// break;
//
// default:
// screen.showMessage(R.string.could_not_import);
// break;
// }
//
// finishedListener.onFinish();
// }));
// }
public void onReorderHabit(@NonNull Habit from, @NonNull Habit to)
{
taskRunner.execute(() -> habitList.reorder(from, to));
}
public void onRepairDB()
{
taskRunner.execute(() ->
{
habitList.repair();
screen.showMessage(Message.DATABASE_REPAIRED);
});
}
public void onSendBugReport()
{
system.dumpBugReportToFile();
try
{
String log = system.getBugReport();
screen.showSendBugReportToDeveloperScreen(log);
}
catch (IOException e)
{
e.printStackTrace();
screen.showMessage(Message.COULD_NOT_GENERATE_BUG_REPORT);
}
}
public void onStartup()
{
prefs.incrementLaunchCount();
if (prefs.isFirstRun()) onFirstRun();
}
public void onToggle(@NonNull Habit habit, long timestamp)
{
commandRunner.execute(new ToggleRepetitionCommand(habit, timestamp),
habit.getId());
}
public void onFirstRun()
{
prefs.setFirstRun(false);
prefs.updateLastHint(-1, DateUtils.getStartOfToday());
screen.showIntroScreen();
}
public enum Message
{
COULD_NOT_EXPORT, IMPORT_SUCCESSFUL, IMPORT_FAILED, DATABASE_REPAIRED,
COULD_NOT_GENERATE_BUG_REPORT, FILE_NOT_RECOGNIZED
}
public interface NumberPickerCallback
{
void onNumberPicked(double newValue);
}
public interface OnFinishedListener
{
void onFinish();
}
public interface Screen
{
void showHabitScreen(@NonNull Habit h);
void showIntroScreen();
void showMessage(@NonNull Message m);
void showNumberPicker(double value,
@NonNull String unit,
@NonNull NumberPickerCallback callback);
void showSendBugReportToDeveloperScreen(String log);
void showSendFileScreen(@NonNull String filename);
}
public interface System
{
void dumpBugReportToFile();
String getBugReport() throws IOException;
File getCSVOutputDir();
}
}

@ -19,6 +19,7 @@
package org.isoron.uhabits; package org.isoron.uhabits;
import org.isoron.uhabits.commands.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.models.memory.*; import org.isoron.uhabits.models.memory.*;
import org.isoron.uhabits.tasks.*; import org.isoron.uhabits.tasks.*;
@ -27,6 +28,8 @@ import org.junit.*;
import java.util.*; import java.util.*;
import static org.mockito.Mockito.*;
public class BaseUnitTest public class BaseUnitTest
{ {
protected HabitList habitList; protected HabitList habitList;
@ -37,6 +40,8 @@ public class BaseUnitTest
protected SingleThreadTaskRunner taskRunner; protected SingleThreadTaskRunner taskRunner;
protected CommandRunner commandRunner;
@Before @Before
public void setUp() public void setUp()
{ {
@ -45,9 +50,10 @@ public class BaseUnitTest
DateUtils.setFixedLocalTime(fixed_local_time); DateUtils.setFixedLocalTime(fixed_local_time);
modelFactory = new MemoryModelFactory(); modelFactory = new MemoryModelFactory();
habitList = modelFactory.buildHabitList(); habitList = spy(modelFactory.buildHabitList());
fixtures = new HabitFixtures(modelFactory); fixtures = new HabitFixtures(modelFactory);
taskRunner = new SingleThreadTaskRunner(); taskRunner = new SingleThreadTaskRunner();
commandRunner = new CommandRunner(taskRunner);
} }
@After @After

@ -62,6 +62,31 @@ public class HabitFixtures
return habit; return habit;
} }
public Habit createNumericalHabit()
{
Habit habit = modelFactory.buildHabit();
habit.setType(Habit.NUMBER_HABIT);
habit.setName("Run");
habit.setDescription("How many miles did you run today?");
habit.setUnit("miles");
habit.setTargetType(Habit.AT_LEAST);
habit.setTargetValue(2.0);
habit.setColor(1);
long day = DateUtils.millisecondsInOneDay;
long today = DateUtils.getStartOfToday();
int times[] = { 0, 1, 3, 5, 7, 8, 9, 10 };
int values[] = { 100, 200, 300, 400, 500, 600, 700, 800 };
for(int i = 0; i < times.length; i++)
{
long timestamp = today - times[i] * day;
habit.getRepetitions().add(new Repetition(timestamp, values[i]));
}
return habit;
}
public Habit createShortHabit() public Habit createShortHabit()
{ {
Habit habit = modelFactory.buildHabit(); Habit habit = modelFactory.buildHabit();

@ -0,0 +1,132 @@
/*
* 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.habits.list;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.preferences.*;
import org.isoron.uhabits.utils.*;
import org.junit.*;
import org.junit.runner.*;
import org.mockito.*;
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.junit.Assert.assertFalse;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class ListHabitsBehaviorTest extends BaseUnitTest
{
@Mock
private ListHabitsBehavior.System system;
@Mock
private Preferences prefs;
private ListHabitsBehavior behavior;
@Mock
private ListHabitsBehavior.Screen screen;
private Habit habit1, habit2;
@Captor
ArgumentCaptor<ListHabitsBehavior.NumberPickerCallback> captor;
@Override
@Before
public void setUp()
{
super.setUp();
habit1 = fixtures.createShortHabit();
habit2 = fixtures.createNumericalHabit();
habitList.add(habit1);
habitList.add(habit2);
clearInvocations(habitList);
behavior = new ListHabitsBehavior(habitList, system, taskRunner, screen,
commandRunner, prefs);
}
@Test
public void testOnEdit()
{
behavior.onEdit(habit2, DateUtils.getStartOfToday());
verify(screen).showNumberPicker(eq(0.1), eq("miles"), captor.capture());
captor.getValue().onNumberPicked(100);
assertThat(habit2.getCheckmarks().getTodayValue(), equalTo(100000));
}
@Test
public void testOnHabitClick()
{
behavior.onClickHabit(habit1);
verify(screen).showHabitScreen(habit1);
}
@Test
public void testOnHabitReorder()
{
Habit from = habit1;
Habit to = habit2;
behavior.onReorderHabit(from, to);
verify(habitList).reorder(from, to);
}
@Test
public void testOnRepairDB()
{
behavior.onRepairDB();
verify(habitList).repair();
verify(screen).showMessage(DATABASE_REPAIRED);
}
@Test
public void testOnStartup_firstLaunch()
{
long today = DateUtils.getStartOfToday();
when(prefs.isFirstRun()).thenReturn(true);
behavior.onStartup();
verify(prefs).setFirstRun(false);
verify(prefs).updateLastHint(-1, today);
verify(screen).showIntroScreen();
}
@Test
public void testOnStartup_notFirstLaunch()
{
when(prefs.isFirstRun()).thenReturn(false);
behavior.onStartup();
verify(prefs).incrementLaunchCount();
}
@Test
public void testOnToggle()
{
assertTrue(habit1.isCompletedToday());
behavior.onToggle(habit1, DateUtils.getStartOfToday());
assertFalse(habit1.isCompletedToday());
}
}
Loading…
Cancel
Save