From 3e558be4d44594cae2d620d1a6a385dd70cbd836 Mon Sep 17 00:00:00 2001 From: Alinson Xavier Date: Fri, 26 May 2017 22:04:59 -0400 Subject: [PATCH] Move ListHabitsBehavior to uhabits-core --- .../isoron/uhabits/AndroidTestComponent.java | 20 +- .../habits/list/ListHabitsControllerTest.java | 129 ---------- .../org/isoron/androidbase/BaseSystem.java | 47 ++-- .../activities/ActivityComponent.java | 8 +- .../androidbase/activities/BaseActivity.java | 2 +- .../org/isoron/uhabits/HabitsApplication.java | 8 +- ...AppComponent.java => HabitsComponent.java} | 15 +- .../java/org/isoron/uhabits/HabitsModule.java | 35 +++ .../activities/about/AboutActivity.java | 2 +- .../habits/edit/EditHabitDialog.java | 2 +- .../habits/list/ListHabitsActivity.java | 4 +- .../habits/list/ListHabitsComponent.java | 5 +- .../habits/list/ListHabitsController.java | 124 ++-------- .../habits/list/ListHabitsModule.java | 48 ++++ .../habits/list/ListHabitsScreen.java | 120 ++++++---- .../habits/show/ShowHabitActivity.java | 16 +- .../habits/show/ShowHabitComponent.java | 2 +- .../habits/show/ShowHabitModule.java | 5 +- .../automation/FireSettingReceiver.java | 4 +- .../preferences/AndroidPreferences.java | 2 + .../receivers/ConnectivityReceiver.java | 2 +- .../uhabits/receivers/PebbleReceiver.java | 2 +- .../uhabits/receivers/ReminderReceiver.java | 4 +- .../uhabits/receivers/WidgetReceiver.java | 4 +- .../uhabits/widgets/HabitPickerDialog.java | 2 +- .../activities/BaseActivityTest.java | 1 - .../uhabits/preferences/Preferences.java | 8 + .../ui/habits/list/ListHabitsBehavior.java | 220 ++++++++++++++++++ .../java/org/isoron/uhabits/BaseUnitTest.java | 8 +- .../isoron/uhabits/models/HabitFixtures.java | 25 ++ .../habits/list/ListHabitsBehaviorTest.java | 132 +++++++++++ 31 files changed, 665 insertions(+), 341 deletions(-) delete mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/ListHabitsControllerTest.java rename uhabits-android/src/main/java/org/isoron/{uhabits => androidbase}/activities/ActivityComponent.java (84%) rename uhabits-android/src/main/java/org/isoron/uhabits/{AppComponent.java => HabitsComponent.java} (93%) create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/HabitsModule.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsModule.java create mode 100644 uhabits-core/src/main/java/org/isoron/uhabits/ui/habits/list/ListHabitsBehavior.java create mode 100644 uhabits-core/src/test/java/org/isoron/uhabits/ui/habits/list/ListHabitsBehaviorTest.java diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/AndroidTestComponent.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/AndroidTestComponent.java index 7fbfa78e9..2588208f1 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/AndroidTestComponent.java +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/AndroidTestComponent.java @@ -26,6 +26,18 @@ import org.isoron.uhabits.tasks.*; import dagger.*; +@AppScope +@Component(modules = { + AppModule.class, + HabitsModule.class, + SingleThreadModule.class, + SQLModelFactory.class +}) +public interface AndroidTestComponent extends HabitsComponent +{ + +} + @Module class SingleThreadModule { @@ -36,11 +48,3 @@ class SingleThreadModule return new SingleThreadTaskRunner(); } } - -@AppScope -@Component(modules = { - AppModule.class, SingleThreadModule.class, SQLModelFactory.class -}) -public interface AndroidTestComponent extends AppComponent -{ -} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/ListHabitsControllerTest.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/ListHabitsControllerTest.java deleted file mode 100644 index ee469da95..000000000 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/ListHabitsControllerTest.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2017 Álinson Santos Xavier - * - * 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 . - */ - -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(); - } -} \ No newline at end of file diff --git a/uhabits-android/src/main/java/org/isoron/androidbase/BaseSystem.java b/uhabits-android/src/main/java/org/isoron/androidbase/BaseSystem.java index 0aea883c7..8515c52dc 100644 --- a/uhabits-android/src/main/java/org/isoron/androidbase/BaseSystem.java +++ b/uhabits-android/src/main/java/org/isoron/androidbase/BaseSystem.java @@ -28,6 +28,8 @@ import android.view.*; import org.isoron.androidbase.utils.*; import org.isoron.uhabits.*; +import org.isoron.uhabits.ui.habits.list.*; +import org.isoron.uhabits.ui.habits.show.*; import org.isoron.uhabits.utils.*; import java.io.*; @@ -45,7 +47,9 @@ import javax.inject.*; * permissions. */ @AppScope -public class BaseSystem implements CACertSSLContextProvider +public class BaseSystem implements CACertSSLContextProvider, + ListHabitsBehavior.System, + ShowHabitMenuBehavior.System { private Context context; @@ -84,24 +88,32 @@ public class BaseSystem implements CACertSSLContextProvider * @return the generated file. * @throws IOException when I/O errors occur. */ + @Override @NonNull - public File dumpBugReportToFile() throws IOException + public void dumpBugReportToFile() { - String date = - DateFormats.getBackupDateFormat().format(DateUtils.getLocalTime()); + try + { + String date = DateFormats + .getBackupDateFormat() + .format(DateUtils.getLocalTime()); - if (context == null) throw new RuntimeException( - "application context should not be null"); - File dir = getFilesDir("Logs"); - if (dir == null) throw new IOException("log dir should not be null"); + if (context == null) throw new IllegalStateException(); - File logFile = - new File(String.format("%s/Log %s.txt", dir.getPath(), date)); - FileWriter output = new FileWriter(logFile); - output.write(getBugReport()); - output.close(); + File dir = getFilesDir("Logs"); + if (dir == null) + throw new IOException("log dir should not be null"); - 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. * @throws IOException when any I/O error occur. */ + @Override @NonNull public String getBugReport() throws IOException { @@ -125,6 +138,12 @@ public class BaseSystem implements CACertSSLContextProvider return log; } + @Override + public File getCSVOutputDir() + { + return getFilesDir("CSV"); + } + public String getLogcat() throws IOException { int maxLineCount = 250; diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/ActivityComponent.java b/uhabits-android/src/main/java/org/isoron/androidbase/activities/ActivityComponent.java similarity index 84% rename from uhabits-android/src/main/java/org/isoron/uhabits/activities/ActivityComponent.java rename to uhabits-android/src/main/java/org/isoron/androidbase/activities/ActivityComponent.java index 4a085df13..c8f9dfbe0 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/ActivityComponent.java +++ b/uhabits-android/src/main/java/org/isoron/androidbase/activities/ActivityComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Álinson Santos Xavier + * Copyright (C) 2017 Álinson Santos Xavier * * This file is part of Loop Habit Tracker. * @@ -17,17 +17,17 @@ * with this program. If not, see . */ -package org.isoron.uhabits.activities; +package org.isoron.androidbase.activities; -import org.isoron.androidbase.activities.*; import org.isoron.uhabits.*; +import org.isoron.uhabits.activities.*; import org.isoron.uhabits.activities.common.dialogs.*; import dagger.*; @ActivityScope @Component(modules = { ActivityModule.class }, - dependencies = { AppComponent.class }) + dependencies = { HabitsComponent.class }) public interface ActivityComponent { BaseActivity getActivity(); diff --git a/uhabits-android/src/main/java/org/isoron/androidbase/activities/BaseActivity.java b/uhabits-android/src/main/java/org/isoron/androidbase/activities/BaseActivity.java index dc8f28ed6..f7d80efe1 100644 --- a/uhabits-android/src/main/java/org/isoron/androidbase/activities/BaseActivity.java +++ b/uhabits-android/src/main/java/org/isoron/androidbase/activities/BaseActivity.java @@ -126,7 +126,7 @@ abstract public class BaseActivity extends AppCompatActivity component = DaggerActivityComponent .builder() .activityModule(new ActivityModule(this)) - .appComponent(app.getComponent()) + .habitsComponent(app.getComponent()) .build(); component.getThemeSwitcher().apply(); diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/HabitsApplication.java b/uhabits-android/src/main/java/org/isoron/uhabits/HabitsApplication.java index 19184b300..8c5ed50b7 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/HabitsApplication.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/HabitsApplication.java @@ -41,7 +41,7 @@ public class HabitsApplication extends Application { private Context context; - private static AppComponent component; + private static HabitsComponent component; private WidgetUpdater widgetUpdater; @@ -49,12 +49,12 @@ public class HabitsApplication extends Application private NotificationTray notificationTray; - public AppComponent getComponent() + public HabitsComponent getComponent() { return component; } - public static void setComponent(AppComponent component) + public static void setComponent(HabitsComponent component) { HabitsApplication.component = component; } @@ -78,7 +78,7 @@ public class HabitsApplication extends Application super.onCreate(); context = this; - component = DaggerAppComponent + component = DaggerHabitsComponent .builder() .appModule(new AppModule(context)) .build(); diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/AppComponent.java b/uhabits-android/src/main/java/org/isoron/uhabits/HabitsComponent.java similarity index 93% rename from uhabits-android/src/main/java/org/isoron/uhabits/AppComponent.java rename to uhabits-android/src/main/java/org/isoron/uhabits/HabitsComponent.java index 82007c403..6c7d6716c 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/AppComponent.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/HabitsComponent.java @@ -40,10 +40,15 @@ import dagger.*; @AppScope @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(); CommandRunner getCommandRunner(); @@ -67,13 +72,15 @@ public interface AppComponent IntentParser getIntentParser(); + MidnightTimer getMidnightTimer(); + ModelFactory getModelFactory(); NotificationTray getNotificationTray(); PendingIntentFactory getPendingIntentFactory(); - AndroidPreferences getPreferences(); + Preferences getCorePreferences(); ReminderScheduler getReminderScheduler(); @@ -86,6 +93,4 @@ public interface AppComponent WidgetPreferences getWidgetPreferences(); WidgetUpdater getWidgetUpdater(); - - MidnightTimer getMidnightTimer(); } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/HabitsModule.java b/uhabits-android/src/main/java/org/isoron/uhabits/HabitsModule.java new file mode 100644 index 000000000..00c285e14 --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/HabitsModule.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2017 Álinson Santos Xavier + * + * 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 . + */ + +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; + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/about/AboutActivity.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/about/AboutActivity.java index 7af5e7025..7b5ae0361 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/about/AboutActivity.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/about/AboutActivity.java @@ -36,7 +36,7 @@ public class AboutActivity extends BaseActivity { super.onCreate(savedInstanceState); HabitsApplication app = (HabitsApplication) getApplication(); - AppComponent cmp = app.getComponent(); + HabitsComponent cmp = app.getComponent(); AboutScreen screen = new AboutScreen(this, cmp.getIntentFactory()); AboutBehavior behavior = new AboutBehavior(cmp.getPreferences(), screen); AboutRootView rootView = new AboutRootView(this, behavior); diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitDialog.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitDialog.java index 56ade45da..58ccafe99 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitDialog.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitDialog.java @@ -55,7 +55,7 @@ public class EditHabitDialog extends AppCompatDialogFragment protected HabitList habitList; - protected AppComponent component; + protected HabitsComponent component; protected ModelFactory modelFactory; diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.java index 8953c49a9..1571c8765 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.java @@ -64,8 +64,8 @@ public class ListHabitsActivity extends BaseActivity component = DaggerListHabitsComponent .builder() - .appComponent(app.getComponent()) - .activityModule(new ActivityModule(this)) + .habitsComponent(app.getComponent()) + .listHabitsModule(new ListHabitsModule(this)) .build(); ListHabitsMenu menu = component.getMenu(); diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsComponent.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsComponent.java index c67fba112..61ec5a4b2 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsComponent.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsComponent.java @@ -23,13 +23,12 @@ import org.isoron.androidbase.activities.*; import org.isoron.uhabits.*; import org.isoron.uhabits.activities.habits.list.controllers.*; import org.isoron.uhabits.activities.habits.list.model.*; -import org.isoron.uhabits.utils.*; import dagger.*; @ActivityScope -@Component(modules = { ActivityModule.class }, - dependencies = { AppComponent.class }) +@Component(modules = { ListHabitsModule.class }, + dependencies = { HabitsComponent.class }) public interface ListHabitsComponent { HabitCardListAdapter getAdapter(); diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsController.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsController.java index 81aadca72..ac4f1b7ae 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsController.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsController.java @@ -21,21 +21,16 @@ package org.isoron.uhabits.activities.habits.list; import android.support.annotation.*; -import org.isoron.androidbase.*; import org.isoron.androidbase.activities.*; import org.isoron.uhabits.*; import org.isoron.uhabits.activities.habits.list.controllers.*; 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.isoron.uhabits.ui.habits.list.*; import java.io.*; -import java.util.*; import javax.inject.*; @@ -43,82 +38,53 @@ import javax.inject.*; public class ListHabitsController implements HabitCardListController.HabitListener { - @NonNull - private final ListHabitsScreen screen; + private final ListHabitsBehavior behavior; @NonNull - private final BaseSystem system; - - @NonNull - private final HabitList habitList; + private final ListHabitsScreen screen; @NonNull private final HabitCardListAdapter adapter; - @NonNull - private final AndroidPreferences prefs; - - @NonNull - private final CommandRunner commandRunner; - @NonNull private final TaskRunner taskRunner; - private ReminderScheduler reminderScheduler; - - private WidgetUpdater widgetUpdater; - private ImportDataTaskFactory importTaskFactory; - private ExportCSVTaskFactory exportCSVFactory; - private ExportDBTaskFactory exportDBFactory; @Inject - public ListHabitsController(@NonNull BaseSystem system, - @NonNull CommandRunner commandRunner, - @NonNull HabitList habitList, + public ListHabitsController(@NonNull ListHabitsBehavior behavior, @NonNull HabitCardListAdapter adapter, @NonNull ListHabitsScreen screen, - @NonNull AndroidPreferences prefs, - @NonNull ReminderScheduler reminderScheduler, @NonNull TaskRunner taskRunner, - @NonNull WidgetUpdater widgetUpdater, @NonNull ImportDataTaskFactory importTaskFactory, - @NonNull ExportCSVTaskFactory exportCSVFactory, @NonNull ExportDBTaskFactory exportDBFactory) { + this.behavior = behavior; this.adapter = adapter; - this.commandRunner = commandRunner; - this.habitList = habitList; - this.prefs = prefs; this.screen = screen; - this.system = system; this.taskRunner = taskRunner; - this.reminderScheduler = reminderScheduler; - this.widgetUpdater = widgetUpdater; this.importTaskFactory = importTaskFactory; - this.exportCSVFactory = exportCSVFactory; this.exportDBFactory = exportDBFactory; } + @Override + public void onEdit(@NonNull Habit habit, long timestamp) + { + behavior.onEdit(habit, timestamp); + } + public void onExportCSV() { - List selected = new LinkedList<>(); - 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); - })); + behavior.onExportCSV(); } public void onExportDB() { - taskRunner.execute(exportDBFactory.create(filename -> { + taskRunner.execute(exportDBFactory.create(filename -> + { if (filename != null) screen.showSendFileScreen(filename); else screen.showMessage(R.string.could_not_export); })); @@ -127,19 +93,20 @@ public class ListHabitsController @Override public void onHabitClick(@NonNull Habit h) { - screen.showHabitScreen(h); + behavior.onClickHabit(h); } @Override 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, @NonNull OnFinishedListener finishedListener) { - taskRunner.execute(importTaskFactory.create(file, result -> { + taskRunner.execute(importTaskFactory.create(file, result -> + { switch (result) { case ImportDataTask.SUCCESS: @@ -166,21 +133,6 @@ public class ListHabitsController 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 public void onInvalidToggle() { @@ -189,55 +141,23 @@ public class ListHabitsController public void onRepairDB() { - taskRunner.execute(() -> { - habitList.repair(); - screen.showMessage(R.string.database_repaired); - }); + behavior.onRepairDB(); } public void onSendBugReport() { - try - { - 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); - } + behavior.onSendBugReport(); } public void onStartup() { - prefs.incrementLaunchCount(); - if (prefs.isFirstRun()) onFirstRun(); + behavior.onStartup(); } @Override public void onToggle(@NonNull Habit habit, long timestamp) { - commandRunner.execute(new ToggleRepetitionCommand(habit, timestamp), - habit.getId()); - } - - private void onFirstRun() - { - prefs.setFirstRun(false); - prefs.updateLastHint(-1, DateUtils.getStartOfToday()); - screen.showIntroScreen(); + behavior.onToggle(habit, timestamp); } public interface OnFinishedListener diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsModule.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsModule.java new file mode 100644 index 000000000..ffdb14dba --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsModule.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2017 Álinson Santos Xavier + * + * 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 . + */ + +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; + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.java index 9563eadf2..3b4ef6e28 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.java @@ -39,6 +39,7 @@ import org.isoron.uhabits.commands.*; import org.isoron.uhabits.intents.*; import org.isoron.uhabits.models.*; import org.isoron.uhabits.preferences.*; +import org.isoron.uhabits.ui.habits.list.*; import org.isoron.uhabits.utils.*; import java.io.*; @@ -51,7 +52,7 @@ import static android.view.inputmethod.EditorInfo.*; @ActivityScope public class ListHabitsScreen extends BaseScreen - implements CommandRunner.Listener + implements CommandRunner.Listener, ListHabitsBehavior.Screen { public static final int REQUEST_OPEN_DOCUMENT = 6; @@ -100,9 +101,12 @@ public class ListHabitsScreen extends BaseScreen @NonNull ListHabitsRootView rootView, @NonNull IntentFactory intentFactory, @NonNull ThemeSwitcher themeSwitcher, - @NonNull ConfirmDeleteDialogFactory confirmDeleteDialogFactory, - @NonNull ColorPickerDialogFactory colorPickerFactory, - @NonNull EditHabitDialogFactory editHabitDialogFactory, + @NonNull + ConfirmDeleteDialogFactory confirmDeleteDialogFactory, + @NonNull + ColorPickerDialogFactory colorPickerFactory, + @NonNull + EditHabitDialogFactory editHabitDialogFactory, @NonNull AndroidPreferences prefs, @NonNull CommandParser commandParser) { @@ -127,7 +131,7 @@ public class ListHabitsScreen extends BaseScreen public void onCommandExecuted(@NonNull Command command, @Nullable Long refreshKey) { - if(command.isRemote()) return; + if (command.isRemote()) return; showMessage(commandParser.getExecuteString(command)); } @@ -172,9 +176,16 @@ public class ListHabitsScreen extends BaseScreen activity.showDialog(picker, "picker"); } + public void showCreateBooleanHabitScreen() + { + EditHabitDialog dialog; + dialog = editHabitDialogFactory.createBoolean(); + activity.showDialog(dialog, "editHabit"); + } + public void showCreateHabitScreen() { - if(!prefs.isNumericalHabitsFeatureEnabled()) + if (!prefs.isNumericalHabitsFeatureEnabled()) { showCreateBooleanHabitScreen(); return; @@ -182,8 +193,9 @@ public class ListHabitsScreen extends BaseScreen Dialog dialog = new AlertDialog.Builder(activity) .setTitle("Type of habit") - .setItems(R.array.habitTypes, (d, which) -> { - if(which == 0) showCreateBooleanHabitScreen(); + .setItems(R.array.habitTypes, (d, which) -> + { + if (which == 0) showCreateBooleanHabitScreen(); else showCreateNumericalHabitScreen(); }) .create(); @@ -191,20 +203,6 @@ public class ListHabitsScreen extends BaseScreen 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) { activity.showDialog(confirmDeleteDialogFactory.create(callback)); @@ -223,6 +221,7 @@ public class ListHabitsScreen extends BaseScreen activity.startActivity(intent); } + @Override public void showHabitScreen(@NonNull Habit habit) { Intent intent = intentFactory.startShowHabitActivity(activity, habit); @@ -235,15 +234,48 @@ public class ListHabitsScreen extends BaseScreen activity.startActivityForResult(intent, REQUEST_OPEN_DOCUMENT); } + @Override public void showIntroScreen() { Intent intent = intentFactory.startIntroActivity(activity); 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, @NonNull String unit, - @NonNull NumberPickerCallback callback) + @NonNull ListHabitsBehavior.NumberPickerCallback callback) { LayoutInflater inflater = activity.getLayoutInflater(); View view = inflater.inflate(R.layout.number_picker_dialog, null); @@ -292,21 +324,12 @@ public class ListHabitsScreen extends BaseScreen dialog.show(); } - private void refreshInitialValue(NumberPicker picker2) + @Override + public void showSendBugReportToDeveloperScreen(String log) { - // 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); - } + int to = R.string.bugReportTo; + int subject = R.string.bugReportSubject; + showSendEmailScreen(to, subject, log); } 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"); } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.java index 0a914d873..5c5e8e003 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.java @@ -27,9 +27,6 @@ import android.support.annotation.*; import org.isoron.androidbase.activities.*; import org.isoron.uhabits.*; 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. @@ -37,25 +34,16 @@ import java.io.*; * Shows all the metadata for the habit, in addition to several charts. */ public class ShowHabitActivity extends BaseActivity - implements ShowHabitMenuBehavior.System { @Nullable private HabitList habitList; @Nullable - private AppComponent appComponent; + private HabitsComponent appComponent; @Nullable private ShowHabitScreen screen; - @Override - public File getCSVOutputDir() - { - if(appComponent == null) throw new IllegalStateException(); - - return appComponent.getBaseSystem().getFilesDir("CSV"); - } - @Override protected void onCreate(Bundle savedInstanceState) { @@ -68,7 +56,7 @@ public class ShowHabitActivity extends BaseActivity ShowHabitComponent component = DaggerShowHabitComponent .builder() - .appComponent(app.getComponent()) + .habitsComponent(app.getComponent()) .showHabitModule(new ShowHabitModule(this, habit)) .build(); diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitComponent.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitComponent.java index 3bfc99c54..f298f715b 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitComponent.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitComponent.java @@ -28,7 +28,7 @@ import dagger.*; @ActivityScope @Component(modules = { ShowHabitModule.class }, - dependencies = { AppComponent.class }) + dependencies = { HabitsComponent.class }) public interface ShowHabitComponent { @NonNull diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitModule.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitModule.java index 3c683baac..d806bb854 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitModule.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitModule.java @@ -21,6 +21,7 @@ package org.isoron.uhabits.activities.habits.show; import android.support.annotation.*; +import org.isoron.androidbase.*; import org.isoron.androidbase.activities.*; import org.isoron.uhabits.models.*; import org.isoron.uhabits.ui.habits.show.*; @@ -57,8 +58,8 @@ public class ShowHabitModule extends ActivityModule } @Provides - public ShowHabitMenuBehavior.System getSystem(BaseActivity activity) + public ShowHabitMenuBehavior.System getSystem(BaseSystem system) { - return (ShowHabitActivity) activity; + return system; } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/automation/FireSettingReceiver.java b/uhabits-android/src/main/java/org/isoron/uhabits/automation/FireSettingReceiver.java index 7ff6af588..753f47b57 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/automation/FireSettingReceiver.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/automation/FireSettingReceiver.java @@ -54,7 +54,7 @@ public class FireSettingReceiver extends BroadcastReceiver ReceiverComponent component = DaggerFireSettingReceiver_ReceiverComponent .builder() - .appComponent(app.getComponent()) + .habitsComponent(app.getComponent()) .build(); allHabits = app.getComponent().getHabitList(); @@ -99,7 +99,7 @@ public class FireSettingReceiver extends BroadcastReceiver } @ReceiverScope - @Component(dependencies = AppComponent.class) + @Component(dependencies = HabitsComponent.class) interface ReceiverComponent { WidgetController getWidgetController(); diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/preferences/AndroidPreferences.java b/uhabits-android/src/main/java/org/isoron/uhabits/preferences/AndroidPreferences.java index 9231967b4..b2c2ac2c0 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/preferences/AndroidPreferences.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/preferences/AndroidPreferences.java @@ -31,6 +31,8 @@ import java.util.*; import javax.inject.*; +import dagger.*; + @AppScope public class AndroidPreferences implements SharedPreferences.OnSharedPreferenceChangeListener, Preferences diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ConnectivityReceiver.java b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ConnectivityReceiver.java index a61913a6b..39e9b2fd3 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ConnectivityReceiver.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ConnectivityReceiver.java @@ -36,7 +36,7 @@ public class ConnectivityReceiver extends BroadcastReceiver if (context == null) return; if (intent == null) return; - AppComponent component = + HabitsComponent component = ((HabitsApplication) context.getApplicationContext()).getComponent(); NetworkInfo networkInfo = diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/PebbleReceiver.java b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/PebbleReceiver.java index 7023a02b3..aa44e3faf 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/PebbleReceiver.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/PebbleReceiver.java @@ -73,7 +73,7 @@ public class PebbleReceiver extends PebbleDataReceiver HabitsApplication app = (HabitsApplication) context.getApplicationContext(); - AppComponent component = app.getComponent(); + HabitsComponent component = app.getComponent(); commandRunner = component.getCommandRunner(); taskRunner = component.getTaskRunner(); allHabits = component.getHabitList(); diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderReceiver.java b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderReceiver.java index c8d022f61..5cf0c2600 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderReceiver.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderReceiver.java @@ -56,7 +56,7 @@ public class ReminderReceiver extends BroadcastReceiver ReminderComponent component = DaggerReminderReceiver_ReminderComponent .builder() - .appComponent(app.getComponent()) + .habitsComponent(app.getComponent()) .build(); HabitList habits = app.getComponent().getHabitList(); @@ -105,7 +105,7 @@ public class ReminderReceiver extends BroadcastReceiver } @ReceiverScope - @Component(dependencies = AppComponent.class) + @Component(dependencies = HabitsComponent.class) interface ReminderComponent { ReminderController getReminderController(); diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java index 00e55d5aa..6c65d1a86 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java @@ -56,7 +56,7 @@ public class WidgetReceiver extends BroadcastReceiver WidgetComponent component = DaggerWidgetReceiver_WidgetComponent .builder() - .appComponent(app.getComponent()) + .habitsComponent(app.getComponent()) .build(); IntentParser parser = app.getComponent().getIntentParser(); @@ -93,7 +93,7 @@ public class WidgetReceiver extends BroadcastReceiver } @ReceiverScope - @Component(dependencies = AppComponent.class) + @Component(dependencies = HabitsComponent.class) interface WidgetComponent { WidgetController getWidgetController(); diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HabitPickerDialog.java b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HabitPickerDialog.java index e648db7e6..983e25250 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HabitPickerDialog.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HabitPickerDialog.java @@ -69,7 +69,7 @@ public class HabitPickerDialog extends Activity setContentView(R.layout.widget_configure_activity); HabitsApplication app = (HabitsApplication) getApplicationContext(); - AppComponent component = app.getComponent(); + HabitsComponent component = app.getComponent(); habitList = component.getHabitList(); preferences = component.getWidgetPreferences(); diff --git a/uhabits-android/src/test/java/org/isoron/androidbase/activities/BaseActivityTest.java b/uhabits-android/src/test/java/org/isoron/androidbase/activities/BaseActivityTest.java index 80fd4c592..17374c582 100644 --- a/uhabits-android/src/test/java/org/isoron/androidbase/activities/BaseActivityTest.java +++ b/uhabits-android/src/test/java/org/isoron/androidbase/activities/BaseActivityTest.java @@ -28,7 +28,6 @@ import android.view.*; import android.widget.*; import org.isoron.uhabits.*; -import org.isoron.uhabits.activities.*; import org.isoron.uhabits.activities.common.dialogs.*; import org.junit.*; import org.junit.runner.*; diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/preferences/Preferences.java b/uhabits-core/src/main/java/org/isoron/uhabits/preferences/Preferences.java index cb3004b23..9e82991d0 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/preferences/Preferences.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/preferences/Preferences.java @@ -22,5 +22,13 @@ package org.isoron.uhabits.preferences; public interface Preferences { + void incrementLaunchCount(); + + boolean isFirstRun(); + void setDeveloper(boolean isDeveloper); + + void setFirstRun(boolean b); + + void updateLastHint(int i, long startOfToday); } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/ui/habits/list/ListHabitsBehavior.java b/uhabits-core/src/main/java/org/isoron/uhabits/ui/habits/list/ListHabitsBehavior.java new file mode 100644 index 000000000..498d0d306 --- /dev/null +++ b/uhabits-core/src/main/java/org/isoron/uhabits/ui/habits/list/ListHabitsBehavior.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2017 Álinson Santos Xavier + * + * 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 . + */ + +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 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(); + } +} diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/BaseUnitTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/BaseUnitTest.java index 35118052c..d78adaac8 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/BaseUnitTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/BaseUnitTest.java @@ -19,6 +19,7 @@ package org.isoron.uhabits; +import org.isoron.uhabits.commands.*; import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.memory.*; import org.isoron.uhabits.tasks.*; @@ -27,6 +28,8 @@ import org.junit.*; import java.util.*; +import static org.mockito.Mockito.*; + public class BaseUnitTest { protected HabitList habitList; @@ -37,6 +40,8 @@ public class BaseUnitTest protected SingleThreadTaskRunner taskRunner; + protected CommandRunner commandRunner; + @Before public void setUp() { @@ -45,9 +50,10 @@ public class BaseUnitTest DateUtils.setFixedLocalTime(fixed_local_time); modelFactory = new MemoryModelFactory(); - habitList = modelFactory.buildHabitList(); + habitList = spy(modelFactory.buildHabitList()); fixtures = new HabitFixtures(modelFactory); taskRunner = new SingleThreadTaskRunner(); + commandRunner = new CommandRunner(taskRunner); } @After diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/models/HabitFixtures.java b/uhabits-core/src/test/java/org/isoron/uhabits/models/HabitFixtures.java index 21344456c..29afe1aab 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/models/HabitFixtures.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/models/HabitFixtures.java @@ -62,6 +62,31 @@ public class HabitFixtures 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() { Habit habit = modelFactory.buildHabit(); diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/ui/habits/list/ListHabitsBehaviorTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/ui/habits/list/ListHabitsBehaviorTest.java new file mode 100644 index 000000000..528f70fb0 --- /dev/null +++ b/uhabits-core/src/test/java/org/isoron/uhabits/ui/habits/list/ListHabitsBehaviorTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2017 Álinson Santos Xavier + * + * 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 . + */ + +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 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()); + } +} \ No newline at end of file