[
  {
    "path": ".gitignore",
    "content": ".gradle\n*.iml\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n"
  },
  {
    "path": ".idea/.name",
    "content": "CleanArchitecture"
  },
  {
    "path": ".idea/compiler.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"CompilerConfiguration\">\n    <resourceExtensions />\n    <wildcardResourcePatterns>\n      <entry name=\"!?*.java\" />\n      <entry name=\"!?*.form\" />\n      <entry name=\"!?*.class\" />\n      <entry name=\"!?*.groovy\" />\n      <entry name=\"!?*.scala\" />\n      <entry name=\"!?*.flex\" />\n      <entry name=\"!?*.kt\" />\n      <entry name=\"!?*.clj\" />\n    </wildcardResourcePatterns>\n    <annotationProcessing>\n      <profile default=\"true\" name=\"Default\" enabled=\"false\">\n        <processorPath useClasspath=\"true\" />\n      </profile>\n    </annotationProcessing>\n  </component>\n</project>"
  },
  {
    "path": ".idea/copyright/profiles_settings.xml",
    "content": "<component name=\"CopyrightManager\">\n  <settings default=\"\" />\n</component>"
  },
  {
    "path": ".idea/encodings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"Encoding\">\n    <file url=\"PROJECT\" charset=\"UTF-8\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/gradle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"GradleSettings\">\n    <option name=\"linkedExternalProjectsSettings\">\n      <GradleProjectSettings>\n        <option name=\"distributionType\" value=\"DEFAULT_WRAPPED\" />\n        <option name=\"externalProjectPath\" value=\"$PROJECT_DIR$\" />\n        <option name=\"modules\">\n          <set>\n            <option value=\"$PROJECT_DIR$\" />\n            <option value=\"$PROJECT_DIR$/app\" />\n          </set>\n        </option>\n        <option name=\"myModules\">\n          <set>\n            <option value=\"$PROJECT_DIR$\" />\n            <option value=\"$PROJECT_DIR$/app\" />\n          </set>\n        </option>\n      </GradleProjectSettings>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/misc.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"EntryPointsManager\">\n    <entry_points version=\"2.0\" />\n  </component>\n  <component name=\"JavacSettings\">\n    <option name=\"ADDITIONAL_OPTIONS_STRING\" value=\"--stacktrace --debug\" />\n  </component>\n  <component name=\"NullableNotNullManager\">\n    <option name=\"myDefaultNullable\" value=\"android.support.annotation.Nullable\" />\n    <option name=\"myDefaultNotNull\" value=\"android.support.annotation.NonNull\" />\n    <option name=\"myNullables\">\n      <value>\n        <list size=\"4\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.Nullable\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nullable\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.Nullable\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.Nullable\" />\n        </list>\n      </value>\n    </option>\n    <option name=\"myNotNulls\">\n      <value>\n        <list size=\"4\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.NotNull\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nonnull\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.NonNull\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.NonNull\" />\n        </list>\n      </value>\n    </option>\n  </component>\n  <component name=\"ProjectInspectionProfilesVisibleTreeState\">\n    <entry key=\"Project Default\">\n      <profile-state>\n        <expanded-state>\n          <State>\n            <id />\n          </State>\n          <State>\n            <id>Android Lint</id>\n          </State>\n          <State>\n            <id>C/C++</id>\n          </State>\n          <State>\n            <id>Class structureJava</id>\n          </State>\n          <State>\n            <id>Code maturity issuesJava</id>\n          </State>\n          <State>\n            <id>Code style issuesJava</id>\n          </State>\n          <State>\n            <id>Compiler issuesJava</id>\n          </State>\n          <State>\n            <id>Declaration orderC/C++</id>\n          </State>\n          <State>\n            <id>Finalization issuesJava</id>\n          </State>\n          <State>\n            <id>Groovy</id>\n          </State>\n          <State>\n            <id>Inheritance issuesJava</id>\n          </State>\n          <State>\n            <id>J2ME issuesJava</id>\n          </State>\n          <State>\n            <id>Java</id>\n          </State>\n          <State>\n            <id>Java language level migration aidsJava</id>\n          </State>\n          <State>\n            <id>JavaBeans issuesJava</id>\n          </State>\n          <State>\n            <id>Javadoc issuesJava</id>\n          </State>\n          <State>\n            <id>Numeric issuesJava</id>\n          </State>\n          <State>\n            <id>OtherGroovy</id>\n          </State>\n          <State>\n            <id>Performance issuesJava</id>\n          </State>\n          <State>\n            <id>Probable bugsJava</id>\n          </State>\n          <State>\n            <id>Security issuesJava</id>\n          </State>\n          <State>\n            <id>Serialization issuesJava</id>\n          </State>\n          <State>\n            <id>TestNGJava</id>\n          </State>\n          <State>\n            <id>Threading issuesJava</id>\n          </State>\n          <State>\n            <id>Type checksC/C++</id>\n          </State>\n          <State>\n            <id>Verbose or redundant code constructsJava</id>\n          </State>\n        </expanded-state>\n        <selected-state>\n          <State>\n            <id>Android</id>\n          </State>\n        </selected-state>\n      </profile-state>\n    </entry>\n  </component>\n  <component name=\"ProjectLevelVcsManager\" settingsEditedManually=\"false\">\n    <OptionsSetting value=\"true\" id=\"Add\" />\n    <OptionsSetting value=\"true\" id=\"Remove\" />\n    <OptionsSetting value=\"true\" id=\"Checkout\" />\n    <OptionsSetting value=\"true\" id=\"Update\" />\n    <OptionsSetting value=\"true\" id=\"Status\" />\n    <OptionsSetting value=\"true\" id=\"Edit\" />\n    <ConfirmationsSetting value=\"0\" id=\"Add\" />\n    <ConfirmationsSetting value=\"0\" id=\"Remove\" />\n  </component>\n  <component name=\"ProjectRootManager\" version=\"2\" languageLevel=\"JDK_1_8\" assert-keyword=\"true\" jdk-15=\"true\" project-jdk-name=\"1.8\" project-jdk-type=\"JavaSDK\">\n    <output url=\"file://$PROJECT_DIR$/build/classes\" />\n  </component>\n  <component name=\"ProjectType\">\n    <option name=\"id\" value=\"Android\" />\n  </component>\n  <component name=\"masterDetails\">\n    <states>\n      <state key=\"ProjectJDKs.UI\">\n        <settings>\n          <last-edited>1.7</last-edited>\n          <splitter-proportions>\n            <option name=\"proportions\">\n              <list>\n                <option value=\"0.2\" />\n              </list>\n            </option>\n          </splitter-proportions>\n        </settings>\n      </state>\n    </states>\n  </component>\n</project>"
  },
  {
    "path": ".idea/modules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n      <module fileurl=\"file://$PROJECT_DIR$/CleanArchitecture.iml\" filepath=\"$PROJECT_DIR$/CleanArchitecture.iml\" />\n      <module fileurl=\"file://$PROJECT_DIR$/app/app.iml\" filepath=\"$PROJECT_DIR$/app/app.iml\" />\n    </modules>\n  </component>\n</project>"
  },
  {
    "path": ".idea/runConfigurations.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"RunConfigurationProducerService\">\n    <option name=\"ignoredProducers\">\n      <set>\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer\" />\n      </set>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"\" vcs=\"Git\" />\n  </component>\n</project>"
  },
  {
    "path": "README.md",
    "content": "# CleanArchitecture\n\nThanks for checking out my github repo. There's not much to say in this readme since I wrote two articles about this repo here:\n\n[Article 1 - Dagger 2 introduction](https://medium.com/@patrykpoborca/making-a-best-practice-app-4-dagger-2-267ec5f6c89a)\n\n[Article 2 - Clean Architecture and Testing in JUnit and AndroidJunit with Espresso](https://medium.com/@patrykpoborca/making-a-best-practice-app-5-clean-architecture-testing-84a1672dd000)\n\nTo sum, the articles and this repo go into how to utilize Dagger 2 in order to setup and start your project. How to properly implement some variant of an Architecture so that your app is scalable and testable.\nFinally we go over how to actually implement those tests. I have similar tests in both POJO (Plain old java object) Junit and Android Junit which utilizes Some mockito.\nI also show how annoying/and or obnoxious it is to test imporoperly architected applications by actually testing my \"PlainTweeterActivity\"\n\nI hope you learn something from this, if you have any questions or issues feel free to start an issue here or [tweet me here](https://twitter.com/patrykpoborca)\n\nAlso if you want to see the talk about Dagger 2 I did here [it is](https://www.youtube.com/watch?v=JNbz_rgdQ10)\n\nThanks!\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'me.tatarka.retrolambda'\napply plugin: 'com.android.application'\napply plugin: 'com.neenbedankt.android-apt'\n\n//apply plugin: \"net.ltgt.apt\"\n\nandroid {\n    compileSdkVersion 22\n    buildToolsVersion '23.0.2'\n\n    defaultConfig {\n        applicationId \"io.patrykpoborca.cleanarchitecture\"\n        minSdkVersion 22\n        targetSdkVersion 22\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        encoding \"UTF-8\"\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\ndependencies {\n    dependencies {\n        apt 'com.google.dagger:dagger-compiler:2.0'\n        testProvided 'com.google.dagger:dagger-compiler:2.0'\n        //needed to resolve compilation errors, thanks to tutplus.org for finding the dependency\n        // http://stackoverflow.com/questions/27036933/how-to-set-up-dagger-dependency-injection-from-scratch-in-android-project\n        //test compiles\n        androidTestApt 'com.google.dagger:dagger-compiler:2.0'\n\n        compile fileTree(include: ['*.jar'], dir: 'libs')\n        compile 'com.android.support:appcompat-v7:22.2.0'\n        compile 'com.google.dagger:dagger:2.0'\n        provided 'org.glassfish:javax.annotation:10.0-b28'\n        compile 'io.reactivex:rxandroid:0.25.0'\n        compile 'com.jakewharton:butterknife:7.0.1'\n\n        androidTestCompile 'com.google.dagger:dagger:2.0'\n        testCompile 'com.google.dagger:dagger:2.0'\n        testCompile 'junit:junit:4.12'\n        androidTestCompile 'com.android.support.test:runner:0.3'\n        // Set this dependency to use JUnit 4 rules\n        androidTestCompile 'com.android.support.test:rules:0.3'\n        androidTestCompile 'org.mockito:mockito-core:1.+'\n        androidTestCompile('com.android.support.test:runner:0.3') {\n            exclude group: 'com.android.support', module: 'support-annotations'\n        }\n        androidTestCompile 'com.google.dexmaker:dexmaker:1.2'\n        androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'\n        androidTestCompile 'com.android.support.test:runner:0.3'\n        androidTestCompile 'com.android.support.test:rules:0.3'\n        androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2'\n    }\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in C:\\Users\\Patryk\\AppData\\Local\\Android\\sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/TestHelper.java",
    "content": "package io.patrykpoborca.cleanarchitecture;\n\nimport android.app.Application;\n\nimport io.patrykpoborca.cleanarchitecture.dagger.DaggerTestClassInjector;\nimport io.patrykpoborca.cleanarchitecture.dagger.TestClassInjector;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.ApplicationComponent;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.BaseComponent;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.DaggerApplicationComponent;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.DaggerBaseComponent;\nimport io.patrykpoborca.cleanarchitecture.dagger.mockmodules.MockLocalModule;\nimport io.patrykpoborca.cleanarchitecture.dagger.mockmodules.MockNetworkModule;\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.ApplicationModule;\n\npublic class TestHelper {\n\n    private static ApplicationComponent sApplicationComponent;\n    private static BaseComponent sBaseComponent;\n    private static TestClassInjector sTestClassInjector;\n\n    public static ApplicationComponent getApplicationComponent(){\n        if(sApplicationComponent == null)\n        {\n            sApplicationComponent = DaggerApplicationComponent.builder()\n                    .applicationModule(new ApplicationModule(new Application()))\n                    .build();\n        }\n        return sApplicationComponent;\n    }\n\n    public static BaseComponent getBaseComponent(){\n        if(sBaseComponent == null){\n            sBaseComponent = DaggerBaseComponent.builder()\n                    .applicationComponent(getApplicationComponent())\n                    .localModule(new MockLocalModule())\n                    .networkModule(new MockNetworkModule())\n                    .build();\n        }\n        return sBaseComponent;\n    }\n\n    public static TestClassInjector getTestClassInjector(){\n        if(sTestClassInjector == null){\n            sTestClassInjector = DaggerTestClassInjector.builder()\n                    .baseComponent(getBaseComponent())\n                    .build();\n        }\n\n        return sTestClassInjector;\n    }\n\n    public static void waitFor(IWaitingCallback callback){\n        waitFor(10, callback);\n    }\n\n    public static void waitFor(int maxCycles, IWaitingCallback callback){\n        while(true){\n            maxCycles --;\n            try {\n                Thread.sleep(5);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n            if(callback.checkCondition()){\n                break;\n            }\n            if(maxCycles <= 0){\n                break;\n            }\n        }\n    }\n\n    public static interface IWaitingCallback{\n        /**\n         *\n         * @return true if condition is met, false if we should keep waiting\n         */\n        public boolean checkCondition();\n    }\n}"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/TestClassInjector.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger;\n\nimport dagger.Component;\nimport io.patrykpoborca.cleanarchitecture.dagger.mockmodules.MockTestModule;\nimport io.patrykpoborca.cleanarchitecture.tests.MVPCITest;\nimport io.patrykpoborca.cleanarchitecture.tests.MVPTest;\nimport io.patrykpoborca.cleanarchitecture.tests.MVVMTest;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.BaseComponent;\nimport io.patrykpoborca.cleanarchitecture.dagger.scopes.ActivityScope;\n\n@ActivityScope\n@Component(dependencies = BaseComponent.class, modules = MockTestModule.class)\npublic interface TestClassInjector {\n    void inject(MVVMTest test);\n\n    void inject(MVPTest MVPTest);\n\n    void inject(MVPCITest mvpciTest);\n\n}\n"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockLocalModule.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.mockmodules;\n\nimport android.app.Application;\n\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.LocalModule;\nimport io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockLocalDataCache;\n\npublic class MockLocalModule extends LocalModule{\n\n    @Override\n    protected LocalDataCache providesDataCache(Application application) {\n        return new MockLocalDataCache(application);\n    }\n}\n"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockNetworkModule.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.mockmodules;\n\nimport javax.inject.Named;\n\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.NetworkModule;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockOkHTTP;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockRetrofit;\nimport io.patrykpoborca.cleanarchitecture.network.base.OKHttp;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport io.patrykpoborca.cleanarchitecture.util.Constants;\nimport rx.Scheduler;\n\npublic class MockNetworkModule extends NetworkModule {\n\n    @Override\n    protected OKHttp providesOkHTTP() {\n        return new MockOkHTTP();\n    }\n\n    @Override\n    protected Retrofit providesRetrofit(OKHttp okHttp, @Named(Constants.MAIN_THREAD)Scheduler mainThread) {\n        return new MockRetrofit(okHttp, mainThread);\n    }\n}\n"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockTestModule.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.mockmodules;\n\nimport javax.inject.Named;\n\nimport dagger.Module;\nimport dagger.Provides;\nimport io.patrykpoborca.cleanarchitecture.dagger.scopes.ActivityScope;\nimport io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockMVPCIPview;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockTweeterActivityPview;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockTweeterApi;\nimport io.patrykpoborca.cleanarchitecture.network.TweeterApi;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.TweeterMVPPresenterImpl;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;\nimport io.patrykpoborca.cleanarchitecture.util.Constants;\nimport rx.Scheduler;\n\n@Module\npublic class MockTestModule {\n\n    @Provides\n    @ActivityScope\n    TweeterMVPPresenter providesMainPresenter(TweeterApi api, Retrofit retrofit) {\n        return new TweeterMVPPresenterImpl(api, retrofit);\n    }\n\n    @ActivityScope\n    @Provides\n    public MockTweeterActivityPview providesMockMainPview(TweeterMVPPresenter presenter) {\n        MockTweeterActivityPview mockTweeterActivityPview = new MockTweeterActivityPview();\n        presenter.registerView(mockTweeterActivityPview);\n        return mockTweeterActivityPview;\n    }\n\n    @ActivityScope\n    @Provides\n    public TweeterApi providesMockTweeter(Retrofit retrofit, LocalDataCache dataCache, @Named(Constants.MAIN_THREAD) Scheduler mainThread) {\n        return new MockTweeterApi(retrofit, dataCache, mainThread);\n    }\n\n    @ActivityScope\n    @Provides\n    public MockMVPCIPview providesMockMVPCCIView(){\n        return new MockMVPCIPview();\n    }\n}\n"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockLocalDataCache.java",
    "content": "package io.patrykpoborca.cleanarchitecture.mockimpl;\n\nimport android.content.Context;\n\nimport java.util.List;\n\nimport io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;\nimport rx.Observable;\n\npublic class MockLocalDataCache extends LocalDataCache {\n\n    public MockLocalDataCache(Context context) {\n        super(context);\n    }\n\n    @Override\n    public void saveTweet(String tweet) {\n        sPastTweets.add(tweet);\n    }\n\n    @Override\n    public Observable<List<String>> fetchRecentTweets() {\n        return Observable.just(sPastTweets)\n                .map(arrayList -> {\n                    List<String> list = arrayList;\n                    return list;\n                });\n    }\n}\n"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockMVPCIPview.java",
    "content": "package io.patrykpoborca.cleanarchitecture.mockimpl;\n\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.interfaces.TweeterActivityMVPCIPview;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;\n\npublic class MockMVPCIPview implements TweeterActivityMVPCIPview {\n\n    public UserProfile loggedInProfile;\n    public boolean loggedOutCalled = false;\n    public boolean toggleProgresbarCalled = false;\n\n    @Override\n    public void loggedIn(UserProfile profile) {\n        this.loggedInProfile = profile;\n    }\n\n    @Override\n    public void loggedOut() {\n        loggedOutCalled = true;\n    }\n\n    @Override\n    public void toggleProgressBar(boolean loading) {\n        toggleProgresbarCalled = true;\n    }\n\n    @Override\n    public void displayToast(String toast) {\n\n    }\n}\n"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockOkHTTP.java",
    "content": "package io.patrykpoborca.cleanarchitecture.mockimpl;\n\nimport io.patrykpoborca.cleanarchitecture.network.base.OKHttp;\n\npublic class MockOkHTTP extends OKHttp {\n    @Override\n    public String rawResponse() {\n        return \"Mocked raw response: \";\n    }\n}\n"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockRetrofit.java",
    "content": "package io.patrykpoborca.cleanarchitecture.mockimpl;\n\nimport io.patrykpoborca.cleanarchitecture.network.base.OKHttp;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport rx.Observable;\nimport rx.Scheduler;\n\npublic class MockRetrofit extends Retrofit {\n    private static final String MOCK_PARSE = \"SomeMockResponse\";\n    public static final String MOCKED_STRING = \"MOCKED PAGE:\";\n\n    public MockRetrofit(OKHttp okHttp, Scheduler mainScheduler) {\n        super(okHttp, mainScheduler);\n    }\n\n    @Override\n    public Observable<String> completeRequest() {\n        return Observable.just(okHttp.rawResponse() + MOCK_PARSE)\n                .observeOn(mainScheduler);\n    }\n\n    @Override\n    public Observable<String> fetchSomePage(String url) {\n        return Observable.just(\"<h2>\" + MOCKED_STRING + \" \" + url + \" </h2>\")\n                .observeOn(mainScheduler);\n    }\n}\n"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockTweeterActivityPview.java",
    "content": "package io.patrykpoborca.cleanarchitecture.mockimpl;\n\nimport java.util.List;\n\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPView;\n\npublic class MockTweeterActivityPview implements TweeterMVPPView {\n\n    public String fetchedTweet = null;\n    public List<String> previousTweets = null;\n    public boolean setUserButtonTextCalled = false;\n    public boolean toggleProgressBarCalled = false;\n    public boolean toggleLoginContainerCalled = false;\n    public String displayWebpage = null;\n    public boolean displayToastCalled = false;\n\n    @Override\n    public void displayFetchedTweet(String tweet) {\n        fetchedTweet = tweet;\n    }\n\n    @Override\n    public void displayPreviousTweets(List<String> list) {\n        previousTweets = list;\n    }\n\n    @Override\n    public void setUserButtonText(String text) {\n        setUserButtonTextCalled = true;\n    }\n\n    @Override\n    public void toggleLoginContainer(boolean b) {\n        toggleLoginContainerCalled = true;\n    }\n\n    @Override\n    public void displayWebpage(String html) {\n        displayWebpage = html;\n    }\n\n    @Override\n    public void toggleProgressBar(boolean loading) {\n        toggleProgressBarCalled = true;\n    }\n\n    @Override\n    public void displayToast(String toast) {\n        displayToastCalled = true;\n    }\n}\n"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockTweeterApi.java",
    "content": "package io.patrykpoborca.cleanarchitecture.mockimpl;\n\nimport android.util.Log;\n\nimport io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;\nimport io.patrykpoborca.cleanarchitecture.network.TweeterApi;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;\nimport rx.Observable;\nimport rx.Scheduler;\n\npublic class MockTweeterApi extends TweeterApi{\n    public MockTweeterApi(Retrofit retrofit, LocalDataCache dataCache, Scheduler mainScheduler) {\n        super(retrofit, dataCache, mainScheduler);\n    }\n\n    @Override\n    public Observable<UserProfile> login(String username, String password) {\n        return Observable.just(new UserProfile(username, password));\n    }\n\n    @Override\n    public Observable<Object> logout() {\n        return Observable.just(null);\n    }\n}\n"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/MVPCITest.java",
    "content": "package io.patrykpoborca.cleanarchitecture.tests;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.JUnit4;\n\nimport javax.inject.Inject;\n\nimport io.patrykpoborca.cleanarchitecture.TestHelper;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockLocalDataCache;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockMVPCIPview;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockOkHTTP;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockRetrofit;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.TweeterMVPCIPresenter;\n\n@RunWith(JUnit4.class)\npublic class MVPCITest {\n\n    private static final String SOME_URL = \"SOME_URL\";\n    private static final String USER_PASSWORD = \"USER_PASSWORD\";\n    private static final String USER_NAME = \"USER_NAME\";\n    private String tweetedTweet;\n\n    @Inject\n    TweeterMVPCIPresenter presenter;\n\n    @Inject\n    MockMVPCIPview pView;\n    @Before\n    public void setUp(){\n        TestHelper.getTestClassInjector()\n                .inject(this);\n        presenter.registerPresenter(pView);\n\n        junit.framework.Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);\n        junit.framework.Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);\n        junit.framework.Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);\n    }\n\n    @Test\n    public void testWebPage(){\n        presenter.loadWebPage(SOME_URL)\n                .toBlocking()\n                .forEach(s -> {\n                    junit.framework.Assert.assertTrue(s.contains(MockRetrofit.MOCKED_STRING)\n                            && s.contains(SOME_URL));\n                });\n    }\n\n    @Test\n    public void testLogin(){\n        Assert.assertTrue(pView.loggedInProfile == null);\n        presenter.toggleLogin(USER_NAME, USER_PASSWORD);\n        TestHelper.waitFor(() -> pView.loggedInProfile != null);\n\n        Assert.assertTrue(pView.loggedInProfile.getUserName().equals(USER_NAME));\n        presenter.toggleLogin(USER_NAME, USER_PASSWORD);\n        TestHelper.waitFor(() -> pView.loggedOutCalled);\n        Assert.assertTrue(pView.loggedOutCalled);\n    }\n\n    @Test\n    public void testTweets() {\n        //Sanity test first to see if underlying logic of tweeter api has changed\n        presenter.fetchPreviousTweets()\n                .toBlocking()\n                .forEach(list -> {\n                    Assert.assertNotNull(list);\n                });\n\n    }\n\n    @Test\n    public void testTweetList(){\n        presenter.fetchCurrentTweet()\n                .toBlocking()\n                .forEach(tweet -> {\n                    tweetedTweet = tweet;\n                });\n\n        presenter.fetchPreviousTweets()\n                .toBlocking()\n                .forEach(list -> {\n                    boolean exists = false;\n\n                    for (int i = 0; i < list.size(); i++) {\n                        if (tweetedTweet.contains(list.get(i))) {\n                            exists = true;\n                            break;\n                        }\n                    }\n                    Assert.assertTrue(exists);\n                });\n    }\n\n}\n"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/MVPTest.java",
    "content": "package io.patrykpoborca.cleanarchitecture.tests;\n\nimport android.support.test.runner.AndroidJUnit4;\n\nimport junit.framework.Assert;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport javax.inject.Inject;\n\nimport io.patrykpoborca.cleanarchitecture.TestHelper;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockLocalDataCache;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockTweeterActivityPview;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockOkHTTP;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockRetrofit;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;\n\n@RunWith(AndroidJUnit4.class)\npublic class MVPTest {\n\n    private static final String SOME_URL = \"SOME_URL\";\n    private static final String USER_PASSWORD = \"USER_PASSWORD\";\n    private static final String USER_NAME = \"USER_NAME\";\n\n    @Inject\n    MockTweeterActivityPview pView;\n\n    @Inject\n    TweeterMVPPresenter presenter;\n\n    @Before\n    public void setUp(){\n        TestHelper.getTestClassInjector()\n                .inject(this);\n        Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);\n        Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);\n        Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);\n    }\n\n\n    @Test\n    public void testLogin(){\n        presenter.toggleLogin(USER_NAME, USER_PASSWORD);\n        TestHelper.waitFor(() -> pView.toggleLoginContainerCalled);\n        Assert.assertTrue(pView.toggleLoginContainerCalled);\n\n        pView.toggleLoginContainerCalled = false;\n\n        presenter.toggleLogin(USER_NAME, USER_PASSWORD);\n        TestHelper.waitFor(() -> pView.toggleLoginContainerCalled);\n        Assert.assertTrue(pView.toggleLoginContainerCalled);\n    }\n\n    @Test\n    public void testFetchTweets(){\n        presenter.fetchCurrentTweet();\n        TestHelper.waitFor(() -> pView.fetchedTweet != null);\n        String tweet = pView.fetchedTweet;\n\n        presenter.fetchPreviousTweets();\n        TestHelper.waitFor(() -> pView.previousTweets != null);\n        boolean found = false;\n        for(int i=0; i < pView.previousTweets.size(); i++){\n            found = tweet.contains(pView.previousTweets.get(i));\n            if(found){\n                break;\n            }\n        }\n        Assert.assertTrue(found);\n    }\n\n    @Test\n    public void testWebPage() {\n        presenter.loadWebPage(SOME_URL);\n\n        TestHelper.waitFor(() -> pView.displayWebpage != null);\n        String webPage = pView.displayWebpage;\n        Assert.assertTrue(webPage.contains(SOME_URL));\n    }\n\n}\n"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/MVVMTest.java",
    "content": "package io.patrykpoborca.cleanarchitecture.tests;\n\nimport android.support.test.runner.AndroidJUnit4;\n\nimport junit.framework.Assert;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport javax.inject.Inject;\n\nimport io.patrykpoborca.cleanarchitecture.TestHelper;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockLocalDataCache;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockOkHTTP;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockRetrofit;\nimport io.patrykpoborca.cleanarchitecture.ui.MVVM.MainViewModel;\n\n@RunWith(AndroidJUnit4.class)\npublic class MVVMTest {\n\n    private static final String SOME_URL = \"SOME_URL\";\n    private static final String USER_PASSWORD = \"USER_PASSWORD\";\n    private static final String USER_NAME = \"USER_NAME\";\n    private String tweetedTweet;\n\n    @Inject\n    MainViewModel viewModel;\n\n    @Before\n    public void setUp() {\n        TestHelper.getTestClassInjector()\n                .inject(this);\n\n        Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);\n        Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);\n        Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);\n    }\n\n\n    @Test\n    public void testWebPage() {\n        viewModel.loadWebPage(SOME_URL)\n                .toBlocking()\n                .forEach(s -> {\n                    Assert.assertTrue(s.contains(MockRetrofit.MOCKED_STRING)\n                            && s.contains(SOME_URL));\n                });\n    }\n\n    @Test\n    public void testLogin() {\n        Assert.assertFalse(viewModel.isLoggedIn());\n        viewModel.toggleLogin(USER_NAME, USER_PASSWORD)\n                .toBlocking()\n                .forEach(\n                        user -> {\n                            Assert.assertNotNull(user);\n                            Assert.assertEquals(user.getUserName(), USER_NAME);\n                        }\n                );\n        Assert.assertTrue(viewModel.isLoggedIn());\n    }\n\n    @Test\n    public void testTweets() {\n        //Sanity test first to see if underlying logic of tweeter api has changed\n        viewModel.fetchPreviousTweets()\n                .toBlocking()\n                .forEach(list -> {\n                    Assert.assertNotNull(list);\n                });\n\n    }\n\n    @Test\n    public void testTweetList() {\n\n        viewModel.fetchCurrentTweet()\n                .toBlocking()\n                .forEach(tweet -> {\n                    tweetedTweet = tweet;\n                });\n\n        viewModel.fetchPreviousTweets()\n                .toBlocking()\n                .forEach(list -> {\n                    boolean exists = false;\n\n                    for (int i = 0; i < list.size(); i++) {\n                        if (tweetedTweet.contains(list.get(i))) {\n                            exists = true;\n                            break;\n                        }\n                    }\n                    Assert.assertTrue(exists);\n                });\n    }\n\n}\n"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/PlainTweeterTest.java",
    "content": "package io.patrykpoborca.cleanarchitecture.tests;\n\nimport android.support.test.espresso.matcher.ViewMatchers;\nimport android.support.test.rule.ActivityTestRule;\nimport android.support.test.runner.AndroidJUnit4;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport junit.framework.Assert;\n\nimport org.hamcrest.Description;\nimport org.hamcrest.TypeSafeMatcher;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport io.patrykpoborca.cleanarchitecture.R;\nimport io.patrykpoborca.cleanarchitecture.TestHelper;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.DaggerActivityInjectorComponent;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockLocalDataCache;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockOkHTTP;\nimport io.patrykpoborca.cleanarchitecture.mockimpl.MockRetrofit;\n\nimport static android.support.test.espresso.action.ViewActions.scrollTo;\nimport static android.support.test.espresso.action.ViewActions.typeText;\nimport static android.support.test.espresso.assertion.ViewAssertions.matches;\nimport static android.support.test.espresso.Espresso.onView;\nimport static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;\nimport static android.support.test.espresso.matcher.ViewMatchers.withId;\nimport static android.support.test.espresso.action.ViewActions.click;\nimport static android.support.test.espresso.matcher.ViewMatchers.withText;\n\n@RunWith(AndroidJUnit4.class)\npublic class PlainTweeterTest {\n\n    @Rule\n    public ActivityTestRule<io.patrykpoborca.cleanarchitecture.ui.PlainTweeterActivity> plainTweeterActivity = new ActivityTestRule<>(io.patrykpoborca.cleanarchitecture.ui.PlainTweeterActivity.class,\n            false,\n            true);\n\n    private static final String SOME_URL = \"SOME_URL\";\n    private static final String USER_PASSWORD = \"USER_PASSWORD\";\n    private static final String USER_NAME = \"USER_NAME\";\n    private String fetchedTweet;\n\n    @Before\n    public void setUp() {\n        DaggerActivityInjectorComponent\n                .builder()\n                .baseComponent(TestHelper.getBaseComponent())\n                .build()\n                .inject(plainTweeterActivity.getActivity());\n\n        Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);\n        Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);\n        Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);\n\n    }\n\n    @Test\n    public void testWebpage(){\n        onView(withId(R.id.some_url))\n                .perform(typeText(SOME_URL));\n\n        onView(withId(R.id.some_url))\n                .check(matches(new TypeSafeMatcher<View>() {\n                    @Override\n                    protected boolean matchesSafely(View item) {\n                        TextView text = ((TextView) item);\n                        return text.getText().toString().contains(SOME_URL);\n                    }\n\n                    @Override\n                    public void describeTo(Description description) {\n\n                    }\n                }));\n\n\n        onView(withId(R.id.request_website_button))\n                .perform(click());\n\n        onView(withId(R.id.webpage_text))\n                .check(matches(new TypeSafeMatcher<View>(){\n                    @Override\n                    protected boolean matchesSafely(View item) {\n                        TextView text = ((TextView)item);\n                        return text.getText().toString().contains(SOME_URL);\n                    }\n\n                    @Override\n                    public void describeTo(Description description) {\n\n                    }\n                }));\n    }\n\n    @Test\n    public void testLogin(){\n        onView(withId(R.id.user_name))\n                .perform(typeText(USER_NAME));\n\n        onView(withId(R.id.user_password))\n                .perform(scrollTo())\n                .perform(typeText(USER_PASSWORD));\n\n        //login\n        onView(withId(R.id.user_login_button))\n                .perform(scrollTo())\n                .perform(click());\n\n        onView(withId(R.id.container))\n                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));\n\n        //logout\n        onView(withId(R.id.user_login_button))\n                .perform(click());\n\n        onView(withId(R.id.container))\n                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));\n    }\n\n    @Test\n    public void testTweets(){\n        onView(withId(R.id.current_tweet)).check(matches(withText(R.string.hello_world)));\n        onView(withId(R.id.fetch_tweet_button))\n                .perform(scrollTo())\n                .perform(click());\n\n        onView(withId(R.id.current_tweet)).check(matches(new TypeSafeMatcher<View>() {\n            @Override\n            protected boolean matchesSafely(View item) {\n                boolean result = item instanceof TextView\n                        && !((TextView) item).getText().toString().contains(plainTweeterActivity.getActivity().getResources().getString(R.string.hello_world));\n                fetchedTweet = ((TextView) item).getText().toString();\n\n                return result;\n            }\n\n            @Override\n            public void describeTo(Description description) {\n\n            }\n        }));\n\n        onView(withId(R.id.fetch_last_two_tweets)).perform(click());\n\n        onView(withId(R.id.past_tweets_container)).check(matches(new TypeSafeMatcher<View>() {\n            @Override\n            protected boolean matchesSafely(View item) {\n                ViewGroup parent = ((ViewGroup) item);\n\n                for (int i = 0; i < parent.getChildCount(); i++) {\n                    TextView textView = (TextView) parent.getChildAt(i);\n                    if (fetchedTweet.contains(textView.getText().toString())) {\n                        return true;\n                    }\n                }\n\n                return false;\n            }\n\n            @Override\n            public void describeTo(Description description) {\n\n            }\n        }));\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"io.patrykpoborca.cleanarchitecture\" >\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:theme=\"@style/AppTheme\"\n        android:name=\".CleanArchitectureApplication\">\n        <activity\n            android:name=\".ui.PlainTweeterActivity\"\n            android:label=\"@string/app_name\" >\n        </activity>\n\n        <activity\n            android:name=\".ui.MVP.TweeterActivityMVP\"\n            android:label=\"@string/app_name\" >\n        </activity>\n\n        <activity android:name=\".ui.RouterActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n        <activity android:name=\".ui.MVPCI.TweeterActivityMVPCI\"/>\n\n        <activity android:name=\".ui.MVVM.TweeterActivityMVVM\"/>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/CleanArchitectureApplication.java",
    "content": "package io.patrykpoborca.cleanarchitecture;\n\nimport android.app.Application;\n\nimport io.patrykpoborca.cleanarchitecture.dagger.components.ApplicationComponent;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.BaseComponent;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.DaggerApplicationComponent;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.DaggerBaseComponent;\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.ApplicationModule;\n\n\npublic class CleanArchitectureApplication extends Application{\n\n    private static BaseComponent sBaseComponent;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        ApplicationComponent applicationComponent = DaggerApplicationComponent\n                                        .builder()\n                                        .applicationModule(new ApplicationModule(this))\n                                        .build();\n        sBaseComponent = DaggerBaseComponent.builder()\n                .applicationComponent(applicationComponent)\n                .build();\n    }\n    public static BaseComponent getBaseComponent(){\n        return sBaseComponent;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/components/ActivityInjectorComponent.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.components;\n\nimport dagger.Component;\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.PresenterModule;\nimport io.patrykpoborca.cleanarchitecture.dagger.scopes.ActivityScope;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.TweeterActivityMVP;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.TweeterActivityMVPCI;\nimport io.patrykpoborca.cleanarchitecture.ui.MVVM.TweeterActivityMVVM;\nimport io.patrykpoborca.cleanarchitecture.ui.PlainTweeterActivity;\n\n/**\n * Created by Patryk on 7/28/2015.\n */\n@ActivityScope\n@Component(dependencies = {BaseComponent.class}, modules = PresenterModule.class)\npublic interface ActivityInjectorComponent {\n\n    void inject(PlainTweeterActivity activity);\n\n    void inject(TweeterActivityMVP activityMVP);\n\n    void inject(TweeterActivityMVVM activityMVVM);\n\n    void inject(TweeterActivityMVPCI activityMVPCI);\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/components/ApplicationComponent.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.components;\n\nimport android.app.Application;\n\nimport javax.inject.Singleton;\n\nimport dagger.Component;\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.ApplicationModule;\nimport io.patrykpoborca.cleanarchitecture.dagger.scopes.ApplicationScope;\n\n\n@Singleton\n@Component(modules = ApplicationModule.class)\npublic interface ApplicationComponent {\n    Application getApplication();\n\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/components/BaseComponent.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.components;\n\nimport javax.inject.Named;\nimport javax.inject.Singleton;\n\nimport dagger.Component;\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.LocalModule;\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.NetworkModule;\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.ThreadingModule;\nimport io.patrykpoborca.cleanarchitecture.dagger.scopes.ApplicationScope;\nimport io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;\nimport io.patrykpoborca.cleanarchitecture.network.base.OKHttp;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport io.patrykpoborca.cleanarchitecture.util.Constants;\nimport rx.Scheduler;\n\n\n\n// AppModule [Application] |AppComponent| <- BaseComponent needs that stuff..\n@ApplicationScope\n@Component(modules = {LocalModule.class, NetworkModule.class, ThreadingModule.class}, dependencies = ApplicationComponent.class)\npublic interface BaseComponent {\n\n    OKHttp getOkHTTP();\n\n    Retrofit getRetrofit();\n\n    LocalDataCache getLocalDataCache();\n\n    @Named(Constants.MAIN_THREAD)\n    Scheduler getMainScheduler();\n}"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/interactors/NetworkInteractor.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.interactors;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\n\nimport io.patrykpoborca.cleanarchitecture.dagger.interactors.base.BaseInteractor;\nimport io.patrykpoborca.cleanarchitecture.network.TweeterApi;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;\nimport rx.Observable;\n\n/**\n * Created by Patryk on 7/29/2015.\n */\npublic class NetworkInteractor extends BaseInteractor {\n\n\n    private final Retrofit retrofit;\n    private final TweeterApi tweeterAPI;\n\n    @Inject\n    public NetworkInteractor(Retrofit retrofit, TweeterApi api){\n        this.retrofit = retrofit;\n        this.tweeterAPI = api;\n    }\n\n    public Observable<UserProfile> attemptLogin(String username, String password) {\n        return tweeterAPI.login(username, password);\n    }\n\n    public Observable<Object> logout(){\n        return tweeterAPI.logout();\n    }\n\n    public Observable<String> fetchTweet() {\n        return tweeterAPI.getTweet();\n    }\n\n    public Observable<List<String>> fetchTweets(int count) {\n        return tweeterAPI.fetchXrecents(count);\n    }\n\n    public Observable<String> loadWebpage(String url){\n        return retrofit.fetchSomePage(url);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/interactors/base/BaseInteractor.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.interactors.base;\n\npublic class BaseInteractor {\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/ApplicationModule.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.modules;\n\nimport android.app.Application;\nimport android.content.Context;\n\nimport javax.inject.Singleton;\n\nimport dagger.Module;\nimport dagger.Provides;\nimport io.patrykpoborca.cleanarchitecture.dagger.scopes.ApplicationScope;\n\n\n@Module\npublic class ApplicationModule {\n\n    private static Application sApplication;\n\n    public ApplicationModule(Application application) {\n        sApplication = application;\n    }\n\n    @Singleton\n    @Provides\n    Application providesApplication(){\n        return sApplication;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/InteractorModule.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.modules;\n\nimport dagger.Module;\nimport dagger.Provides;\nimport io.patrykpoborca.cleanarchitecture.dagger.interactors.NetworkInteractor;\nimport io.patrykpoborca.cleanarchitecture.network.TweeterApi;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\n\n/**\n * Created by Patryk on 7/31/2015.\n */\n@Module\npublic class InteractorModule {\n\n    @Provides\n    NetworkInteractor providesNetworkInteractor(Retrofit retrofit, TweeterApi api){\n        return new NetworkInteractor(retrofit, api);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/LocalModule.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.modules;\n\nimport android.app.Application;\nimport android.content.Context;\n\nimport javax.inject.Singleton;\n\nimport dagger.Module;\nimport dagger.Provides;\nimport io.patrykpoborca.cleanarchitecture.dagger.scopes.ApplicationScope;\nimport io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;\n\n\n@Module\npublic class LocalModule {\n\n    @ApplicationScope\n    @Provides\n    protected LocalDataCache providesDataCache(Application application){\n        return new LocalDataCache(application);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/NetworkModule.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.modules;\n\nimport javax.inject.Named;\nimport javax.inject.Singleton;\n\nimport dagger.Module;\nimport dagger.Provides;\nimport io.patrykpoborca.cleanarchitecture.dagger.scopes.ApplicationScope;\nimport io.patrykpoborca.cleanarchitecture.network.base.OKHttp;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport io.patrykpoborca.cleanarchitecture.util.Constants;\nimport rx.Scheduler;\n\n\n@Module\npublic class NetworkModule {\n\n    @ApplicationScope\n    @Provides\n    protected OKHttp providesOkHTTP(){\n        return new OKHttp();\n    }\n\n    @ApplicationScope\n    @Provides\n    protected Retrofit providesRetrofit(OKHttp okHttp, @Named(Constants.MAIN_THREAD) Scheduler mainThread) {\n        return new Retrofit(okHttp, mainThread);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/PresenterModule.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.modules;\n\nimport dagger.Module;\nimport dagger.Provides;\nimport io.patrykpoborca.cleanarchitecture.dagger.scopes.ActivityScope;\nimport io.patrykpoborca.cleanarchitecture.network.TweeterApi;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.TweeterMVPPresenterImpl;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;\n\n@Module\npublic class PresenterModule {\n\n    @Provides\n    @ActivityScope\n    TweeterMVPPresenter providesMainPresenter(TweeterApi api, Retrofit retrofit){\n        return new TweeterMVPPresenterImpl(api, retrofit);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/ThreadingModule.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.modules;\n\nimport javax.inject.Named;\n\nimport dagger.Module;\nimport dagger.Provides;\nimport io.patrykpoborca.cleanarchitecture.util.Constants;\nimport rx.Scheduler;\nimport rx.android.schedulers.AndroidSchedulers;\n\n@Module\npublic class ThreadingModule {\n    @Named(Constants.MAIN_THREAD)\n    @Provides\n    public Scheduler providesMainThread(){\n        return AndroidSchedulers.mainThread();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/scopes/ActivityScope.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.scopes;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport javax.inject.Scope;\n\n@Retention(RetentionPolicy.RUNTIME)\n@Scope\npublic @interface ActivityScope {\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/scopes/ApplicationScope.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.scopes;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport javax.inject.Scope;\n\n@Retention(RetentionPolicy.RUNTIME)\n@Scope\npublic @interface ApplicationScope {\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/scopes/ExposedAPIScope.java",
    "content": "package io.patrykpoborca.cleanarchitecture.dagger.scopes;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport javax.inject.Scope;\n\n@Scope\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface ExposedAPIScope {\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/localdata/LocalDataCache.java",
    "content": "package io.patrykpoborca.cleanarchitecture.localdata;\n\nimport android.content.Context;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport rx.Observable;\n\n\npublic class LocalDataCache {\n\n    //pretend this is some read/write to disk :)\n    protected static ArrayList<String> sPastTweets;\n    private Context context;\n\n    public LocalDataCache(Context context) {\n        this.context = context;\n        sPastTweets = new ArrayList<>();\n    }\n\n    public void saveTweet(String tweet) {\n        sPastTweets.add(tweet);\n    }\n\n    public Observable<List<String>> fetchRecentTweets() {\n        return Observable.just(sPastTweets)\n                .map(arrayList -> {\n                    List<String> list = arrayList;\n                    return list;\n                })\n                .delay(2, TimeUnit.SECONDS);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/network/TweeterApi.java",
    "content": "package io.patrykpoborca.cleanarchitecture.network;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport javax.inject.Inject;\nimport javax.inject.Named;\n\nimport io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;\nimport io.patrykpoborca.cleanarchitecture.util.Constants;\nimport rx.Observable;\nimport rx.Scheduler;\n\n\npublic class TweeterApi {\n\n    protected final Scheduler mainScheduler;\n    Retrofit retrofit;\n    LocalDataCache localDataCache;\n    private UserProfile userName;\n\n    @Inject\n    public TweeterApi(Retrofit retro, LocalDataCache cache, @Named(Constants.MAIN_THREAD) Scheduler mainScheduler) {\n        this.localDataCache = cache;\n        this.retrofit = retro;\n        this.mainScheduler = mainScheduler;\n    }\n\n    public Observable<String> getTweet(){\n        return retrofit.completeRequest()\n                .map(tweet -> {\n                    localDataCache.saveTweet(tweet);\n\n                    if (isLoggedIn()) {\n                        tweet = userName.getUserName() + \" -> \" + tweet;\n                    }\n                    else {\n                        tweet = \"Some user -> \" + tweet;\n                    }\n\n                    return tweet;\n                })\n                .observeOn(mainScheduler);\n    }\n\n    public Observable<List<String>> fetchXrecents(int count){\n\n        return localDataCache.fetchRecentTweets()\n                .map(list ->{\n                    List<String> tweets = new ArrayList<>(count);\n                    int size = list.size() <= count ? list.size() : count;\n                    for(int i=list.size() -1; i >= 0 && size > tweets.size(); i--){\n                        tweets.add(list.get(i));\n                    }\n                    return tweets;\n                })\n                .observeOn(mainScheduler);\n    }\n\n    public Observable<UserProfile> login(String username, String password) {\n\n        Observable<UserProfile> observable = Observable.just(new UserProfile(username, password))\n                .delay(2, TimeUnit.SECONDS)\n                .observeOn(mainScheduler);\n        \n        observable.subscribe(user -> this.userName = user);\n        return observable;\n    }\n\n    public Observable<Object> logout(){\n        userName = null;\n        return Observable.just(null)\n                .delay(2, TimeUnit.SECONDS)\n                .observeOn(mainScheduler);\n    }\n\n    public boolean isLoggedIn(){\n        return this.userName != null;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/network/base/OKHttp.java",
    "content": "package io.patrykpoborca.cleanarchitecture.network.base;\n\nimport java.util.UUID;\n\n\npublic class OKHttp {\n\n    public String rawResponse(){\n        return UUID.randomUUID().toString();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/network/base/Retrofit.java",
    "content": "package io.patrykpoborca.cleanarchitecture.network.base;\n\nimport java.util.concurrent.TimeUnit;\n\nimport rx.Observable;\nimport rx.Scheduler;\nimport rx.android.schedulers.AndroidSchedulers;\n\npublic class Retrofit {\n\n    protected OKHttp okHttp;\n    protected final Scheduler mainScheduler;\n    public Retrofit(OKHttp okHttp, Scheduler mainScheduler) {\n        this.okHttp = okHttp;\n        this.mainScheduler = mainScheduler;\n    }\n\n    public Observable<String> completeRequest(){\n        return Observable.just(okHttp.rawResponse() + \" Some Parsing Done\")\n                .delay(2, TimeUnit.SECONDS);\n    }\n\n    public Observable<String> fetchSomePage(String url){\n        return Observable.just(\"<h2>\" + \"Fake response from fake retrofit: \" + url + \" </h2>\")\n                .delay(2, TimeUnit.SECONDS)\n                .observeOn(mainScheduler);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/BaseCleanArchitectureActivity.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui;\n\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport rx.Subscription;\n\npublic class BaseCleanArchitectureActivity extends AppCompatActivity{\n\n    private List<Subscription> subscriptions;\n\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        if(subscriptions == null){\n            subscriptions = new ArrayList<>();\n        }\n    }\n\n    protected void registerSubscription(Subscription subscription){\n        subscriptions.add(subscription);\n    }\n\n    @Override\n    protected void onStop() {\n        super.onStop();\n        unsubscribeSubscriptions();\n    }\n\n    protected void unsubscribeSubscriptions(){\n        for(int i= 0; i < subscriptions.size(); i++){\n            subscriptions.get(i).unsubscribe();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/TweeterActivityMVP.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVP;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.AlertDialog;\nimport android.text.Html;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport io.patrykpoborca.cleanarchitecture.CleanArchitectureApplication;\nimport io.patrykpoborca.cleanarchitecture.R;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.DaggerActivityInjectorComponent;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.base.BasePresenterActivity;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPView;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;\nimport io.patrykpoborca.cleanarchitecture.util.Utility;\n\n\npublic class TweeterActivityMVP extends BasePresenterActivity<TweeterMVPPresenter> implements TweeterMVPPView {\n\n    @Inject\n    TweeterMVPPresenter presenter;\n\n    @Bind(R.id.fetch_tweet_button) Button fetchTweetButton;\n    @Bind(R.id.fetch_last_two_tweets) Button fetchLastTwoButton;\n    @Bind(R.id.current_tweet) TextView currentTweetTextView;\n    @Bind(R.id.past_tweets_container) LinearLayout pastTweetContainer;\n    @Bind(R.id.user_login_button) Button loginButton;\n    @Bind(R.id.user_name) TextView userNameTextView;\n    @Bind(R.id.user_password) TextView userPasswordTextView;\n    @Bind(R.id.container) ViewGroup container;\n    @Bind(R.id.some_url) EditText urlText;\n    @Bind(R.id.webpage_text) TextView websiteText;\n    @Bind(R.id.request_website_button) Button websiteFetchbutton;\n    @Bind(R.id.help_history) View helpHistory;\n    @Bind(R.id.help_login) View helpLogin;\n    @Bind(R.id.help_url) View helpUrl;\n\n    private View.OnClickListener onClickListener = new View.OnClickListener() {\n        @Override\n        public void onClick(View view) {\n            if(view == fetchLastTwoButton){\n                getPresenter().fetchPreviousTweets();\n            }\n            else if(view == fetchTweetButton){\n                getPresenter().fetchCurrentTweet();\n            }\n            else if(view == loginButton){\n                getPresenter().toggleLogin(userNameTextView.getText().toString(),\n                                    userPasswordTextView.getText().toString());\n            }\n            else if(view == websiteFetchbutton){\n                getPresenter().loadWebPage(urlText.getText().toString());\n            }\n\n        }\n    };\n\n    private final View.OnClickListener dialogClickListener = new View.OnClickListener() {\n        @Override\n        public void onClick(View view) {\n            if(view == helpHistory){\n                new AlertDialog.Builder(TweeterActivityMVP.this)\n                        .setMessage(R.string.history_text)\n                        .setPositiveButton(\"Ok\", null)\n                        .create()\n                        .show();\n            }\n            else if(view == helpUrl){\n                new AlertDialog.Builder(TweeterActivityMVP.this)\n                        .setMessage(R.string.url_text)\n                        .setPositiveButton(\"Ok\", null)\n                        .create()\n                        .show();\n            }\n            else if(view == helpLogin){\n                new AlertDialog.Builder(TweeterActivityMVP.this)\n                        .setMessage(R.string.login_text)\n                        .setPositiveButton(\"Ok\", null)\n                        .create()\n                        .show();\n            }\n        }\n    };\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n        ButterKnife.bind(this);\n\n        this.fetchLastTwoButton.setOnClickListener(onClickListener);\n        this.fetchTweetButton.setOnClickListener(onClickListener);\n        this.loginButton.setOnClickListener(onClickListener);\n        this.websiteFetchbutton.setOnClickListener(onClickListener);\n        this.helpHistory.setOnClickListener(dialogClickListener);\n        this.helpLogin.setOnClickListener(dialogClickListener);\n        this.helpUrl.setOnClickListener(dialogClickListener);\n        setTitle(\"MVP Activity IMPL\");\n    }\n\n    @Override\n    protected TweeterMVPPresenter getPresenter() {\n        if(presenter == null){\n\n            DaggerActivityInjectorComponent.builder()\n                    .baseComponent(CleanArchitectureApplication.getBaseComponent())\n                    .build()\n                    .inject(this);\n        }\n\n        return presenter;\n    }\n\n\n\n    @Override\n    public void displayFetchedTweet(String tweet) {\n        currentTweetTextView.setText(tweet);\n    }\n\n    @Override\n    public void displayPreviousTweets(List<String> tweets) {\n        pastTweetContainer.removeAllViews(); //clear container...\n        for(int i= 0;  i < tweets.size(); i++){\n            TextView text = new TextView(this);\n            text.setText(tweets.get(i));\n            pastTweetContainer.addView(text);\n        }\n    }\n\n    @Override\n    protected void registerViewToPresenter() {\n        getPresenter().registerView(this);\n    }\n\n    @Override\n    public void displayToast(String toast) {\n        Toast.makeText(this, toast, Toast.LENGTH_LONG).show();\n    }\n\n    @Override\n    public void toggleProgressBar(boolean loading) {\n        Utility.toggleProgressbar(this, loading);\n    }\n\n    @Override\n    public void setUserButtonText(String text) {\n        this.loginButton.setText(text);\n    }\n\n    @Override\n    public void toggleLoginContainer(boolean b) {\n        container.setVisibility(b ? View.VISIBLE : View.GONE);\n    }\n\n    @Override\n    public void displayWebpage(String html) {\n        websiteText.setText(Html.fromHtml(html));\n    }\n\n    public static Intent newInstance(Context context) {\n        return new Intent(context, TweeterActivityMVP.class);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/TweeterMVPPresenterImpl.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVP;\n\nimport io.patrykpoborca.cleanarchitecture.network.TweeterApi;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPView;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;\n\n/**\n * Created by Patryk on 7/28/2015.\n */\npublic class TweeterMVPPresenterImpl implements TweeterMVPPresenter {\n\n    private static final int TWEET_COUNT = 2;\n    private final TweeterApi tweeterApi;\n    private final Retrofit retrofit;\n    private TweeterMVPPView mainMVPView;\n    private int tweetsAdded = 0;\n\n\n    public TweeterMVPPresenterImpl(TweeterApi tweeterApi, Retrofit retrofit) {\n        this.tweeterApi = tweeterApi;\n        this.retrofit = retrofit;\n    }\n\n    @Override\n    public void registerView(TweeterMVPPView activity) {\n        this.mainMVPView = activity;\n    }\n\n    @Override\n    public void onAttach() {\n\n    }\n\n    @Override\n    public void onDetach() {\n\n    }\n\n    @Override\n    public void fetchCurrentTweet() {\n        mainMVPView.toggleProgressBar(true);\n        tweeterApi.getTweet().subscribe(s -> {\n            mainMVPView.toggleProgressBar(false);\n            tweetsAdded ++;\n            if(tweetsAdded > TWEET_COUNT){\n                mainMVPView.displayToast(\"Tweet size exceeded \" + TWEET_COUNT);\n            }\n            this.mainMVPView.displayFetchedTweet(s);\n        });\n    }\n\n    @Override\n    public void fetchPreviousTweets() {\n\n        mainMVPView.toggleProgressBar(true);\n        tweeterApi.fetchXrecents(TWEET_COUNT)\n                .subscribe(l -> {\n                    mainMVPView.displayPreviousTweets(l);\n                    mainMVPView.toggleProgressBar(false);\n                });\n    }\n\n    @Override\n    public void toggleLogin(String userName, String userPassword) {\n        mainMVPView.toggleProgressBar(true);\n        if(tweeterApi.isLoggedIn()){\n            tweeterApi.logout()\n                    .subscribe(s -> {\n                        mainMVPView.toggleProgressBar(false);\n                        mainMVPView.setUserButtonText(\"Login\");\n                        mainMVPView.displayToast(\"User logged out\");\n                        mainMVPView.toggleLoginContainer(true);\n                        //could implement more literal less reusable methods, such as loggedIn and loggedOut such as in the MVPCI example.\n                        //However I wanted to be extremely verbose in the MVP example.\n                    });\n        }\n        else {\n            this.tweeterApi.login(userName, userPassword)\n                    .subscribe(userProfile -> {\n                        mainMVPView.displayToast(userProfile.getFormattedCredentials() + \" Logged in\");\n                        mainMVPView.setUserButtonText(\"Log \" + userProfile.getUserName() + \" out\");\n                        mainMVPView.toggleProgressBar(false);\n                        mainMVPView.toggleLoginContainer(false);\n                    });\n        }\n    }\n\n    @Override\n    public void loadWebPage(String url) {\n        mainMVPView.toggleProgressBar(true);\n        retrofit.fetchSomePage(url)\n                .subscribe(s -> {\n                    mainMVPView.displayWebpage(s);\n                    mainMVPView.toggleProgressBar(false);\n                });\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/base/BasePresenterActivity.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVP.base;\n\nimport android.os.Bundle;\n\nimport io.patrykpoborca.cleanarchitecture.ui.BaseCleanArchitectureActivity;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces.PView;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces.Presenter;\n\n/**\n * Created by Patryk on 7/28/2015.\n */\npublic abstract class BasePresenterActivity<T extends Presenter> extends BaseCleanArchitectureActivity implements PView {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        getPresenter().registerView(this);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        getPresenter().onAttach();\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        getPresenter().onDetach();\n    }\n\n    protected abstract void registerViewToPresenter();\n    protected abstract T getPresenter();\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/base/Interfaces/PView.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces;\n\n/**\n * Created by Patryk on 7/28/2015.\n */\npublic interface PView {\n\n    public void toggleProgressBar(boolean loading);\n\n    public void displayToast(String toast);\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/base/Interfaces/Presenter.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces;\n\n/**\n * Created by Patryk on 7/28/2015.\n */\npublic interface Presenter<T extends PView> {\n\n    public void registerView(T activity);\n    public void onAttach();\n    public void onDetach();\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/interfaces/TweeterMVPPView.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces;\n\nimport java.util.List;\n\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces.PView;\n\n/**\n * Created by Patryk on 7/28/2015.\n */\npublic interface TweeterMVPPView extends PView {\n    public void displayFetchedTweet(String tweet);\n\n    public void displayPreviousTweets(List<String> list);\n\n    public void setUserButtonText(String text);\n\n    void toggleLoginContainer(boolean b);\n\n    void displayWebpage(String html);\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/interfaces/TweeterMVPPresenter.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces;\n\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces.Presenter;\n\n/**\n * Created by Patryk on 7/28/2015.\n */\n    public interface TweeterMVPPresenter extends Presenter<TweeterMVPPView> {\n\n    public void fetchCurrentTweet();\n\n    public void fetchPreviousTweets();\n\n    public void toggleLogin(String userName, String userPassword);\n\n    void loadWebPage(String url);\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/TweeterActivityMVPCI.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVPCI;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.AlertDialog;\nimport android.text.Html;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport io.patrykpoborca.cleanarchitecture.CleanArchitectureApplication;\nimport io.patrykpoborca.cleanarchitecture.R;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.DaggerActivityInjectorComponent;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.base.BasePresenterActivityMVPCI;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.interfaces.TweeterActivityMVPCIPview;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;\nimport io.patrykpoborca.cleanarchitecture.util.Utility;\n\n\n\n/**\n * Presenter as a Supervising controller is actually a bridge between observable models and the view, any complex operations are performed within the controller, basic databinding\n * circumvents a lot of unecessary boilerplate.\n *  Model <- Presenter -> View\n */\npublic class TweeterActivityMVPCI extends BasePresenterActivityMVPCI<TweeterMVPCIPresenter> implements TweeterActivityMVPCIPview {\n\n    @Bind(R.id.fetch_tweet_button) Button fetchTweetButton;\n    @Bind(R.id.fetch_last_two_tweets) Button fetchLastTwoButton;\n    @Bind(R.id.current_tweet) TextView currentTweetTextView;\n    @Bind(R.id.past_tweets_container) LinearLayout pastTweetContainer;\n    @Bind(R.id.user_login_button) Button loginButton;\n    @Bind(R.id.user_name) TextView userNameTextView;\n    @Bind(R.id.user_password) TextView userPasswordTextView;\n    @Bind(R.id.container) ViewGroup container;\n    @Bind(R.id.some_url) EditText urlText;\n    @Bind(R.id.webpage_text) TextView websiteText;\n    @Bind(R.id.request_website_button) Button websiteFetchbutton;\n    @Bind(R.id.help_history) View helpHistory;\n    @Bind(R.id.help_login) View helpLogin;\n    @Bind(R.id.help_url) View helpUrl;\n\n    @Inject\n    TweeterMVPCIPresenter presenter;\n\n    private final View.OnClickListener onClickListener = new View.OnClickListener() {\n        @Override\n        public void onClick(View view) {\n            if(view == fetchTweetButton){\n                registerSubscription(\n                        getPresenter().fetchCurrentTweet().subscribe(s -> currentTweetTextView.setText(s)));\n            }\n            else if(view == fetchLastTwoButton){\n                pastTweetContainer.removeAllViews(); //clear container...\n                registerSubscription(\n                        getPresenter().fetchPreviousTweets().subscribe(TweeterActivityMVPCI.this::displayTweets)\n                );\n            }\n            else if(view == loginButton){\n                getPresenter().toggleLogin(userNameTextView.getText().toString(), userPasswordTextView.getText().toString());\n            }\n            else if(view == websiteFetchbutton){\n                registerSubscription(getPresenter().loadWebPage(urlText.getText().toString())\n                        .subscribe(s -> websiteText.setText(Html.fromHtml(s))));\n            }\n        }\n    };\n\n    private final View.OnClickListener dialogClickListener = new View.OnClickListener() {\n        @Override\n        public void onClick(View view) {\n            if(view == helpHistory){\n                new AlertDialog.Builder(TweeterActivityMVPCI.this)\n                        .setMessage(R.string.history_text)\n                        .setPositiveButton(\"Ok\", null)\n                        .create()\n                        .show();\n            }\n            else if(view == helpUrl){\n                new AlertDialog.Builder(TweeterActivityMVPCI.this)\n                        .setMessage(R.string.url_text)\n                        .setPositiveButton(\"Ok\", null)\n                        .create()\n                        .show();\n            }\n            else if(view == helpLogin){\n                new AlertDialog.Builder(TweeterActivityMVPCI.this)\n                        .setMessage(R.string.login_text)\n                        .setPositiveButton(\"Ok\", null)\n                        .create()\n                        .show();\n            }\n        }\n    };\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n        ButterKnife.bind(this);\n        this.fetchLastTwoButton.setOnClickListener(onClickListener);\n        this.fetchTweetButton.setOnClickListener(onClickListener);\n        this.loginButton.setOnClickListener(onClickListener);\n        this.websiteFetchbutton.setOnClickListener(onClickListener);\n        this.helpHistory.setOnClickListener(dialogClickListener);\n        this.helpLogin.setOnClickListener(dialogClickListener);\n        this.helpUrl.setOnClickListener(dialogClickListener);\n        setTitle(\"MVPCI activity\");\n    }\n\n    @Override\n    protected TweeterMVPCIPresenter getPresenter() {\n\n        if(presenter == null){\n            DaggerActivityInjectorComponent.builder()\n                    .baseComponent(CleanArchitectureApplication.getBaseComponent())\n                    .build()\n                    .inject(this);\n        }\n\n        return presenter;\n    }\n\n    @Override\n    public void displayToast(String toast) {\n        Toast.makeText(this, toast, Toast.LENGTH_LONG).show();\n    }\n\n    private void displayTweets(List<String> list) {\n        pastTweetContainer.removeAllViews();\n\n        for(int i= 0; i < list.size(); i++){\n            TextView textView = new TextView(this);\n            textView.setText(list.get(i));\n            pastTweetContainer.addView(textView);\n        }\n    }\n\n    @Override\n    public void toggleProgressBar(boolean show) {\n        Utility.toggleProgressbar(this, show);\n    }\n\n\n    @Override\n    public void loggedIn(UserProfile profile) {\n        Toast.makeText(this, (profile.getFormattedCredentials() + \" Logged in\"), Toast.LENGTH_SHORT).show();\n        loginButton.setText(\"Log \" + profile.getUserName() + \" out\");\n        container.setVisibility(View.GONE);\n    }\n\n    @Override\n    public void loggedOut() {\n        loginButton.setText(R.string.log_user_in);\n        container.setVisibility(View.VISIBLE);\n    }\n\n\n    public static Intent newInstance(Context context) {\n        return new Intent(context, TweeterActivityMVPCI.class);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/TweeterMVPCIPresenter.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVPCI;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\nimport javax.inject.Named;\n\nimport io.patrykpoborca.cleanarchitecture.dagger.interactors.NetworkInteractor;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.base.BasePresenterMVPCI;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.interfaces.TweeterActivityMVPCIPview;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;\nimport io.patrykpoborca.cleanarchitecture.util.Constants;\nimport rx.Observable;\nimport rx.Scheduler;\n\n/**\n * Created by Patryk on 7/29/2015.\n */\npublic class TweeterMVPCIPresenter extends BasePresenterMVPCI<TweeterActivityMVPCIPview> {\n\n    private static final int TWEET_COUNT = 2;\n    private final NetworkInteractor interactor;\n    private final Scheduler mainScheduler;\n    private boolean loggedIn = false;\n    private int tweetsAdded = 0;\n\n\n    @Inject\n    public TweeterMVPCIPresenter(NetworkInteractor interactor, @Named(Constants.MAIN_THREAD) Scheduler mainScheduler) {\n        this.interactor = interactor;\n        this.mainScheduler = mainScheduler;\n    }\n\n    @Override\n    public void onAttach() {\n        super.onAttach();\n    }\n\n    @Override\n    public void onDettach() {\n        super.onDettach();\n    }\n\n    public Observable<String> fetchCurrentTweet() {\n        getPView().toggleProgressBar(true);\n\n        Observable<String> observable = interactor.fetchTweet();\n        observable.subscribe(s -> {\n            getPView().toggleProgressBar(false);\n            tweetsAdded++;\n            if (tweetsAdded > TWEET_COUNT) {\n                getPView().displayToast(\"Tweet size exceeded \" + TWEET_COUNT);\n            }\n        });\n        return observable;\n    }\n    \n    public Observable<List<String>> fetchPreviousTweets() {\n        getPView().toggleProgressBar(true);\n\n        Observable<List<String>> observable = interactor.fetchTweets(TWEET_COUNT);\n        observable.subscribe(l -> {\n            getPView().toggleProgressBar(false);\n        });\n        return observable;\n    }\n    \n    public void toggleLogin(String userName, String password){\n\n        getPView().toggleProgressBar(true);\n        if(!loggedIn) {\n            loggedIn = true;\n            Observable<UserProfile> observable = interactor.attemptLogin(userName, password);\n            observable.subscribe(p->\n            {\n                getPView().toggleProgressBar(false);\n                getPView().loggedIn(p);\n            });\n\n        }\n        else{\n            UserProfile profile = null;\n            loggedIn = false;\n            //avoid relying on timer task/handler\n            interactor.logout()\n                    .observeOn(mainScheduler)\n                    .subscribe(s -> {\n                        getPView().loggedOut();\n                        getPView().toggleProgressBar(false);\n                    });\n        }\n    }\n\n    public Observable<String> loadWebPage(String url){\n        getPView().toggleProgressBar(true);\n        Observable<String> observable = interactor.loadWebpage(url);\n\n        observable.subscribe(s -> getPView().toggleProgressBar(false));\n        return observable;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/base/BasePresenterActivityMVPCI.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVPCI.base;\n\nimport android.os.Bundle;\n\nimport io.patrykpoborca.cleanarchitecture.ui.BaseCleanArchitectureActivity;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces.PView;\n\npublic abstract class BasePresenterActivityMVPCI<T extends BasePresenterMVPCI> extends BaseCleanArchitectureActivity implements PView{\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        getPresenter().registerPresenter(this);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        getPresenter().onAttach();\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        getPresenter().onDettach();\n    }\n\n    protected abstract T getPresenter();\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/base/BasePresenterMVPCI.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVPCI.base;\n\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces.PView;\n\npublic class BasePresenterMVPCI<T extends PView> {\n\n    private T pView;\n\n    public void onAttach(){\n\n    }\n    public void onDettach(){\n\n    }\n\n    public void registerPresenter(T view){\n        this.pView = view;\n    }\n\n    protected T getPView(){\n        return this.pView;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/interfaces/TweeterActivityMVPCIPview.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVPCI.interfaces;\n\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces.PView;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;\n\n/**\n * Created by Patryk on 7/29/2015.\n */\npublic interface TweeterActivityMVPCIPview extends PView{\n    public void loggedIn(UserProfile profile);\n\n    public void loggedOut();\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/models/UserProfile.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVPCI.models;\n\n/**\n * Created by Patryk on 7/29/2015.\n */\npublic class UserProfile {\n    private final String password;\n    private final String username;\n\n    public UserProfile(String username, String password) {\n        this.username = username;\n        this.password =password;\n    }\n\n    public String getFormattedCredentials(){\n        return \"User Profile = \" + username + \" \" + password;\n    }\n\n    public String getUserName() {\n        return username;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/MainViewmodel.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVVM;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\n\nimport io.patrykpoborca.cleanarchitecture.network.TweeterApi;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;\nimport io.patrykpoborca.cleanarchitecture.ui.MVVM.base.BaseViewModel;\nimport rx.Observable;\nimport rx.subjects.PublishSubject;\n\npublic class MainViewModel extends BaseViewModel {\n\n    private static final int TWEET_COUNT = 2;\n    private final TweeterApi tweeterApi;\n    private final Retrofit retroFit;\n    private boolean loggedIn = false;\n    private int tweetsAdded = 0;\n    private PublishSubject<String> messageStream;\n\n\n    @Inject\n    public MainViewModel(TweeterApi api, Retrofit retrofit){\n        this.tweeterApi = api;\n        this.retroFit = retrofit;\n    }\n\n    public Observable<String> fetchCurrentTweet(){\n        tweetsAdded ++;\n\n        Observable<String> observable=  tweeterApi.getTweet();\n\n        if(tweetsAdded > TWEET_COUNT){\n            observable.subscribe(s ->  messageStream.onNext(\"Tweet size exceeded \" + TWEET_COUNT));\n        }\n        return observable;\n    }\n\n\n    public Observable<List<String>> fetchPreviousTweets(){\n        return tweeterApi.fetchXrecents(2);\n    }\n\n    public boolean isLoggedIn(){\n        return loggedIn;\n    }\n\n    public Observable<UserProfile> toggleLogin(String userName, String password){\n        loggedIn = !loggedIn;\n        if(loggedIn) {\n            return this.tweeterApi.login(userName, password);\n        }\n        else{\n            UserProfile profile = null;\n            return tweeterApi.logout()\n                    .map(o -> profile);\n        }\n    }\n\n    public Observable<String> getMessageStream() {\n        if(messageStream == null){\n            messageStream = PublishSubject.<String>create();\n        }\n        return messageStream.asObservable();\n    }\n\n    public Observable<String> loadWebPage(String url){\n        return retroFit.fetchSomePage(url);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/TweeterActivityMVVM.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVVM;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.AlertDialog;\nimport android.text.Html;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport io.patrykpoborca.cleanarchitecture.CleanArchitectureApplication;\nimport io.patrykpoborca.cleanarchitecture.R;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.DaggerActivityInjectorComponent;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;\nimport io.patrykpoborca.cleanarchitecture.ui.MVVM.base.BaseViewModelActivity;\nimport io.patrykpoborca.cleanarchitecture.util.Utility;\n\n\npublic class TweeterActivityMVVM extends BaseViewModelActivity<MainViewModel> {\n\n    @Bind(R.id.fetch_tweet_button) Button fetchTweetButton;\n    @Bind(R.id.fetch_last_two_tweets) Button fetchLastTwoButton;\n    @Bind(R.id.current_tweet) TextView currentTweetTextView;\n    @Bind(R.id.past_tweets_container) LinearLayout pastTweetContainer;\n    @Bind(R.id.user_login_button) Button loginButton;\n    @Bind(R.id.user_name) TextView userNameTextView;\n    @Bind(R.id.user_password) TextView userPasswordTextView;\n    @Bind(R.id.container) ViewGroup container;\n    @Bind(R.id.some_url) EditText urlText;\n    @Bind(R.id.webpage_text) TextView websiteText;\n    @Bind(R.id.request_website_button) Button websiteFetchbutton;\n    @Bind(R.id.help_history) View helpHistory;\n    @Bind(R.id.help_login) View helpLogin;\n    @Bind(R.id.help_url) View helpUrl;\n\n    @Inject\n    MainViewModel viewModel;\n    private View.OnClickListener onClickListener = new View.OnClickListener() {\n        @Override\n        public void onClick(View view) {\n            Utility.toggleProgressbar(TweeterActivityMVVM.this, true);\n            if(view == loginButton){\n                registerSubscription(\n                        getViewModel().toggleLogin(userNameTextView.getText().toString(),\n                                userPasswordTextView.getText().toString())\n                                .subscribe(TweeterActivityMVVM.this::toggleLogin)\n                );\n            }\n            else if(view == fetchLastTwoButton){\n                registerSubscription(\n                        getViewModel().fetchPreviousTweets()\n                        .subscribe(TweeterActivityMVVM.this::displayTweets)\n                );\n            }\n            else if(view == fetchTweetButton){\n                registerSubscription(\n                        getViewModel().fetchCurrentTweet()\n                        .subscribe(tweet -> {\n                            currentTweetTextView.setText(tweet);\n                            Utility.toggleProgressbar(TweeterActivityMVVM.this, false);\n                        })\n                );\n            }\n            else if(view == websiteFetchbutton){\n                registerSubscription(\n                        getViewModel().loadWebPage(urlText.getText().toString())\n                            .subscribe(s -> {\n                                websiteText.setText(Html.fromHtml(s));\n                                Utility.toggleProgressbar(TweeterActivityMVVM.this, false);\n                            })\n                );\n            }\n        }\n    };\n\n    private final View.OnClickListener dialogClickListener = new View.OnClickListener() {\n        @Override\n        public void onClick(View view) {\n            if(view == helpHistory){\n                new AlertDialog.Builder(TweeterActivityMVVM.this)\n                        .setMessage(R.string.history_text)\n                        .setPositiveButton(\"Ok\", null)\n                        .create()\n                        .show();\n            }\n            else if(view == helpUrl){\n                new AlertDialog.Builder(TweeterActivityMVVM.this)\n                        .setMessage(R.string.url_text)\n                        .setPositiveButton(\"Ok\", null)\n                        .create()\n                        .show();\n            }\n            else if(view == helpLogin){\n                new AlertDialog.Builder(TweeterActivityMVVM.this)\n                        .setMessage(R.string.login_text)\n                        .setPositiveButton(\"Ok\", null)\n                        .create()\n                        .show();\n            }\n        }\n    };\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n        ButterKnife.bind(this);\n\n        this.fetchLastTwoButton.setOnClickListener(onClickListener);\n        this.fetchTweetButton.setOnClickListener(onClickListener);\n        this.loginButton.setOnClickListener(onClickListener);\n        this.websiteFetchbutton.setOnClickListener(onClickListener);\n        this.helpHistory.setOnClickListener(dialogClickListener);\n        this.helpLogin.setOnClickListener(dialogClickListener);\n        this.helpUrl.setOnClickListener(dialogClickListener);\n\n        setTitle(\"Tweeteractivity MVVM Impl\");\n    }\n\n    @Override\n    protected MainViewModel getViewModel() {\n        if(viewModel == null){\n            DaggerActivityInjectorComponent.builder()\n                    .baseComponent(CleanArchitectureApplication.getBaseComponent())\n                    .build()\n                    .inject(this);\n        }\n\n        return viewModel;\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n\n        registerSubscription(getViewModel().getMessageStream()\n                .subscribe(s -> Toast.makeText(this, s, Toast.LENGTH_LONG).show()));\n    }\n\n    private void displayTweets(List<String> list) {\n        pastTweetContainer.removeAllViews();\n        Utility.toggleProgressbar(this, false);\n\n        for(int i= 0; i < list.size(); i++){\n            TextView textView = new TextView(this);\n            textView.setText(list.get(i));\n            pastTweetContainer.addView(textView);\n        }\n    }\n\n    private void toggleLogin(UserProfile profile){\n        Utility.toggleProgressbar(this, false);\n\n        //unlike the variations of MVP, the\n        if(getViewModel().isLoggedIn()) {\n            Toast.makeText(this, (profile.getFormattedCredentials() + \" Logged in\"), Toast.LENGTH_SHORT).show();\n            loginButton.setText(\"Log \" + profile.getUserName() + \" out\");\n            container.setVisibility(View.GONE);\n        }\n        else{\n            loginButton.setText(R.string.log_user_in);\n            container.setVisibility(View.VISIBLE);\n        }\n    }\n\n    public static Intent newInstance(Context context) {\n        return new Intent(context, TweeterActivityMVVM.class);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/base/BaseViewModel.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVVM.base;\n\npublic class BaseViewModel {\n\n    public void onAttach(){\n\n    }\n\n    public void onDettach(){\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/base/BaseViewModelActivity.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui.MVVM.base;\n\nimport android.os.Bundle;\n\nimport io.patrykpoborca.cleanarchitecture.ui.BaseCleanArchitectureActivity;\n\npublic abstract class BaseViewModelActivity<T extends BaseViewModel> extends BaseCleanArchitectureActivity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        getViewModel();\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        getViewModel().onAttach();\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        getViewModel().onDettach();\n    }\n\n    protected abstract T getViewModel();\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/PlainTweeterActivity.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.AlertDialog;\nimport android.text.Html;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport io.patrykpoborca.cleanarchitecture.CleanArchitectureApplication;\nimport io.patrykpoborca.cleanarchitecture.R;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.DaggerActivityInjectorComponent;\nimport io.patrykpoborca.cleanarchitecture.network.TweeterApi;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;\nimport io.patrykpoborca.cleanarchitecture.util.Utility;\n\npublic class PlainTweeterActivity extends BaseCleanArchitectureActivity {\n\n    private static final int TWEET_COUNT = 2;\n    @Inject\n    TweeterApi tweeterApi;\n\n    @Inject\n    Retrofit retrofit;\n\n    @Bind(R.id.fetch_tweet_button)\n    Button fetchTweetButton;\n    @Bind(R.id.fetch_last_two_tweets)\n    Button fetchLastTwoButton;\n    @Bind(R.id.current_tweet)\n    TextView currentTweetTextView;\n    @Bind(R.id.past_tweets_container)\n    LinearLayout pastTweetContainer;\n    @Bind(R.id.user_login_button)\n    Button loginButton;\n    @Bind(R.id.user_name)\n    TextView userNameTextView;\n    @Bind(R.id.user_password)\n    TextView userPasswordTextView;\n    @Bind(R.id.container)\n    ViewGroup container;\n    @Bind(R.id.some_url)\n    EditText urlText;\n    @Bind(R.id.webpage_text)\n    TextView websiteText;\n    @Bind(R.id.request_website_button)\n    Button websiteFetchbutton;\n    @Bind(R.id.help_history)\n    View helpHistory;\n    @Bind(R.id.help_login)\n    View helpLogin;\n    @Bind(R.id.help_url)\n    View helpUrl;\n\n\n    private int tweetsAdded = 0;\n\n    private final View.OnClickListener onClickListener = new View.OnClickListener() {\n        @Override\n        public void onClick(View view) {\n\n            Utility.toggleProgressbar(PlainTweeterActivity.this, true);\n            if (view == fetchLastTwoButton) {\n                registerSubscription(\n                        tweeterApi.fetchXrecents(2)\n                                .subscribe(PlainTweeterActivity.this::displayPreviousTweets)\n                );\n            }\n            else if (view == fetchTweetButton) {\n                registerSubscription(\n                        tweeterApi.getTweet()\n                                .subscribe(s -> {\n                                    currentTweetTextView.setText(s);\n                                    tweetsAdded++;\n                                    if (tweetsAdded > TWEET_COUNT) {\n                                        Toast.makeText(PlainTweeterActivity.this, \"Tweet size exceeded \" + TWEET_COUNT, Toast.LENGTH_LONG).show();\n                                    }\n                                    Utility.toggleProgressbar(PlainTweeterActivity.this, false);\n                                })\n                );\n            }\n            else if (view == loginButton) {\n                if (tweeterApi.isLoggedIn()) {\n                    registerSubscription(tweeterApi.logout()\n                            .subscribe(s -> {\n                                container.setVisibility(View.VISIBLE);\n                                loginButton.setText(R.string.log_user_in);\n                                Utility.toggleProgressbar(PlainTweeterActivity.this, false);\n                            }));\n                }\n                else {\n                    registerSubscription(\n                            tweeterApi.login(\n                                    userNameTextView.getText().toString(),\n                                    userPasswordTextView.getText().toString())\n                                    .subscribe(PlainTweeterActivity.this::userLogin)\n                    );\n                }\n            }\n            else if (view == websiteFetchbutton) {\n                retrofit.fetchSomePage(urlText.getText().toString())\n                        .subscribe(s -> {\n                            websiteText.setText(Html.fromHtml(s));\n                            Utility.toggleProgressbar(PlainTweeterActivity.this, false);\n                        });\n            }\n\n        }\n    };\n\n    private final View.OnClickListener dialogClickListener = new View.OnClickListener() {\n        @Override\n        public void onClick(View view) {\n            if (view == helpHistory) {\n                new AlertDialog.Builder(PlainTweeterActivity.this)\n                        .setMessage(R.string.history_text)\n                        .setPositiveButton(\"Ok\", null)\n                        .create()\n                        .show();\n            }\n            else if (view == helpUrl) {\n                new AlertDialog.Builder(PlainTweeterActivity.this)\n                        .setMessage(R.string.url_text)\n                        .setPositiveButton(\"Ok\", null)\n                        .create()\n                        .show();\n            }\n            else if (view == helpLogin) {\n                new AlertDialog.Builder(PlainTweeterActivity.this)\n                        .setMessage(R.string.login_text)\n                        .setPositiveButton(\"Ok\", null)\n                        .create()\n                        .show();\n            }\n        }\n    };\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        DaggerActivityInjectorComponent.builder()\n                .baseComponent(CleanArchitectureApplication.getBaseComponent())\n                .build()\n                .inject(this);\n\n        ButterKnife.bind(this);\n\n        setTitle(\"Plain Activity IMPL\");\n\n        this.fetchLastTwoButton.setOnClickListener(onClickListener);\n        this.fetchTweetButton.setOnClickListener(onClickListener);\n        this.loginButton.setOnClickListener(onClickListener);\n        this.websiteFetchbutton.setOnClickListener(onClickListener);\n        this.helpHistory.setOnClickListener(dialogClickListener);\n        this.helpLogin.setOnClickListener(dialogClickListener);\n        this.helpUrl.setOnClickListener(dialogClickListener);\n    }\n\n    public void displayPreviousTweets(List<String> tweets) {\n        pastTweetContainer.removeAllViews(); //clear container...\n        Utility.toggleProgressbar(PlainTweeterActivity.this, false);\n        for (int i = 0; i < tweets.size(); i++) {\n            TextView text = new TextView(this);\n            text.setText(tweets.get(i));\n            pastTweetContainer.addView(text);\n        }\n    }\n\n    public void userLogin(UserProfile profile) {\n        Utility.toggleProgressbar(this, false);\n\n        container.setVisibility(View.GONE);\n        loginButton.setText(\"Log \" + profile.getUserName() + \" out\");\n    }\n\n    public static Intent newInstance(Context context) {\n        return new Intent(context, PlainTweeterActivity.class);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/RouterActivity.java",
    "content": "package io.patrykpoborca.cleanarchitecture.ui;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.Toast;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport io.patrykpoborca.cleanarchitecture.R;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.TweeterActivityMVP;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.TweeterActivityMVPCI;\nimport io.patrykpoborca.cleanarchitecture.ui.MVVM.TweeterActivityMVVM;\n\n/**\n * Created by Patryk on 7/28/2015.\n */\npublic class RouterActivity extends AppCompatActivity {\n\n\n    @Bind(R.id.stupid_activity)\n    View stupidActivity;\n\n    @Bind(R.id.mvp_activity)\n    View mvpActivity;\n\n    @Bind(R.id.mvpci_activity)\n    View mvpciActivity;\n\n    @Bind(R.id.mvvm_activity)\n    View mvvmActivity;\n\n    private View.OnClickListener onClickListener = new View.OnClickListener() {\n        @Override\n        public void onClick(View view) {\n            Intent intent = null;\n            if(view == stupidActivity){\n                intent = PlainTweeterActivity.newInstance(RouterActivity.this);\n            }\n            else if(view == mvpciActivity){\n                intent = TweeterActivityMVPCI.newInstance(RouterActivity.this);\n            }\n            else if(view == mvvmActivity) {\n                intent = TweeterActivityMVVM.newInstance(RouterActivity.this);\n            }\n            else if(view == mvpActivity){\n                intent = TweeterActivityMVP.newInstance(RouterActivity.this);\n            }\n\n            startActivity(intent);\n        }\n    };\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_router);\n        ButterKnife.bind(this);\n\n        mvvmActivity.setOnClickListener(onClickListener);\n        mvpciActivity.setOnClickListener(onClickListener);\n        mvpActivity.setOnClickListener(onClickListener);\n        stupidActivity.setOnClickListener(onClickListener);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/util/Constants.java",
    "content": "package io.patrykpoborca.cleanarchitecture.util;\n\npublic class Constants {\n\n    public static final String MAIN_THREAD = \"MAIN_THREAD\";\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/util/LoadingFragment.java",
    "content": "package io.patrykpoborca.cleanarchitecture.util;\n\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.Fragment;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport io.patrykpoborca.cleanarchitecture.R;\n\npublic class LoadingFragment extends Fragment {\n\n    @Nullable\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.fragment_progress, container, false);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/util/utility.java",
    "content": "package io.patrykpoborca.cleanarchitecture.util;\n\nimport android.support.v4.app.Fragment;\nimport android.support.v7.app.AppCompatActivity;\nimport android.util.Log;\n\nimport rx.Observable;\n\npublic class Utility {\n\n    private static final String PROGRESS_TAG = \"PROGRESS\";\n\n    public static void toggleProgressbar(AppCompatActivity activity, boolean show) {\n        try {\n            Fragment fragment = activity.getSupportFragmentManager()\n                    .findFragmentByTag(PROGRESS_TAG);\n            if (show && fragment == null) {\n                activity.getSupportFragmentManager().beginTransaction()\n                        .add(android.R.id.content, new LoadingFragment(), PROGRESS_TAG)\n                        .commit();\n            }\n            else if (!show && fragment != null) {\n                activity.getSupportFragmentManager().beginTransaction()\n                        .remove(fragment)\n                        .commit();\n\n            }\n        } catch (Exception e) {\n            Log.e(Utility.class.getSimpleName(), \"\", e);\n        }\n    }\n\n    public static void toggleProgressbar(AppCompatActivity activity, Observable observable) {\n        toggleProgressbar(activity, true);\n        observable.doOnCompleted(() -> toggleProgressbar(activity, false));\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            xmlns:tools=\"http://schemas.android.com/tools\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:paddingBottom=\"@dimen/activity_vertical_margin\"\n            android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n            android:paddingRight=\"@dimen/activity_horizontal_margin\"\n            android:paddingTop=\"@dimen/activity_vertical_margin\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <FrameLayout android:layout_width=\"match_parent\"\n                     android:layout_height=\"wrap_content\"\n                     android:minHeight=\"100dp\">\n            <View android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n                  android:background=\"@android:color/holo_blue_light\"\n                android:alpha=\"0.4\"/>\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"History:\"/>\n\n            <ImageView android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"top|right\"\n                android:src=\"@drawable/ic_help_outline_black_24dp\"\n                android:layout_marginTop=\"5dp\"\n                android:layout_marginRight=\"5dp\"\n                android:id=\"@+id/help_history\"/>\n\n            <LinearLayout\n                android:id=\"@+id/past_tweets_container\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"20dp\"\n                android:layout_marginBottom=\"30dp\"\n                android:orientation=\"vertical\"/>\n        </FrameLayout>\n        <View\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\"\n            android:layout_marginBottom=\"10dp\"\n            android:background=\"@android:color/black\"/>\n\n        <TextView\n            android:id=\"@+id/current_tweet\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/hello_world\"/>\n\n        <LinearLayout android:layout_width=\"match_parent\"\n                      android:layout_height=\"wrap_content\"\n                        android:layout_marginBottom=\"20dp\">\n            <Button\n                android:id=\"@+id/fetch_tweet_button\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"Fetch Tweet!\"/>\n\n            <Button\n                android:id=\"@+id/fetch_last_two_tweets\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"Fetch Last two Tweets!\"/>\n        </LinearLayout>\n\n\n        <ImageView android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\"\n                   android:layout_gravity=\"top|right\"\n                   android:src=\"@drawable/ic_help_outline_black_24dp\"\n                   android:layout_marginTop=\"5dp\"\n                   android:layout_marginRight=\"5dp\"\n                   android:id=\"@+id/help_login\"/>\n\n        <LinearLayout android:layout_width=\"match_parent\"\n                      android:layout_height=\"wrap_content\"\n                      android:orientation=\"vertical\"\n                        android:id=\"@+id/container\">\n\n            <TextView android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\"\n                      android:text=\"UserName:\"/>\n            <EditText android:id=\"@+id/user_name\" android:layout_width=\"match_parent\"\n                      android:layout_height=\"wrap_content\"/>\n            <TextView android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\"\n                      android:text=\"Password:\"/>\n            <EditText android:id=\"@+id/user_password\" android:layout_width=\"match_parent\"\n                      android:layout_height=\"wrap_content\"\n                      android:inputType=\"textWebPassword\"/>\n        </LinearLayout>\n\n        <Button\n            android:id=\"@+id/user_login_button\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/log_user_in\"/>\n\n        <ImageView android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\"\n                   android:layout_gravity=\"top|right\"\n                   android:src=\"@drawable/ic_help_outline_black_24dp\"\n                   android:layout_marginTop=\"5dp\"\n                   android:layout_marginRight=\"5dp\"\n                   android:id=\"@+id/help_url\"/>\n\n        <LinearLayout android:layout_width=\"match_parent\"\n                      android:layout_height=\"wrap_content\">\n            <EditText android:layout_width=\"0dp\" android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:id=\"@+id/some_url\"/>\n\n        <Button android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\"\n            android:id=\"@+id/request_website_button\"\n            android:text=\"Request\"/>\n        </LinearLayout>\n\n        <FrameLayout android:layout_width=\"match_parent\"\n                      android:layout_height=\"wrap_content\">\n            <View android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n                  android:background=\"@android:color/holo_blue_light\"\n                  android:alpha=\"0.4\"/>\n\n            <TextView android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\"\n                android:id=\"@+id/webpage_text\"/>\n        </FrameLayout>\n    </LinearLayout>\n</ScrollView>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_router.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"10dp\"\n        android:layout_marginTop=\"30dp\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textSize=\"20sp\"\n            android:text=\"Dagger 2 Clean Architecture Demo\"\n            android:layout_gravity=\"center_horizontal\"\n            android:textColor=\"@android:color/black\"/>\n\n        <Button\n            android:id=\"@+id/stupid_activity\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:text=\"Stupid Activity\"/>\n\n        <Button\n            android:id=\"@+id/mvp_activity\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:layout_marginTop=\"10dp\"\n            android:text=\"MVP Activity\"/>\n\n        <Button\n            android:id=\"@+id/mvpci_activity\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:layout_marginTop=\"10dp\"\n            android:text=\"MVPCI Activity\"/>\n\n        <Button\n            android:id=\"@+id/mvvm_activity\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:layout_marginTop=\"10dp\"\n            android:text=\"MVVM Activity\"/>\n\n    </LinearLayout>\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/fragment_progress.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n             android:layout_width=\"match_parent\"\n             android:layout_height=\"match_parent\">\n\n    <View android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n          android:background=\"@android:color/white\"\n          android:alpha=\"0.7\"/>\n    <ProgressBar android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\"\n        android:indeterminate=\"true\"\n        android:layout_gravity=\"center\"/>\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/menu/menu_main.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n      xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n      xmlns:tools=\"http://schemas.android.com/tools\"\n      tools:context=\".MainActivity\">\n    <item android:id=\"@+id/action_settings\"\n          android:title=\"@string/action_settings\"\n          android:orderInCategory=\"100\"\n          app:showAsAction=\"never\"/>\n</menu>\n"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">CleanArchitecture</string>\n\n    <string name=\"hello_world\">Hello world!</string>\n    <string name=\"action_settings\">Settings</string>\n    <string name=\"log_user_in\">Log User In</string>\n    <string name=\"repo\">Check out the sourcecode</string>\n    <string name=\"history_text\">This box will container past two tweets fetched through out the\n        app.\n    </string>\n    <string name=\"url_text\">This is the moced webpage that will be fetched. For this purpose the url\n        you entered will simply be injected into HTML header tags\n    </string>\n    <string name=\"login_text\">This is to simulate logging into the application. If you do log in,\n        any fetched tweets will be displayed using your user-name\n    </string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/test/java/dagger/TestClassInjector.java",
    "content": "package dagger;\n\nimport dagger.mockmodules.MockTestModule;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.BaseComponent;\nimport io.patrykpoborca.cleanarchitecture.dagger.scopes.ActivityScope;\nimport tests.MVPCITest;\nimport tests.MVVMTest;\nimport tests.MVPTest;\n\n@ActivityScope\n@Component(dependencies = BaseComponent.class, modules = MockTestModule.class)\npublic interface TestClassInjector {\n    void inject(MVVMTest viewmodelTest);\n\n    void inject(MVPCITest presenterTest);\n\n    void inject(MVPTest MVPTest);\n}\n"
  },
  {
    "path": "app/src/test/java/dagger/mockmodules/MockLocalModule.java",
    "content": "package dagger.mockmodules;\n\nimport android.app.Application;\n\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.LocalModule;\nimport io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;\nimport mockimpl.MockLocalDataCache;\n\npublic class MockLocalModule extends LocalModule{\n\n    @Override\n    protected LocalDataCache providesDataCache(Application application) {\n        return new MockLocalDataCache(application);\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/dagger/mockmodules/MockNetworkModule.java",
    "content": "package dagger.mockmodules;\n\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.NetworkModule;\nimport io.patrykpoborca.cleanarchitecture.network.base.OKHttp;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport mockimpl.MockOkHTTP;\nimport mockimpl.MockRetrofit;\nimport rx.Scheduler;\n\npublic class MockNetworkModule extends NetworkModule {\n\n    @Override\n    protected OKHttp providesOkHTTP() {\n        return new MockOkHTTP();\n    }\n\n    @Override\n    protected Retrofit providesRetrofit(OKHttp okHttp, Scheduler mainScheduler) {\n        return new MockRetrofit(okHttp, mainScheduler);\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/dagger/mockmodules/MockTestModule.java",
    "content": "package dagger.mockmodules;\n\nimport javax.inject.Named;\n\nimport dagger.Module;\nimport dagger.Provides;\nimport io.patrykpoborca.cleanarchitecture.dagger.scopes.ActivityScope;\nimport io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;\nimport io.patrykpoborca.cleanarchitecture.network.TweeterApi;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.TweeterMVPPresenterImpl;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;\nimport io.patrykpoborca.cleanarchitecture.util.Constants;\nimport mockimpl.MockMVPCIPview;\nimport mockimpl.MockTweeterActivityPview;\nimport mockimpl.MockTweeterApi;\nimport rx.Scheduler;\n\n@Module\npublic class MockTestModule {\n\n    @Provides\n    @ActivityScope\n    TweeterMVPPresenter providesMainPresenter(TweeterApi api, Retrofit retrofit){\n        return new TweeterMVPPresenterImpl(api, retrofit);\n    }\n\n    @ActivityScope\n    @Provides\n    public MockTweeterActivityPview providesMockMainPview(TweeterMVPPresenter presenter){\n        MockTweeterActivityPview mockTweeterActivityPview = new MockTweeterActivityPview();\n        presenter.registerView(mockTweeterActivityPview);\n        return mockTweeterActivityPview;\n    }\n\n    @ActivityScope\n    @Provides\n    public TweeterApi providesMockTweeter(Retrofit retrofit, LocalDataCache dataCache, @Named(Constants.MAIN_THREAD) Scheduler mainScheduler){\n        return new MockTweeterApi(retrofit, dataCache, mainScheduler);\n    }\n\n    @ActivityScope\n    @Provides\n    public MockMVPCIPview providesMockMVPCCIView(){\n        return new MockMVPCIPview();\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/dagger/mockmodules/MockThreadingModule.java",
    "content": "package dagger.mockmodules;\n\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.ThreadingModule;\nimport rx.Scheduler;\nimport rx.schedulers.Schedulers;\n\npublic class MockThreadingModule extends ThreadingModule {\n\n    @Override\n    public Scheduler providesMainThread() {\n        return Schedulers.immediate();\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/helper/TestHelper.java",
    "content": "package helper;\n\nimport android.app.Application;\n\nimport dagger.DaggerTestClassInjector;\nimport dagger.TestClassInjector;\nimport dagger.mockmodules.MockLocalModule;\nimport dagger.mockmodules.MockNetworkModule;\nimport dagger.mockmodules.MockThreadingModule;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.ApplicationComponent;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.BaseComponent;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.DaggerApplicationComponent;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.DaggerBaseComponent;\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.ApplicationModule;\n\n\npublic class TestHelper {\n\n    private static ApplicationComponent sApplicationComponent;\n    private static BaseComponent sBaseComponent;\n    private static TestClassInjector sTestClassInjector;\n\n    public static ApplicationComponent getApplicationComponent(){\n        if(sApplicationComponent == null)\n        {\n            sApplicationComponent = DaggerApplicationComponent.builder()\n                    .applicationModule(new ApplicationModule(new Application()))\n                    .build();\n        }\n        return sApplicationComponent;\n    }\n\n    public static BaseComponent getBaseComponent(){\n        if(sBaseComponent == null){\n            sBaseComponent = DaggerBaseComponent.builder()\n                    .applicationComponent(getApplicationComponent())\n                    .localModule(new MockLocalModule())\n                    .networkModule(new MockNetworkModule())\n                    .threadingModule(new MockThreadingModule())\n                    .build();\n        }\n        return sBaseComponent;\n    }\n\n    public static TestClassInjector getTestClassInjector(){\n        if(sTestClassInjector == null){\n            sTestClassInjector = DaggerTestClassInjector.builder()\n                    .baseComponent(getBaseComponent())\n                    .build();\n        }\n\n        return sTestClassInjector;\n    }\n\n    public static void waitFor(IWaitingCallback callback){\n        waitFor(10, callback);\n    }\n\n    public static void waitFor(int maxCycles, IWaitingCallback callback){\n        while(true){\n            maxCycles --;\n            try {\n                Thread.sleep(5);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n            if(callback.checkCondition()){\n                break;\n            }\n            if(maxCycles <= 0){\n                break;\n            }\n        }\n    }\n\n    public static interface IWaitingCallback{\n        /**\n         *\n         * @return true if condition is met, false if we should keep waiting\n         */\n        public boolean checkCondition();\n    }\n}"
  },
  {
    "path": "app/src/test/java/mockimpl/MockLocalDataCache.java",
    "content": "package mockimpl;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;\nimport rx.Observable;\n\npublic class MockLocalDataCache extends LocalDataCache {\n\n    public MockLocalDataCache(Context context) {\n        super(context);\n    }\n\n    /**\n     *  No mock-impl needed for our scenario here.. see MockOKHttp/MockRetrofit\n     */\n    @Override\n    public void saveTweet(String tweet) {\n        sPastTweets.add(tweet);\n    }\n\n    @Override\n    public Observable<List<String>> fetchRecentTweets() {\n        return Observable.just(sPastTweets)\n                .map(arrayList -> {\n                    List<String> list = arrayList;\n                    return list;\n                });\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/mockimpl/MockMVPCIPview.java",
    "content": "package mockimpl;\n\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.interfaces.TweeterActivityMVPCIPview;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;\n\npublic class MockMVPCIPview implements TweeterActivityMVPCIPview {\n\n    public UserProfile loggedInProfile;\n    public boolean loggedOutCalled = false;\n    public boolean toggleProgresbarCalled = false;\n\n    @Override\n    public void loggedIn(UserProfile profile) {\n        this.loggedInProfile = profile;\n    }\n\n    @Override\n    public void loggedOut() {\n        loggedOutCalled = true;\n    }\n\n    @Override\n    public void toggleProgressBar(boolean loading) {\n        toggleProgresbarCalled = true;\n    }\n\n    @Override\n    public void displayToast(String toast) {\n\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/mockimpl/MockOkHTTP.java",
    "content": "package mockimpl;\n\nimport io.patrykpoborca.cleanarchitecture.network.base.OKHttp;\n\npublic class MockOkHTTP extends OKHttp {\n    @Override\n    public String rawResponse() {\n        return \"Mocked raw response: \";\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/mockimpl/MockRetrofit.java",
    "content": "package mockimpl;\n\nimport java.util.concurrent.TimeUnit;\n\nimport io.patrykpoborca.cleanarchitecture.network.base.OKHttp;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport rx.Observable;\nimport rx.Scheduler;\nimport rx.android.schedulers.AndroidSchedulers;\n\npublic class MockRetrofit extends Retrofit{\n    private static final String MOCK_PARSE = \"SomeMockResponse\";\n    public static final String MOCKED_STRING = \"MOCKED PAGE:\";\n\n    public MockRetrofit(OKHttp okHttp, Scheduler mainScheduler) {\n        super(okHttp, mainScheduler);\n    }\n\n    @Override\n    public Observable<String> completeRequest() {\n        return Observable.just(okHttp.rawResponse() + MOCK_PARSE);\n    }\n\n    @Override\n    public Observable<String> fetchSomePage(String url) {\n        return Observable.just(\"<h2>\" + MOCKED_STRING + \" \" + url + \" </h2>\");\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/mockimpl/MockTweeterActivityPview.java",
    "content": "package mockimpl;\n\nimport java.util.List;\n\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPView;\n\npublic class MockTweeterActivityPview implements TweeterMVPPView {\n\n    public String fetchedTweet = null;\n    public List<String> previousTweets = null;\n    public boolean setUserButtonTextCalled = false;\n    public boolean toggleProgressBarCalled = false;\n    public boolean toggleLoginContainerCalled = false;\n    public String displayWebpage = null;\n    public boolean displayToastCalled = false;\n\n    @Override\n    public void displayFetchedTweet(String tweet) {\n        fetchedTweet = tweet;\n    }\n\n    @Override\n    public void displayPreviousTweets(List<String> list) {\n        previousTweets = list;\n    }\n\n    @Override\n    public void setUserButtonText(String text) {\n        setUserButtonTextCalled = true;\n    }\n\n    @Override\n    public void toggleLoginContainer(boolean b) {\n        toggleLoginContainerCalled = true;\n    }\n\n    @Override\n    public void displayWebpage(String html) {\n        displayWebpage = html;\n    }\n\n    @Override\n    public void toggleProgressBar(boolean loading) {\n        toggleProgressBarCalled = true;\n    }\n\n    @Override\n    public void displayToast(String toast) {\n        displayToastCalled = true;\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/mockimpl/MockTweeterApi.java",
    "content": "package mockimpl;\n\nimport android.util.Log;\n\nimport io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;\nimport io.patrykpoborca.cleanarchitecture.network.TweeterApi;\nimport io.patrykpoborca.cleanarchitecture.network.base.Retrofit;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;\nimport rx.Observable;\nimport rx.Scheduler;\n\npublic class MockTweeterApi extends TweeterApi{\n    public MockTweeterApi(Retrofit retrofit, LocalDataCache dataCache, Scheduler mainScheduler) {\n        super(retrofit, dataCache, mainScheduler);\n    }\n\n    @Override\n    public Observable<UserProfile> login(String username, String password) {\n        return Observable.just(new UserProfile(username, password))\n                .observeOn(mainScheduler);\n    }\n\n    @Override\n    public Observable<Object> logout() {\n        return Observable.just(null)\n                .observeOn(mainScheduler);\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/tests/MVPCITest.java",
    "content": "package tests;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.JUnit4;\n\nimport javax.inject.Inject;\n\nimport helper.TestHelper;\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.TweeterMVPCIPresenter;\nimport mockimpl.MockLocalDataCache;\nimport mockimpl.MockMVPCIPview;\nimport mockimpl.MockOkHTTP;\nimport mockimpl.MockRetrofit;\n\n@RunWith(JUnit4.class)\npublic class MVPCITest {\n\n    private static final String SOME_URL = \"SOME_URL\";\n    private static final String USER_PASSWORD = \"USER_PASSWORD\";\n    private static final String USER_NAME = \"USER_NAME\";\n    private String tweetedTweet;\n\n    @Inject\n    TweeterMVPCIPresenter presenter;\n\n    @Inject\n    MockMVPCIPview pView;\n    @Before\n    public void setUp(){\n        TestHelper.getTestClassInjector()\n                .inject(this);\n        presenter.registerPresenter(pView);\n\n        junit.framework.Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);\n        junit.framework.Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);\n        junit.framework.Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);\n    }\n\n    @Test\n    public void testWebPage(){\n        presenter.loadWebPage(SOME_URL)\n                .toBlocking()\n                .forEach(s -> {\n                    junit.framework.Assert.assertTrue(s.contains(MockRetrofit.MOCKED_STRING)\n                            && s.contains(SOME_URL));\n                });\n    }\n\n    @Test\n    public void testLogin(){\n        Assert.assertTrue(pView.loggedInProfile == null);\n        presenter.toggleLogin(USER_NAME, USER_PASSWORD);\n        TestHelper.waitFor(() -> pView.loggedInProfile != null);\n\n        Assert.assertTrue(pView.loggedInProfile.getUserName().equals(USER_NAME));\n        presenter.toggleLogin(USER_NAME, USER_PASSWORD);\n        TestHelper.waitFor(() -> pView.loggedOutCalled);\n        Assert.assertTrue(pView.loggedOutCalled);\n    }\n\n    @Test\n    public void testTweets() {\n        //Sanity test first to see if underlying logic of tweeter api has changed\n        presenter.fetchPreviousTweets()\n                .toBlocking()\n                .forEach(list -> {\n                    Assert.assertNotNull(list);\n                });\n\n    }\n\n    @Test\n    public void testTweetList(){\n        presenter.fetchCurrentTweet()\n                .toBlocking()\n                .forEach(tweet -> {\n                    tweetedTweet = tweet;\n                });\n\n        presenter.fetchPreviousTweets()\n                .toBlocking()\n                .forEach(list -> {\n                    boolean exists = false;\n\n                    for (int i = 0; i < list.size(); i++) {\n                        if (tweetedTweet.contains(list.get(i))) {\n                            exists = true;\n                            break;\n                        }\n                    }\n                    Assert.assertTrue(exists);\n                });\n    }\n\n}\n"
  },
  {
    "path": "app/src/test/java/tests/MVPTest.java",
    "content": "package tests;\n\n\nimport junit.framework.Assert;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.JUnit4;\n\nimport javax.inject.Inject;\n\nimport helper.TestHelper;\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;\nimport mockimpl.MockLocalDataCache;\nimport mockimpl.MockOkHTTP;\nimport mockimpl.MockRetrofit;\nimport mockimpl.MockTweeterActivityPview;\n\n@RunWith(JUnit4.class)\npublic class MVPTest {\n\n    private static final String SOME_URL = \"SOME_URL\";\n    private static final String USER_PASSWORD = \"USER_PASSWORD\";\n    private static final String USER_NAME = \"USER_NAME\";\n\n    @Inject\n    MockTweeterActivityPview pView;\n\n    @Inject\n    TweeterMVPPresenter presenter;\n\n    @Before\n    public void setUp(){\n        TestHelper.getTestClassInjector()\n                .inject(this);\n\n        Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);\n        Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);\n        Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);\n    }\n\n\n    @Test\n    public void testLogin(){\n        presenter.toggleLogin(USER_NAME, USER_PASSWORD);\n        TestHelper.waitFor(() -> pView.toggleLoginContainerCalled);\n        Assert.assertTrue(pView.toggleLoginContainerCalled);\n\n        pView.toggleLoginContainerCalled = false;\n\n        presenter.toggleLogin(USER_NAME, USER_PASSWORD);\n        TestHelper.waitFor(() -> pView.toggleLoginContainerCalled);\n        Assert.assertTrue(pView.toggleLoginContainerCalled);\n    }\n\n    @Test\n    public void testFetchTweets(){\n        presenter.fetchCurrentTweet();\n        TestHelper.waitFor(() -> pView.fetchedTweet != null);\n        String tweet = pView.fetchedTweet;\n\n        presenter.fetchPreviousTweets();\n        TestHelper.waitFor(() -> pView.previousTweets != null);\n        boolean found = false;\n        for(int i=0; i < pView.previousTweets.size(); i++){\n            found = tweet.contains(pView.previousTweets.get(i));\n            if(found){\n                break;\n            }\n        }\n        Assert.assertTrue(found);\n    }\n\n    @Test\n    public void testWebPage() {\n        presenter.loadWebPage(SOME_URL);\n\n        TestHelper.waitFor(() -> pView.displayWebpage != null);\n        String webPage = pView.displayWebpage;\n        Assert.assertTrue(webPage.contains(SOME_URL));\n    }\n\n}\n"
  },
  {
    "path": "app/src/test/java/tests/MVVMTest.java",
    "content": "package tests;\n\nimport junit.framework.Assert;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.JUnit4;\n\nimport javax.inject.Inject;\n\nimport helper.TestHelper;\nimport io.patrykpoborca.cleanarchitecture.ui.MVVM.MainViewModel;\nimport mockimpl.MockLocalDataCache;\nimport mockimpl.MockOkHTTP;\nimport mockimpl.MockRetrofit;\n\n@RunWith(JUnit4.class)\npublic class MVVMTest {\n\n    private static final String SOME_URL = \"SOME_URL\";\n    private static final String USER_PASSWORD = \"USER_PASSWORD\";\n    private static final String USER_NAME = \"USER_NAME\";\n    private String tweetedTweet;\n\n    @Inject\n    MainViewModel viewModel;\n\n    @Before\n    public void setUp() {\n        TestHelper.getTestClassInjector()\n                .inject(this);\n\n        Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);\n        Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);\n        Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);\n\n    }\n\n\n    @Test\n    public void testWebPage() {\n        viewModel.loadWebPage(SOME_URL)\n                .toBlocking()\n                .forEach(s -> {\n                    Assert.assertTrue(s.contains(MockRetrofit.MOCKED_STRING)\n                            && s.contains(SOME_URL));\n                });\n    }\n\n    @Test\n    public void testLogin() {\n        Assert.assertFalse(viewModel.isLoggedIn());\n        viewModel.toggleLogin(USER_NAME, USER_PASSWORD)\n                .toBlocking()\n                .forEach(\n                        user -> {\n                            Assert.assertNotNull(user);\n                            Assert.assertEquals(user.getUserName(), USER_NAME);\n                        }\n                );\n        Assert.assertTrue(viewModel.isLoggedIn());\n    }\n\n    @Test\n    public void testTweets() {\n        //Sanity test first to see if underlying logic of tweeter api has changed\n        viewModel.fetchPreviousTweets()\n                .toBlocking()\n                .forEach(list -> {\n                    Assert.assertNotNull(list);\n                });\n\n    }\n\n    @Test\n    public void testTweetList() {\n\n        viewModel.fetchCurrentTweet()\n                .toBlocking()\n                .forEach(tweet -> {\n                    tweetedTweet = tweet;\n                });\n\n        viewModel.fetchPreviousTweets()\n                .toBlocking()\n                .forEach(list -> {\n                    boolean exists = false;\n\n                    for (int i = 0; i < list.size(); i++) {\n                        if (tweetedTweet.contains(list.get(i))) {\n                            exists = true;\n                            break;\n                        }\n                    }\n                    Assert.assertTrue(exists);\n                });\n    }\n\n}\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.0.0-beta6'\n        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.5' //added apt for source code generation\n        classpath 'me.tatarka:gradle-retrolambda:3.2.2'\n//        classpath \"net.ltgt.gradle:gradle-apt-plugin:0.3\"\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\napply plugin: 'me.tatarka.retrolambda'\n\nretrolambda {\n    jdk System.getenv(\"JAVA8_HOME\")\n    oldJdk System.getenv(\"JAVA7_HOME\")\n    javaVersion JavaVersion.VERSION_1_7\n}\n\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Tue Mar 29 10:09:27 CDT 2016\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.10-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched.\nif $cygwin ; then\n    [ -n \"$JAVA_HOME\" ] && JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\nfi\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >&-\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >&-\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app'\n"
  }
]