├── .gitignore ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── io │ │ └── caster │ │ └── simplemvp │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── io │ │ │ └── caster │ │ │ └── simplemvp │ │ │ ├── AppComponent.java │ │ │ ├── AppModule.java │ │ │ ├── MvpApplication.java │ │ │ ├── model │ │ │ └── User.java │ │ │ ├── presentation │ │ │ ├── UserPresenter.java │ │ │ └── UserPresenterImpl.java │ │ │ ├── repository │ │ │ ├── InMemoryUserRepositoryImpl.java │ │ │ └── UserRepository.java │ │ │ └── view │ │ │ ├── UserView.java │ │ │ ├── activity │ │ │ └── MainActivity.java │ │ │ └── fragment │ │ │ └── UserFragment.java │ └── res │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── content_main.xml │ │ └── fragment_main.xml │ │ ├── menu │ │ └── menu_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── io │ └── caster │ └── simplemvp │ ├── .keep │ └── PresenterTests.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .idea/ -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'com.neenbedankt.android-apt' 3 | 4 | android { 5 | compileSdkVersion 23 6 | buildToolsVersion "23.0.2" 7 | 8 | defaultConfig { 9 | applicationId "io.caster.simplemvp" 10 | minSdkVersion 16 11 | targetSdkVersion 23 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | compile fileTree(dir: 'libs', include: ['*.jar']) 25 | testCompile 'junit:junit:4.12' 26 | testCompile "org.mockito:mockito-core:1.10.19" 27 | 28 | compile 'com.android.support:appcompat-v7:23.1.1' 29 | compile 'com.android.support:design:23.1.1' 30 | 31 | compile 'com.jakewharton:butterknife:7.0.1' 32 | compile 'com.google.dagger:dagger:2.0.2' 33 | apt 'com.google.dagger:dagger-compiler:2.0.2' 34 | provided 'javax.annotation:jsr250-api:1.0' 35 | } 36 | -------------------------------------------------------------------------------- /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 /opt/android/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/androidTest/java/io/caster/simplemvp/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package io.caster.simplemvp; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/io/caster/simplemvp/AppComponent.java: -------------------------------------------------------------------------------- 1 | package io.caster.simplemvp; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Component; 6 | import io.caster.simplemvp.view.fragment.UserFragment; 7 | 8 | @Singleton 9 | @Component(modules = { AppModule.class }) 10 | public interface AppComponent { 11 | void inject(UserFragment target); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/io/caster/simplemvp/AppModule.java: -------------------------------------------------------------------------------- 1 | package io.caster.simplemvp; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Module; 6 | import dagger.Provides; 7 | import io.caster.simplemvp.presentation.UserPresenter; 8 | import io.caster.simplemvp.presentation.UserPresenterImpl; 9 | import io.caster.simplemvp.repository.UserRepository; 10 | import io.caster.simplemvp.repository.InMemoryUserRepositoryImpl; 11 | 12 | @Module 13 | public class AppModule { 14 | @Provides @Singleton 15 | public UserRepository provideUserRepository() { 16 | return new InMemoryUserRepositoryImpl(); 17 | } 18 | 19 | @Provides 20 | public UserPresenter provideUserPresenter(UserRepository userRepository) { 21 | return new UserPresenterImpl(userRepository); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/io/caster/simplemvp/MvpApplication.java: -------------------------------------------------------------------------------- 1 | package io.caster.simplemvp; 2 | 3 | import android.app.Application; 4 | 5 | public class MvpApplication extends Application { 6 | 7 | private AppComponent component; 8 | 9 | 10 | @Override 11 | public void onCreate() { 12 | super.onCreate(); 13 | 14 | component = DaggerAppComponent.builder().appModule(new AppModule()).build(); 15 | 16 | } 17 | 18 | public AppComponent getComponent() { 19 | return component; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/io/caster/simplemvp/model/User.java: -------------------------------------------------------------------------------- 1 | package io.caster.simplemvp.model; 2 | 3 | public class User { 4 | private int id; 5 | private String firstName; 6 | private String lastName; 7 | 8 | 9 | public int getId() { 10 | return id; 11 | } 12 | 13 | public void setId(int id) { 14 | this.id = id; 15 | } 16 | 17 | public String getFirstName() { 18 | return firstName; 19 | } 20 | 21 | public void setFirstName(String firstName) { 22 | this.firstName = firstName; 23 | } 24 | 25 | public String getLastName() { 26 | return lastName; 27 | } 28 | 29 | public void setLastName(String lastName) { 30 | this.lastName = lastName; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/io/caster/simplemvp/presentation/UserPresenter.java: -------------------------------------------------------------------------------- 1 | package io.caster.simplemvp.presentation; 2 | 3 | import io.caster.simplemvp.view.UserView; 4 | 5 | public interface UserPresenter { 6 | void loadUserDetails(); 7 | void setView(UserView view); 8 | void saveUser(); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/io/caster/simplemvp/presentation/UserPresenterImpl.java: -------------------------------------------------------------------------------- 1 | package io.caster.simplemvp.presentation; 2 | 3 | import io.caster.simplemvp.model.User; 4 | import io.caster.simplemvp.repository.UserRepository; 5 | import io.caster.simplemvp.view.UserView; 6 | 7 | public class UserPresenterImpl implements UserPresenter { 8 | 9 | private UserView view; 10 | private UserRepository userRepository; 11 | private User u; 12 | 13 | public UserPresenterImpl(UserRepository userRepository) { 14 | this.userRepository = userRepository; 15 | } 16 | 17 | @Override 18 | public void loadUserDetails() { 19 | int userId = view.getUserId(); 20 | u = userRepository.getUser(userId); 21 | if(u == null) { 22 | view.showUserNotFoundMessage(); 23 | } else { 24 | view.displayFirstName(u.getFirstName()); 25 | view.displayLastName(u.getLastName()); 26 | } 27 | } 28 | 29 | @Override 30 | public void setView(UserView view) { 31 | this.view = view; 32 | loadUserDetails(); 33 | } 34 | 35 | @Override 36 | public void saveUser() { 37 | if(u != null) { 38 | if(view.getFirstName().trim().equals("") || view.getLastName().trim().equals("")) { 39 | view.showUserNameIsRequired(); 40 | } else { 41 | u.setFirstName(view.getFirstName()); 42 | u.setLastName(view.getLastName()); 43 | userRepository.save(u); 44 | view.showUserSavedMessage(); 45 | } 46 | 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/io/caster/simplemvp/repository/InMemoryUserRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package io.caster.simplemvp.repository; 2 | 3 | import io.caster.simplemvp.model.User; 4 | 5 | public class InMemoryUserRepositoryImpl implements UserRepository { 6 | private User u; 7 | 8 | /** 9 | * Gets the user from memory. 10 | * 11 | * @param id The id of the user. 12 | * @return a {@link User} 13 | */ 14 | @Override 15 | public User getUser(int id) { 16 | // Normally this would go to a DB/etc and fetch the user with an ID. 17 | // Here though, we're just doing something in memory, so we're kind of just 18 | // faking it out. 19 | if (u == null) { 20 | u = new User(); 21 | u.setId(id); 22 | u.setFirstName("Captain"); 23 | u.setLastName("Crunch"); 24 | } 25 | return u; 26 | } 27 | 28 | /** 29 | * Save's the in-memory user. 30 | * 31 | * @param u The user. 32 | */ 33 | @Override 34 | public void save(User u) { 35 | if(this.u == null) { 36 | this.u = getUser(0); // create the in memory user. 37 | } 38 | this.u.setId(u.getId()); 39 | this.u.setFirstName(u.getFirstName()); 40 | this.u.setLastName(u.getLastName()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/io/caster/simplemvp/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package io.caster.simplemvp.repository; 2 | 3 | import io.caster.simplemvp.model.User; 4 | 5 | public interface UserRepository { 6 | User getUser(int id); 7 | void save(User u); 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/io/caster/simplemvp/view/UserView.java: -------------------------------------------------------------------------------- 1 | package io.caster.simplemvp.view; 2 | 3 | public interface UserView { 4 | int getUserId(); 5 | 6 | void displayFirstName(String name); 7 | void displayLastName(String name); 8 | 9 | void showUserNotFoundMessage(); 10 | void showUserSavedMessage(); 11 | 12 | String getFirstName(); 13 | String getLastName(); 14 | 15 | void showUserNameIsRequired(); 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/io/caster/simplemvp/view/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package io.caster.simplemvp.view.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.design.widget.FloatingActionButton; 5 | import android.support.design.widget.Snackbar; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.support.v7.widget.Toolbar; 8 | import android.view.View; 9 | import android.view.Menu; 10 | import android.view.MenuItem; 11 | 12 | import io.caster.simplemvp.R; 13 | 14 | public class MainActivity extends AppCompatActivity { 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_main); 20 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 21 | setSupportActionBar(toolbar); 22 | 23 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 24 | fab.setOnClickListener(new View.OnClickListener() { 25 | @Override 26 | public void onClick(View view) { 27 | Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) 28 | .setAction("Action", null).show(); 29 | } 30 | }); 31 | } 32 | 33 | @Override 34 | public boolean onCreateOptionsMenu(Menu menu) { 35 | // Inflate the menu; this adds items to the action bar if it is present. 36 | getMenuInflater().inflate(R.menu.menu_main, menu); 37 | return true; 38 | } 39 | 40 | @Override 41 | public boolean onOptionsItemSelected(MenuItem item) { 42 | // Handle action bar item clicks here. The action bar will 43 | // automatically handle clicks on the Home/Up button, so long 44 | // as you specify a parent activity in AndroidManifest.xml. 45 | int id = item.getItemId(); 46 | 47 | //noinspection SimplifiableIfStatement 48 | if (id == R.id.action_settings) { 49 | return true; 50 | } 51 | 52 | return super.onOptionsItemSelected(item); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/io/caster/simplemvp/view/fragment/UserFragment.java: -------------------------------------------------------------------------------- 1 | package io.caster.simplemvp.view.fragment; 2 | 3 | import android.support.annotation.Nullable; 4 | import android.support.v4.app.Fragment; 5 | import android.os.Bundle; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.Button; 10 | import android.widget.EditText; 11 | import android.widget.TextView; 12 | import android.widget.Toast; 13 | 14 | import javax.inject.Inject; 15 | 16 | import butterknife.Bind; 17 | import butterknife.ButterKnife; 18 | import butterknife.OnClick; 19 | import io.caster.simplemvp.MvpApplication; 20 | import io.caster.simplemvp.R; 21 | import io.caster.simplemvp.presentation.UserPresenter; 22 | import io.caster.simplemvp.view.UserView; 23 | 24 | /** 25 | * The V in MVP (Model View Presenter) 26 | */ 27 | public class UserFragment extends Fragment implements UserView { 28 | 29 | @Inject UserPresenter userPresenter; 30 | 31 | protected EditText userFirstName; 32 | protected EditText userLastName; 33 | 34 | private static final String USER_ID = "user_id"; 35 | 36 | public UserFragment() { 37 | } 38 | 39 | @Override 40 | public void onCreate(@Nullable Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | ((MvpApplication)getActivity().getApplication()).getComponent().inject(this); 43 | } 44 | 45 | @Override 46 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 47 | Bundle savedInstanceState) { 48 | View v = inflater.inflate(R.layout.fragment_main, container, false); 49 | userFirstName = (EditText) v.findViewById(R.id.user_first_name); 50 | userLastName = (EditText) v.findViewById(R.id.user_last_name); 51 | v.findViewById(R.id.user_save).setOnClickListener(new View.OnClickListener() { 52 | @Override 53 | public void onClick(View v) { 54 | userPresenter.saveUser(); 55 | } 56 | }); 57 | return v; 58 | } 59 | 60 | @Override 61 | public void onResume() { 62 | super.onResume(); 63 | userPresenter.setView(this); 64 | } 65 | 66 | @Override 67 | public int getUserId() { 68 | return getArguments() == null ? 0 : getArguments().getInt(USER_ID, 0); 69 | } 70 | 71 | @Override 72 | public void displayFirstName(String name) { 73 | userFirstName.setText(name); 74 | } 75 | 76 | @Override 77 | public void displayLastName(String name) { 78 | userLastName.setText(name); 79 | } 80 | 81 | @Override 82 | public void showUserNotFoundMessage() { 83 | Toast.makeText(getActivity(), R.string.user_not_found, Toast.LENGTH_LONG).show(); 84 | } 85 | 86 | @Override 87 | public void showUserSavedMessage() { 88 | Toast.makeText(getActivity(), R.string.user_saved, Toast.LENGTH_SHORT).show(); 89 | } 90 | 91 | @Override 92 | public String getFirstName() { 93 | return userFirstName.getText().toString(); 94 | } 95 | 96 | @Override 97 | public String getLastName() { 98 | return userLastName.getText().toString(); 99 | } 100 | 101 | @Override 102 | public void showUserNameIsRequired() { 103 | Toast.makeText(getActivity(), R.string.user_name_required_message, Toast.LENGTH_SHORT).show(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_main.xml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 18 | 19 | 24 | 25 |