├── settings.gradle ├── app ├── .gitignore ├── src │ ├── test │ │ ├── resources │ │ │ └── mockito-extensions │ │ │ │ └── org.mockito.plugins.MockMaker │ │ └── java │ │ │ └── io │ │ │ └── mvpstarter │ │ │ └── sample │ │ │ ├── util │ │ │ ├── DefaultConfig.java │ │ │ └── RxSchedulersOverrideRule.java │ │ │ ├── DataManagerTest.java │ │ │ ├── MainPresenterTest.java │ │ │ └── DetailPresenterTest.java │ ├── main │ │ ├── res │ │ │ ├── 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 │ │ │ ├── layout │ │ │ │ ├── item_pokemon.xml │ │ │ │ ├── activity_maps_sample.xml │ │ │ │ ├── view_statistic.xml │ │ │ │ ├── view_error.xml │ │ │ │ ├── activity_main.xml │ │ │ │ └── activity_detail.xml │ │ │ └── values │ │ │ │ ├── dimens.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ ├── java │ │ │ └── io │ │ │ │ └── mvpstarter │ │ │ │ └── sample │ │ │ │ ├── data │ │ │ │ ├── model │ │ │ │ │ └── response │ │ │ │ │ │ ├── NamedResource.java │ │ │ │ │ │ ├── PokemonListResponse.java │ │ │ │ │ │ ├── Sprites.java │ │ │ │ │ │ ├── Pokemon.java │ │ │ │ │ │ └── Statistic.java │ │ │ │ ├── local │ │ │ │ │ ├── DbManager.java │ │ │ │ │ └── PreferencesHelper.java │ │ │ │ ├── remote │ │ │ │ │ └── PokemonService.java │ │ │ │ └── DataManager.java │ │ │ │ ├── Constants.java │ │ │ │ ├── util │ │ │ │ ├── rx │ │ │ │ │ └── scheduler │ │ │ │ │ │ ├── SchedulerUtils.java │ │ │ │ │ │ ├── IoMainScheduler.java │ │ │ │ │ │ ├── SingleMainScheduler.java │ │ │ │ │ │ ├── NewThreadMainScheduler.java │ │ │ │ │ │ ├── ComputationMainScheduler.java │ │ │ │ │ │ ├── TrampolineMainScheduler.java │ │ │ │ │ │ └── BaseScheduler.java │ │ │ │ ├── ViewUtil.java │ │ │ │ └── NetworkUtil.java │ │ │ │ ├── injection │ │ │ │ ├── ActivityContext.java │ │ │ │ ├── ApplicationContext.java │ │ │ │ ├── ConfigPersistent.java │ │ │ │ ├── component │ │ │ │ │ ├── FragmentComponent.java │ │ │ │ │ ├── ActivityComponent.java │ │ │ │ │ ├── AppComponent.java │ │ │ │ │ └── ConfigPersistentComponent.java │ │ │ │ ├── PerActivity.java │ │ │ │ ├── PerFragment.java │ │ │ │ └── module │ │ │ │ │ ├── ApiModule.java │ │ │ │ │ ├── ActivityModule.java │ │ │ │ │ ├── FragmentModule.java │ │ │ │ │ ├── AppModule.java │ │ │ │ │ └── NetworkModule.java │ │ │ │ ├── features │ │ │ │ ├── main │ │ │ │ │ ├── MainMvpView.java │ │ │ │ │ ├── MainPresenter.java │ │ │ │ │ ├── PokemonAdapter.java │ │ │ │ │ └── MainActivity.java │ │ │ │ ├── base │ │ │ │ │ ├── Presenter.java │ │ │ │ │ ├── MvpView.java │ │ │ │ │ ├── BasePresenter.java │ │ │ │ │ ├── BaseFragment.java │ │ │ │ │ └── BaseActivity.java │ │ │ │ ├── detail │ │ │ │ │ ├── DetailMvpView.java │ │ │ │ │ ├── widget │ │ │ │ │ │ └── StatisticView.java │ │ │ │ │ ├── DetailPresenter.java │ │ │ │ │ ├── MapsSampleActivity.java │ │ │ │ │ └── DetailActivity.java │ │ │ │ └── common │ │ │ │ │ └── ErrorView.java │ │ │ │ └── MvpStarterApplication.java │ │ └── AndroidManifest.xml │ ├── debug │ │ ├── AndroidManifest.xml │ │ └── res │ │ │ └── values │ │ │ └── google_maps_api.xml │ ├── commonTest │ │ └── java │ │ │ └── io │ │ │ └── mvpstarter │ │ │ └── sample │ │ │ └── common │ │ │ ├── injection │ │ │ ├── component │ │ │ │ └── TestComponent.java │ │ │ └── module │ │ │ │ └── ApplicationTestModule.java │ │ │ ├── TestComponentRule.java │ │ │ └── TestDataFactory.java │ ├── androidTest │ │ ├── java │ │ │ └── io │ │ │ │ └── mvpstarter │ │ │ │ └── sample │ │ │ │ ├── runner │ │ │ │ ├── TestRunner.java │ │ │ │ └── RxAndroidJUnitRunner.java │ │ │ │ ├── util │ │ │ │ ├── ErrorTestUtil.java │ │ │ │ ├── RxIdlingResource.java │ │ │ │ └── RxIdlingScheduler.java │ │ │ │ ├── DetailActivityTest.java │ │ │ │ └── MainActivityTest.java │ │ └── assets │ │ │ └── getPokemon.json │ └── release │ │ └── res │ │ └── values │ │ └── google_maps_api.xml ├── proguard-rules.pro ├── lint.xml ├── build.gradle └── dependencies.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── aars └── cloudtestingscreenshotter_lib.aar ├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── config ├── quality │ ├── findbugs │ │ └── android-exclude-filter.xml │ ├── pmd │ │ └── pmd-ruleset.xml │ ├── quality.gradle │ └── checkstyle │ │ └── checkstyle-config.xml └── jacoco.gradle ├── .travis.yml ├── scripts ├── ci.sh └── remoteTesting.sh ├── gradle.properties ├── circle.yml ├── gradlew.bat ├── CONTRIBUTING.md ├── gradlew └── README.md /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *iml 3 | *.iml 4 | .idea -------------------------------------------------------------------------------- /app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker: -------------------------------------------------------------------------------- 1 | mock-maker-inline -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidstarters/android-starter/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /aars/cloudtestingscreenshotter_lib.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidstarters/android-starter/HEAD/aars/cloudtestingscreenshotter_lib.aar -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidstarters/android-starter/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidstarters/android-starter/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidstarters/android-starter/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidstarters/android-starter/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidstarters/android-starter/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | .DS_Store 5 | /build 6 | .idea/ 7 | *iml 8 | *.iml 9 | */build 10 | fastlane 11 | .tasks.cache.json -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/data/model/response/NamedResource.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.data.model.response; 2 | 3 | public class NamedResource { 4 | public String name; 5 | public String url; 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/Constants.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample; 2 | 3 | /** 4 | * Created by shivam on 29/5/17. 5 | */ 6 | public interface Constants { 7 | 8 | String PREF_FILE_NAME = "mvpstarter_pref_file"; 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/data/model/response/PokemonListResponse.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.data.model.response; 2 | 3 | import java.util.List; 4 | 5 | public class PokemonListResponse { 6 | public List results; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/test/java/io/mvpstarter/sample/util/DefaultConfig.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.util; 2 | 3 | public class DefaultConfig { 4 | //The api level that Roboelectric will use to run the unit tests 5 | public static final int EMULATE_SDK = 24; 6 | } 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Dec 21 11:38:13 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/data/model/response/Sprites.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.data.model.response; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class Sprites { 6 | @SerializedName("front_default") 7 | public String frontDefault; 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/data/model/response/Pokemon.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.data.model.response; 2 | 3 | import java.util.List; 4 | 5 | public class Pokemon { 6 | public String id; 7 | public String name; 8 | public Sprites sprites; 9 | public List stats; 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/data/model/response/Statistic.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.data.model.response; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class Statistic { 6 | public NamedResource stat; 7 | 8 | @SerializedName("base_stat") 9 | public int baseStat; 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/util/rx/scheduler/SchedulerUtils.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.util.rx.scheduler; 2 | 3 | /** 4 | * Created by lam on 2/6/17. 5 | */ 6 | public class SchedulerUtils { 7 | 8 | public static IoMainScheduler ioToMain() { 9 | return new IoMainScheduler<>(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/injection/ActivityContext.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.injection; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | import javax.inject.Qualifier; 7 | 8 | @Qualifier 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface ActivityContext { 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/injection/ApplicationContext.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.injection; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | import javax.inject.Qualifier; 7 | 8 | @Qualifier 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface ApplicationContext { 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_pokemon.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/data/local/DbManager.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.data.local; 2 | 3 | import javax.inject.Inject; 4 | import javax.inject.Singleton; 5 | 6 | /** 7 | * Created by shivam on 29/5/17. 8 | */ 9 | 10 | // To be implemented with Realm 11 | 12 | @Singleton 13 | public class DbManager { 14 | 15 | @Inject 16 | public DbManager() { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/features/main/MainMvpView.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.features.main; 2 | 3 | import java.util.List; 4 | 5 | import io.mvpstarter.sample.features.base.MvpView; 6 | 7 | public interface MainMvpView extends MvpView { 8 | 9 | void showPokemon(List pokemon); 10 | 11 | void showProgress(boolean show); 12 | 13 | void showError(Throwable error); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/features/base/Presenter.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.features.base; 2 | 3 | /** 4 | * Every presenter in the app must either implement this interface or extend BasePresenter 5 | * indicating the MvpView type that wants to be attached with. 6 | */ 7 | public interface Presenter { 8 | 9 | void attachView(V mvpView); 10 | 11 | void detachView(); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_maps_sample.xml: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24sp 5 | 6 | 7 | 8 | 16sp 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/features/base/MvpView.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.features.base; 2 | 3 | /** 4 | * Base interface that any class that wants to act as a View in the MVP (Model View Presenter) 5 | * pattern must implement. Generally this interface will be extended by a more specific interface 6 | * that then usually will be implemented by an Activity or Fragment. 7 | */ 8 | public interface MvpView { 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/util/rx/scheduler/IoMainScheduler.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.util.rx.scheduler; 2 | 3 | import io.reactivex.android.schedulers.AndroidSchedulers; 4 | import io.reactivex.schedulers.Schedulers; 5 | 6 | /** 7 | * Created by lam on 2/6/17. 8 | */ 9 | public class IoMainScheduler extends BaseScheduler { 10 | 11 | public IoMainScheduler() { 12 | super(Schedulers.io(), AndroidSchedulers.mainThread()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/injection/ConfigPersistent.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.injection; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | import javax.inject.Scope; 7 | 8 | 9 | /** 10 | * A scoping annotation to permit dependencies conform to the life of the {@link 11 | * ConfigPersistentComponent} 12 | */ 13 | @Scope 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface ConfigPersistent { 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/util/rx/scheduler/SingleMainScheduler.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.util.rx.scheduler; 2 | 3 | import io.reactivex.android.schedulers.AndroidSchedulers; 4 | import io.reactivex.schedulers.Schedulers; 5 | 6 | /** 7 | * Created by lam on 2/6/17. 8 | */ 9 | public class SingleMainScheduler extends BaseScheduler { 10 | 11 | protected SingleMainScheduler() { 12 | super(Schedulers.single(), AndroidSchedulers.mainThread()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/commonTest/java/io/mvpstarter/sample/common/injection/component/TestComponent.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.common.injection.component; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Component; 6 | import io.mvpstarter.sample.common.injection.module.ApplicationTestModule; 7 | import io.mvpstarter.sample.injection.component.AppComponent; 8 | 9 | @Singleton 10 | @Component(modules = ApplicationTestModule.class) 11 | public interface TestComponent extends AppComponent { 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/injection/component/FragmentComponent.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.injection.component; 2 | 3 | import dagger.Subcomponent; 4 | import io.mvpstarter.sample.injection.PerFragment; 5 | import io.mvpstarter.sample.injection.module.FragmentModule; 6 | 7 | /** 8 | * This component inject dependencies to all Fragments across the application 9 | */ 10 | @PerFragment 11 | @Subcomponent(modules = FragmentModule.class) 12 | public interface FragmentComponent { 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/injection/PerActivity.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.injection; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | import javax.inject.Scope; 7 | 8 | /** 9 | * A scoping annotation to permit objects whose lifetime should conform to the life of the Activity 10 | * to be memorised in the correct component. 11 | */ 12 | @Scope 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface PerActivity { 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/injection/PerFragment.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.injection; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | import javax.inject.Scope; 7 | 8 | /** 9 | * A scoping annotation to permit objects whose lifetime should conform to the life of the Fragment 10 | * to be memorised in the correct component. 11 | */ 12 | @Scope 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface PerFragment { 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/util/rx/scheduler/NewThreadMainScheduler.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.util.rx.scheduler; 2 | 3 | import io.reactivex.android.schedulers.AndroidSchedulers; 4 | import io.reactivex.schedulers.Schedulers; 5 | 6 | /** 7 | * Created by lam on 2/6/17. 8 | */ 9 | public class NewThreadMainScheduler extends BaseScheduler { 10 | 11 | protected NewThreadMainScheduler() { 12 | super(Schedulers.newThread(), AndroidSchedulers.mainThread()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /config/quality/findbugs/android-exclude-filter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/util/rx/scheduler/ComputationMainScheduler.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.util.rx.scheduler; 2 | 3 | import io.reactivex.android.schedulers.AndroidSchedulers; 4 | import io.reactivex.schedulers.Schedulers; 5 | 6 | /** 7 | * Created by lam on 2/6/17. 8 | */ 9 | public class ComputationMainScheduler extends BaseScheduler { 10 | 11 | protected ComputationMainScheduler() { 12 | super(Schedulers.computation(), AndroidSchedulers.mainThread()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/util/rx/scheduler/TrampolineMainScheduler.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.util.rx.scheduler; 2 | 3 | import io.reactivex.android.schedulers.AndroidSchedulers; 4 | import io.reactivex.schedulers.Schedulers; 5 | 6 | /** 7 | * Created by lam on 2/6/17. 8 | */ 9 | public class TrampolineMainScheduler extends BaseScheduler { 10 | 11 | protected TrampolineMainScheduler() { 12 | super(Schedulers.trampoline(), AndroidSchedulers.mainThread()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/features/detail/DetailMvpView.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.features.detail; 2 | 3 | import io.mvpstarter.sample.data.model.response.Pokemon; 4 | import io.mvpstarter.sample.data.model.response.Statistic; 5 | import io.mvpstarter.sample.features.base.MvpView; 6 | 7 | public interface DetailMvpView extends MvpView { 8 | 9 | void showPokemon(Pokemon pokemon); 10 | 11 | void showStat(Statistic statistic); 12 | 13 | void showProgress(boolean show); 14 | 15 | void showError(Throwable error); 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #F44336 4 | #D32F2F 5 | 6 | #FF5722 7 | 8 | 9 | 10 | #FFFFFF 11 | 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: android 4 | jdk: oraclejdk8 5 | 6 | android: 7 | components: 8 | - platform-tools 9 | - tools # to get the new `repository-11.xml` 10 | - tools # see https://github.com/travis-ci/travis-ci/issues/6040#issuecomment-219367943) 11 | - build-tools-27.0.0 12 | - android-27 13 | - extra-android-m2repository 14 | - extra-google-m2repository 15 | - extra-android-support 16 | - extra-google-google_play_services 17 | 18 | before_script: 19 | - chmod +x gradlew 20 | 21 | script: "./gradlew testDebugUnitTest -PdisablePreDex" 22 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/injection/module/ApiModule.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.injection.module; 2 | 3 | import javax.inject.Singleton; 4 | 5 | import dagger.Module; 6 | import dagger.Provides; 7 | import io.mvpstarter.sample.data.remote.PokemonService; 8 | import retrofit2.Retrofit; 9 | 10 | /** 11 | * Created by shivam on 29/5/17. 12 | */ 13 | @Module(includes = {NetworkModule.class}) 14 | public class ApiModule { 15 | 16 | @Provides 17 | @Singleton 18 | PokemonService providePokemonApi(Retrofit retrofit) { 19 | return retrofit.create(PokemonService.class); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/data/remote/PokemonService.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.data.remote; 2 | 3 | import io.mvpstarter.sample.data.model.response.Pokemon; 4 | import io.mvpstarter.sample.data.model.response.PokemonListResponse; 5 | import io.reactivex.Single; 6 | import retrofit2.http.GET; 7 | import retrofit2.http.Path; 8 | import retrofit2.http.Query; 9 | 10 | public interface PokemonService { 11 | 12 | @GET("pokemon") 13 | Single getPokemonList(@Query("limit") int limit); 14 | 15 | @GET("pokemon/{name}") 16 | Single getPokemon(@Path("name") String name); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/injection/component/ActivityComponent.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.injection.component; 2 | 3 | import dagger.Subcomponent; 4 | import io.mvpstarter.sample.features.detail.DetailActivity; 5 | import io.mvpstarter.sample.features.main.MainActivity; 6 | import io.mvpstarter.sample.injection.PerActivity; 7 | import io.mvpstarter.sample.injection.module.ActivityModule; 8 | 9 | @PerActivity 10 | @Subcomponent(modules = ActivityModule.class) 11 | public interface ActivityComponent { 12 | 13 | void inject(MainActivity mainActivity); 14 | 15 | void inject(DetailActivity detailActivity); 16 | } 17 | -------------------------------------------------------------------------------- /scripts/ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -xe 3 | 4 | # Get the location for report directory from 1st param or use current directory 5 | if [ ! -z "$1" ]; then 6 | report_location=$1 7 | else 8 | report_location=`pwd` 9 | fi 10 | 11 | ./gradlew --no-daemon --info clean 12 | ./gradlew --no-daemon --info checkstyle -PdisablePreDex 13 | 14 | # If we have a service key for the GCloud Cli then use remote testing otherwise run local tests 15 | if [ -n "${GCLOUD_SERVICE_KEY+1}" ]; then 16 | ./gradlew --no-daemon --info assembleAndroidTest -PdisablePreDex 17 | scripts/remoteTesting.sh ${report_location} 18 | else 19 | ./gradlew --no-daemon --info testDebugUnitTest -PdisablePreDex 20 | fi 21 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/injection/component/AppComponent.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.injection.component; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import javax.inject.Singleton; 7 | 8 | import dagger.Component; 9 | import io.mvpstarter.sample.data.DataManager; 10 | import io.mvpstarter.sample.injection.ApplicationContext; 11 | import io.mvpstarter.sample.injection.module.AppModule; 12 | 13 | @Singleton 14 | @Component(modules = AppModule.class) 15 | public interface AppComponent { 16 | 17 | @ApplicationContext 18 | Context context(); 19 | 20 | Application application(); 21 | 22 | DataManager apiManager(); 23 | } 24 | -------------------------------------------------------------------------------- /app/src/androidTest/java/io/mvpstarter/sample/runner/TestRunner.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.runner; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import io.appflate.restmock.android.RESTMockTestRunner; 7 | import io.mvpstarter.sample.MvpStarterApplication; 8 | 9 | /** 10 | * Created by ravindra on 4/2/17. 11 | */ 12 | public class TestRunner extends RESTMockTestRunner { 13 | 14 | @Override 15 | public Application newApplication(ClassLoader cl, String className, Context context) 16 | throws InstantiationException, IllegalAccessException, ClassNotFoundException { 17 | return super.newApplication(cl, MvpStarterApplication.class.getName(), context); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/injection/module/ActivityModule.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.injection.module; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | 6 | import dagger.Module; 7 | import dagger.Provides; 8 | import io.mvpstarter.sample.injection.ActivityContext; 9 | 10 | @Module 11 | public class ActivityModule { 12 | 13 | private Activity activity; 14 | 15 | public ActivityModule(Activity activity) { 16 | this.activity = activity; 17 | } 18 | 19 | @Provides 20 | Activity provideActivity() { 21 | return activity; 22 | } 23 | 24 | @Provides 25 | @ActivityContext 26 | Context providesContext() { 27 | return activity; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /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 /usr/local/Cellar/android-sdk/24.4.1/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/io/mvpstarter/sample/injection/module/FragmentModule.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.injection.module; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.support.v4.app.Fragment; 6 | 7 | import dagger.Module; 8 | import dagger.Provides; 9 | import io.mvpstarter.sample.injection.ActivityContext; 10 | 11 | @Module 12 | public class FragmentModule { 13 | private Fragment fragment; 14 | 15 | public FragmentModule(Fragment fragment) { 16 | this.fragment = fragment; 17 | } 18 | 19 | @Provides 20 | Fragment providesFragment() { 21 | return fragment; 22 | } 23 | 24 | @Provides 25 | Activity provideActivity() { 26 | return fragment.getActivity(); 27 | } 28 | 29 | @Provides 30 | @ActivityContext 31 | Context providesContext() { 32 | return fragment.getActivity(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | MvpStarter 3 | 4 | OK 5 | 6 | Sorry 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Oops 15 | There was a problem loading the pokemon, please try again! 16 | Reload 17 | Map 18 | Something bad happened. Please try again. 19 | 20 | -------------------------------------------------------------------------------- /app/src/release/res/values/google_maps_api.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | YOUR_KEY_HERE 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | // Unused will be removed on release 9 | // Using the material icons provided from Google 10 | // We might want to index our app later 11 | // Butterknife, Okio and Realm 12 | // Annotation binding 13 | 14 | 15 | // CI issue with sdk.dir in local.properties 16 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/util/ViewUtil.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.util; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.res.Resources; 6 | import android.view.inputmethod.InputMethodManager; 7 | 8 | public final class ViewUtil { 9 | 10 | public static float pxToDp(float px) { 11 | float densityDpi = Resources.getSystem().getDisplayMetrics().densityDpi; 12 | return px / (densityDpi / 160f); 13 | } 14 | 15 | public static int dpToPx(int dp) { 16 | float density = Resources.getSystem().getDisplayMetrics().density; 17 | return Math.round(dp * density); 18 | } 19 | 20 | public static void hideKeyboard(Activity activity) { 21 | InputMethodManager imm = 22 | (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); 23 | imm.hideSoftInputFromWindow(activity.getWindow().getDecorView().getWindowToken(), 0); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 | 20 | 21 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/util/NetworkUtil.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.util; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | 7 | import retrofit2.HttpException; 8 | 9 | public class NetworkUtil { 10 | 11 | /** 12 | * Returns true if the Throwable is an instance of RetrofitError with an http status code equals 13 | * to the given one. 14 | */ 15 | public static boolean isHttpStatusCode(Throwable throwable, int statusCode) { 16 | return throwable instanceof HttpException 17 | && ((HttpException) throwable).code() == statusCode; 18 | } 19 | 20 | public static boolean isNetworkConnected(Context context) { 21 | ConnectivityManager cm = 22 | (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 23 | NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); 24 | return activeNetwork != null && activeNetwork.isConnectedOrConnecting(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/debug/res/values/google_maps_api.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | YOUR_KEY_HERE 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_statistic.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 17 | 18 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/injection/module/AppModule.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.injection.module; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.content.SharedPreferences; 6 | 7 | import dagger.Module; 8 | import dagger.Provides; 9 | import io.mvpstarter.sample.injection.ApplicationContext; 10 | 11 | import static io.mvpstarter.sample.Constants.PREF_FILE_NAME; 12 | 13 | @Module(includes = {ApiModule.class}) 14 | public class AppModule { 15 | private final Application application; 16 | 17 | public AppModule(Application application) { 18 | this.application = application; 19 | } 20 | 21 | @Provides 22 | Application provideApplication() { 23 | return application; 24 | } 25 | 26 | @Provides 27 | @ApplicationContext 28 | Context provideContext() { 29 | return application; 30 | } 31 | 32 | @Provides 33 | @ApplicationContext 34 | SharedPreferences provideSharedPreference(@ApplicationContext Context context) { 35 | return context.getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/data/DataManager.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.data; 2 | 3 | import java.util.List; 4 | 5 | import javax.inject.Inject; 6 | import javax.inject.Singleton; 7 | 8 | import io.mvpstarter.sample.data.model.response.Pokemon; 9 | import io.mvpstarter.sample.data.remote.PokemonService; 10 | import io.reactivex.Single; 11 | 12 | /** 13 | * Created by shivam on 29/5/17. 14 | */ 15 | @Singleton 16 | public class DataManager { 17 | 18 | private PokemonService pokemonService; 19 | 20 | @Inject 21 | public DataManager(PokemonService pokemonService) { 22 | this.pokemonService = pokemonService; 23 | } 24 | 25 | public Single> getPokemonList(int limit) { 26 | return pokemonService 27 | .getPokemonList(limit) 28 | .toObservable() 29 | .flatMapIterable(namedResources -> namedResources.results) 30 | .map(namedResource -> namedResource.name) 31 | .toList(); 32 | } 33 | 34 | public Single getPokemon(String name) { 35 | return pokemonService.getPokemon(name); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/androidTest/java/io/mvpstarter/sample/util/ErrorTestUtil.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.util; 2 | 3 | import io.mvpstarter.sample.R; 4 | 5 | import static android.support.test.espresso.Espresso.onView; 6 | import static android.support.test.espresso.action.ViewActions.click; 7 | import static android.support.test.espresso.assertion.ViewAssertions.matches; 8 | import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; 9 | import static android.support.test.espresso.matcher.ViewMatchers.withText; 10 | import static org.hamcrest.Matchers.allOf; 11 | 12 | public class ErrorTestUtil { 13 | 14 | public static void checkErrorViewsDisplay() { 15 | onView(allOf(withText(R.string.error_title), isDisplayed())).check(matches(isDisplayed())); 16 | onView(allOf(withText(R.string.error_message), isDisplayed())) 17 | .check(matches(isDisplayed())); 18 | } 19 | 20 | public static void checkClickingReloadShowsContentWithText(String expectedText) { 21 | onView(allOf(withText(R.string.error_reload), isDisplayed())).perform(click()); 22 | onView(withText(expectedText)).check(matches(isDisplayed())); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/io/mvpstarter/sample/injection/component/ConfigPersistentComponent.java: -------------------------------------------------------------------------------- 1 | package io.mvpstarter.sample.injection.component; 2 | 3 | import dagger.Component; 4 | import io.mvpstarter.sample.features.base.BaseActivity; 5 | import io.mvpstarter.sample.features.base.BaseFragment; 6 | import io.mvpstarter.sample.injection.ConfigPersistent; 7 | import io.mvpstarter.sample.injection.module.ActivityModule; 8 | import io.mvpstarter.sample.injection.module.FragmentModule; 9 | 10 | /** 11 | * A dagger component that will live during the lifecycle of an Activity or Fragment but it won't be 12 | * destroy during configuration changes. Check {@link BaseActivity} and {@link BaseFragment} to see 13 | * how this components survives configuration changes. Use the {@link ConfigPersistent} scope to 14 | * annotate dependencies that need to survive configuration changes (for example Presenters). 15 | */ 16 | @ConfigPersistent 17 | @Component(dependencies = AppComponent.class) 18 | public interface ConfigPersistentComponent { 19 | 20 | ActivityComponent activityComponent(ActivityModule activityModule); 21 | 22 | FragmentComponent fragmentComponent(FragmentModule fragmentModule); 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_error.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 22 | 23 |