Construct ListHabits using dagger

pull/151/head
Alinson S. Xavier 9 years ago
parent 74f78f0fdf
commit 7f75f9b6da

@ -50,37 +50,42 @@ android {
}
dependencies {
compile 'com.android.support:support-v4:23.3.0'
androidTestApt 'com.google.dagger:dagger-compiler:2.2'
androidTestCompile 'com.android.support:support-annotations:23.3.0'
androidTestCompile 'com.android.support.test:rules:0.5'
androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.google.auto.factory:auto-factory:1.0-beta3'
androidTestCompile "com.google.dexmaker:dexmaker:1.2"
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
androidTestCompile 'org.mockito:mockito-core:1.10.19'
apt 'com.google.dagger:dagger-compiler:2.2'
apt 'com.jakewharton:butterknife-compiler:8.0.1'
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:design:23.3.0'
compile 'com.android.support:preference-v14:23.3.0'
compile 'com.android.support:support-v4:23.3.0'
compile 'com.getpebble:pebblekit:3.0.0'
compile 'com.github.paolorotolo:appintro:3.4.0'
compile 'org.apmem.tools:layouts:1.10@aar'
compile 'com.opencsv:opencsv:3.7'
compile 'com.google.auto.factory:auto-factory:1.0-beta3'
compile 'com.google.dagger:dagger:2.2'
compile 'com.jakewharton:butterknife:8.0.1'
compile 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'
compile 'com.opencsv:opencsv:3.7'
compile 'org.apmem.tools:layouts:1.10@aar'
compile 'org.jetbrains:annotations-java5:15.0'
compile 'com.getpebble:pebblekit:3.0.0'
compile 'com.jakewharton:butterknife:8.0.1'
apt 'com.jakewharton:butterknife-compiler:8.0.1'
provided 'javax.annotation:jsr250-api:1.0'
compile 'com.google.dagger:dagger:2.2'
apt 'com.google.dagger:dagger-compiler:2.2'
testApt 'com.google.dagger:dagger-compiler:2.2'
androidTestApt 'com.google.dagger:dagger-compiler:2.2'
provided 'javax.annotation:jsr250-api:1.0'
testCompile 'junit:junit:4.12'
testCompile 'org.hamcrest:hamcrest-library:1.3'
testCompile 'org.mockito:mockito-core:1.10.19'
androidTestCompile 'com.android.support:support-annotations:23.3.0'
androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.android.support.test:rules:0.5'
androidTestCompile 'org.mockito:mockito-core:1.10.19'
androidTestCompile "com.google.dexmaker:dexmaker:1.2"
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.1') {
exclude group: 'com.android.support'
}

@ -23,6 +23,7 @@ import org.isoron.uhabits.ui.common.dialogs.*;
import dagger.*;
@ActivityScope
@Component(modules = { ActivityModule.class })
public interface ActivityComponent
{

@ -26,17 +26,29 @@ import dagger.*;
@Module
public class ActivityModule
{
private final Context context;
private BaseActivity activity;
public ActivityModule(@ActivityContext Context context)
public ActivityModule(BaseActivity activity)
{
this.context = context;
this.activity = activity;
}
@Provides
BaseActivity getActivity()
{
return activity;
}
@Provides
@ActivityContext
Context getContext()
{
return context;
return activity;
}
@Provides
BaseSystem getBaseSystem()
{
return new BaseSystem(activity);
}
}

@ -0,0 +1,27 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.ui;
import javax.inject.*;
@Scope
public @interface ActivityScope
{
}

@ -20,16 +20,19 @@
package org.isoron.uhabits.ui.common.dialogs;
import android.content.*;
import android.support.annotation.*;
import android.support.v7.app.*;
import com.google.auto.factory.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.ui.*;
import butterknife.*;
/**
* Dialog that asks the user confirmation before executing a delete operation.
*/
@AutoFactory(allowSubclasses = true)
public class ConfirmDeleteDialog extends AlertDialog
{
@BindString(R.string.delete_habits_message)
@ -41,8 +44,8 @@ public class ConfirmDeleteDialog extends AlertDialog
@BindString(android.R.string.no)
protected String no;
protected ConfirmDeleteDialog(@NonNull Context context,
@NonNull Callback callback)
protected ConfirmDeleteDialog(@Provided @ActivityContext Context context,
Callback callback)
{
super(context);
ButterKnife.bind(this);

@ -26,8 +26,6 @@ import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.*;
import org.isoron.uhabits.ui.habits.edit.*;
import java.io.*;
import javax.inject.*;
public class DialogFactory
@ -46,28 +44,9 @@ public class DialogFactory
return ColorPickerDialog.newInstance(context, paletteColor);
}
@NonNull
public ConfirmDeleteDialog buildConfirmDeleteDialog(
@NonNull ConfirmDeleteDialog.Callback callback)
{
return new ConfirmDeleteDialog(context, callback);
}
@NonNull
public CreateHabitDialog buildCreateHabitDialog()
{
return new CreateHabitDialog();
}
@NonNull
public EditHabitDialog buildEditHabitDialog(Habit habit)
{
return EditHabitDialog.newInstance(habit);
}
@NonNull
public FilePickerDialog buildFilePicker(File dir)
{
return new FilePickerDialog(context, dir);
}
}

@ -26,12 +26,17 @@ import android.view.*;
import android.view.WindowManager.*;
import android.widget.*;
import com.google.auto.factory.*;
import org.isoron.uhabits.ui.*;
import java.io.*;
import java.util.*;
/**
* Dialog that allows the user to pick a file.
*/
@AutoFactory(allowSubclasses = true)
public class FilePickerDialog implements AdapterView.OnItemClickListener
{
private static final String PARENT_DIR = "..";
@ -46,7 +51,8 @@ public class FilePickerDialog implements AdapterView.OnItemClickListener
private OnFileSelectedListener listener;
public FilePickerDialog(Context context, File initialDirectory)
public FilePickerDialog(@Provided @ActivityContext Context context,
File initialDirectory)
{
this.context = context;

@ -19,10 +19,13 @@
package org.isoron.uhabits.ui.habits.edit;
import com.google.auto.factory.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.commands.*;
import org.isoron.uhabits.models.*;
@AutoFactory(allowSubclasses = true)
public class CreateHabitDialog extends BaseDialog
{
@Override

@ -22,7 +22,6 @@ package org.isoron.uhabits.ui.habits.list;
import android.os.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.*;
import org.isoron.uhabits.ui.habits.list.model.*;
@ -31,38 +30,30 @@ import org.isoron.uhabits.ui.habits.list.model.*;
*/
public class ListHabitsActivity extends BaseActivity
{
private HabitList habits;
private HabitCardListAdapter adapter;
private ListHabitsRootView rootView;
private ListHabitsScreen screen;
private ListHabitsMenu menu;
private ListHabitsSelectionMenu selectionMenu;
private ListHabitsController controller;
private BaseSystem system;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
habits = HabitsApplication.getComponent().getHabitList();
int checkmarkCount = ListHabitsRootView.MAX_CHECKMARK_COUNT;
ListHabitsComponent component = DaggerListHabitsComponent
.builder()
.appComponent(HabitsApplication.getComponent())
.activityModule(new ActivityModule(this))
.build();
system = new BaseSystem(this);
adapter = new HabitCardListAdapter(habits, checkmarkCount);
ListHabitsMenu menu = component.getMenu();
ListHabitsSelectionMenu selectionMenu = component.getSelectionMenu();
ListHabitsController controller = component.getController();
rootView = new ListHabitsRootView(this, adapter);
screen = new ListHabitsScreen(this, rootView);
menu = new ListHabitsMenu(this, screen, adapter);
selectionMenu = new ListHabitsSelectionMenu(habits, screen, adapter);
controller = new ListHabitsController(habits, screen, system, adapter);
adapter = component.getAdapter();
rootView = component.getRootView();
screen = component.getScreen();
screen.setMenu(menu);
screen.setController(controller);

@ -0,0 +1,44 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.ui.habits.list;
import org.isoron.uhabits.*;
import org.isoron.uhabits.ui.*;
import org.isoron.uhabits.ui.habits.list.model.*;
import dagger.*;
@ActivityScope
@Component(modules = { ActivityModule.class },
dependencies = { AppComponent.class })
public interface ListHabitsComponent
{
HabitCardListAdapter getAdapter();
ListHabitsController getController();
ListHabitsMenu getMenu();
ListHabitsRootView getRootView();
ListHabitsScreen getScreen();
ListHabitsSelectionMenu getSelectionMenu();
}

@ -35,6 +35,9 @@ import org.isoron.uhabits.utils.*;
import java.io.*;
import java.util.*;
import javax.inject.*;
@ActivityScope
public class ListHabitsController
implements HabitCardListController.HabitListener
{
@ -59,20 +62,30 @@ public class ListHabitsController
@NonNull
private final TaskRunner taskRunner;
public ListHabitsController(@NonNull HabitList habitList,
private ReminderScheduler reminderScheduler;
private WidgetUpdater widgetUpdater;
@Inject
public ListHabitsController(@NonNull BaseSystem system,
@NonNull CommandRunner commandRunner,
@NonNull HabitList habitList,
@NonNull HabitCardListAdapter adapter,
@NonNull ListHabitsScreen screen,
@NonNull BaseSystem system,
@NonNull HabitCardListAdapter adapter)
@NonNull Preferences prefs,
@NonNull ReminderScheduler reminderScheduler,
@NonNull TaskRunner taskRunner,
@NonNull WidgetUpdater widgetUpdater)
{
this.adapter = adapter;
this.commandRunner = commandRunner;
this.habitList = habitList;
this.prefs = prefs;
this.screen = screen;
this.system = system;
this.habitList = habitList;
this.adapter = adapter;
AppComponent component = HabitsApplication.getComponent();
prefs = component.getPreferences();
taskRunner = component.getTaskRunner();
commandRunner = component.getCommandRunner();
this.taskRunner = taskRunner;
this.reminderScheduler = reminderScheduler;
this.widgetUpdater = widgetUpdater;
}
public void onExportCSV()
@ -166,17 +179,10 @@ public class ListHabitsController
prefs.updateLastAppVersion();
if (prefs.isFirstRun()) onFirstRun();
new Handler().postDelayed(() ->
{
AppComponent component = HabitsApplication.getComponent();
ReminderScheduler scheduler = component.getReminderScheduler();
WidgetUpdater widgetUpdater = component.getWidgetUpdater();
taskRunner.execute(() -> {
scheduler.schedule(habitList);
new Handler().postDelayed(() -> taskRunner.execute(() -> {
reminderScheduler.schedule(habitList);
widgetUpdater.updateWidgets();
});
}, 1000);
}), 1000);
}
@Override

@ -28,6 +28,9 @@ import org.isoron.uhabits.ui.*;
import org.isoron.uhabits.ui.habits.list.model.*;
import org.isoron.uhabits.utils.*;
import javax.inject.*;
@ActivityScope
public class ListHabitsMenu extends BaseMenu
{
@NonNull
@ -41,15 +44,16 @@ public class ListHabitsMenu extends BaseMenu
private final Preferences preferences;
@Inject
public ListHabitsMenu(@NonNull BaseActivity activity,
@NonNull ListHabitsScreen screen,
@NonNull HabitCardListAdapter adapter)
@NonNull HabitCardListAdapter adapter,
@NonNull Preferences preferences)
{
super(activity);
this.screen = screen;
this.adapter = adapter;
preferences = HabitsApplication.getComponent().getPreferences();
this.preferences = preferences;
showCompleted = preferences.getShowCompleted();
showArchived = preferences.getShowArchived();

@ -34,8 +34,11 @@ import org.isoron.uhabits.ui.habits.list.model.*;
import org.isoron.uhabits.ui.habits.list.views.*;
import org.isoron.uhabits.utils.*;
import javax.inject.*;
import butterknife.*;
@ActivityScope
public class ListHabitsRootView extends BaseRootView
implements ModelObservable.Listener
{
@ -65,8 +68,9 @@ public class ListHabitsRootView extends BaseRootView
@NonNull
private final HabitCardListAdapter listAdapter;
public ListHabitsRootView(@NonNull Context context,
@NonNull HabitCardListAdapter listAdapter)
@Inject
public ListHabitsRootView(@ActivityContext Context context,
HabitCardListAdapter listAdapter)
{
super(context);
addView(inflate(getContext(), R.layout.list_habits, null));

@ -36,6 +36,9 @@ import org.isoron.uhabits.utils.*;
import java.io.*;
import javax.inject.*;
@ActivityScope
public class ListHabitsScreen extends BaseScreen
implements CommandRunner.Listener
{
@ -48,7 +51,7 @@ public class ListHabitsScreen extends BaseScreen
public static final int RESULT_IMPORT_DATA = 1;
@Nullable
ListHabitsController controller;
private ListHabitsController controller;
@NonNull
private final DialogFactory dialogFactory;
@ -59,19 +62,38 @@ public class ListHabitsScreen extends BaseScreen
@NonNull
private final DirFinder dirFinder;
@NonNull
private final CommandRunner commandRunner;
@NonNull
private final ConfirmDeleteDialogFactory confirmDeleteDialogFactory;
@NonNull
private final CreateHabitDialogFactory createHabitDialogFactory;
@NonNull
private final FilePickerDialogFactory filePickerDialogFactory;
@Inject
public ListHabitsScreen(@NonNull BaseActivity activity,
@NonNull ListHabitsRootView rootView)
@NonNull CommandRunner commandRunner,
@NonNull DirFinder dirFinder,
@NonNull DialogFactory dialogFactory,
@NonNull ListHabitsRootView rootView,
@NonNull IntentFactory intentFactory,
@NonNull ConfirmDeleteDialogFactory confirmDeleteDialogFactory,
@NonNull CreateHabitDialogFactory createHabitDialogFactory,
@NonNull FilePickerDialogFactory filePickerDialogFactory)
{
super(activity);
setRootView(rootView);
AppComponent comp = HabitsApplication.getComponent();
intentFactory = comp.getIntentFactory();
dirFinder = comp.getDirFinder();
commandRunner = comp.getCommandRunner();
dialogFactory = activity.getComponent().getDialogFactory();
this.commandRunner = commandRunner;
this.confirmDeleteDialogFactory = confirmDeleteDialogFactory;
this.createHabitDialogFactory = createHabitDialogFactory;
this.dialogFactory = dialogFactory;
this.dirFinder = dirFinder;
this.filePickerDialogFactory = filePickerDialogFactory;
this.intentFactory = intentFactory;
}
public void onAttached()
@ -146,15 +168,12 @@ public class ListHabitsScreen extends BaseScreen
public void showCreateHabitScreen()
{
CreateHabitDialog dialog = dialogFactory.buildCreateHabitDialog();
activity.showDialog(dialog, "editHabit");
activity.showDialog(createHabitDialogFactory.create(), "editHabit");
}
public void showDeleteConfirmationScreen(ConfirmDeleteDialog.Callback callback)
{
ConfirmDeleteDialog dialog =
dialogFactory.buildConfirmDeleteDialog(callback);
activity.showDialog(dialog);
activity.showDialog(confirmDeleteDialogFactory.create(callback));
}
public void showEditHabitScreen(Habit habit)
@ -185,7 +204,8 @@ public class ListHabitsScreen extends BaseScreen
return;
}
FilePickerDialog picker = dialogFactory.buildFilePicker(dir);
FilePickerDialog picker = filePickerDialogFactory.create(dir);
if (controller != null)
picker.setListener(file -> controller.onImportData(file));
activity.showDialog(picker.getDialog());

@ -33,13 +33,14 @@ import java.util.*;
import javax.inject.*;
@ActivityScope
public class ListHabitsSelectionMenu extends BaseSelectionMenu
implements HabitCardListController.SelectionListener
{
@NonNull
private final ListHabitsScreen screen;
@Inject
@NonNull
CommandRunner commandRunner;
@NonNull
@ -51,15 +52,16 @@ public class ListHabitsSelectionMenu extends BaseSelectionMenu
@NonNull
private final HabitList habitList;
@Inject
public ListHabitsSelectionMenu(@NonNull HabitList habitList,
@NonNull ListHabitsScreen screen,
@NonNull HabitCardListAdapter listAdapter)
@NonNull HabitCardListAdapter listAdapter,
@NonNull CommandRunner commandRunner)
{
this.habitList = habitList;
this.screen = screen;
this.listAdapter = listAdapter;
commandRunner = HabitsApplication.getComponent().getCommandRunner();
this.commandRunner = commandRunner;
}
@Override

@ -24,16 +24,20 @@ import android.support.v7.widget.*;
import android.view.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.*;
import org.isoron.uhabits.ui.habits.list.views.*;
import java.util.*;
import javax.inject.*;
/**
* Provides data that backs a {@link HabitCardListView}.
* <p>
* The data if fetched and cached by a {@link HabitCardListCache}. This adapter
* also holds a list of items that have been selected.
*/
@ActivityScope
public class HabitCardListAdapter
extends RecyclerView.Adapter<HabitCardViewHolder>
implements HabitCardListCache.Listener
@ -50,6 +54,12 @@ public class HabitCardListAdapter
@NonNull
private final HabitCardListCache cache;
@Inject
public HabitCardListAdapter(HabitList allHabits)
{
this(allHabits, 10);
}
public HabitCardListAdapter(@NonNull HabitList allHabits,
int checkmarkCount)
{

@ -25,6 +25,7 @@ import org.isoron.uhabits.*;
import org.isoron.uhabits.commands.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.ui.*;
import org.isoron.uhabits.utils.*;
import java.util.*;
@ -37,6 +38,7 @@ import java.util.*;
* the ListView very slow. It also registers itself as an observer of the
* models, in order to update itself automatically.
*/
@ActivityScope
public class HabitCardListCache implements CommandRunner.Listener
{
private int checkmarkCount;

@ -24,6 +24,9 @@ import android.content.*;
import android.support.v7.app.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.commands.*;
import org.isoron.uhabits.intents.*;
import org.isoron.uhabits.io.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.*;
import org.isoron.uhabits.ui.common.dialogs.*;
@ -35,6 +38,9 @@ import org.junit.runners.*;
import java.io.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.*;
@RunWith(JUnit4.class)
@ -52,31 +58,44 @@ public class ListHabitsScreenTest extends BaseUnitTest
private Intent intent;
private ConfirmDeleteDialogFactory confirmDeleteDialogFactory;
private CreateHabitDialogFactory createHabitDialogFactory;
private FilePickerDialogFactory filePickerDialogFactory;
@Before
@Override
public void setUp()
{
super.setUp();
ActivityComponent activityComponent = mock(ActivityComponent.class);
activity = mock(BaseActivity.class);
when(activity.getComponent()).thenReturn(activityComponent);
commandRunner = mock(CommandRunner.class);
dirFinder = mock(DirFinder.class);
dialogFactory = mock(DialogFactory.class);
rootView = mock(ListHabitsRootView.class);
intentFactory = mock(IntentFactory.class);
confirmDeleteDialogFactory = mock(ConfirmDeleteDialogFactory.class);
createHabitDialogFactory = mock(CreateHabitDialogFactory.class);
filePickerDialogFactory = mock(FilePickerDialogFactory.class);
screen = new ListHabitsScreen(activity, commandRunner, dirFinder,
dialogFactory, rootView, intentFactory, confirmDeleteDialogFactory,
createHabitDialogFactory, filePickerDialogFactory);
controller = mock(ListHabitsController.class);
intent = mock(Intent.class);
screen.setController(controller);
habit = new Habit();
screen = new ListHabitsScreen(activity, rootView);
screen.setController(controller);
intent = mock(Intent.class);
}
@Test
public void testCreateHabitScreen()
{
CreateHabitDialog dialog = mock(CreateHabitDialog.class);
when(dialogFactory.buildCreateHabitDialog()).thenReturn(dialog);
when(createHabitDialogFactory.create()).thenReturn(dialog);
screen.showCreateHabitScreen();
@ -140,7 +159,7 @@ public class ListHabitsScreenTest extends BaseUnitTest
callback = mock(ConfirmDeleteDialog.Callback.class);
ConfirmDeleteDialog dialog = mock(ConfirmDeleteDialog.class);
when(dialogFactory.buildConfirmDeleteDialog(callback)).thenReturn(dialog);
when(confirmDeleteDialogFactory.create(callback)).thenReturn(dialog);
screen.showDeleteConfirmationScreen(callback);
@ -183,7 +202,7 @@ public class ListHabitsScreenTest extends BaseUnitTest
FilePickerDialog picker = mock(FilePickerDialog.class);
AppCompatDialog dialog = mock(AppCompatDialog.class);
when(picker.getDialog()).thenReturn(dialog);
when(dialogFactory.buildFilePicker(dir)).thenReturn(picker);
when(filePickerDialogFactory.create(dir)).thenReturn(picker);
screen.showImportScreen();

Loading…
Cancel
Save