├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── drawable-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values
│ │ │ │ ├── styles.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ └── strings.xml
│ │ │ ├── menu
│ │ │ │ ├── delete_note.xml
│ │ │ │ └── notes.xml
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ └── layout
│ │ │ │ ├── activity_notes.xml
│ │ │ │ └── note_details.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── corneliudascalu
│ │ │ │ └── mvpnotes
│ │ │ │ ├── ui
│ │ │ │ └── view
│ │ │ │ │ ├── details
│ │ │ │ │ ├── interfaces
│ │ │ │ │ │ ├── NoteDetailsView.java
│ │ │ │ │ │ └── NoteDetailsPresenter.java
│ │ │ │ │ ├── NoteDetailsModule.java
│ │ │ │ │ ├── SimpleNoteDetailsPresenter.java
│ │ │ │ │ └── NoteDetailsDialogFragment.java
│ │ │ │ │ └── main
│ │ │ │ │ ├── NotesView.java
│ │ │ │ │ ├── OnNoteOperationListener.java
│ │ │ │ │ ├── NotesPresenter.java
│ │ │ │ │ ├── NotesModule.java
│ │ │ │ │ ├── SimpleNotesPresenter.java
│ │ │ │ │ └── NotesActivity.java
│ │ │ │ ├── common
│ │ │ │ ├── ObjectGraphCreator.java
│ │ │ │ ├── InjectedDialogFragment.java
│ │ │ │ ├── BaseInjectedActivity.java
│ │ │ │ └── ObjectGraphHolder.java
│ │ │ │ ├── util
│ │ │ │ ├── DateTimeSerializer.java
│ │ │ │ └── DateTimeDeserializer.java
│ │ │ │ ├── AppModule.java
│ │ │ │ ├── data
│ │ │ │ ├── interactor
│ │ │ │ │ ├── NoteInteractor.java
│ │ │ │ │ ├── InteractorsModule.java
│ │ │ │ │ └── impl
│ │ │ │ │ │ └── NoteInteractorImpl.java
│ │ │ │ └── model
│ │ │ │ │ ├── DatabaseModule.java
│ │ │ │ │ ├── Note.java
│ │ │ │ │ └── SimpleDatabase.java
│ │ │ │ └── MVPNotesApp.java
│ │ └── AndroidManifest.xml
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── corneliudascalu
│ │ └── mvpnotes
│ │ └── tests
│ │ ├── MockNoteInteractorModule.java
│ │ ├── MockNoteInteractor.java
│ │ └── MainInstrumentationTest.java
├── proguard-rules.pro
├── build.gradle
└── app.iml
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── README.md
├── .gitignore
├── mvp-notes.iml
├── gradle.properties
├── gradlew.bat
├── gradlew
└── LICENSE
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/corneliudascalu/mvp-notes/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/corneliudascalu/mvp-notes/HEAD/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/corneliudascalu/mvp-notes/HEAD/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/corneliudascalu/mvp-notes/HEAD/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/corneliudascalu/mvp-notes/HEAD/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | mvp-notes
2 | =========
3 |
4 | Sample Android project implementing the MVP paradigm, using Dagger and Espresso
5 |
6 | The code is commented, and the related blog post is [here].
7 |
8 | [here]: http://corneliudascalu.github.io/model-view-presenter-in-android/
9 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Jul 05 00:38:42 EEST 2014
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/delete_note.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MVPNotes
5 | Hello world!
6 | Settings
7 | Create
8 | Delete
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/notes.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | .idea/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/corneliudascalu/mvpnotes/ui/view/details/interfaces/NoteDetailsView.java:
--------------------------------------------------------------------------------
1 | package com.corneliudascalu.mvpnotes.ui.view.details.interfaces;
2 |
3 | import com.corneliudascalu.mvpnotes.data.model.Note;
4 |
5 | /**
6 | * @author Corneliu Dascalu
7 | */
8 | public interface NoteDetailsView {
9 |
10 | void setNote(Note note);
11 |
12 | void close();
13 |
14 | void showError(String error);
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/corneliudascalu/mvpnotes/ui/view/details/interfaces/NoteDetailsPresenter.java:
--------------------------------------------------------------------------------
1 | package com.corneliudascalu.mvpnotes.ui.view.details.interfaces;
2 |
3 | import com.corneliudascalu.mvpnotes.data.model.Note;
4 |
5 | /**
6 | * @author Corneliu Dascalu
7 | */
8 | public interface NoteDetailsPresenter {
9 |
10 | void setData(Note note);
11 |
12 | void viewReady();
13 |
14 | void deleteNote();
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/corneliudascalu/mvpnotes/common/ObjectGraphCreator.java:
--------------------------------------------------------------------------------
1 | package com.corneliudascalu.mvpnotes.common;
2 |
3 | import android.app.Application;
4 | import dagger.ObjectGraph;
5 |
6 | /**
7 | * Defines the structure of the object graph creator. There's no reason to have more than one,
8 | * but it's useful when testing
9 | *
10 | * @author Corneliu Dascalu
11 | */
12 | public interface ObjectGraphCreator {
13 | ObjectGraph create(Application application);
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/corneliudascalu/mvpnotes/ui/view/main/NotesView.java:
--------------------------------------------------------------------------------
1 | package com.corneliudascalu.mvpnotes.ui.view.main;
2 |
3 | import com.corneliudascalu.mvpnotes.data.model.Note;
4 |
5 | /**
6 | * Defines the methods of a NotesView. In our case, the interface will be implemented by an activity,
7 | * but it could just as well be implemented by a fragment or a simple view.
8 | *
9 | * @author Corneliu Dascalu
10 | */
11 | public interface NotesView {
12 | void setNoteError(String error);
13 |
14 | void addNotes(Note... note);
15 |
16 | void removeNote(Note note);
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/corneliudascalu/mvpnotes/ui/view/main/OnNoteOperationListener.java:
--------------------------------------------------------------------------------
1 | package com.corneliudascalu.mvpnotes.ui.view.main;
2 |
3 | import com.corneliudascalu.mvpnotes.data.model.Note;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * @author Corneliu Dascalu
9 | */
10 | public interface OnNoteOperationListener {
11 |
12 | void onNoteAdded(Note note);
13 |
14 | void onNoteAddError(Note.Error error);
15 |
16 | void onNoteDeleted(Note note);
17 |
18 | void onNoteDeleteError(Note.Error error);
19 |
20 | void onNoteRetrieved(Note note);
21 |
22 | void onNoteListRetrieved(List notes);
23 |
24 | void onRetrieveError(Note.Error error);
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/corneliudascalu/mvpnotes/util/DateTimeSerializer.java:
--------------------------------------------------------------------------------
1 | package com.corneliudascalu.mvpnotes.util;
2 |
3 | import com.google.gson.JsonElement;
4 | import com.google.gson.JsonPrimitive;
5 | import com.google.gson.JsonSerializationContext;
6 | import com.google.gson.JsonSerializer;
7 |
8 | import org.joda.time.DateTime;
9 |
10 | import java.lang.reflect.Type;
11 |
12 | /**
13 | * @author Corneliu Dascalu
14 | */
15 | public class DateTimeSerializer implements JsonSerializer {
16 |
17 | @Override
18 | public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
19 | return new JsonPrimitive(src.toString());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/corneliudascalu/mvpnotes/AppModule.java:
--------------------------------------------------------------------------------
1 | package com.corneliudascalu.mvpnotes;
2 |
3 | import com.corneliudascalu.mvpnotes.data.interactor.InteractorsModule;
4 |
5 | import javax.inject.Singleton;
6 |
7 | import dagger.Module;
8 | import dagger.Provides;
9 |
10 | /**
11 | * @author Corneliu Dascalu
12 | */
13 | @Module(injects = {MVPNotesApp.class},
14 | includes = {InteractorsModule.class}
15 | )
16 | public class AppModule {
17 | private MVPNotesApp app;
18 |
19 | public AppModule(MVPNotesApp app) {
20 | this.app = app;
21 | }
22 |
23 | @Provides
24 | @Singleton
25 | public MVPNotesApp provideApplication() {
26 | return app;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/corneliu/programs/android-studio/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/corneliudascalu/mvpnotes/ui/view/main/NotesPresenter.java:
--------------------------------------------------------------------------------
1 | package com.corneliudascalu.mvpnotes.ui.view.main;
2 |
3 | import com.corneliudascalu.mvpnotes.data.model.Note;
4 |
5 | /**
6 | * Defines the methods of a NotesPresenter implementation
7 | *
8 | * @author Corneliu Dascalu
9 | */
10 | public interface NotesPresenter {
11 |
12 | /**
13 | * Request a list of notes from the presenter
14 | */
15 | void requestNotes();
16 |
17 | /**
18 | * Send a note to the presenter, to store it
19 | */
20 | void submitNewNote(String title, String text);
21 |
22 | /**
23 | * Request to the presenter to delete this note
24 | */
25 | void deleteNote(Note note);
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/corneliudascalu/mvpnotes/tests/MockNoteInteractorModule.java:
--------------------------------------------------------------------------------
1 | package com.corneliudascalu.mvpnotes.tests;
2 |
3 | import com.corneliudascalu.mvpnotes.data.interactor.NoteInteractor;
4 | import dagger.Module;
5 | import dagger.Provides;
6 |
7 | /**
8 | * An interactor module that supplies a different {@link com.corneliudascalu.mvpnotes.data.interactor
9 | * .NoteInteractor}, by overriding the one from the {@link com.corneliudascalu.mvpnotes.data.interactor
10 | * .InteractorsModule}
11 | *
12 | * @author Corneliu Dascalu
13 | */
14 | @Module(overrides = true, library = true)
15 | public class MockNoteInteractorModule {
16 |
17 | @Provides
18 | NoteInteractor provideNoteInteractor() {
19 | return new MockNoteInteractor();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/corneliudascalu/mvpnotes/util/DateTimeDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.corneliudascalu.mvpnotes.util;
2 |
3 | import com.google.gson.JsonDeserializationContext;
4 | import com.google.gson.JsonDeserializer;
5 | import com.google.gson.JsonElement;
6 | import com.google.gson.JsonParseException;
7 |
8 | import org.joda.time.DateTime;
9 |
10 | import java.lang.reflect.Type;
11 |
12 | /**
13 | * @author Corneliu Dascalu
14 | */
15 | public class DateTimeDeserializer implements JsonDeserializer {
16 |
17 | @Override
18 | public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
19 | throws JsonParseException {
20 | return new DateTime(json.getAsJsonPrimitive().getAsString());
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/corneliudascalu/mvpnotes/data/interactor/NoteInteractor.java:
--------------------------------------------------------------------------------
1 | package com.corneliudascalu.mvpnotes.data.interactor;
2 |
3 | import com.corneliudascalu.mvpnotes.data.model.Note;
4 | import com.corneliudascalu.mvpnotes.ui.view.main.OnNoteOperationListener;
5 |
6 | /**
7 | * Defines the notes interactor, which takes care of storing and deleting notes, either directly or
8 | * by communicating
9 | * with another layer.
10 | *
11 | * @author Corneliu Dascalu
12 | */
13 | public interface NoteInteractor {
14 |
15 | void storeNote(Note note, OnNoteOperationListener listener);
16 |
17 | void deleteNote(Note note, OnNoteOperationListener listener);
18 |
19 | void getNote(long id, OnNoteOperationListener listener);
20 |
21 | void getAllNotes(OnNoteOperationListener listener);
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/corneliudascalu/mvpnotes/data/interactor/InteractorsModule.java:
--------------------------------------------------------------------------------
1 | package com.corneliudascalu.mvpnotes.data.interactor;
2 |
3 | import com.corneliudascalu.mvpnotes.MVPNotesApp;
4 | import com.corneliudascalu.mvpnotes.data.interactor.impl.NoteInteractorImpl;
5 |
6 | import dagger.Module;
7 | import dagger.Provides;
8 |
9 | /**
10 | * Provides the list of interactors used throughout the app. Handy to have them all in the same
11 | * file,
12 | * and the {@code library} annotation means that only needed interactors will be injected in the
13 | * target object
14 | *
15 | * @author Corneliu Dascalu
16 | */
17 | @Module(library = true, complete = false)
18 | public class InteractorsModule {
19 |
20 | @Provides
21 | public NoteInteractor provideNotesInteractor(MVPNotesApp app) {
22 | return new NoteInteractorImpl(app);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/mvp-notes.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Settings specified in this file will override any Gradle settings
5 | # configured through the IDE.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/corneliudascalu/mvpnotes/common/InjectedDialogFragment.java:
--------------------------------------------------------------------------------
1 | package com.corneliudascalu.mvpnotes.common;
2 |
3 | import android.app.DialogFragment;
4 | import android.os.Bundle;
5 |
6 | import java.util.List;
7 |
8 | import dagger.ObjectGraph;
9 |
10 | /**
11 | * @author Corneliu Dascalu
12 | */
13 | public abstract class InjectedDialogFragment extends DialogFragment {
14 |
15 | private ObjectGraph objectGraph;
16 |
17 | @Override
18 | public void onCreate(Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | objectGraph = ObjectGraphHolder
21 | .createScopedObjectGraph(getActivity().getApplication(), getModules().toArray());
22 | objectGraph.inject(this);
23 | }
24 |
25 | protected abstract List