master d8437d80fe2e cached
102 files
135.7 KB
34.2k tokens
322 symbols
1 requests
Download .txt
Repository: patrykpoborca/CleanArchitecture
Branch: master
Commit: d8437d80fe2e
Files: 102
Total size: 135.7 KB

Directory structure:
gitextract_n6u9vjvq/

├── .gitignore
├── .idea/
│   ├── .name
│   ├── compiler.xml
│   ├── copyright/
│   │   └── profiles_settings.xml
│   ├── encodings.xml
│   ├── gradle.xml
│   ├── misc.xml
│   ├── modules.xml
│   ├── runConfigurations.xml
│   └── vcs.xml
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── io/
│       │           └── patrykpoborca/
│       │               └── cleanarchitecture/
│       │                   ├── TestHelper.java
│       │                   ├── dagger/
│       │                   │   ├── TestClassInjector.java
│       │                   │   └── mockmodules/
│       │                   │       ├── MockLocalModule.java
│       │                   │       ├── MockNetworkModule.java
│       │                   │       └── MockTestModule.java
│       │                   ├── mockimpl/
│       │                   │   ├── MockLocalDataCache.java
│       │                   │   ├── MockMVPCIPview.java
│       │                   │   ├── MockOkHTTP.java
│       │                   │   ├── MockRetrofit.java
│       │                   │   ├── MockTweeterActivityPview.java
│       │                   │   └── MockTweeterApi.java
│       │                   └── tests/
│       │                       ├── MVPCITest.java
│       │                       ├── MVPTest.java
│       │                       ├── MVVMTest.java
│       │                       └── PlainTweeterTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── io/
│       │   │       └── patrykpoborca/
│       │   │           └── cleanarchitecture/
│       │   │               ├── CleanArchitectureApplication.java
│       │   │               ├── dagger/
│       │   │               │   ├── components/
│       │   │               │   │   ├── ActivityInjectorComponent.java
│       │   │               │   │   ├── ApplicationComponent.java
│       │   │               │   │   └── BaseComponent.java
│       │   │               │   ├── interactors/
│       │   │               │   │   ├── NetworkInteractor.java
│       │   │               │   │   └── base/
│       │   │               │   │       └── BaseInteractor.java
│       │   │               │   ├── modules/
│       │   │               │   │   ├── ApplicationModule.java
│       │   │               │   │   ├── InteractorModule.java
│       │   │               │   │   ├── LocalModule.java
│       │   │               │   │   ├── NetworkModule.java
│       │   │               │   │   ├── PresenterModule.java
│       │   │               │   │   └── ThreadingModule.java
│       │   │               │   └── scopes/
│       │   │               │       ├── ActivityScope.java
│       │   │               │       ├── ApplicationScope.java
│       │   │               │       └── ExposedAPIScope.java
│       │   │               ├── localdata/
│       │   │               │   └── LocalDataCache.java
│       │   │               ├── network/
│       │   │               │   ├── TweeterApi.java
│       │   │               │   └── base/
│       │   │               │       ├── OKHttp.java
│       │   │               │       └── Retrofit.java
│       │   │               ├── ui/
│       │   │               │   ├── BaseCleanArchitectureActivity.java
│       │   │               │   ├── MVP/
│       │   │               │   │   ├── TweeterActivityMVP.java
│       │   │               │   │   ├── TweeterMVPPresenterImpl.java
│       │   │               │   │   ├── base/
│       │   │               │   │   │   ├── BasePresenterActivity.java
│       │   │               │   │   │   └── Interfaces/
│       │   │               │   │   │       ├── PView.java
│       │   │               │   │   │       └── Presenter.java
│       │   │               │   │   └── interfaces/
│       │   │               │   │       ├── TweeterMVPPView.java
│       │   │               │   │       └── TweeterMVPPresenter.java
│       │   │               │   ├── MVPCI/
│       │   │               │   │   ├── TweeterActivityMVPCI.java
│       │   │               │   │   ├── TweeterMVPCIPresenter.java
│       │   │               │   │   ├── base/
│       │   │               │   │   │   ├── BasePresenterActivityMVPCI.java
│       │   │               │   │   │   └── BasePresenterMVPCI.java
│       │   │               │   │   ├── interfaces/
│       │   │               │   │   │   └── TweeterActivityMVPCIPview.java
│       │   │               │   │   └── models/
│       │   │               │   │       └── UserProfile.java
│       │   │               │   ├── MVVM/
│       │   │               │   │   ├── MainViewmodel.java
│       │   │               │   │   ├── TweeterActivityMVVM.java
│       │   │               │   │   └── base/
│       │   │               │   │       ├── BaseViewModel.java
│       │   │               │   │       └── BaseViewModelActivity.java
│       │   │               │   ├── PlainTweeterActivity.java
│       │   │               │   └── RouterActivity.java
│       │   │               └── util/
│       │   │                   ├── Constants.java
│       │   │                   ├── LoadingFragment.java
│       │   │                   └── utility.java
│       │   └── res/
│       │       ├── layout/
│       │       │   ├── activity_main.xml
│       │       │   ├── activity_router.xml
│       │       │   └── fragment_progress.xml
│       │       ├── menu/
│       │       │   └── menu_main.xml
│       │       ├── values/
│       │       │   ├── dimens.xml
│       │       │   ├── strings.xml
│       │       │   └── styles.xml
│       │       └── values-w820dp/
│       │           └── dimens.xml
│       └── test/
│           └── java/
│               ├── dagger/
│               │   ├── TestClassInjector.java
│               │   └── mockmodules/
│               │       ├── MockLocalModule.java
│               │       ├── MockNetworkModule.java
│               │       ├── MockTestModule.java
│               │       └── MockThreadingModule.java
│               ├── helper/
│               │   └── TestHelper.java
│               ├── mockimpl/
│               │   ├── MockLocalDataCache.java
│               │   ├── MockMVPCIPview.java
│               │   ├── MockOkHTTP.java
│               │   ├── MockRetrofit.java
│               │   ├── MockTweeterActivityPview.java
│               │   └── MockTweeterApi.java
│               └── tests/
│                   ├── MVPCITest.java
│                   ├── MVPTest.java
│                   └── MVVMTest.java
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.gradle
*.iml
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures


================================================
FILE: .idea/.name
================================================
CleanArchitecture

================================================
FILE: .idea/compiler.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="CompilerConfiguration">
    <resourceExtensions />
    <wildcardResourcePatterns>
      <entry name="!?*.java" />
      <entry name="!?*.form" />
      <entry name="!?*.class" />
      <entry name="!?*.groovy" />
      <entry name="!?*.scala" />
      <entry name="!?*.flex" />
      <entry name="!?*.kt" />
      <entry name="!?*.clj" />
    </wildcardResourcePatterns>
    <annotationProcessing>
      <profile default="true" name="Default" enabled="false">
        <processorPath useClasspath="true" />
      </profile>
    </annotationProcessing>
  </component>
</project>

================================================
FILE: .idea/copyright/profiles_settings.xml
================================================
<component name="CopyrightManager">
  <settings default="" />
</component>

================================================
FILE: .idea/encodings.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="Encoding">
    <file url="PROJECT" charset="UTF-8" />
  </component>
</project>

================================================
FILE: .idea/gradle.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="GradleSettings">
    <option name="linkedExternalProjectsSettings">
      <GradleProjectSettings>
        <option name="distributionType" value="DEFAULT_WRAPPED" />
        <option name="externalProjectPath" value="$PROJECT_DIR$" />
        <option name="modules">
          <set>
            <option value="$PROJECT_DIR$" />
            <option value="$PROJECT_DIR$/app" />
          </set>
        </option>
        <option name="myModules">
          <set>
            <option value="$PROJECT_DIR$" />
            <option value="$PROJECT_DIR$/app" />
          </set>
        </option>
      </GradleProjectSettings>
    </option>
  </component>
</project>

================================================
FILE: .idea/misc.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="EntryPointsManager">
    <entry_points version="2.0" />
  </component>
  <component name="JavacSettings">
    <option name="ADDITIONAL_OPTIONS_STRING" value="--stacktrace --debug" />
  </component>
  <component name="NullableNotNullManager">
    <option name="myDefaultNullable" value="android.support.annotation.Nullable" />
    <option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
    <option name="myNullables">
      <value>
        <list size="4">
          <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
          <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
          <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
          <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
        </list>
      </value>
    </option>
    <option name="myNotNulls">
      <value>
        <list size="4">
          <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
          <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
          <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
          <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
        </list>
      </value>
    </option>
  </component>
  <component name="ProjectInspectionProfilesVisibleTreeState">
    <entry key="Project Default">
      <profile-state>
        <expanded-state>
          <State>
            <id />
          </State>
          <State>
            <id>Android Lint</id>
          </State>
          <State>
            <id>C/C++</id>
          </State>
          <State>
            <id>Class structureJava</id>
          </State>
          <State>
            <id>Code maturity issuesJava</id>
          </State>
          <State>
            <id>Code style issuesJava</id>
          </State>
          <State>
            <id>Compiler issuesJava</id>
          </State>
          <State>
            <id>Declaration orderC/C++</id>
          </State>
          <State>
            <id>Finalization issuesJava</id>
          </State>
          <State>
            <id>Groovy</id>
          </State>
          <State>
            <id>Inheritance issuesJava</id>
          </State>
          <State>
            <id>J2ME issuesJava</id>
          </State>
          <State>
            <id>Java</id>
          </State>
          <State>
            <id>Java language level migration aidsJava</id>
          </State>
          <State>
            <id>JavaBeans issuesJava</id>
          </State>
          <State>
            <id>Javadoc issuesJava</id>
          </State>
          <State>
            <id>Numeric issuesJava</id>
          </State>
          <State>
            <id>OtherGroovy</id>
          </State>
          <State>
            <id>Performance issuesJava</id>
          </State>
          <State>
            <id>Probable bugsJava</id>
          </State>
          <State>
            <id>Security issuesJava</id>
          </State>
          <State>
            <id>Serialization issuesJava</id>
          </State>
          <State>
            <id>TestNGJava</id>
          </State>
          <State>
            <id>Threading issuesJava</id>
          </State>
          <State>
            <id>Type checksC/C++</id>
          </State>
          <State>
            <id>Verbose or redundant code constructsJava</id>
          </State>
        </expanded-state>
        <selected-state>
          <State>
            <id>Android</id>
          </State>
        </selected-state>
      </profile-state>
    </entry>
  </component>
  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
    <OptionsSetting value="true" id="Add" />
    <OptionsSetting value="true" id="Remove" />
    <OptionsSetting value="true" id="Checkout" />
    <OptionsSetting value="true" id="Update" />
    <OptionsSetting value="true" id="Status" />
    <OptionsSetting value="true" id="Edit" />
    <ConfirmationsSetting value="0" id="Add" />
    <ConfirmationsSetting value="0" id="Remove" />
  </component>
  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
    <output url="file://$PROJECT_DIR$/build/classes" />
  </component>
  <component name="ProjectType">
    <option name="id" value="Android" />
  </component>
  <component name="masterDetails">
    <states>
      <state key="ProjectJDKs.UI">
        <settings>
          <last-edited>1.7</last-edited>
          <splitter-proportions>
            <option name="proportions">
              <list>
                <option value="0.2" />
              </list>
            </option>
          </splitter-proportions>
        </settings>
      </state>
    </states>
  </component>
</project>

================================================
FILE: .idea/modules.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ProjectModuleManager">
    <modules>
      <module fileurl="file://$PROJECT_DIR$/CleanArchitecture.iml" filepath="$PROJECT_DIR$/CleanArchitecture.iml" />
      <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
    </modules>
  </component>
</project>

================================================
FILE: .idea/runConfigurations.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="RunConfigurationProducerService">
    <option name="ignoredProducers">
      <set>
        <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
      </set>
    </option>
  </component>
</project>

================================================
FILE: .idea/vcs.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="VcsDirectoryMappings">
    <mapping directory="" vcs="Git" />
  </component>
</project>

================================================
FILE: README.md
================================================
# CleanArchitecture

Thanks for checking out my github repo. There's not much to say in this readme since I wrote two articles about this repo here:

[Article 1 - Dagger 2 introduction](https://medium.com/@patrykpoborca/making-a-best-practice-app-4-dagger-2-267ec5f6c89a)

[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)

To 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.
Finally 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.
I also show how annoying/and or obnoxious it is to test imporoperly architected applications by actually testing my "PlainTweeterActivity"

I 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)

Also if you want to see the talk about Dagger 2 I did here [it is](https://www.youtube.com/watch?v=JNbz_rgdQ10)

Thanks!


================================================
FILE: app/.gitignore
================================================
/build


================================================
FILE: app/build.gradle
================================================
apply plugin: 'me.tatarka.retrolambda'
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'

//apply plugin: "net.ltgt.apt"

android {
    compileSdkVersion 22
    buildToolsVersion '23.0.2'

    defaultConfig {
        applicationId "io.patrykpoborca.cleanarchitecture"
        minSdkVersion 22
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        encoding "UTF-8"
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    dependencies {
        apt 'com.google.dagger:dagger-compiler:2.0'
        testProvided 'com.google.dagger:dagger-compiler:2.0'
        //needed to resolve compilation errors, thanks to tutplus.org for finding the dependency
        // http://stackoverflow.com/questions/27036933/how-to-set-up-dagger-dependency-injection-from-scratch-in-android-project
        //test compiles
        androidTestApt 'com.google.dagger:dagger-compiler:2.0'

        compile fileTree(include: ['*.jar'], dir: 'libs')
        compile 'com.android.support:appcompat-v7:22.2.0'
        compile 'com.google.dagger:dagger:2.0'
        provided 'org.glassfish:javax.annotation:10.0-b28'
        compile 'io.reactivex:rxandroid:0.25.0'
        compile 'com.jakewharton:butterknife:7.0.1'

        androidTestCompile 'com.google.dagger:dagger:2.0'
        testCompile 'com.google.dagger:dagger:2.0'
        testCompile 'junit:junit:4.12'
        androidTestCompile 'com.android.support.test:runner:0.3'
        // Set this dependency to use JUnit 4 rules
        androidTestCompile 'com.android.support.test:rules:0.3'
        androidTestCompile 'org.mockito:mockito-core:1.+'
        androidTestCompile('com.android.support.test:runner:0.3') {
            exclude group: 'com.android.support', module: 'support-annotations'
        }
        androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
        androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
        androidTestCompile 'com.android.support.test:runner:0.3'
        androidTestCompile 'com.android.support.test:rules:0.3'
        androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2'
    }
}


================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Users\Patryk\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}


================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/TestHelper.java
================================================
package io.patrykpoborca.cleanarchitecture;

import android.app.Application;

import io.patrykpoborca.cleanarchitecture.dagger.DaggerTestClassInjector;
import io.patrykpoborca.cleanarchitecture.dagger.TestClassInjector;
import io.patrykpoborca.cleanarchitecture.dagger.components.ApplicationComponent;
import io.patrykpoborca.cleanarchitecture.dagger.components.BaseComponent;
import io.patrykpoborca.cleanarchitecture.dagger.components.DaggerApplicationComponent;
import io.patrykpoborca.cleanarchitecture.dagger.components.DaggerBaseComponent;
import io.patrykpoborca.cleanarchitecture.dagger.mockmodules.MockLocalModule;
import io.patrykpoborca.cleanarchitecture.dagger.mockmodules.MockNetworkModule;
import io.patrykpoborca.cleanarchitecture.dagger.modules.ApplicationModule;

public class TestHelper {

    private static ApplicationComponent sApplicationComponent;
    private static BaseComponent sBaseComponent;
    private static TestClassInjector sTestClassInjector;

    public static ApplicationComponent getApplicationComponent(){
        if(sApplicationComponent == null)
        {
            sApplicationComponent = DaggerApplicationComponent.builder()
                    .applicationModule(new ApplicationModule(new Application()))
                    .build();
        }
        return sApplicationComponent;
    }

    public static BaseComponent getBaseComponent(){
        if(sBaseComponent == null){
            sBaseComponent = DaggerBaseComponent.builder()
                    .applicationComponent(getApplicationComponent())
                    .localModule(new MockLocalModule())
                    .networkModule(new MockNetworkModule())
                    .build();
        }
        return sBaseComponent;
    }

    public static TestClassInjector getTestClassInjector(){
        if(sTestClassInjector == null){
            sTestClassInjector = DaggerTestClassInjector.builder()
                    .baseComponent(getBaseComponent())
                    .build();
        }

        return sTestClassInjector;
    }

    public static void waitFor(IWaitingCallback callback){
        waitFor(10, callback);
    }

    public static void waitFor(int maxCycles, IWaitingCallback callback){
        while(true){
            maxCycles --;
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(callback.checkCondition()){
                break;
            }
            if(maxCycles <= 0){
                break;
            }
        }
    }

    public static interface IWaitingCallback{
        /**
         *
         * @return true if condition is met, false if we should keep waiting
         */
        public boolean checkCondition();
    }
}

================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/TestClassInjector.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger;

import dagger.Component;
import io.patrykpoborca.cleanarchitecture.dagger.mockmodules.MockTestModule;
import io.patrykpoborca.cleanarchitecture.tests.MVPCITest;
import io.patrykpoborca.cleanarchitecture.tests.MVPTest;
import io.patrykpoborca.cleanarchitecture.tests.MVVMTest;
import io.patrykpoborca.cleanarchitecture.dagger.components.BaseComponent;
import io.patrykpoborca.cleanarchitecture.dagger.scopes.ActivityScope;

@ActivityScope
@Component(dependencies = BaseComponent.class, modules = MockTestModule.class)
public interface TestClassInjector {
    void inject(MVVMTest test);

    void inject(MVPTest MVPTest);

    void inject(MVPCITest mvpciTest);

}


================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockLocalModule.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.mockmodules;

import android.app.Application;

import io.patrykpoborca.cleanarchitecture.dagger.modules.LocalModule;
import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockLocalDataCache;

public class MockLocalModule extends LocalModule{

    @Override
    protected LocalDataCache providesDataCache(Application application) {
        return new MockLocalDataCache(application);
    }
}


================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockNetworkModule.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.mockmodules;

import javax.inject.Named;

import io.patrykpoborca.cleanarchitecture.dagger.modules.NetworkModule;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockOkHTTP;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockRetrofit;
import io.patrykpoborca.cleanarchitecture.network.base.OKHttp;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.util.Constants;
import rx.Scheduler;

public class MockNetworkModule extends NetworkModule {

    @Override
    protected OKHttp providesOkHTTP() {
        return new MockOkHTTP();
    }

    @Override
    protected Retrofit providesRetrofit(OKHttp okHttp, @Named(Constants.MAIN_THREAD)Scheduler mainThread) {
        return new MockRetrofit(okHttp, mainThread);
    }
}


================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockTestModule.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.mockmodules;

import javax.inject.Named;

import dagger.Module;
import dagger.Provides;
import io.patrykpoborca.cleanarchitecture.dagger.scopes.ActivityScope;
import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockMVPCIPview;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockTweeterActivityPview;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockTweeterApi;
import io.patrykpoborca.cleanarchitecture.network.TweeterApi;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVP.TweeterMVPPresenterImpl;
import io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;
import io.patrykpoborca.cleanarchitecture.util.Constants;
import rx.Scheduler;

@Module
public class MockTestModule {

    @Provides
    @ActivityScope
    TweeterMVPPresenter providesMainPresenter(TweeterApi api, Retrofit retrofit) {
        return new TweeterMVPPresenterImpl(api, retrofit);
    }

    @ActivityScope
    @Provides
    public MockTweeterActivityPview providesMockMainPview(TweeterMVPPresenter presenter) {
        MockTweeterActivityPview mockTweeterActivityPview = new MockTweeterActivityPview();
        presenter.registerView(mockTweeterActivityPview);
        return mockTweeterActivityPview;
    }

    @ActivityScope
    @Provides
    public TweeterApi providesMockTweeter(Retrofit retrofit, LocalDataCache dataCache, @Named(Constants.MAIN_THREAD) Scheduler mainThread) {
        return new MockTweeterApi(retrofit, dataCache, mainThread);
    }

    @ActivityScope
    @Provides
    public MockMVPCIPview providesMockMVPCCIView(){
        return new MockMVPCIPview();
    }
}


================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockLocalDataCache.java
================================================
package io.patrykpoborca.cleanarchitecture.mockimpl;

import android.content.Context;

import java.util.List;

import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;
import rx.Observable;

public class MockLocalDataCache extends LocalDataCache {

    public MockLocalDataCache(Context context) {
        super(context);
    }

    @Override
    public void saveTweet(String tweet) {
        sPastTweets.add(tweet);
    }

    @Override
    public Observable<List<String>> fetchRecentTweets() {
        return Observable.just(sPastTweets)
                .map(arrayList -> {
                    List<String> list = arrayList;
                    return list;
                });
    }
}


================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockMVPCIPview.java
================================================
package io.patrykpoborca.cleanarchitecture.mockimpl;

import io.patrykpoborca.cleanarchitecture.ui.MVPCI.interfaces.TweeterActivityMVPCIPview;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;

public class MockMVPCIPview implements TweeterActivityMVPCIPview {

    public UserProfile loggedInProfile;
    public boolean loggedOutCalled = false;
    public boolean toggleProgresbarCalled = false;

    @Override
    public void loggedIn(UserProfile profile) {
        this.loggedInProfile = profile;
    }

    @Override
    public void loggedOut() {
        loggedOutCalled = true;
    }

    @Override
    public void toggleProgressBar(boolean loading) {
        toggleProgresbarCalled = true;
    }

    @Override
    public void displayToast(String toast) {

    }
}


================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockOkHTTP.java
================================================
package io.patrykpoborca.cleanarchitecture.mockimpl;

import io.patrykpoborca.cleanarchitecture.network.base.OKHttp;

public class MockOkHTTP extends OKHttp {
    @Override
    public String rawResponse() {
        return "Mocked raw response: ";
    }
}


================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockRetrofit.java
================================================
package io.patrykpoborca.cleanarchitecture.mockimpl;

import io.patrykpoborca.cleanarchitecture.network.base.OKHttp;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import rx.Observable;
import rx.Scheduler;

public class MockRetrofit extends Retrofit {
    private static final String MOCK_PARSE = "SomeMockResponse";
    public static final String MOCKED_STRING = "MOCKED PAGE:";

    public MockRetrofit(OKHttp okHttp, Scheduler mainScheduler) {
        super(okHttp, mainScheduler);
    }

    @Override
    public Observable<String> completeRequest() {
        return Observable.just(okHttp.rawResponse() + MOCK_PARSE)
                .observeOn(mainScheduler);
    }

    @Override
    public Observable<String> fetchSomePage(String url) {
        return Observable.just("<h2>" + MOCKED_STRING + " " + url + " </h2>")
                .observeOn(mainScheduler);
    }
}


================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockTweeterActivityPview.java
================================================
package io.patrykpoborca.cleanarchitecture.mockimpl;

import java.util.List;

import io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPView;

public class MockTweeterActivityPview implements TweeterMVPPView {

    public String fetchedTweet = null;
    public List<String> previousTweets = null;
    public boolean setUserButtonTextCalled = false;
    public boolean toggleProgressBarCalled = false;
    public boolean toggleLoginContainerCalled = false;
    public String displayWebpage = null;
    public boolean displayToastCalled = false;

    @Override
    public void displayFetchedTweet(String tweet) {
        fetchedTweet = tweet;
    }

    @Override
    public void displayPreviousTweets(List<String> list) {
        previousTweets = list;
    }

    @Override
    public void setUserButtonText(String text) {
        setUserButtonTextCalled = true;
    }

    @Override
    public void toggleLoginContainer(boolean b) {
        toggleLoginContainerCalled = true;
    }

    @Override
    public void displayWebpage(String html) {
        displayWebpage = html;
    }

    @Override
    public void toggleProgressBar(boolean loading) {
        toggleProgressBarCalled = true;
    }

    @Override
    public void displayToast(String toast) {
        displayToastCalled = true;
    }
}


================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockTweeterApi.java
================================================
package io.patrykpoborca.cleanarchitecture.mockimpl;

import android.util.Log;

import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;
import io.patrykpoborca.cleanarchitecture.network.TweeterApi;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;
import rx.Observable;
import rx.Scheduler;

public class MockTweeterApi extends TweeterApi{
    public MockTweeterApi(Retrofit retrofit, LocalDataCache dataCache, Scheduler mainScheduler) {
        super(retrofit, dataCache, mainScheduler);
    }

    @Override
    public Observable<UserProfile> login(String username, String password) {
        return Observable.just(new UserProfile(username, password));
    }

    @Override
    public Observable<Object> logout() {
        return Observable.just(null);
    }
}


================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/MVPCITest.java
================================================
package io.patrykpoborca.cleanarchitecture.tests;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import javax.inject.Inject;

import io.patrykpoborca.cleanarchitecture.TestHelper;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockLocalDataCache;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockMVPCIPview;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockOkHTTP;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockRetrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.TweeterMVPCIPresenter;

@RunWith(JUnit4.class)
public class MVPCITest {

    private static final String SOME_URL = "SOME_URL";
    private static final String USER_PASSWORD = "USER_PASSWORD";
    private static final String USER_NAME = "USER_NAME";
    private String tweetedTweet;

    @Inject
    TweeterMVPCIPresenter presenter;

    @Inject
    MockMVPCIPview pView;
    @Before
    public void setUp(){
        TestHelper.getTestClassInjector()
                .inject(this);
        presenter.registerPresenter(pView);

        junit.framework.Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);
        junit.framework.Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);
        junit.framework.Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);
    }

    @Test
    public void testWebPage(){
        presenter.loadWebPage(SOME_URL)
                .toBlocking()
                .forEach(s -> {
                    junit.framework.Assert.assertTrue(s.contains(MockRetrofit.MOCKED_STRING)
                            && s.contains(SOME_URL));
                });
    }

    @Test
    public void testLogin(){
        Assert.assertTrue(pView.loggedInProfile == null);
        presenter.toggleLogin(USER_NAME, USER_PASSWORD);
        TestHelper.waitFor(() -> pView.loggedInProfile != null);

        Assert.assertTrue(pView.loggedInProfile.getUserName().equals(USER_NAME));
        presenter.toggleLogin(USER_NAME, USER_PASSWORD);
        TestHelper.waitFor(() -> pView.loggedOutCalled);
        Assert.assertTrue(pView.loggedOutCalled);
    }

    @Test
    public void testTweets() {
        //Sanity test first to see if underlying logic of tweeter api has changed
        presenter.fetchPreviousTweets()
                .toBlocking()
                .forEach(list -> {
                    Assert.assertNotNull(list);
                });

    }

    @Test
    public void testTweetList(){
        presenter.fetchCurrentTweet()
                .toBlocking()
                .forEach(tweet -> {
                    tweetedTweet = tweet;
                });

        presenter.fetchPreviousTweets()
                .toBlocking()
                .forEach(list -> {
                    boolean exists = false;

                    for (int i = 0; i < list.size(); i++) {
                        if (tweetedTweet.contains(list.get(i))) {
                            exists = true;
                            break;
                        }
                    }
                    Assert.assertTrue(exists);
                });
    }

}


================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/MVPTest.java
================================================
package io.patrykpoborca.cleanarchitecture.tests;

import android.support.test.runner.AndroidJUnit4;

import junit.framework.Assert;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import javax.inject.Inject;

import io.patrykpoborca.cleanarchitecture.TestHelper;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockLocalDataCache;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockTweeterActivityPview;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockOkHTTP;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockRetrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;

@RunWith(AndroidJUnit4.class)
public class MVPTest {

    private static final String SOME_URL = "SOME_URL";
    private static final String USER_PASSWORD = "USER_PASSWORD";
    private static final String USER_NAME = "USER_NAME";

    @Inject
    MockTweeterActivityPview pView;

    @Inject
    TweeterMVPPresenter presenter;

    @Before
    public void setUp(){
        TestHelper.getTestClassInjector()
                .inject(this);
        Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);
        Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);
        Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);
    }


    @Test
    public void testLogin(){
        presenter.toggleLogin(USER_NAME, USER_PASSWORD);
        TestHelper.waitFor(() -> pView.toggleLoginContainerCalled);
        Assert.assertTrue(pView.toggleLoginContainerCalled);

        pView.toggleLoginContainerCalled = false;

        presenter.toggleLogin(USER_NAME, USER_PASSWORD);
        TestHelper.waitFor(() -> pView.toggleLoginContainerCalled);
        Assert.assertTrue(pView.toggleLoginContainerCalled);
    }

    @Test
    public void testFetchTweets(){
        presenter.fetchCurrentTweet();
        TestHelper.waitFor(() -> pView.fetchedTweet != null);
        String tweet = pView.fetchedTweet;

        presenter.fetchPreviousTweets();
        TestHelper.waitFor(() -> pView.previousTweets != null);
        boolean found = false;
        for(int i=0; i < pView.previousTweets.size(); i++){
            found = tweet.contains(pView.previousTweets.get(i));
            if(found){
                break;
            }
        }
        Assert.assertTrue(found);
    }

    @Test
    public void testWebPage() {
        presenter.loadWebPage(SOME_URL);

        TestHelper.waitFor(() -> pView.displayWebpage != null);
        String webPage = pView.displayWebpage;
        Assert.assertTrue(webPage.contains(SOME_URL));
    }

}


================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/MVVMTest.java
================================================
package io.patrykpoborca.cleanarchitecture.tests;

import android.support.test.runner.AndroidJUnit4;

import junit.framework.Assert;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import javax.inject.Inject;

import io.patrykpoborca.cleanarchitecture.TestHelper;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockLocalDataCache;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockOkHTTP;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockRetrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVVM.MainViewModel;

@RunWith(AndroidJUnit4.class)
public class MVVMTest {

    private static final String SOME_URL = "SOME_URL";
    private static final String USER_PASSWORD = "USER_PASSWORD";
    private static final String USER_NAME = "USER_NAME";
    private String tweetedTweet;

    @Inject
    MainViewModel viewModel;

    @Before
    public void setUp() {
        TestHelper.getTestClassInjector()
                .inject(this);

        Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);
        Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);
        Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);
    }


    @Test
    public void testWebPage() {
        viewModel.loadWebPage(SOME_URL)
                .toBlocking()
                .forEach(s -> {
                    Assert.assertTrue(s.contains(MockRetrofit.MOCKED_STRING)
                            && s.contains(SOME_URL));
                });
    }

    @Test
    public void testLogin() {
        Assert.assertFalse(viewModel.isLoggedIn());
        viewModel.toggleLogin(USER_NAME, USER_PASSWORD)
                .toBlocking()
                .forEach(
                        user -> {
                            Assert.assertNotNull(user);
                            Assert.assertEquals(user.getUserName(), USER_NAME);
                        }
                );
        Assert.assertTrue(viewModel.isLoggedIn());
    }

    @Test
    public void testTweets() {
        //Sanity test first to see if underlying logic of tweeter api has changed
        viewModel.fetchPreviousTweets()
                .toBlocking()
                .forEach(list -> {
                    Assert.assertNotNull(list);
                });

    }

    @Test
    public void testTweetList() {

        viewModel.fetchCurrentTweet()
                .toBlocking()
                .forEach(tweet -> {
                    tweetedTweet = tweet;
                });

        viewModel.fetchPreviousTweets()
                .toBlocking()
                .forEach(list -> {
                    boolean exists = false;

                    for (int i = 0; i < list.size(); i++) {
                        if (tweetedTweet.contains(list.get(i))) {
                            exists = true;
                            break;
                        }
                    }
                    Assert.assertTrue(exists);
                });
    }

}


================================================
FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/PlainTweeterTest.java
================================================
package io.patrykpoborca.cleanarchitecture.tests;

import android.support.test.espresso.matcher.ViewMatchers;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import junit.framework.Assert;

import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import io.patrykpoborca.cleanarchitecture.R;
import io.patrykpoborca.cleanarchitecture.TestHelper;
import io.patrykpoborca.cleanarchitecture.dagger.components.DaggerActivityInjectorComponent;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockLocalDataCache;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockOkHTTP;
import io.patrykpoborca.cleanarchitecture.mockimpl.MockRetrofit;

import static android.support.test.espresso.action.ViewActions.scrollTo;
import static android.support.test.espresso.action.ViewActions.typeText;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.matcher.ViewMatchers.withText;

@RunWith(AndroidJUnit4.class)
public class PlainTweeterTest {

    @Rule
    public ActivityTestRule<io.patrykpoborca.cleanarchitecture.ui.PlainTweeterActivity> plainTweeterActivity = new ActivityTestRule<>(io.patrykpoborca.cleanarchitecture.ui.PlainTweeterActivity.class,
            false,
            true);

    private static final String SOME_URL = "SOME_URL";
    private static final String USER_PASSWORD = "USER_PASSWORD";
    private static final String USER_NAME = "USER_NAME";
    private String fetchedTweet;

    @Before
    public void setUp() {
        DaggerActivityInjectorComponent
                .builder()
                .baseComponent(TestHelper.getBaseComponent())
                .build()
                .inject(plainTweeterActivity.getActivity());

        Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);
        Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);
        Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);

    }

    @Test
    public void testWebpage(){
        onView(withId(R.id.some_url))
                .perform(typeText(SOME_URL));

        onView(withId(R.id.some_url))
                .check(matches(new TypeSafeMatcher<View>() {
                    @Override
                    protected boolean matchesSafely(View item) {
                        TextView text = ((TextView) item);
                        return text.getText().toString().contains(SOME_URL);
                    }

                    @Override
                    public void describeTo(Description description) {

                    }
                }));


        onView(withId(R.id.request_website_button))
                .perform(click());

        onView(withId(R.id.webpage_text))
                .check(matches(new TypeSafeMatcher<View>(){
                    @Override
                    protected boolean matchesSafely(View item) {
                        TextView text = ((TextView)item);
                        return text.getText().toString().contains(SOME_URL);
                    }

                    @Override
                    public void describeTo(Description description) {

                    }
                }));
    }

    @Test
    public void testLogin(){
        onView(withId(R.id.user_name))
                .perform(typeText(USER_NAME));

        onView(withId(R.id.user_password))
                .perform(scrollTo())
                .perform(typeText(USER_PASSWORD));

        //login
        onView(withId(R.id.user_login_button))
                .perform(scrollTo())
                .perform(click());

        onView(withId(R.id.container))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));

        //logout
        onView(withId(R.id.user_login_button))
                .perform(click());

        onView(withId(R.id.container))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
    }

    @Test
    public void testTweets(){
        onView(withId(R.id.current_tweet)).check(matches(withText(R.string.hello_world)));
        onView(withId(R.id.fetch_tweet_button))
                .perform(scrollTo())
                .perform(click());

        onView(withId(R.id.current_tweet)).check(matches(new TypeSafeMatcher<View>() {
            @Override
            protected boolean matchesSafely(View item) {
                boolean result = item instanceof TextView
                        && !((TextView) item).getText().toString().contains(plainTweeterActivity.getActivity().getResources().getString(R.string.hello_world));
                fetchedTweet = ((TextView) item).getText().toString();

                return result;
            }

            @Override
            public void describeTo(Description description) {

            }
        }));

        onView(withId(R.id.fetch_last_two_tweets)).perform(click());

        onView(withId(R.id.past_tweets_container)).check(matches(new TypeSafeMatcher<View>() {
            @Override
            protected boolean matchesSafely(View item) {
                ViewGroup parent = ((ViewGroup) item);

                for (int i = 0; i < parent.getChildCount(); i++) {
                    TextView textView = (TextView) parent.getChildAt(i);
                    if (fetchedTweet.contains(textView.getText().toString())) {
                        return true;
                    }
                }

                return false;
            }

            @Override
            public void describeTo(Description description) {

            }
        }));
    }

}


================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="io.patrykpoborca.cleanarchitecture" >

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        android:name=".CleanArchitectureApplication">
        <activity
            android:name=".ui.PlainTweeterActivity"
            android:label="@string/app_name" >
        </activity>

        <activity
            android:name=".ui.MVP.TweeterActivityMVP"
            android:label="@string/app_name" >
        </activity>

        <activity android:name=".ui.RouterActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name=".ui.MVPCI.TweeterActivityMVPCI"/>

        <activity android:name=".ui.MVVM.TweeterActivityMVVM"/>
    </application>

</manifest>


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/CleanArchitectureApplication.java
================================================
package io.patrykpoborca.cleanarchitecture;

import android.app.Application;

import io.patrykpoborca.cleanarchitecture.dagger.components.ApplicationComponent;
import io.patrykpoborca.cleanarchitecture.dagger.components.BaseComponent;
import io.patrykpoborca.cleanarchitecture.dagger.components.DaggerApplicationComponent;
import io.patrykpoborca.cleanarchitecture.dagger.components.DaggerBaseComponent;
import io.patrykpoborca.cleanarchitecture.dagger.modules.ApplicationModule;


public class CleanArchitectureApplication extends Application{

    private static BaseComponent sBaseComponent;

    @Override
    public void onCreate() {
        super.onCreate();

        ApplicationComponent applicationComponent = DaggerApplicationComponent
                                        .builder()
                                        .applicationModule(new ApplicationModule(this))
                                        .build();
        sBaseComponent = DaggerBaseComponent.builder()
                .applicationComponent(applicationComponent)
                .build();
    }
    public static BaseComponent getBaseComponent(){
        return sBaseComponent;
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/components/ActivityInjectorComponent.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.components;

import dagger.Component;
import io.patrykpoborca.cleanarchitecture.dagger.modules.PresenterModule;
import io.patrykpoborca.cleanarchitecture.dagger.scopes.ActivityScope;
import io.patrykpoborca.cleanarchitecture.ui.MVP.TweeterActivityMVP;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.TweeterActivityMVPCI;
import io.patrykpoborca.cleanarchitecture.ui.MVVM.TweeterActivityMVVM;
import io.patrykpoborca.cleanarchitecture.ui.PlainTweeterActivity;

/**
 * Created by Patryk on 7/28/2015.
 */
@ActivityScope
@Component(dependencies = {BaseComponent.class}, modules = PresenterModule.class)
public interface ActivityInjectorComponent {

    void inject(PlainTweeterActivity activity);

    void inject(TweeterActivityMVP activityMVP);

    void inject(TweeterActivityMVVM activityMVVM);

    void inject(TweeterActivityMVPCI activityMVPCI);
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/components/ApplicationComponent.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.components;

import android.app.Application;

import javax.inject.Singleton;

import dagger.Component;
import io.patrykpoborca.cleanarchitecture.dagger.modules.ApplicationModule;
import io.patrykpoborca.cleanarchitecture.dagger.scopes.ApplicationScope;


@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
    Application getApplication();

}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/components/BaseComponent.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.components;

import javax.inject.Named;
import javax.inject.Singleton;

import dagger.Component;
import io.patrykpoborca.cleanarchitecture.dagger.modules.LocalModule;
import io.patrykpoborca.cleanarchitecture.dagger.modules.NetworkModule;
import io.patrykpoborca.cleanarchitecture.dagger.modules.ThreadingModule;
import io.patrykpoborca.cleanarchitecture.dagger.scopes.ApplicationScope;
import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;
import io.patrykpoborca.cleanarchitecture.network.base.OKHttp;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.util.Constants;
import rx.Scheduler;



// AppModule [Application] |AppComponent| <- BaseComponent needs that stuff..
@ApplicationScope
@Component(modules = {LocalModule.class, NetworkModule.class, ThreadingModule.class}, dependencies = ApplicationComponent.class)
public interface BaseComponent {

    OKHttp getOkHTTP();

    Retrofit getRetrofit();

    LocalDataCache getLocalDataCache();

    @Named(Constants.MAIN_THREAD)
    Scheduler getMainScheduler();
}

================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/interactors/NetworkInteractor.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.interactors;

import java.util.List;

import javax.inject.Inject;

import io.patrykpoborca.cleanarchitecture.dagger.interactors.base.BaseInteractor;
import io.patrykpoborca.cleanarchitecture.network.TweeterApi;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;
import rx.Observable;

/**
 * Created by Patryk on 7/29/2015.
 */
public class NetworkInteractor extends BaseInteractor {


    private final Retrofit retrofit;
    private final TweeterApi tweeterAPI;

    @Inject
    public NetworkInteractor(Retrofit retrofit, TweeterApi api){
        this.retrofit = retrofit;
        this.tweeterAPI = api;
    }

    public Observable<UserProfile> attemptLogin(String username, String password) {
        return tweeterAPI.login(username, password);
    }

    public Observable<Object> logout(){
        return tweeterAPI.logout();
    }

    public Observable<String> fetchTweet() {
        return tweeterAPI.getTweet();
    }

    public Observable<List<String>> fetchTweets(int count) {
        return tweeterAPI.fetchXrecents(count);
    }

    public Observable<String> loadWebpage(String url){
        return retrofit.fetchSomePage(url);
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/interactors/base/BaseInteractor.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.interactors.base;

public class BaseInteractor {
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/ApplicationModule.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.modules;

import android.app.Application;
import android.content.Context;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;
import io.patrykpoborca.cleanarchitecture.dagger.scopes.ApplicationScope;


@Module
public class ApplicationModule {

    private static Application sApplication;

    public ApplicationModule(Application application) {
        sApplication = application;
    }

    @Singleton
    @Provides
    Application providesApplication(){
        return sApplication;
    }

}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/InteractorModule.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.modules;

import dagger.Module;
import dagger.Provides;
import io.patrykpoborca.cleanarchitecture.dagger.interactors.NetworkInteractor;
import io.patrykpoborca.cleanarchitecture.network.TweeterApi;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;

/**
 * Created by Patryk on 7/31/2015.
 */
@Module
public class InteractorModule {

    @Provides
    NetworkInteractor providesNetworkInteractor(Retrofit retrofit, TweeterApi api){
        return new NetworkInteractor(retrofit, api);
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/LocalModule.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.modules;

import android.app.Application;
import android.content.Context;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;
import io.patrykpoborca.cleanarchitecture.dagger.scopes.ApplicationScope;
import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;


@Module
public class LocalModule {

    @ApplicationScope
    @Provides
    protected LocalDataCache providesDataCache(Application application){
        return new LocalDataCache(application);
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/NetworkModule.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.modules;

import javax.inject.Named;
import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;
import io.patrykpoborca.cleanarchitecture.dagger.scopes.ApplicationScope;
import io.patrykpoborca.cleanarchitecture.network.base.OKHttp;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.util.Constants;
import rx.Scheduler;


@Module
public class NetworkModule {

    @ApplicationScope
    @Provides
    protected OKHttp providesOkHTTP(){
        return new OKHttp();
    }

    @ApplicationScope
    @Provides
    protected Retrofit providesRetrofit(OKHttp okHttp, @Named(Constants.MAIN_THREAD) Scheduler mainThread) {
        return new Retrofit(okHttp, mainThread);
    }
}

================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/PresenterModule.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.modules;

import dagger.Module;
import dagger.Provides;
import io.patrykpoborca.cleanarchitecture.dagger.scopes.ActivityScope;
import io.patrykpoborca.cleanarchitecture.network.TweeterApi;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVP.TweeterMVPPresenterImpl;
import io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;

@Module
public class PresenterModule {

    @Provides
    @ActivityScope
    TweeterMVPPresenter providesMainPresenter(TweeterApi api, Retrofit retrofit){
        return new TweeterMVPPresenterImpl(api, retrofit);
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/ThreadingModule.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.modules;

import javax.inject.Named;

import dagger.Module;
import dagger.Provides;
import io.patrykpoborca.cleanarchitecture.util.Constants;
import rx.Scheduler;
import rx.android.schedulers.AndroidSchedulers;

@Module
public class ThreadingModule {
    @Named(Constants.MAIN_THREAD)
    @Provides
    public Scheduler providesMainThread(){
        return AndroidSchedulers.mainThread();
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/scopes/ActivityScope.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.scopes;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import javax.inject.Scope;

@Retention(RetentionPolicy.RUNTIME)
@Scope
public @interface ActivityScope {
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/scopes/ApplicationScope.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.scopes;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import javax.inject.Scope;

@Retention(RetentionPolicy.RUNTIME)
@Scope
public @interface ApplicationScope {
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/scopes/ExposedAPIScope.java
================================================
package io.patrykpoborca.cleanarchitecture.dagger.scopes;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import javax.inject.Scope;

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ExposedAPIScope {
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/localdata/LocalDataCache.java
================================================
package io.patrykpoborca.cleanarchitecture.localdata;

import android.content.Context;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import rx.Observable;


public class LocalDataCache {

    //pretend this is some read/write to disk :)
    protected static ArrayList<String> sPastTweets;
    private Context context;

    public LocalDataCache(Context context) {
        this.context = context;
        sPastTweets = new ArrayList<>();
    }

    public void saveTweet(String tweet) {
        sPastTweets.add(tweet);
    }

    public Observable<List<String>> fetchRecentTweets() {
        return Observable.just(sPastTweets)
                .map(arrayList -> {
                    List<String> list = arrayList;
                    return list;
                })
                .delay(2, TimeUnit.SECONDS);
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/network/TweeterApi.java
================================================
package io.patrykpoborca.cleanarchitecture.network;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.inject.Inject;
import javax.inject.Named;

import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;
import io.patrykpoborca.cleanarchitecture.util.Constants;
import rx.Observable;
import rx.Scheduler;


public class TweeterApi {

    protected final Scheduler mainScheduler;
    Retrofit retrofit;
    LocalDataCache localDataCache;
    private UserProfile userName;

    @Inject
    public TweeterApi(Retrofit retro, LocalDataCache cache, @Named(Constants.MAIN_THREAD) Scheduler mainScheduler) {
        this.localDataCache = cache;
        this.retrofit = retro;
        this.mainScheduler = mainScheduler;
    }

    public Observable<String> getTweet(){
        return retrofit.completeRequest()
                .map(tweet -> {
                    localDataCache.saveTweet(tweet);

                    if (isLoggedIn()) {
                        tweet = userName.getUserName() + " -> " + tweet;
                    }
                    else {
                        tweet = "Some user -> " + tweet;
                    }

                    return tweet;
                })
                .observeOn(mainScheduler);
    }

    public Observable<List<String>> fetchXrecents(int count){

        return localDataCache.fetchRecentTweets()
                .map(list ->{
                    List<String> tweets = new ArrayList<>(count);
                    int size = list.size() <= count ? list.size() : count;
                    for(int i=list.size() -1; i >= 0 && size > tweets.size(); i--){
                        tweets.add(list.get(i));
                    }
                    return tweets;
                })
                .observeOn(mainScheduler);
    }

    public Observable<UserProfile> login(String username, String password) {

        Observable<UserProfile> observable = Observable.just(new UserProfile(username, password))
                .delay(2, TimeUnit.SECONDS)
                .observeOn(mainScheduler);
        
        observable.subscribe(user -> this.userName = user);
        return observable;
    }

    public Observable<Object> logout(){
        userName = null;
        return Observable.just(null)
                .delay(2, TimeUnit.SECONDS)
                .observeOn(mainScheduler);
    }

    public boolean isLoggedIn(){
        return this.userName != null;
    }

}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/network/base/OKHttp.java
================================================
package io.patrykpoborca.cleanarchitecture.network.base;

import java.util.UUID;


public class OKHttp {

    public String rawResponse(){
        return UUID.randomUUID().toString();
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/network/base/Retrofit.java
================================================
package io.patrykpoborca.cleanarchitecture.network.base;

import java.util.concurrent.TimeUnit;

import rx.Observable;
import rx.Scheduler;
import rx.android.schedulers.AndroidSchedulers;

public class Retrofit {

    protected OKHttp okHttp;
    protected final Scheduler mainScheduler;
    public Retrofit(OKHttp okHttp, Scheduler mainScheduler) {
        this.okHttp = okHttp;
        this.mainScheduler = mainScheduler;
    }

    public Observable<String> completeRequest(){
        return Observable.just(okHttp.rawResponse() + " Some Parsing Done")
                .delay(2, TimeUnit.SECONDS);
    }

    public Observable<String> fetchSomePage(String url){
        return Observable.just("<h2>" + "Fake response from fake retrofit: " + url + " </h2>")
                .delay(2, TimeUnit.SECONDS)
                .observeOn(mainScheduler);
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/BaseCleanArchitectureActivity.java
================================================
package io.patrykpoborca.cleanarchitecture.ui;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import java.util.ArrayList;
import java.util.List;

import rx.Subscription;

public class BaseCleanArchitectureActivity extends AppCompatActivity{

    private List<Subscription> subscriptions;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(subscriptions == null){
            subscriptions = new ArrayList<>();
        }
    }

    protected void registerSubscription(Subscription subscription){
        subscriptions.add(subscription);
    }

    @Override
    protected void onStop() {
        super.onStop();
        unsubscribeSubscriptions();
    }

    protected void unsubscribeSubscriptions(){
        for(int i= 0; i < subscriptions.size(); i++){
            subscriptions.get(i).unsubscribe();
        }
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/TweeterActivityMVP.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVP;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.text.Html;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

import javax.inject.Inject;

import butterknife.Bind;
import butterknife.ButterKnife;
import io.patrykpoborca.cleanarchitecture.CleanArchitectureApplication;
import io.patrykpoborca.cleanarchitecture.R;
import io.patrykpoborca.cleanarchitecture.dagger.components.DaggerActivityInjectorComponent;
import io.patrykpoborca.cleanarchitecture.ui.MVP.base.BasePresenterActivity;
import io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPView;
import io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;
import io.patrykpoborca.cleanarchitecture.util.Utility;


public class TweeterActivityMVP extends BasePresenterActivity<TweeterMVPPresenter> implements TweeterMVPPView {

    @Inject
    TweeterMVPPresenter presenter;

    @Bind(R.id.fetch_tweet_button) Button fetchTweetButton;
    @Bind(R.id.fetch_last_two_tweets) Button fetchLastTwoButton;
    @Bind(R.id.current_tweet) TextView currentTweetTextView;
    @Bind(R.id.past_tweets_container) LinearLayout pastTweetContainer;
    @Bind(R.id.user_login_button) Button loginButton;
    @Bind(R.id.user_name) TextView userNameTextView;
    @Bind(R.id.user_password) TextView userPasswordTextView;
    @Bind(R.id.container) ViewGroup container;
    @Bind(R.id.some_url) EditText urlText;
    @Bind(R.id.webpage_text) TextView websiteText;
    @Bind(R.id.request_website_button) Button websiteFetchbutton;
    @Bind(R.id.help_history) View helpHistory;
    @Bind(R.id.help_login) View helpLogin;
    @Bind(R.id.help_url) View helpUrl;

    private View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(view == fetchLastTwoButton){
                getPresenter().fetchPreviousTweets();
            }
            else if(view == fetchTweetButton){
                getPresenter().fetchCurrentTweet();
            }
            else if(view == loginButton){
                getPresenter().toggleLogin(userNameTextView.getText().toString(),
                                    userPasswordTextView.getText().toString());
            }
            else if(view == websiteFetchbutton){
                getPresenter().loadWebPage(urlText.getText().toString());
            }

        }
    };

    private final View.OnClickListener dialogClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(view == helpHistory){
                new AlertDialog.Builder(TweeterActivityMVP.this)
                        .setMessage(R.string.history_text)
                        .setPositiveButton("Ok", null)
                        .create()
                        .show();
            }
            else if(view == helpUrl){
                new AlertDialog.Builder(TweeterActivityMVP.this)
                        .setMessage(R.string.url_text)
                        .setPositiveButton("Ok", null)
                        .create()
                        .show();
            }
            else if(view == helpLogin){
                new AlertDialog.Builder(TweeterActivityMVP.this)
                        .setMessage(R.string.login_text)
                        .setPositiveButton("Ok", null)
                        .create()
                        .show();
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        this.fetchLastTwoButton.setOnClickListener(onClickListener);
        this.fetchTweetButton.setOnClickListener(onClickListener);
        this.loginButton.setOnClickListener(onClickListener);
        this.websiteFetchbutton.setOnClickListener(onClickListener);
        this.helpHistory.setOnClickListener(dialogClickListener);
        this.helpLogin.setOnClickListener(dialogClickListener);
        this.helpUrl.setOnClickListener(dialogClickListener);
        setTitle("MVP Activity IMPL");
    }

    @Override
    protected TweeterMVPPresenter getPresenter() {
        if(presenter == null){

            DaggerActivityInjectorComponent.builder()
                    .baseComponent(CleanArchitectureApplication.getBaseComponent())
                    .build()
                    .inject(this);
        }

        return presenter;
    }



    @Override
    public void displayFetchedTweet(String tweet) {
        currentTweetTextView.setText(tweet);
    }

    @Override
    public void displayPreviousTweets(List<String> tweets) {
        pastTweetContainer.removeAllViews(); //clear container...
        for(int i= 0;  i < tweets.size(); i++){
            TextView text = new TextView(this);
            text.setText(tweets.get(i));
            pastTweetContainer.addView(text);
        }
    }

    @Override
    protected void registerViewToPresenter() {
        getPresenter().registerView(this);
    }

    @Override
    public void displayToast(String toast) {
        Toast.makeText(this, toast, Toast.LENGTH_LONG).show();
    }

    @Override
    public void toggleProgressBar(boolean loading) {
        Utility.toggleProgressbar(this, loading);
    }

    @Override
    public void setUserButtonText(String text) {
        this.loginButton.setText(text);
    }

    @Override
    public void toggleLoginContainer(boolean b) {
        container.setVisibility(b ? View.VISIBLE : View.GONE);
    }

    @Override
    public void displayWebpage(String html) {
        websiteText.setText(Html.fromHtml(html));
    }

    public static Intent newInstance(Context context) {
        return new Intent(context, TweeterActivityMVP.class);
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/TweeterMVPPresenterImpl.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVP;

import io.patrykpoborca.cleanarchitecture.network.TweeterApi;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPView;
import io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;

/**
 * Created by Patryk on 7/28/2015.
 */
public class TweeterMVPPresenterImpl implements TweeterMVPPresenter {

    private static final int TWEET_COUNT = 2;
    private final TweeterApi tweeterApi;
    private final Retrofit retrofit;
    private TweeterMVPPView mainMVPView;
    private int tweetsAdded = 0;


    public TweeterMVPPresenterImpl(TweeterApi tweeterApi, Retrofit retrofit) {
        this.tweeterApi = tweeterApi;
        this.retrofit = retrofit;
    }

    @Override
    public void registerView(TweeterMVPPView activity) {
        this.mainMVPView = activity;
    }

    @Override
    public void onAttach() {

    }

    @Override
    public void onDetach() {

    }

    @Override
    public void fetchCurrentTweet() {
        mainMVPView.toggleProgressBar(true);
        tweeterApi.getTweet().subscribe(s -> {
            mainMVPView.toggleProgressBar(false);
            tweetsAdded ++;
            if(tweetsAdded > TWEET_COUNT){
                mainMVPView.displayToast("Tweet size exceeded " + TWEET_COUNT);
            }
            this.mainMVPView.displayFetchedTweet(s);
        });
    }

    @Override
    public void fetchPreviousTweets() {

        mainMVPView.toggleProgressBar(true);
        tweeterApi.fetchXrecents(TWEET_COUNT)
                .subscribe(l -> {
                    mainMVPView.displayPreviousTweets(l);
                    mainMVPView.toggleProgressBar(false);
                });
    }

    @Override
    public void toggleLogin(String userName, String userPassword) {
        mainMVPView.toggleProgressBar(true);
        if(tweeterApi.isLoggedIn()){
            tweeterApi.logout()
                    .subscribe(s -> {
                        mainMVPView.toggleProgressBar(false);
                        mainMVPView.setUserButtonText("Login");
                        mainMVPView.displayToast("User logged out");
                        mainMVPView.toggleLoginContainer(true);
                        //could implement more literal less reusable methods, such as loggedIn and loggedOut such as in the MVPCI example.
                        //However I wanted to be extremely verbose in the MVP example.
                    });
        }
        else {
            this.tweeterApi.login(userName, userPassword)
                    .subscribe(userProfile -> {
                        mainMVPView.displayToast(userProfile.getFormattedCredentials() + " Logged in");
                        mainMVPView.setUserButtonText("Log " + userProfile.getUserName() + " out");
                        mainMVPView.toggleProgressBar(false);
                        mainMVPView.toggleLoginContainer(false);
                    });
        }
    }

    @Override
    public void loadWebPage(String url) {
        mainMVPView.toggleProgressBar(true);
        retrofit.fetchSomePage(url)
                .subscribe(s -> {
                    mainMVPView.displayWebpage(s);
                    mainMVPView.toggleProgressBar(false);
                });
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/base/BasePresenterActivity.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVP.base;

import android.os.Bundle;

import io.patrykpoborca.cleanarchitecture.ui.BaseCleanArchitectureActivity;
import io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces.PView;
import io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces.Presenter;

/**
 * Created by Patryk on 7/28/2015.
 */
public abstract class BasePresenterActivity<T extends Presenter> extends BaseCleanArchitectureActivity implements PView {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getPresenter().registerView(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        getPresenter().onAttach();
    }

    @Override
    protected void onPause() {
        super.onPause();
        getPresenter().onDetach();
    }

    protected abstract void registerViewToPresenter();
    protected abstract T getPresenter();
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/base/Interfaces/PView.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces;

/**
 * Created by Patryk on 7/28/2015.
 */
public interface PView {

    public void toggleProgressBar(boolean loading);

    public void displayToast(String toast);
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/base/Interfaces/Presenter.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces;

/**
 * Created by Patryk on 7/28/2015.
 */
public interface Presenter<T extends PView> {

    public void registerView(T activity);
    public void onAttach();
    public void onDetach();
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/interfaces/TweeterMVPPView.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces;

import java.util.List;

import io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces.PView;

/**
 * Created by Patryk on 7/28/2015.
 */
public interface TweeterMVPPView extends PView {
    public void displayFetchedTweet(String tweet);

    public void displayPreviousTweets(List<String> list);

    public void setUserButtonText(String text);

    void toggleLoginContainer(boolean b);

    void displayWebpage(String html);
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/interfaces/TweeterMVPPresenter.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces;

import io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces.Presenter;

/**
 * Created by Patryk on 7/28/2015.
 */
    public interface TweeterMVPPresenter extends Presenter<TweeterMVPPView> {

    public void fetchCurrentTweet();

    public void fetchPreviousTweets();

    public void toggleLogin(String userName, String userPassword);

    void loadWebPage(String url);
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/TweeterActivityMVPCI.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVPCI;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.text.Html;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

import javax.inject.Inject;

import butterknife.Bind;
import butterknife.ButterKnife;
import io.patrykpoborca.cleanarchitecture.CleanArchitectureApplication;
import io.patrykpoborca.cleanarchitecture.R;
import io.patrykpoborca.cleanarchitecture.dagger.components.DaggerActivityInjectorComponent;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.base.BasePresenterActivityMVPCI;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.interfaces.TweeterActivityMVPCIPview;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;
import io.patrykpoborca.cleanarchitecture.util.Utility;



/**
 * 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
 * circumvents a lot of unecessary boilerplate.
 *  Model <- Presenter -> View
 */
public class TweeterActivityMVPCI extends BasePresenterActivityMVPCI<TweeterMVPCIPresenter> implements TweeterActivityMVPCIPview {

    @Bind(R.id.fetch_tweet_button) Button fetchTweetButton;
    @Bind(R.id.fetch_last_two_tweets) Button fetchLastTwoButton;
    @Bind(R.id.current_tweet) TextView currentTweetTextView;
    @Bind(R.id.past_tweets_container) LinearLayout pastTweetContainer;
    @Bind(R.id.user_login_button) Button loginButton;
    @Bind(R.id.user_name) TextView userNameTextView;
    @Bind(R.id.user_password) TextView userPasswordTextView;
    @Bind(R.id.container) ViewGroup container;
    @Bind(R.id.some_url) EditText urlText;
    @Bind(R.id.webpage_text) TextView websiteText;
    @Bind(R.id.request_website_button) Button websiteFetchbutton;
    @Bind(R.id.help_history) View helpHistory;
    @Bind(R.id.help_login) View helpLogin;
    @Bind(R.id.help_url) View helpUrl;

    @Inject
    TweeterMVPCIPresenter presenter;

    private final View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(view == fetchTweetButton){
                registerSubscription(
                        getPresenter().fetchCurrentTweet().subscribe(s -> currentTweetTextView.setText(s)));
            }
            else if(view == fetchLastTwoButton){
                pastTweetContainer.removeAllViews(); //clear container...
                registerSubscription(
                        getPresenter().fetchPreviousTweets().subscribe(TweeterActivityMVPCI.this::displayTweets)
                );
            }
            else if(view == loginButton){
                getPresenter().toggleLogin(userNameTextView.getText().toString(), userPasswordTextView.getText().toString());
            }
            else if(view == websiteFetchbutton){
                registerSubscription(getPresenter().loadWebPage(urlText.getText().toString())
                        .subscribe(s -> websiteText.setText(Html.fromHtml(s))));
            }
        }
    };

    private final View.OnClickListener dialogClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(view == helpHistory){
                new AlertDialog.Builder(TweeterActivityMVPCI.this)
                        .setMessage(R.string.history_text)
                        .setPositiveButton("Ok", null)
                        .create()
                        .show();
            }
            else if(view == helpUrl){
                new AlertDialog.Builder(TweeterActivityMVPCI.this)
                        .setMessage(R.string.url_text)
                        .setPositiveButton("Ok", null)
                        .create()
                        .show();
            }
            else if(view == helpLogin){
                new AlertDialog.Builder(TweeterActivityMVPCI.this)
                        .setMessage(R.string.login_text)
                        .setPositiveButton("Ok", null)
                        .create()
                        .show();
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        this.fetchLastTwoButton.setOnClickListener(onClickListener);
        this.fetchTweetButton.setOnClickListener(onClickListener);
        this.loginButton.setOnClickListener(onClickListener);
        this.websiteFetchbutton.setOnClickListener(onClickListener);
        this.helpHistory.setOnClickListener(dialogClickListener);
        this.helpLogin.setOnClickListener(dialogClickListener);
        this.helpUrl.setOnClickListener(dialogClickListener);
        setTitle("MVPCI activity");
    }

    @Override
    protected TweeterMVPCIPresenter getPresenter() {

        if(presenter == null){
            DaggerActivityInjectorComponent.builder()
                    .baseComponent(CleanArchitectureApplication.getBaseComponent())
                    .build()
                    .inject(this);
        }

        return presenter;
    }

    @Override
    public void displayToast(String toast) {
        Toast.makeText(this, toast, Toast.LENGTH_LONG).show();
    }

    private void displayTweets(List<String> list) {
        pastTweetContainer.removeAllViews();

        for(int i= 0; i < list.size(); i++){
            TextView textView = new TextView(this);
            textView.setText(list.get(i));
            pastTweetContainer.addView(textView);
        }
    }

    @Override
    public void toggleProgressBar(boolean show) {
        Utility.toggleProgressbar(this, show);
    }


    @Override
    public void loggedIn(UserProfile profile) {
        Toast.makeText(this, (profile.getFormattedCredentials() + " Logged in"), Toast.LENGTH_SHORT).show();
        loginButton.setText("Log " + profile.getUserName() + " out");
        container.setVisibility(View.GONE);
    }

    @Override
    public void loggedOut() {
        loginButton.setText(R.string.log_user_in);
        container.setVisibility(View.VISIBLE);
    }


    public static Intent newInstance(Context context) {
        return new Intent(context, TweeterActivityMVPCI.class);
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/TweeterMVPCIPresenter.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVPCI;

import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;

import io.patrykpoborca.cleanarchitecture.dagger.interactors.NetworkInteractor;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.base.BasePresenterMVPCI;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.interfaces.TweeterActivityMVPCIPview;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;
import io.patrykpoborca.cleanarchitecture.util.Constants;
import rx.Observable;
import rx.Scheduler;

/**
 * Created by Patryk on 7/29/2015.
 */
public class TweeterMVPCIPresenter extends BasePresenterMVPCI<TweeterActivityMVPCIPview> {

    private static final int TWEET_COUNT = 2;
    private final NetworkInteractor interactor;
    private final Scheduler mainScheduler;
    private boolean loggedIn = false;
    private int tweetsAdded = 0;


    @Inject
    public TweeterMVPCIPresenter(NetworkInteractor interactor, @Named(Constants.MAIN_THREAD) Scheduler mainScheduler) {
        this.interactor = interactor;
        this.mainScheduler = mainScheduler;
    }

    @Override
    public void onAttach() {
        super.onAttach();
    }

    @Override
    public void onDettach() {
        super.onDettach();
    }

    public Observable<String> fetchCurrentTweet() {
        getPView().toggleProgressBar(true);

        Observable<String> observable = interactor.fetchTweet();
        observable.subscribe(s -> {
            getPView().toggleProgressBar(false);
            tweetsAdded++;
            if (tweetsAdded > TWEET_COUNT) {
                getPView().displayToast("Tweet size exceeded " + TWEET_COUNT);
            }
        });
        return observable;
    }
    
    public Observable<List<String>> fetchPreviousTweets() {
        getPView().toggleProgressBar(true);

        Observable<List<String>> observable = interactor.fetchTweets(TWEET_COUNT);
        observable.subscribe(l -> {
            getPView().toggleProgressBar(false);
        });
        return observable;
    }
    
    public void toggleLogin(String userName, String password){

        getPView().toggleProgressBar(true);
        if(!loggedIn) {
            loggedIn = true;
            Observable<UserProfile> observable = interactor.attemptLogin(userName, password);
            observable.subscribe(p->
            {
                getPView().toggleProgressBar(false);
                getPView().loggedIn(p);
            });

        }
        else{
            UserProfile profile = null;
            loggedIn = false;
            //avoid relying on timer task/handler
            interactor.logout()
                    .observeOn(mainScheduler)
                    .subscribe(s -> {
                        getPView().loggedOut();
                        getPView().toggleProgressBar(false);
                    });
        }
    }

    public Observable<String> loadWebPage(String url){
        getPView().toggleProgressBar(true);
        Observable<String> observable = interactor.loadWebpage(url);

        observable.subscribe(s -> getPView().toggleProgressBar(false));
        return observable;
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/base/BasePresenterActivityMVPCI.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVPCI.base;

import android.os.Bundle;

import io.patrykpoborca.cleanarchitecture.ui.BaseCleanArchitectureActivity;
import io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces.PView;

public abstract class BasePresenterActivityMVPCI<T extends BasePresenterMVPCI> extends BaseCleanArchitectureActivity implements PView{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getPresenter().registerPresenter(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        getPresenter().onAttach();
    }

    @Override
    protected void onPause() {
        super.onPause();
        getPresenter().onDettach();
    }

    protected abstract T getPresenter();
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/base/BasePresenterMVPCI.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVPCI.base;

import io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces.PView;

public class BasePresenterMVPCI<T extends PView> {

    private T pView;

    public void onAttach(){

    }
    public void onDettach(){

    }

    public void registerPresenter(T view){
        this.pView = view;
    }

    protected T getPView(){
        return this.pView;
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/interfaces/TweeterActivityMVPCIPview.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVPCI.interfaces;

import io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces.PView;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;

/**
 * Created by Patryk on 7/29/2015.
 */
public interface TweeterActivityMVPCIPview extends PView{
    public void loggedIn(UserProfile profile);

    public void loggedOut();
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/models/UserProfile.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVPCI.models;

/**
 * Created by Patryk on 7/29/2015.
 */
public class UserProfile {
    private final String password;
    private final String username;

    public UserProfile(String username, String password) {
        this.username = username;
        this.password =password;
    }

    public String getFormattedCredentials(){
        return "User Profile = " + username + " " + password;
    }

    public String getUserName() {
        return username;
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/MainViewmodel.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVVM;

import java.util.List;

import javax.inject.Inject;

import io.patrykpoborca.cleanarchitecture.network.TweeterApi;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;
import io.patrykpoborca.cleanarchitecture.ui.MVVM.base.BaseViewModel;
import rx.Observable;
import rx.subjects.PublishSubject;

public class MainViewModel extends BaseViewModel {

    private static final int TWEET_COUNT = 2;
    private final TweeterApi tweeterApi;
    private final Retrofit retroFit;
    private boolean loggedIn = false;
    private int tweetsAdded = 0;
    private PublishSubject<String> messageStream;


    @Inject
    public MainViewModel(TweeterApi api, Retrofit retrofit){
        this.tweeterApi = api;
        this.retroFit = retrofit;
    }

    public Observable<String> fetchCurrentTweet(){
        tweetsAdded ++;

        Observable<String> observable=  tweeterApi.getTweet();

        if(tweetsAdded > TWEET_COUNT){
            observable.subscribe(s ->  messageStream.onNext("Tweet size exceeded " + TWEET_COUNT));
        }
        return observable;
    }


    public Observable<List<String>> fetchPreviousTweets(){
        return tweeterApi.fetchXrecents(2);
    }

    public boolean isLoggedIn(){
        return loggedIn;
    }

    public Observable<UserProfile> toggleLogin(String userName, String password){
        loggedIn = !loggedIn;
        if(loggedIn) {
            return this.tweeterApi.login(userName, password);
        }
        else{
            UserProfile profile = null;
            return tweeterApi.logout()
                    .map(o -> profile);
        }
    }

    public Observable<String> getMessageStream() {
        if(messageStream == null){
            messageStream = PublishSubject.<String>create();
        }
        return messageStream.asObservable();
    }

    public Observable<String> loadWebPage(String url){
        return retroFit.fetchSomePage(url);
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/TweeterActivityMVVM.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVVM;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.text.Html;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

import javax.inject.Inject;

import butterknife.Bind;
import butterknife.ButterKnife;
import io.patrykpoborca.cleanarchitecture.CleanArchitectureApplication;
import io.patrykpoborca.cleanarchitecture.R;
import io.patrykpoborca.cleanarchitecture.dagger.components.DaggerActivityInjectorComponent;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;
import io.patrykpoborca.cleanarchitecture.ui.MVVM.base.BaseViewModelActivity;
import io.patrykpoborca.cleanarchitecture.util.Utility;


public class TweeterActivityMVVM extends BaseViewModelActivity<MainViewModel> {

    @Bind(R.id.fetch_tweet_button) Button fetchTweetButton;
    @Bind(R.id.fetch_last_two_tweets) Button fetchLastTwoButton;
    @Bind(R.id.current_tweet) TextView currentTweetTextView;
    @Bind(R.id.past_tweets_container) LinearLayout pastTweetContainer;
    @Bind(R.id.user_login_button) Button loginButton;
    @Bind(R.id.user_name) TextView userNameTextView;
    @Bind(R.id.user_password) TextView userPasswordTextView;
    @Bind(R.id.container) ViewGroup container;
    @Bind(R.id.some_url) EditText urlText;
    @Bind(R.id.webpage_text) TextView websiteText;
    @Bind(R.id.request_website_button) Button websiteFetchbutton;
    @Bind(R.id.help_history) View helpHistory;
    @Bind(R.id.help_login) View helpLogin;
    @Bind(R.id.help_url) View helpUrl;

    @Inject
    MainViewModel viewModel;
    private View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Utility.toggleProgressbar(TweeterActivityMVVM.this, true);
            if(view == loginButton){
                registerSubscription(
                        getViewModel().toggleLogin(userNameTextView.getText().toString(),
                                userPasswordTextView.getText().toString())
                                .subscribe(TweeterActivityMVVM.this::toggleLogin)
                );
            }
            else if(view == fetchLastTwoButton){
                registerSubscription(
                        getViewModel().fetchPreviousTweets()
                        .subscribe(TweeterActivityMVVM.this::displayTweets)
                );
            }
            else if(view == fetchTweetButton){
                registerSubscription(
                        getViewModel().fetchCurrentTweet()
                        .subscribe(tweet -> {
                            currentTweetTextView.setText(tweet);
                            Utility.toggleProgressbar(TweeterActivityMVVM.this, false);
                        })
                );
            }
            else if(view == websiteFetchbutton){
                registerSubscription(
                        getViewModel().loadWebPage(urlText.getText().toString())
                            .subscribe(s -> {
                                websiteText.setText(Html.fromHtml(s));
                                Utility.toggleProgressbar(TweeterActivityMVVM.this, false);
                            })
                );
            }
        }
    };

    private final View.OnClickListener dialogClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(view == helpHistory){
                new AlertDialog.Builder(TweeterActivityMVVM.this)
                        .setMessage(R.string.history_text)
                        .setPositiveButton("Ok", null)
                        .create()
                        .show();
            }
            else if(view == helpUrl){
                new AlertDialog.Builder(TweeterActivityMVVM.this)
                        .setMessage(R.string.url_text)
                        .setPositiveButton("Ok", null)
                        .create()
                        .show();
            }
            else if(view == helpLogin){
                new AlertDialog.Builder(TweeterActivityMVVM.this)
                        .setMessage(R.string.login_text)
                        .setPositiveButton("Ok", null)
                        .create()
                        .show();
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        this.fetchLastTwoButton.setOnClickListener(onClickListener);
        this.fetchTweetButton.setOnClickListener(onClickListener);
        this.loginButton.setOnClickListener(onClickListener);
        this.websiteFetchbutton.setOnClickListener(onClickListener);
        this.helpHistory.setOnClickListener(dialogClickListener);
        this.helpLogin.setOnClickListener(dialogClickListener);
        this.helpUrl.setOnClickListener(dialogClickListener);

        setTitle("Tweeteractivity MVVM Impl");
    }

    @Override
    protected MainViewModel getViewModel() {
        if(viewModel == null){
            DaggerActivityInjectorComponent.builder()
                    .baseComponent(CleanArchitectureApplication.getBaseComponent())
                    .build()
                    .inject(this);
        }

        return viewModel;
    }

    @Override
    protected void onResume() {
        super.onResume();

        registerSubscription(getViewModel().getMessageStream()
                .subscribe(s -> Toast.makeText(this, s, Toast.LENGTH_LONG).show()));
    }

    private void displayTweets(List<String> list) {
        pastTweetContainer.removeAllViews();
        Utility.toggleProgressbar(this, false);

        for(int i= 0; i < list.size(); i++){
            TextView textView = new TextView(this);
            textView.setText(list.get(i));
            pastTweetContainer.addView(textView);
        }
    }

    private void toggleLogin(UserProfile profile){
        Utility.toggleProgressbar(this, false);

        //unlike the variations of MVP, the
        if(getViewModel().isLoggedIn()) {
            Toast.makeText(this, (profile.getFormattedCredentials() + " Logged in"), Toast.LENGTH_SHORT).show();
            loginButton.setText("Log " + profile.getUserName() + " out");
            container.setVisibility(View.GONE);
        }
        else{
            loginButton.setText(R.string.log_user_in);
            container.setVisibility(View.VISIBLE);
        }
    }

    public static Intent newInstance(Context context) {
        return new Intent(context, TweeterActivityMVVM.class);
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/base/BaseViewModel.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVVM.base;

public class BaseViewModel {

    public void onAttach(){

    }

    public void onDettach(){

    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/base/BaseViewModelActivity.java
================================================
package io.patrykpoborca.cleanarchitecture.ui.MVVM.base;

import android.os.Bundle;

import io.patrykpoborca.cleanarchitecture.ui.BaseCleanArchitectureActivity;

public abstract class BaseViewModelActivity<T extends BaseViewModel> extends BaseCleanArchitectureActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getViewModel();
    }

    @Override
    protected void onResume() {
        super.onResume();
        getViewModel().onAttach();
    }

    @Override
    protected void onPause() {
        super.onPause();
        getViewModel().onDettach();
    }

    protected abstract T getViewModel();
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/PlainTweeterActivity.java
================================================
package io.patrykpoborca.cleanarchitecture.ui;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.text.Html;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

import javax.inject.Inject;

import butterknife.Bind;
import butterknife.ButterKnife;
import io.patrykpoborca.cleanarchitecture.CleanArchitectureApplication;
import io.patrykpoborca.cleanarchitecture.R;
import io.patrykpoborca.cleanarchitecture.dagger.components.DaggerActivityInjectorComponent;
import io.patrykpoborca.cleanarchitecture.network.TweeterApi;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;
import io.patrykpoborca.cleanarchitecture.util.Utility;

public class PlainTweeterActivity extends BaseCleanArchitectureActivity {

    private static final int TWEET_COUNT = 2;
    @Inject
    TweeterApi tweeterApi;

    @Inject
    Retrofit retrofit;

    @Bind(R.id.fetch_tweet_button)
    Button fetchTweetButton;
    @Bind(R.id.fetch_last_two_tweets)
    Button fetchLastTwoButton;
    @Bind(R.id.current_tweet)
    TextView currentTweetTextView;
    @Bind(R.id.past_tweets_container)
    LinearLayout pastTweetContainer;
    @Bind(R.id.user_login_button)
    Button loginButton;
    @Bind(R.id.user_name)
    TextView userNameTextView;
    @Bind(R.id.user_password)
    TextView userPasswordTextView;
    @Bind(R.id.container)
    ViewGroup container;
    @Bind(R.id.some_url)
    EditText urlText;
    @Bind(R.id.webpage_text)
    TextView websiteText;
    @Bind(R.id.request_website_button)
    Button websiteFetchbutton;
    @Bind(R.id.help_history)
    View helpHistory;
    @Bind(R.id.help_login)
    View helpLogin;
    @Bind(R.id.help_url)
    View helpUrl;


    private int tweetsAdded = 0;

    private final View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            Utility.toggleProgressbar(PlainTweeterActivity.this, true);
            if (view == fetchLastTwoButton) {
                registerSubscription(
                        tweeterApi.fetchXrecents(2)
                                .subscribe(PlainTweeterActivity.this::displayPreviousTweets)
                );
            }
            else if (view == fetchTweetButton) {
                registerSubscription(
                        tweeterApi.getTweet()
                                .subscribe(s -> {
                                    currentTweetTextView.setText(s);
                                    tweetsAdded++;
                                    if (tweetsAdded > TWEET_COUNT) {
                                        Toast.makeText(PlainTweeterActivity.this, "Tweet size exceeded " + TWEET_COUNT, Toast.LENGTH_LONG).show();
                                    }
                                    Utility.toggleProgressbar(PlainTweeterActivity.this, false);
                                })
                );
            }
            else if (view == loginButton) {
                if (tweeterApi.isLoggedIn()) {
                    registerSubscription(tweeterApi.logout()
                            .subscribe(s -> {
                                container.setVisibility(View.VISIBLE);
                                loginButton.setText(R.string.log_user_in);
                                Utility.toggleProgressbar(PlainTweeterActivity.this, false);
                            }));
                }
                else {
                    registerSubscription(
                            tweeterApi.login(
                                    userNameTextView.getText().toString(),
                                    userPasswordTextView.getText().toString())
                                    .subscribe(PlainTweeterActivity.this::userLogin)
                    );
                }
            }
            else if (view == websiteFetchbutton) {
                retrofit.fetchSomePage(urlText.getText().toString())
                        .subscribe(s -> {
                            websiteText.setText(Html.fromHtml(s));
                            Utility.toggleProgressbar(PlainTweeterActivity.this, false);
                        });
            }

        }
    };

    private final View.OnClickListener dialogClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (view == helpHistory) {
                new AlertDialog.Builder(PlainTweeterActivity.this)
                        .setMessage(R.string.history_text)
                        .setPositiveButton("Ok", null)
                        .create()
                        .show();
            }
            else if (view == helpUrl) {
                new AlertDialog.Builder(PlainTweeterActivity.this)
                        .setMessage(R.string.url_text)
                        .setPositiveButton("Ok", null)
                        .create()
                        .show();
            }
            else if (view == helpLogin) {
                new AlertDialog.Builder(PlainTweeterActivity.this)
                        .setMessage(R.string.login_text)
                        .setPositiveButton("Ok", null)
                        .create()
                        .show();
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DaggerActivityInjectorComponent.builder()
                .baseComponent(CleanArchitectureApplication.getBaseComponent())
                .build()
                .inject(this);

        ButterKnife.bind(this);

        setTitle("Plain Activity IMPL");

        this.fetchLastTwoButton.setOnClickListener(onClickListener);
        this.fetchTweetButton.setOnClickListener(onClickListener);
        this.loginButton.setOnClickListener(onClickListener);
        this.websiteFetchbutton.setOnClickListener(onClickListener);
        this.helpHistory.setOnClickListener(dialogClickListener);
        this.helpLogin.setOnClickListener(dialogClickListener);
        this.helpUrl.setOnClickListener(dialogClickListener);
    }

    public void displayPreviousTweets(List<String> tweets) {
        pastTweetContainer.removeAllViews(); //clear container...
        Utility.toggleProgressbar(PlainTweeterActivity.this, false);
        for (int i = 0; i < tweets.size(); i++) {
            TextView text = new TextView(this);
            text.setText(tweets.get(i));
            pastTweetContainer.addView(text);
        }
    }

    public void userLogin(UserProfile profile) {
        Utility.toggleProgressbar(this, false);

        container.setVisibility(View.GONE);
        loginButton.setText("Log " + profile.getUserName() + " out");
    }

    public static Intent newInstance(Context context) {
        return new Intent(context, PlainTweeterActivity.class);
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/RouterActivity.java
================================================
package io.patrykpoborca.cleanarchitecture.ui;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import butterknife.Bind;
import butterknife.ButterKnife;
import io.patrykpoborca.cleanarchitecture.R;
import io.patrykpoborca.cleanarchitecture.ui.MVP.TweeterActivityMVP;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.TweeterActivityMVPCI;
import io.patrykpoborca.cleanarchitecture.ui.MVVM.TweeterActivityMVVM;

/**
 * Created by Patryk on 7/28/2015.
 */
public class RouterActivity extends AppCompatActivity {


    @Bind(R.id.stupid_activity)
    View stupidActivity;

    @Bind(R.id.mvp_activity)
    View mvpActivity;

    @Bind(R.id.mvpci_activity)
    View mvpciActivity;

    @Bind(R.id.mvvm_activity)
    View mvvmActivity;

    private View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent = null;
            if(view == stupidActivity){
                intent = PlainTweeterActivity.newInstance(RouterActivity.this);
            }
            else if(view == mvpciActivity){
                intent = TweeterActivityMVPCI.newInstance(RouterActivity.this);
            }
            else if(view == mvvmActivity) {
                intent = TweeterActivityMVVM.newInstance(RouterActivity.this);
            }
            else if(view == mvpActivity){
                intent = TweeterActivityMVP.newInstance(RouterActivity.this);
            }

            startActivity(intent);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_router);
        ButterKnife.bind(this);

        mvvmActivity.setOnClickListener(onClickListener);
        mvpciActivity.setOnClickListener(onClickListener);
        mvpActivity.setOnClickListener(onClickListener);
        stupidActivity.setOnClickListener(onClickListener);
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/util/Constants.java
================================================
package io.patrykpoborca.cleanarchitecture.util;

public class Constants {

    public static final String MAIN_THREAD = "MAIN_THREAD";
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/util/LoadingFragment.java
================================================
package io.patrykpoborca.cleanarchitecture.util;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import io.patrykpoborca.cleanarchitecture.R;

public class LoadingFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_progress, container, false);
    }
}


================================================
FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/util/utility.java
================================================
package io.patrykpoborca.cleanarchitecture.util;

import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import rx.Observable;

public class Utility {

    private static final String PROGRESS_TAG = "PROGRESS";

    public static void toggleProgressbar(AppCompatActivity activity, boolean show) {
        try {
            Fragment fragment = activity.getSupportFragmentManager()
                    .findFragmentByTag(PROGRESS_TAG);
            if (show && fragment == null) {
                activity.getSupportFragmentManager().beginTransaction()
                        .add(android.R.id.content, new LoadingFragment(), PROGRESS_TAG)
                        .commit();
            }
            else if (!show && fragment != null) {
                activity.getSupportFragmentManager().beginTransaction()
                        .remove(fragment)
                        .commit();

            }
        } catch (Exception e) {
            Log.e(Utility.class.getSimpleName(), "", e);
        }
    }

    public static void toggleProgressbar(AppCompatActivity activity, Observable observable) {
        toggleProgressbar(activity, true);
        observable.doOnCompleted(() -> toggleProgressbar(activity, false));
    }
}


================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingBottom="@dimen/activity_vertical_margin"
            android:paddingLeft="@dimen/activity_horizontal_margin"
            android:paddingRight="@dimen/activity_horizontal_margin"
            android:paddingTop="@dimen/activity_vertical_margin">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <FrameLayout android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:minHeight="100dp">
            <View android:layout_width="match_parent" android:layout_height="match_parent"
                  android:background="@android:color/holo_blue_light"
                android:alpha="0.4"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="History:"/>

            <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content"
                android:layout_gravity="top|right"
                android:src="@drawable/ic_help_outline_black_24dp"
                android:layout_marginTop="5dp"
                android:layout_marginRight="5dp"
                android:id="@+id/help_history"/>

            <LinearLayout
                android:id="@+id/past_tweets_container"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:layout_marginBottom="30dp"
                android:orientation="vertical"/>
        </FrameLayout>
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:layout_marginBottom="10dp"
            android:background="@android:color/black"/>

        <TextView
            android:id="@+id/current_tweet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/hello_world"/>

        <LinearLayout android:layout_width="match_parent"
                      android:layout_height="wrap_content"
                        android:layout_marginBottom="20dp">
            <Button
                android:id="@+id/fetch_tweet_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Fetch Tweet!"/>

            <Button
                android:id="@+id/fetch_last_two_tweets"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Fetch Last two Tweets!"/>
        </LinearLayout>


        <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content"
                   android:layout_gravity="top|right"
                   android:src="@drawable/ic_help_outline_black_24dp"
                   android:layout_marginTop="5dp"
                   android:layout_marginRight="5dp"
                   android:id="@+id/help_login"/>

        <LinearLayout android:layout_width="match_parent"
                      android:layout_height="wrap_content"
                      android:orientation="vertical"
                        android:id="@+id/container">

            <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
                      android:text="UserName:"/>
            <EditText android:id="@+id/user_name" android:layout_width="match_parent"
                      android:layout_height="wrap_content"/>
            <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
                      android:text="Password:"/>
            <EditText android:id="@+id/user_password" android:layout_width="match_parent"
                      android:layout_height="wrap_content"
                      android:inputType="textWebPassword"/>
        </LinearLayout>

        <Button
            android:id="@+id/user_login_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/log_user_in"/>

        <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content"
                   android:layout_gravity="top|right"
                   android:src="@drawable/ic_help_outline_black_24dp"
                   android:layout_marginTop="5dp"
                   android:layout_marginRight="5dp"
                   android:id="@+id/help_url"/>

        <LinearLayout android:layout_width="match_parent"
                      android:layout_height="wrap_content">
            <EditText android:layout_width="0dp" android:layout_height="wrap_content"
                android:layout_weight="1"
                android:id="@+id/some_url"/>

        <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:id="@+id/request_website_button"
            android:text="Request"/>
        </LinearLayout>

        <FrameLayout android:layout_width="match_parent"
                      android:layout_height="wrap_content">
            <View android:layout_width="match_parent" android:layout_height="match_parent"
                  android:background="@android:color/holo_blue_light"
                  android:alpha="0.4"/>

            <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
                android:id="@+id/webpage_text"/>
        </FrameLayout>
    </LinearLayout>
</ScrollView>


================================================
FILE: app/src/main/res/layout/activity_router.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"

            android:layout_width="match_parent"
            android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="30dp"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            android:text="Dagger 2 Clean Architecture Demo"
            android:layout_gravity="center_horizontal"
            android:textColor="@android:color/black"/>

        <Button
            android:id="@+id/stupid_activity"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="Stupid Activity"/>

        <Button
            android:id="@+id/mvp_activity"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:text="MVP Activity"/>

        <Button
            android:id="@+id/mvpci_activity"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:text="MVPCI Activity"/>

        <Button
            android:id="@+id/mvvm_activity"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:text="MVVM Activity"/>

    </LinearLayout>
</ScrollView>

================================================
FILE: app/src/main/res/layout/fragment_progress.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="match_parent">

    <View android:layout_width="match_parent" android:layout_height="match_parent"
          android:background="@android:color/white"
          android:alpha="0.7"/>
    <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:indeterminate="true"
        android:layout_gravity="center"/>
</FrameLayout>

================================================
FILE: app/src/main/res/menu/menu_main.xml
================================================
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      tools:context=".MainActivity">
    <item android:id="@+id/action_settings"
          android:title="@string/action_settings"
          android:orderInCategory="100"
          app:showAsAction="never"/>
</menu>


================================================
FILE: app/src/main/res/values/dimens.xml
================================================
<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
</resources>


================================================
FILE: app/src/main/res/values/strings.xml
================================================
<resources>
    <string name="app_name">CleanArchitecture</string>

    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>
    <string name="log_user_in">Log User In</string>
    <string name="repo">Check out the sourcecode</string>
    <string name="history_text">This box will container past two tweets fetched through out the
        app.
    </string>
    <string name="url_text">This is the moced webpage that will be fetched. For this purpose the url
        you entered will simply be injected into HTML header tags
    </string>
    <string name="login_text">This is to simulate logging into the application. If you do log in,
        any fetched tweets will be displayed using your user-name
    </string>
</resources>


================================================
FILE: app/src/main/res/values/styles.xml
================================================
<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
    </style>

</resources>


================================================
FILE: app/src/main/res/values-w820dp/dimens.xml
================================================
<resources>
    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
         (such as screen margins) for screens with more than 820dp of available width. This
         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
    <dimen name="activity_horizontal_margin">64dp</dimen>
</resources>


================================================
FILE: app/src/test/java/dagger/TestClassInjector.java
================================================
package dagger;

import dagger.mockmodules.MockTestModule;
import io.patrykpoborca.cleanarchitecture.dagger.components.BaseComponent;
import io.patrykpoborca.cleanarchitecture.dagger.scopes.ActivityScope;
import tests.MVPCITest;
import tests.MVVMTest;
import tests.MVPTest;

@ActivityScope
@Component(dependencies = BaseComponent.class, modules = MockTestModule.class)
public interface TestClassInjector {
    void inject(MVVMTest viewmodelTest);

    void inject(MVPCITest presenterTest);

    void inject(MVPTest MVPTest);
}


================================================
FILE: app/src/test/java/dagger/mockmodules/MockLocalModule.java
================================================
package dagger.mockmodules;

import android.app.Application;

import io.patrykpoborca.cleanarchitecture.dagger.modules.LocalModule;
import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;
import mockimpl.MockLocalDataCache;

public class MockLocalModule extends LocalModule{

    @Override
    protected LocalDataCache providesDataCache(Application application) {
        return new MockLocalDataCache(application);
    }
}


================================================
FILE: app/src/test/java/dagger/mockmodules/MockNetworkModule.java
================================================
package dagger.mockmodules;

import io.patrykpoborca.cleanarchitecture.dagger.modules.NetworkModule;
import io.patrykpoborca.cleanarchitecture.network.base.OKHttp;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import mockimpl.MockOkHTTP;
import mockimpl.MockRetrofit;
import rx.Scheduler;

public class MockNetworkModule extends NetworkModule {

    @Override
    protected OKHttp providesOkHTTP() {
        return new MockOkHTTP();
    }

    @Override
    protected Retrofit providesRetrofit(OKHttp okHttp, Scheduler mainScheduler) {
        return new MockRetrofit(okHttp, mainScheduler);
    }
}


================================================
FILE: app/src/test/java/dagger/mockmodules/MockTestModule.java
================================================
package dagger.mockmodules;

import javax.inject.Named;

import dagger.Module;
import dagger.Provides;
import io.patrykpoborca.cleanarchitecture.dagger.scopes.ActivityScope;
import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;
import io.patrykpoborca.cleanarchitecture.network.TweeterApi;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVP.TweeterMVPPresenterImpl;
import io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;
import io.patrykpoborca.cleanarchitecture.util.Constants;
import mockimpl.MockMVPCIPview;
import mockimpl.MockTweeterActivityPview;
import mockimpl.MockTweeterApi;
import rx.Scheduler;

@Module
public class MockTestModule {

    @Provides
    @ActivityScope
    TweeterMVPPresenter providesMainPresenter(TweeterApi api, Retrofit retrofit){
        return new TweeterMVPPresenterImpl(api, retrofit);
    }

    @ActivityScope
    @Provides
    public MockTweeterActivityPview providesMockMainPview(TweeterMVPPresenter presenter){
        MockTweeterActivityPview mockTweeterActivityPview = new MockTweeterActivityPview();
        presenter.registerView(mockTweeterActivityPview);
        return mockTweeterActivityPview;
    }

    @ActivityScope
    @Provides
    public TweeterApi providesMockTweeter(Retrofit retrofit, LocalDataCache dataCache, @Named(Constants.MAIN_THREAD) Scheduler mainScheduler){
        return new MockTweeterApi(retrofit, dataCache, mainScheduler);
    }

    @ActivityScope
    @Provides
    public MockMVPCIPview providesMockMVPCCIView(){
        return new MockMVPCIPview();
    }
}


================================================
FILE: app/src/test/java/dagger/mockmodules/MockThreadingModule.java
================================================
package dagger.mockmodules;

import io.patrykpoborca.cleanarchitecture.dagger.modules.ThreadingModule;
import rx.Scheduler;
import rx.schedulers.Schedulers;

public class MockThreadingModule extends ThreadingModule {

    @Override
    public Scheduler providesMainThread() {
        return Schedulers.immediate();
    }
}


================================================
FILE: app/src/test/java/helper/TestHelper.java
================================================
package helper;

import android.app.Application;

import dagger.DaggerTestClassInjector;
import dagger.TestClassInjector;
import dagger.mockmodules.MockLocalModule;
import dagger.mockmodules.MockNetworkModule;
import dagger.mockmodules.MockThreadingModule;
import io.patrykpoborca.cleanarchitecture.dagger.components.ApplicationComponent;
import io.patrykpoborca.cleanarchitecture.dagger.components.BaseComponent;
import io.patrykpoborca.cleanarchitecture.dagger.components.DaggerApplicationComponent;
import io.patrykpoborca.cleanarchitecture.dagger.components.DaggerBaseComponent;
import io.patrykpoborca.cleanarchitecture.dagger.modules.ApplicationModule;


public class TestHelper {

    private static ApplicationComponent sApplicationComponent;
    private static BaseComponent sBaseComponent;
    private static TestClassInjector sTestClassInjector;

    public static ApplicationComponent getApplicationComponent(){
        if(sApplicationComponent == null)
        {
            sApplicationComponent = DaggerApplicationComponent.builder()
                    .applicationModule(new ApplicationModule(new Application()))
                    .build();
        }
        return sApplicationComponent;
    }

    public static BaseComponent getBaseComponent(){
        if(sBaseComponent == null){
            sBaseComponent = DaggerBaseComponent.builder()
                    .applicationComponent(getApplicationComponent())
                    .localModule(new MockLocalModule())
                    .networkModule(new MockNetworkModule())
                    .threadingModule(new MockThreadingModule())
                    .build();
        }
        return sBaseComponent;
    }

    public static TestClassInjector getTestClassInjector(){
        if(sTestClassInjector == null){
            sTestClassInjector = DaggerTestClassInjector.builder()
                    .baseComponent(getBaseComponent())
                    .build();
        }

        return sTestClassInjector;
    }

    public static void waitFor(IWaitingCallback callback){
        waitFor(10, callback);
    }

    public static void waitFor(int maxCycles, IWaitingCallback callback){
        while(true){
            maxCycles --;
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(callback.checkCondition()){
                break;
            }
            if(maxCycles <= 0){
                break;
            }
        }
    }

    public static interface IWaitingCallback{
        /**
         *
         * @return true if condition is met, false if we should keep waiting
         */
        public boolean checkCondition();
    }
}

================================================
FILE: app/src/test/java/mockimpl/MockLocalDataCache.java
================================================
package mockimpl;

import android.content.Context;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;
import rx.Observable;

public class MockLocalDataCache extends LocalDataCache {

    public MockLocalDataCache(Context context) {
        super(context);
    }

    /**
     *  No mock-impl needed for our scenario here.. see MockOKHttp/MockRetrofit
     */
    @Override
    public void saveTweet(String tweet) {
        sPastTweets.add(tweet);
    }

    @Override
    public Observable<List<String>> fetchRecentTweets() {
        return Observable.just(sPastTweets)
                .map(arrayList -> {
                    List<String> list = arrayList;
                    return list;
                });
    }
}


================================================
FILE: app/src/test/java/mockimpl/MockMVPCIPview.java
================================================
package mockimpl;

import io.patrykpoborca.cleanarchitecture.ui.MVPCI.interfaces.TweeterActivityMVPCIPview;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;

public class MockMVPCIPview implements TweeterActivityMVPCIPview {

    public UserProfile loggedInProfile;
    public boolean loggedOutCalled = false;
    public boolean toggleProgresbarCalled = false;

    @Override
    public void loggedIn(UserProfile profile) {
        this.loggedInProfile = profile;
    }

    @Override
    public void loggedOut() {
        loggedOutCalled = true;
    }

    @Override
    public void toggleProgressBar(boolean loading) {
        toggleProgresbarCalled = true;
    }

    @Override
    public void displayToast(String toast) {

    }
}


================================================
FILE: app/src/test/java/mockimpl/MockOkHTTP.java
================================================
package mockimpl;

import io.patrykpoborca.cleanarchitecture.network.base.OKHttp;

public class MockOkHTTP extends OKHttp {
    @Override
    public String rawResponse() {
        return "Mocked raw response: ";
    }
}


================================================
FILE: app/src/test/java/mockimpl/MockRetrofit.java
================================================
package mockimpl;

import java.util.concurrent.TimeUnit;

import io.patrykpoborca.cleanarchitecture.network.base.OKHttp;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import rx.Observable;
import rx.Scheduler;
import rx.android.schedulers.AndroidSchedulers;

public class MockRetrofit extends Retrofit{
    private static final String MOCK_PARSE = "SomeMockResponse";
    public static final String MOCKED_STRING = "MOCKED PAGE:";

    public MockRetrofit(OKHttp okHttp, Scheduler mainScheduler) {
        super(okHttp, mainScheduler);
    }

    @Override
    public Observable<String> completeRequest() {
        return Observable.just(okHttp.rawResponse() + MOCK_PARSE);
    }

    @Override
    public Observable<String> fetchSomePage(String url) {
        return Observable.just("<h2>" + MOCKED_STRING + " " + url + " </h2>");
    }
}


================================================
FILE: app/src/test/java/mockimpl/MockTweeterActivityPview.java
================================================
package mockimpl;

import java.util.List;

import io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPView;

public class MockTweeterActivityPview implements TweeterMVPPView {

    public String fetchedTweet = null;
    public List<String> previousTweets = null;
    public boolean setUserButtonTextCalled = false;
    public boolean toggleProgressBarCalled = false;
    public boolean toggleLoginContainerCalled = false;
    public String displayWebpage = null;
    public boolean displayToastCalled = false;

    @Override
    public void displayFetchedTweet(String tweet) {
        fetchedTweet = tweet;
    }

    @Override
    public void displayPreviousTweets(List<String> list) {
        previousTweets = list;
    }

    @Override
    public void setUserButtonText(String text) {
        setUserButtonTextCalled = true;
    }

    @Override
    public void toggleLoginContainer(boolean b) {
        toggleLoginContainerCalled = true;
    }

    @Override
    public void displayWebpage(String html) {
        displayWebpage = html;
    }

    @Override
    public void toggleProgressBar(boolean loading) {
        toggleProgressBarCalled = true;
    }

    @Override
    public void displayToast(String toast) {
        displayToastCalled = true;
    }
}


================================================
FILE: app/src/test/java/mockimpl/MockTweeterApi.java
================================================
package mockimpl;

import android.util.Log;

import io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;
import io.patrykpoborca.cleanarchitecture.network.TweeterApi;
import io.patrykpoborca.cleanarchitecture.network.base.Retrofit;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.models.UserProfile;
import rx.Observable;
import rx.Scheduler;

public class MockTweeterApi extends TweeterApi{
    public MockTweeterApi(Retrofit retrofit, LocalDataCache dataCache, Scheduler mainScheduler) {
        super(retrofit, dataCache, mainScheduler);
    }

    @Override
    public Observable<UserProfile> login(String username, String password) {
        return Observable.just(new UserProfile(username, password))
                .observeOn(mainScheduler);
    }

    @Override
    public Observable<Object> logout() {
        return Observable.just(null)
                .observeOn(mainScheduler);
    }
}


================================================
FILE: app/src/test/java/tests/MVPCITest.java
================================================
package tests;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import javax.inject.Inject;

import helper.TestHelper;
import io.patrykpoborca.cleanarchitecture.ui.MVPCI.TweeterMVPCIPresenter;
import mockimpl.MockLocalDataCache;
import mockimpl.MockMVPCIPview;
import mockimpl.MockOkHTTP;
import mockimpl.MockRetrofit;

@RunWith(JUnit4.class)
public class MVPCITest {

    private static final String SOME_URL = "SOME_URL";
    private static final String USER_PASSWORD = "USER_PASSWORD";
    private static final String USER_NAME = "USER_NAME";
    private String tweetedTweet;

    @Inject
    TweeterMVPCIPresenter presenter;

    @Inject
    MockMVPCIPview pView;
    @Before
    public void setUp(){
        TestHelper.getTestClassInjector()
                .inject(this);
        presenter.registerPresenter(pView);

        junit.framework.Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);
        junit.framework.Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);
        junit.framework.Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);
    }

    @Test
    public void testWebPage(){
        presenter.loadWebPage(SOME_URL)
                .toBlocking()
                .forEach(s -> {
                    junit.framework.Assert.assertTrue(s.contains(MockRetrofit.MOCKED_STRING)
                            && s.contains(SOME_URL));
                });
    }

    @Test
    public void testLogin(){
        Assert.assertTrue(pView.loggedInProfile == null);
        presenter.toggleLogin(USER_NAME, USER_PASSWORD);
        TestHelper.waitFor(() -> pView.loggedInProfile != null);

        Assert.assertTrue(pView.loggedInProfile.getUserName().equals(USER_NAME));
        presenter.toggleLogin(USER_NAME, USER_PASSWORD);
        TestHelper.waitFor(() -> pView.loggedOutCalled);
        Assert.assertTrue(pView.loggedOutCalled);
    }

    @Test
    public void testTweets() {
        //Sanity test first to see if underlying logic of tweeter api has changed
        presenter.fetchPreviousTweets()
                .toBlocking()
                .forEach(list -> {
                    Assert.assertNotNull(list);
                });

    }

    @Test
    public void testTweetList(){
        presenter.fetchCurrentTweet()
                .toBlocking()
                .forEach(tweet -> {
                    tweetedTweet = tweet;
                });

        presenter.fetchPreviousTweets()
                .toBlocking()
                .forEach(list -> {
                    boolean exists = false;

                    for (int i = 0; i < list.size(); i++) {
                        if (tweetedTweet.contains(list.get(i))) {
                            exists = true;
                            break;
                        }
                    }
                    Assert.assertTrue(exists);
                });
    }

}


================================================
FILE: app/src/test/java/tests/MVPTest.java
================================================
package tests;


import junit.framework.Assert;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import javax.inject.Inject;

import helper.TestHelper;
import io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPresenter;
import mockimpl.MockLocalDataCache;
import mockimpl.MockOkHTTP;
import mockimpl.MockRetrofit;
import mockimpl.MockTweeterActivityPview;

@RunWith(JUnit4.class)
public class MVPTest {

    private static final String SOME_URL = "SOME_URL";
    private static final String USER_PASSWORD = "USER_PASSWORD";
    private static final String USER_NAME = "USER_NAME";

    @Inject
    MockTweeterActivityPview pView;

    @Inject
    TweeterMVPPresenter presenter;

    @Before
    public void setUp(){
        TestHelper.getTestClassInjector()
                .inject(this);

        Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);
        Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);
        Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);
    }


    @Test
    public void testLogin(){
        presenter.toggleLogin(USER_NAME, USER_PASSWORD);
        TestHelper.waitFor(() -> pView.toggleLoginContainerCalled);
        Assert.assertTrue(pView.toggleLoginContainerCalled);

        pView.toggleLoginContainerCalled = false;

        presenter.toggleLogin(USER_NAME, USER_PASSWORD);
        TestHelper.waitFor(() -> pView.toggleLoginContainerCalled);
        Assert.assertTrue(pView.toggleLoginContainerCalled);
    }

    @Test
    public void testFetchTweets(){
        presenter.fetchCurrentTweet();
        TestHelper.waitFor(() -> pView.fetchedTweet != null);
        String tweet = pView.fetchedTweet;

        presenter.fetchPreviousTweets();
        TestHelper.waitFor(() -> pView.previousTweets != null);
        boolean found = false;
        for(int i=0; i < pView.previousTweets.size(); i++){
            found = tweet.contains(pView.previousTweets.get(i));
            if(found){
                break;
            }
        }
        Assert.assertTrue(found);
    }

    @Test
    public void testWebPage() {
        presenter.loadWebPage(SOME_URL);

        TestHelper.waitFor(() -> pView.displayWebpage != null);
        String webPage = pView.displayWebpage;
        Assert.assertTrue(webPage.contains(SOME_URL));
    }

}


================================================
FILE: app/src/test/java/tests/MVVMTest.java
================================================
package tests;

import junit.framework.Assert;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import javax.inject.Inject;

import helper.TestHelper;
import io.patrykpoborca.cleanarchitecture.ui.MVVM.MainViewModel;
import mockimpl.MockLocalDataCache;
import mockimpl.MockOkHTTP;
import mockimpl.MockRetrofit;

@RunWith(JUnit4.class)
public class MVVMTest {

    private static final String SOME_URL = "SOME_URL";
    private static final String USER_PASSWORD = "USER_PASSWORD";
    private static final String USER_NAME = "USER_NAME";
    private String tweetedTweet;

    @Inject
    MainViewModel viewModel;

    @Before
    public void setUp() {
        TestHelper.getTestClassInjector()
                .inject(this);

        Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);
        Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);
        Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);

    }


    @Test
    public void testWebPage() {
        viewModel.loadWebPage(SOME_URL)
                .toBlocking()
                .forEach(s -> {
                    Assert.assertTrue(s.contains(MockRetrofit.MOCKED_STRING)
                            && s.contains(SOME_URL));
                });
    }

    @Test
    public void testLogin() {
        Assert.assertFalse(viewModel.isLoggedIn());
        viewModel.toggleLogin(USER_NAME, USER_PASSWORD)
                .toBlocking()
                .forEach(
                        user -> {
                            Assert.assertNotNull(user);
                            Assert.assertEquals(user.getUserName(), USER_NAME);
                        }
                );
        Assert.assertTrue(viewModel.isLoggedIn());
    }

    @Test
    public void testTweets() {
        //Sanity test first to see if underlying logic of tweeter api has changed
        viewModel.fetchPreviousTweets()
                .toBlocking()
                .forEach(list -> {
                    Assert.assertNotNull(list);
                });

    }

    @Test
    public void testTweetList() {

        viewModel.fetchCurrentTweet()
                .toBlocking()
                .forEach(tweet -> {
                    tweetedTweet = tweet;
                });

        viewModel.fetchPreviousTweets()
                .toBlocking()
                .forEach(list -> {
                    boolean exists = false;

                    for (int i = 0; i < list.size(); i++) {
                        if (tweetedTweet.contains(list.get(i))) {
                            exists = true;
                            break;
                        }
                    }
                    Assert.assertTrue(exists);
                });
    }

}


================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:2.0.0-beta6'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.5' //added apt for source code generation
        classpath 'me.tatarka:gradle-retrolambda:3.2.2'
//        classpath "net.ltgt.gradle:gradle-apt-plugin:0.3"
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
apply plugin: 'me.tatarka.retrolambda'

retrolambda {
    jdk System.getenv("JAVA8_HOME")
    oldJdk System.getenv("JAVA7_HOME")
    javaVersion JavaVersion.VERSION_1_7
}

allprojects {
    repositories {
        jcenter()
    }
}


================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Tue Mar 29 10:09:27 CDT 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip


================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

================================================
FILE: gradlew
================================================
#!/usr/bin/env bash

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn ( ) {
    echo "$*"
}

die ( ) {
    echo
    echo "$*"
    echo
    exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
esac

# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
    else
        JAVACMD="$JAVA_HOME/bin/java"
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD="java"
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`

    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=$((i+1))
    done
    case $i in
        (0) set -- ;;
        (1) set -- "$args0" ;;
        (2) set -- "$args0" "$args1" ;;
        (3) set -- "$args0" "$args1" "$args2" ;;
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
    esac
fi

# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
    JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"

exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"


================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windowz variants

if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*
goto execute

:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: settings.gradle
================================================
include ':app'
Download .txt
gitextract_n6u9vjvq/

├── .gitignore
├── .idea/
│   ├── .name
│   ├── compiler.xml
│   ├── copyright/
│   │   └── profiles_settings.xml
│   ├── encodings.xml
│   ├── gradle.xml
│   ├── misc.xml
│   ├── modules.xml
│   ├── runConfigurations.xml
│   └── vcs.xml
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── io/
│       │           └── patrykpoborca/
│       │               └── cleanarchitecture/
│       │                   ├── TestHelper.java
│       │                   ├── dagger/
│       │                   │   ├── TestClassInjector.java
│       │                   │   └── mockmodules/
│       │                   │       ├── MockLocalModule.java
│       │                   │       ├── MockNetworkModule.java
│       │                   │       └── MockTestModule.java
│       │                   ├── mockimpl/
│       │                   │   ├── MockLocalDataCache.java
│       │                   │   ├── MockMVPCIPview.java
│       │                   │   ├── MockOkHTTP.java
│       │                   │   ├── MockRetrofit.java
│       │                   │   ├── MockTweeterActivityPview.java
│       │                   │   └── MockTweeterApi.java
│       │                   └── tests/
│       │                       ├── MVPCITest.java
│       │                       ├── MVPTest.java
│       │                       ├── MVVMTest.java
│       │                       └── PlainTweeterTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── io/
│       │   │       └── patrykpoborca/
│       │   │           └── cleanarchitecture/
│       │   │               ├── CleanArchitectureApplication.java
│       │   │               ├── dagger/
│       │   │               │   ├── components/
│       │   │               │   │   ├── ActivityInjectorComponent.java
│       │   │               │   │   ├── ApplicationComponent.java
│       │   │               │   │   └── BaseComponent.java
│       │   │               │   ├── interactors/
│       │   │               │   │   ├── NetworkInteractor.java
│       │   │               │   │   └── base/
│       │   │               │   │       └── BaseInteractor.java
│       │   │               │   ├── modules/
│       │   │               │   │   ├── ApplicationModule.java
│       │   │               │   │   ├── InteractorModule.java
│       │   │               │   │   ├── LocalModule.java
│       │   │               │   │   ├── NetworkModule.java
│       │   │               │   │   ├── PresenterModule.java
│       │   │               │   │   └── ThreadingModule.java
│       │   │               │   └── scopes/
│       │   │               │       ├── ActivityScope.java
│       │   │               │       ├── ApplicationScope.java
│       │   │               │       └── ExposedAPIScope.java
│       │   │               ├── localdata/
│       │   │               │   └── LocalDataCache.java
│       │   │               ├── network/
│       │   │               │   ├── TweeterApi.java
│       │   │               │   └── base/
│       │   │               │       ├── OKHttp.java
│       │   │               │       └── Retrofit.java
│       │   │               ├── ui/
│       │   │               │   ├── BaseCleanArchitectureActivity.java
│       │   │               │   ├── MVP/
│       │   │               │   │   ├── TweeterActivityMVP.java
│       │   │               │   │   ├── TweeterMVPPresenterImpl.java
│       │   │               │   │   ├── base/
│       │   │               │   │   │   ├── BasePresenterActivity.java
│       │   │               │   │   │   └── Interfaces/
│       │   │               │   │   │       ├── PView.java
│       │   │               │   │   │       └── Presenter.java
│       │   │               │   │   └── interfaces/
│       │   │               │   │       ├── TweeterMVPPView.java
│       │   │               │   │       └── TweeterMVPPresenter.java
│       │   │               │   ├── MVPCI/
│       │   │               │   │   ├── TweeterActivityMVPCI.java
│       │   │               │   │   ├── TweeterMVPCIPresenter.java
│       │   │               │   │   ├── base/
│       │   │               │   │   │   ├── BasePresenterActivityMVPCI.java
│       │   │               │   │   │   └── BasePresenterMVPCI.java
│       │   │               │   │   ├── interfaces/
│       │   │               │   │   │   └── TweeterActivityMVPCIPview.java
│       │   │               │   │   └── models/
│       │   │               │   │       └── UserProfile.java
│       │   │               │   ├── MVVM/
│       │   │               │   │   ├── MainViewmodel.java
│       │   │               │   │   ├── TweeterActivityMVVM.java
│       │   │               │   │   └── base/
│       │   │               │   │       ├── BaseViewModel.java
│       │   │               │   │       └── BaseViewModelActivity.java
│       │   │               │   ├── PlainTweeterActivity.java
│       │   │               │   └── RouterActivity.java
│       │   │               └── util/
│       │   │                   ├── Constants.java
│       │   │                   ├── LoadingFragment.java
│       │   │                   └── utility.java
│       │   └── res/
│       │       ├── layout/
│       │       │   ├── activity_main.xml
│       │       │   ├── activity_router.xml
│       │       │   └── fragment_progress.xml
│       │       ├── menu/
│       │       │   └── menu_main.xml
│       │       ├── values/
│       │       │   ├── dimens.xml
│       │       │   ├── strings.xml
│       │       │   └── styles.xml
│       │       └── values-w820dp/
│       │           └── dimens.xml
│       └── test/
│           └── java/
│               ├── dagger/
│               │   ├── TestClassInjector.java
│               │   └── mockmodules/
│               │       ├── MockLocalModule.java
│               │       ├── MockNetworkModule.java
│               │       ├── MockTestModule.java
│               │       └── MockThreadingModule.java
│               ├── helper/
│               │   └── TestHelper.java
│               ├── mockimpl/
│               │   ├── MockLocalDataCache.java
│               │   ├── MockMVPCIPview.java
│               │   ├── MockOkHTTP.java
│               │   ├── MockRetrofit.java
│               │   ├── MockTweeterActivityPview.java
│               │   └── MockTweeterApi.java
│               └── tests/
│                   ├── MVPCITest.java
│                   ├── MVPTest.java
│                   └── MVVMTest.java
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
Download .txt
SYMBOL INDEX (322 symbols across 69 files)

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/TestHelper.java
  class TestHelper (line 15) | public class TestHelper {
    method getApplicationComponent (line 21) | public static ApplicationComponent getApplicationComponent(){
    method getBaseComponent (line 31) | public static BaseComponent getBaseComponent(){
    method getTestClassInjector (line 42) | public static TestClassInjector getTestClassInjector(){
    method waitFor (line 52) | public static void waitFor(IWaitingCallback callback){
    method waitFor (line 56) | public static void waitFor(int maxCycles, IWaitingCallback callback){
    type IWaitingCallback (line 73) | public static interface IWaitingCallback{
      method checkCondition (line 78) | public boolean checkCondition();

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/TestClassInjector.java
  type TestClassInjector (line 11) | @ActivityScope
    method inject (line 14) | void inject(MVVMTest test);
    method inject (line 16) | void inject(MVPTest MVPTest);
    method inject (line 18) | void inject(MVPCITest mvpciTest);

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockLocalModule.java
  class MockLocalModule (line 9) | public class MockLocalModule extends LocalModule{
    method providesDataCache (line 11) | @Override

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockNetworkModule.java
  class MockNetworkModule (line 13) | public class MockNetworkModule extends NetworkModule {
    method providesOkHTTP (line 15) | @Override
    method providesRetrofit (line 20) | @Override

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockTestModule.java
  class MockTestModule (line 19) | @Module
    method providesMainPresenter (line 22) | @Provides
    method providesMockMainPview (line 28) | @ActivityScope
    method providesMockTweeter (line 36) | @ActivityScope
    method providesMockMVPCCIView (line 42) | @ActivityScope

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockLocalDataCache.java
  class MockLocalDataCache (line 10) | public class MockLocalDataCache extends LocalDataCache {
    method MockLocalDataCache (line 12) | public MockLocalDataCache(Context context) {
    method saveTweet (line 16) | @Override
    method fetchRecentTweets (line 21) | @Override

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockMVPCIPview.java
  class MockMVPCIPview (line 6) | public class MockMVPCIPview implements TweeterActivityMVPCIPview {
    method loggedIn (line 12) | @Override
    method loggedOut (line 17) | @Override
    method toggleProgressBar (line 22) | @Override
    method displayToast (line 27) | @Override

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockOkHTTP.java
  class MockOkHTTP (line 5) | public class MockOkHTTP extends OKHttp {
    method rawResponse (line 6) | @Override

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockRetrofit.java
  class MockRetrofit (line 8) | public class MockRetrofit extends Retrofit {
    method MockRetrofit (line 12) | public MockRetrofit(OKHttp okHttp, Scheduler mainScheduler) {
    method completeRequest (line 16) | @Override
    method fetchSomePage (line 22) | @Override

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockTweeterActivityPview.java
  class MockTweeterActivityPview (line 7) | public class MockTweeterActivityPview implements TweeterMVPPView {
    method displayFetchedTweet (line 17) | @Override
    method displayPreviousTweets (line 22) | @Override
    method setUserButtonText (line 27) | @Override
    method toggleLoginContainer (line 32) | @Override
    method displayWebpage (line 37) | @Override
    method toggleProgressBar (line 42) | @Override
    method displayToast (line 47) | @Override

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockTweeterApi.java
  class MockTweeterApi (line 12) | public class MockTweeterApi extends TweeterApi{
    method MockTweeterApi (line 13) | public MockTweeterApi(Retrofit retrofit, LocalDataCache dataCache, Sch...
    method login (line 17) | @Override
    method logout (line 22) | @Override

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/MVPCITest.java
  class MVPCITest (line 18) | @RunWith(JUnit4.class)
    method setUp (line 31) | @Before
    method testWebPage (line 42) | @Test
    method testLogin (line 52) | @Test
    method testTweets (line 64) | @Test
    method testTweetList (line 75) | @Test

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/MVPTest.java
  class MVPTest (line 20) | @RunWith(AndroidJUnit4.class)
    method setUp (line 33) | @Before
    method testLogin (line 43) | @Test
    method testFetchTweets (line 56) | @Test
    method testWebPage (line 74) | @Test

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/MVVMTest.java
  class MVVMTest (line 19) | @RunWith(AndroidJUnit4.class)
    method setUp (line 30) | @Before
    method testWebPage (line 41) | @Test
    method testLogin (line 51) | @Test
    method testTweets (line 65) | @Test
    method testTweetList (line 76) | @Test

FILE: app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/PlainTweeterTest.java
  class PlainTweeterTest (line 36) | @RunWith(AndroidJUnit4.class)
    method setUp (line 49) | @Before
    method testWebpage (line 63) | @Test
    method testLogin (line 101) | @Test
    method testTweets (line 126) | @Test

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/CleanArchitectureApplication.java
  class CleanArchitectureApplication (line 12) | public class CleanArchitectureApplication extends Application{
    method onCreate (line 16) | @Override
    method getBaseComponent (line 28) | public static BaseComponent getBaseComponent(){

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/components/ActivityInjectorComponent.java
  type ActivityInjectorComponent (line 14) | @ActivityScope
    method inject (line 18) | void inject(PlainTweeterActivity activity);
    method inject (line 20) | void inject(TweeterActivityMVP activityMVP);
    method inject (line 22) | void inject(TweeterActivityMVVM activityMVVM);
    method inject (line 24) | void inject(TweeterActivityMVPCI activityMVPCI);

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/components/ApplicationComponent.java
  type ApplicationComponent (line 12) | @Singleton
    method getApplication (line 15) | Application getApplication();

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/components/BaseComponent.java
  type BaseComponent (line 20) | @ApplicationScope
    method getOkHTTP (line 24) | OKHttp getOkHTTP();
    method getRetrofit (line 26) | Retrofit getRetrofit();
    method getLocalDataCache (line 28) | LocalDataCache getLocalDataCache();
    method getMainScheduler (line 30) | @Named(Constants.MAIN_THREAD)

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/interactors/NetworkInteractor.java
  class NetworkInteractor (line 16) | public class NetworkInteractor extends BaseInteractor {
    method NetworkInteractor (line 22) | @Inject
    method attemptLogin (line 28) | public Observable<UserProfile> attemptLogin(String username, String pa...
    method logout (line 32) | public Observable<Object> logout(){
    method fetchTweet (line 36) | public Observable<String> fetchTweet() {
    method fetchTweets (line 40) | public Observable<List<String>> fetchTweets(int count) {
    method loadWebpage (line 44) | public Observable<String> loadWebpage(String url){

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/interactors/base/BaseInteractor.java
  class BaseInteractor (line 3) | public class BaseInteractor {

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/ApplicationModule.java
  class ApplicationModule (line 13) | @Module
    method ApplicationModule (line 18) | public ApplicationModule(Application application) {
    method providesApplication (line 22) | @Singleton

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/InteractorModule.java
  class InteractorModule (line 12) | @Module
    method providesNetworkInteractor (line 15) | @Provides

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/LocalModule.java
  class LocalModule (line 14) | @Module
    method providesDataCache (line 17) | @ApplicationScope

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/NetworkModule.java
  class NetworkModule (line 15) | @Module
    method providesOkHTTP (line 18) | @ApplicationScope
    method providesRetrofit (line 24) | @ApplicationScope

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/PresenterModule.java
  class PresenterModule (line 11) | @Module
    method providesMainPresenter (line 14) | @Provides

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/ThreadingModule.java
  class ThreadingModule (line 11) | @Module
    method providesMainThread (line 13) | @Named(Constants.MAIN_THREAD)

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/localdata/LocalDataCache.java
  class LocalDataCache (line 12) | public class LocalDataCache {
    method LocalDataCache (line 18) | public LocalDataCache(Context context) {
    method saveTweet (line 23) | public void saveTweet(String tweet) {
    method fetchRecentTweets (line 27) | public Observable<List<String>> fetchRecentTweets() {

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/network/TweeterApi.java
  class TweeterApi (line 18) | public class TweeterApi {
    method TweeterApi (line 25) | @Inject
    method getTweet (line 32) | public Observable<String> getTweet(){
    method fetchXrecents (line 49) | public Observable<List<String>> fetchXrecents(int count){
    method login (line 63) | public Observable<UserProfile> login(String username, String password) {
    method logout (line 73) | public Observable<Object> logout(){
    method isLoggedIn (line 80) | public boolean isLoggedIn(){

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/network/base/OKHttp.java
  class OKHttp (line 6) | public class OKHttp {
    method rawResponse (line 8) | public String rawResponse(){

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/network/base/Retrofit.java
  class Retrofit (line 9) | public class Retrofit {
    method Retrofit (line 13) | public Retrofit(OKHttp okHttp, Scheduler mainScheduler) {
    method completeRequest (line 18) | public Observable<String> completeRequest(){
    method fetchSomePage (line 23) | public Observable<String> fetchSomePage(String url){

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/BaseCleanArchitectureActivity.java
  class BaseCleanArchitectureActivity (line 11) | public class BaseCleanArchitectureActivity extends AppCompatActivity{
    method onCreate (line 16) | @Override
    method registerSubscription (line 24) | protected void registerSubscription(Subscription subscription){
    method onStop (line 28) | @Override
    method unsubscribeSubscriptions (line 34) | protected void unsubscribeSubscriptions(){

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/TweeterActivityMVP.java
  class TweeterActivityMVP (line 31) | public class TweeterActivityMVP extends BasePresenterActivity<TweeterMVP...
    method onClick (line 52) | @Override
    method onClick (line 72) | @Override
    method onCreate (line 98) | @Override
    method getPresenter (line 114) | @Override
    method displayFetchedTweet (line 129) | @Override
    method displayPreviousTweets (line 134) | @Override
    method registerViewToPresenter (line 144) | @Override
    method displayToast (line 149) | @Override
    method toggleProgressBar (line 154) | @Override
    method setUserButtonText (line 159) | @Override
    method toggleLoginContainer (line 164) | @Override
    method displayWebpage (line 169) | @Override
    method newInstance (line 174) | public static Intent newInstance(Context context) {

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/TweeterMVPPresenterImpl.java
  class TweeterMVPPresenterImpl (line 11) | public class TweeterMVPPresenterImpl implements TweeterMVPPresenter {
    method TweeterMVPPresenterImpl (line 20) | public TweeterMVPPresenterImpl(TweeterApi tweeterApi, Retrofit retrofi...
    method registerView (line 25) | @Override
    method onAttach (line 30) | @Override
    method onDetach (line 35) | @Override
    method fetchCurrentTweet (line 40) | @Override
    method fetchPreviousTweets (line 53) | @Override
    method toggleLogin (line 64) | @Override
    method loadWebPage (line 89) | @Override

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/base/BasePresenterActivity.java
  class BasePresenterActivity (line 12) | public abstract class BasePresenterActivity<T extends Presenter> extends...
    method onCreate (line 14) | @Override
    method onResume (line 20) | @Override
    method onPause (line 26) | @Override
    method registerViewToPresenter (line 32) | protected abstract void registerViewToPresenter();
    method getPresenter (line 33) | protected abstract T getPresenter();

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/base/Interfaces/PView.java
  type PView (line 6) | public interface PView {
    method toggleProgressBar (line 8) | public void toggleProgressBar(boolean loading);
    method displayToast (line 10) | public void displayToast(String toast);

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/base/Interfaces/Presenter.java
  type Presenter (line 6) | public interface Presenter<T extends PView> {
    method registerView (line 8) | public void registerView(T activity);
    method onAttach (line 9) | public void onAttach();
    method onDetach (line 10) | public void onDetach();

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/interfaces/TweeterMVPPView.java
  type TweeterMVPPView (line 10) | public interface TweeterMVPPView extends PView {
    method displayFetchedTweet (line 11) | public void displayFetchedTweet(String tweet);
    method displayPreviousTweets (line 13) | public void displayPreviousTweets(List<String> list);
    method setUserButtonText (line 15) | public void setUserButtonText(String text);
    method toggleLoginContainer (line 17) | void toggleLoginContainer(boolean b);
    method displayWebpage (line 19) | void displayWebpage(String html);

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/interfaces/TweeterMVPPresenter.java
  type TweeterMVPPresenter (line 8) | public interface TweeterMVPPresenter extends Presenter<TweeterMVPPView> {
    method fetchCurrentTweet (line 10) | public void fetchCurrentTweet();
    method fetchPreviousTweets (line 12) | public void fetchPreviousTweets();
    method toggleLogin (line 14) | public void toggleLogin(String userName, String userPassword);
    method loadWebPage (line 16) | void loadWebPage(String url);

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/TweeterActivityMVPCI.java
  class TweeterActivityMVPCI (line 37) | public class TweeterActivityMVPCI extends BasePresenterActivityMVPCI<Twe...
    method onClick (line 58) | @Override
    method onClick (line 81) | @Override
    method onCreate (line 107) | @Override
    method getPresenter (line 122) | @Override
    method displayToast (line 135) | @Override
    method displayTweets (line 140) | private void displayTweets(List<String> list) {
    method toggleProgressBar (line 150) | @Override
    method loggedIn (line 156) | @Override
    method loggedOut (line 163) | @Override
    method newInstance (line 170) | public static Intent newInstance(Context context) {

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/TweeterMVPCIPresenter.java
  class TweeterMVPCIPresenter (line 19) | public class TweeterMVPCIPresenter extends BasePresenterMVPCI<TweeterAct...
    method TweeterMVPCIPresenter (line 28) | @Inject
    method onAttach (line 34) | @Override
    method onDettach (line 39) | @Override
    method fetchCurrentTweet (line 44) | public Observable<String> fetchCurrentTweet() {
    method fetchPreviousTweets (line 58) | public Observable<List<String>> fetchPreviousTweets() {
    method toggleLogin (line 68) | public void toggleLogin(String userName, String password){
    method loadWebPage (line 94) | public Observable<String> loadWebPage(String url){

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/base/BasePresenterActivityMVPCI.java
  class BasePresenterActivityMVPCI (line 8) | public abstract class BasePresenterActivityMVPCI<T extends BasePresenter...
    method onCreate (line 10) | @Override
    method onResume (line 16) | @Override
    method onPause (line 22) | @Override
    method getPresenter (line 28) | protected abstract T getPresenter();

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/base/BasePresenterMVPCI.java
  class BasePresenterMVPCI (line 5) | public class BasePresenterMVPCI<T extends PView> {
    method onAttach (line 9) | public void onAttach(){
    method onDettach (line 12) | public void onDettach(){
    method registerPresenter (line 16) | public void registerPresenter(T view){
    method getPView (line 20) | protected T getPView(){

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/interfaces/TweeterActivityMVPCIPview.java
  type TweeterActivityMVPCIPview (line 9) | public interface TweeterActivityMVPCIPview extends PView{
    method loggedIn (line 10) | public void loggedIn(UserProfile profile);
    method loggedOut (line 12) | public void loggedOut();

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/models/UserProfile.java
  class UserProfile (line 6) | public class UserProfile {
    method UserProfile (line 10) | public UserProfile(String username, String password) {
    method getFormattedCredentials (line 15) | public String getFormattedCredentials(){
    method getUserName (line 19) | public String getUserName() {

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/MainViewmodel.java
  class MainViewModel (line 14) | public class MainViewModel extends BaseViewModel {
    method MainViewModel (line 24) | @Inject
    method fetchCurrentTweet (line 30) | public Observable<String> fetchCurrentTweet(){
    method fetchPreviousTweets (line 42) | public Observable<List<String>> fetchPreviousTweets(){
    method isLoggedIn (line 46) | public boolean isLoggedIn(){
    method toggleLogin (line 50) | public Observable<UserProfile> toggleLogin(String userName, String pas...
    method getMessageStream (line 62) | public Observable<String> getMessageStream() {
    method loadWebPage (line 69) | public Observable<String> loadWebPage(String url){

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/TweeterActivityMVVM.java
  class TweeterActivityMVVM (line 30) | public class TweeterActivityMVVM extends BaseViewModelActivity<MainViewM...
    method onClick (line 50) | @Override
    method onClick (line 88) | @Override
    method onCreate (line 114) | @Override
    method getViewModel (line 131) | @Override
    method onResume (line 143) | @Override
    method displayTweets (line 151) | private void displayTweets(List<String> list) {
    method toggleLogin (line 162) | private void toggleLogin(UserProfile profile){
    method newInstance (line 177) | public static Intent newInstance(Context context) {

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/base/BaseViewModel.java
  class BaseViewModel (line 3) | public class BaseViewModel {
    method onAttach (line 5) | public void onAttach(){
    method onDettach (line 9) | public void onDettach(){

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/base/BaseViewModelActivity.java
  class BaseViewModelActivity (line 7) | public abstract class BaseViewModelActivity<T extends BaseViewModel> ext...
    method onCreate (line 9) | @Override
    method onResume (line 15) | @Override
    method onPause (line 21) | @Override
    method getViewModel (line 27) | protected abstract T getViewModel();

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/PlainTweeterActivity.java
  class PlainTweeterActivity (line 30) | public class PlainTweeterActivity extends BaseCleanArchitectureActivity {
    method onClick (line 72) | @Override
    method onClick (line 125) | @Override
    method onCreate (line 151) | @Override
    method displayPreviousTweets (line 174) | public void displayPreviousTweets(List<String> tweets) {
    method userLogin (line 184) | public void userLogin(UserProfile profile) {
    method newInstance (line 191) | public static Intent newInstance(Context context) {

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/RouterActivity.java
  class RouterActivity (line 21) | public class RouterActivity extends AppCompatActivity {
    method onClick (line 37) | @Override
    method onCreate (line 57) | @Override

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/util/Constants.java
  class Constants (line 3) | public class Constants {

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/util/LoadingFragment.java
  class LoadingFragment (line 12) | public class LoadingFragment extends Fragment {
    method onCreateView (line 14) | @Nullable

FILE: app/src/main/java/io/patrykpoborca/cleanarchitecture/util/utility.java
  class Utility (line 9) | public class Utility {
    method toggleProgressbar (line 13) | public static void toggleProgressbar(AppCompatActivity activity, boole...
    method toggleProgressbar (line 33) | public static void toggleProgressbar(AppCompatActivity activity, Obser...

FILE: app/src/test/java/dagger/TestClassInjector.java
  type TestClassInjector (line 10) | @ActivityScope
    method inject (line 13) | void inject(MVVMTest viewmodelTest);
    method inject (line 15) | void inject(MVPCITest presenterTest);
    method inject (line 17) | void inject(MVPTest MVPTest);

FILE: app/src/test/java/dagger/mockmodules/MockLocalModule.java
  class MockLocalModule (line 9) | public class MockLocalModule extends LocalModule{
    method providesDataCache (line 11) | @Override

FILE: app/src/test/java/dagger/mockmodules/MockNetworkModule.java
  class MockNetworkModule (line 10) | public class MockNetworkModule extends NetworkModule {
    method providesOkHTTP (line 12) | @Override
    method providesRetrofit (line 17) | @Override

FILE: app/src/test/java/dagger/mockmodules/MockTestModule.java
  class MockTestModule (line 19) | @Module
    method providesMainPresenter (line 22) | @Provides
    method providesMockMainPview (line 28) | @ActivityScope
    method providesMockTweeter (line 36) | @ActivityScope
    method providesMockMVPCCIView (line 42) | @ActivityScope

FILE: app/src/test/java/dagger/mockmodules/MockThreadingModule.java
  class MockThreadingModule (line 7) | public class MockThreadingModule extends ThreadingModule {
    method providesMainThread (line 9) | @Override

FILE: app/src/test/java/helper/TestHelper.java
  class TestHelper (line 17) | public class TestHelper {
    method getApplicationComponent (line 23) | public static ApplicationComponent getApplicationComponent(){
    method getBaseComponent (line 33) | public static BaseComponent getBaseComponent(){
    method getTestClassInjector (line 45) | public static TestClassInjector getTestClassInjector(){
    method waitFor (line 55) | public static void waitFor(IWaitingCallback callback){
    method waitFor (line 59) | public static void waitFor(int maxCycles, IWaitingCallback callback){
    type IWaitingCallback (line 76) | public static interface IWaitingCallback{
      method checkCondition (line 81) | public boolean checkCondition();

FILE: app/src/test/java/mockimpl/MockLocalDataCache.java
  class MockLocalDataCache (line 12) | public class MockLocalDataCache extends LocalDataCache {
    method MockLocalDataCache (line 14) | public MockLocalDataCache(Context context) {
    method saveTweet (line 21) | @Override
    method fetchRecentTweets (line 26) | @Override

FILE: app/src/test/java/mockimpl/MockMVPCIPview.java
  class MockMVPCIPview (line 6) | public class MockMVPCIPview implements TweeterActivityMVPCIPview {
    method loggedIn (line 12) | @Override
    method loggedOut (line 17) | @Override
    method toggleProgressBar (line 22) | @Override
    method displayToast (line 27) | @Override

FILE: app/src/test/java/mockimpl/MockOkHTTP.java
  class MockOkHTTP (line 5) | public class MockOkHTTP extends OKHttp {
    method rawResponse (line 6) | @Override

FILE: app/src/test/java/mockimpl/MockRetrofit.java
  class MockRetrofit (line 11) | public class MockRetrofit extends Retrofit{
    method MockRetrofit (line 15) | public MockRetrofit(OKHttp okHttp, Scheduler mainScheduler) {
    method completeRequest (line 19) | @Override
    method fetchSomePage (line 24) | @Override

FILE: app/src/test/java/mockimpl/MockTweeterActivityPview.java
  class MockTweeterActivityPview (line 7) | public class MockTweeterActivityPview implements TweeterMVPPView {
    method displayFetchedTweet (line 17) | @Override
    method displayPreviousTweets (line 22) | @Override
    method setUserButtonText (line 27) | @Override
    method toggleLoginContainer (line 32) | @Override
    method displayWebpage (line 37) | @Override
    method toggleProgressBar (line 42) | @Override
    method displayToast (line 47) | @Override

FILE: app/src/test/java/mockimpl/MockTweeterApi.java
  class MockTweeterApi (line 12) | public class MockTweeterApi extends TweeterApi{
    method MockTweeterApi (line 13) | public MockTweeterApi(Retrofit retrofit, LocalDataCache dataCache, Sch...
    method login (line 17) | @Override
    method logout (line 23) | @Override

FILE: app/src/test/java/tests/MVPCITest.java
  class MVPCITest (line 18) | @RunWith(JUnit4.class)
    method setUp (line 31) | @Before
    method testWebPage (line 42) | @Test
    method testLogin (line 52) | @Test
    method testTweets (line 64) | @Test
    method testTweetList (line 75) | @Test

FILE: app/src/test/java/tests/MVPTest.java
  class MVPTest (line 20) | @RunWith(JUnit4.class)
    method setUp (line 33) | @Before
    method testLogin (line 44) | @Test
    method testFetchTweets (line 57) | @Test
    method testWebPage (line 75) | @Test

FILE: app/src/test/java/tests/MVVMTest.java
  class MVVMTest (line 18) | @RunWith(JUnit4.class)
    method setUp (line 29) | @Before
    method testWebPage (line 41) | @Test
    method testLogin (line 51) | @Test
    method testTweets (line 65) | @Test
    method testTweetList (line 76) | @Test
Condensed preview — 102 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (154K chars).
[
  {
    "path": ".gitignore",
    "chars": 97,
    "preview": ".gradle\n*.iml\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n"
  },
  {
    "path": ".idea/.name",
    "chars": 17,
    "preview": "CleanArchitecture"
  },
  {
    "path": ".idea/compiler.xml",
    "chars": 656,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"CompilerConfiguration\">\n    <resourceExt"
  },
  {
    "path": ".idea/copyright/profiles_settings.xml",
    "chars": 74,
    "preview": "<component name=\"CopyrightManager\">\n  <settings default=\"\" />\n</component>"
  },
  {
    "path": ".idea/encodings.xml",
    "chars": 159,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"Encoding\">\n    <file url=\"PROJECT\" chars"
  },
  {
    "path": ".idea/gradle.xml",
    "chars": 739,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"GradleSettings\">\n    <option name=\"linke"
  },
  {
    "path": ".idea/misc.xml",
    "chars": 5090,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"EntryPointsManager\">\n    <entry_points v"
  },
  {
    "path": ".idea/modules.xml",
    "chars": 371,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n   "
  },
  {
    "path": ".idea/runConfigurations.xml",
    "chars": 564,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"RunConfigurationProducerService\">\n    <o"
  },
  {
    "path": ".idea/vcs.xml",
    "chars": 167,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping dire"
  },
  {
    "path": "README.md",
    "chars": 1265,
    "preview": "# CleanArchitecture\n\nThanks for checking out my github repo. There's not much to say in this readme since I wrote two ar"
  },
  {
    "path": "app/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "chars": 2508,
    "preview": "apply plugin: 'me.tatarka.retrolambda'\napply plugin: 'com.android.application'\napply plugin: 'com.neenbedankt.android-ap"
  },
  {
    "path": "app/proguard-rules.pro",
    "chars": 672,
    "preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in C:"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/TestHelper.java",
    "chars": 2789,
    "preview": "package io.patrykpoborca.cleanarchitecture;\n\nimport android.app.Application;\n\nimport io.patrykpoborca.cleanarchitecture."
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/TestClassInjector.java",
    "chars": 715,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger;\n\nimport dagger.Component;\nimport io.patrykpoborca.cleanarchitecture.d"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockLocalModule.java",
    "chars": 506,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.mockmodules;\n\nimport android.app.Application;\n\nimport io.patrykpoborca"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockNetworkModule.java",
    "chars": 833,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.mockmodules;\n\nimport javax.inject.Named;\n\nimport io.patrykpoborca.clea"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/dagger/mockmodules/MockTestModule.java",
    "chars": 1772,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.mockmodules;\n\nimport javax.inject.Named;\n\nimport dagger.Module;\nimport"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockLocalDataCache.java",
    "chars": 699,
    "preview": "package io.patrykpoborca.cleanarchitecture.mockimpl;\n\nimport android.content.Context;\n\nimport java.util.List;\n\nimport io"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockMVPCIPview.java",
    "chars": 792,
    "preview": "package io.patrykpoborca.cleanarchitecture.mockimpl;\n\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.interfaces.Twee"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockOkHTTP.java",
    "chars": 255,
    "preview": "package io.patrykpoborca.cleanarchitecture.mockimpl;\n\nimport io.patrykpoborca.cleanarchitecture.network.base.OKHttp;\n\npu"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockRetrofit.java",
    "chars": 892,
    "preview": "package io.patrykpoborca.cleanarchitecture.mockimpl;\n\nimport io.patrykpoborca.cleanarchitecture.network.base.OKHttp;\nimp"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockTweeterActivityPview.java",
    "chars": 1310,
    "preview": "package io.patrykpoborca.cleanarchitecture.mockimpl;\n\nimport java.util.List;\n\nimport io.patrykpoborca.cleanarchitecture."
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/mockimpl/MockTweeterApi.java",
    "chars": 862,
    "preview": "package io.patrykpoborca.cleanarchitecture.mockimpl;\n\nimport android.util.Log;\n\nimport io.patrykpoborca.cleanarchitectur"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/MVPCITest.java",
    "chars": 3251,
    "preview": "package io.patrykpoborca.cleanarchitecture.tests;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Te"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/MVPTest.java",
    "chars": 2691,
    "preview": "package io.patrykpoborca.cleanarchitecture.tests;\n\nimport android.support.test.runner.AndroidJUnit4;\n\nimport junit.frame"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/MVVMTest.java",
    "chars": 3061,
    "preview": "package io.patrykpoborca.cleanarchitecture.tests;\n\nimport android.support.test.runner.AndroidJUnit4;\n\nimport junit.frame"
  },
  {
    "path": "app/src/androidTest/java/io/patrykpoborca/cleanarchitecture/tests/PlainTweeterTest.java",
    "chars": 6208,
    "preview": "package io.patrykpoborca.cleanarchitecture.tests;\n\nimport android.support.test.espresso.matcher.ViewMatchers;\nimport and"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "chars": 1109,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package="
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/CleanArchitectureApplication.java",
    "chars": 1172,
    "preview": "package io.patrykpoborca.cleanarchitecture;\n\nimport android.app.Application;\n\nimport io.patrykpoborca.cleanarchitecture."
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/components/ActivityInjectorComponent.java",
    "chars": 906,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.components;\n\nimport dagger.Component;\nimport io.patrykpoborca.cleanarc"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/components/ApplicationComponent.java",
    "chars": 439,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.components;\n\nimport android.app.Application;\n\nimport javax.inject.Sing"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/components/BaseComponent.java",
    "chars": 1138,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.components;\n\nimport javax.inject.Named;\nimport javax.inject.Singleton;"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/interactors/NetworkInteractor.java",
    "chars": 1289,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.interactors;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\n\nimp"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/interactors/base/BaseInteractor.java",
    "chars": 101,
    "preview": "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",
    "chars": 572,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.modules;\n\nimport android.app.Application;\nimport android.content.Conte"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/InteractorModule.java",
    "chars": 557,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.modules;\n\nimport dagger.Module;\nimport dagger.Provides;\nimport io.patr"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/LocalModule.java",
    "chars": 548,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.modules;\n\nimport android.app.Application;\nimport android.content.Conte"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/NetworkModule.java",
    "chars": 798,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.modules;\n\nimport javax.inject.Named;\nimport javax.inject.Singleton;\n\ni"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/PresenterModule.java",
    "chars": 682,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.modules;\n\nimport dagger.Module;\nimport dagger.Provides;\nimport io.patr"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/modules/ThreadingModule.java",
    "chars": 447,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.modules;\n\nimport javax.inject.Named;\n\nimport dagger.Module;\nimport dag"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/scopes/ActivityScope.java",
    "chars": 251,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.scopes;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annot"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/scopes/ApplicationScope.java",
    "chars": 254,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.scopes;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annot"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/dagger/scopes/ExposedAPIScope.java",
    "chars": 253,
    "preview": "package io.patrykpoborca.cleanarchitecture.dagger.scopes;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annot"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/localdata/LocalDataCache.java",
    "chars": 864,
    "preview": "package io.patrykpoborca.cleanarchitecture.localdata;\n\nimport android.content.Context;\n\nimport java.util.ArrayList;\nimpo"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/network/TweeterApi.java",
    "chars": 2619,
    "preview": "package io.patrykpoborca.cleanarchitecture.network;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/network/base/OKHttp.java",
    "chars": 192,
    "preview": "package io.patrykpoborca.cleanarchitecture.network.base;\n\nimport java.util.UUID;\n\n\npublic class OKHttp {\n\n    public Str"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/network/base/Retrofit.java",
    "chars": 855,
    "preview": "package io.patrykpoborca.cleanarchitecture.network.base;\n\nimport java.util.concurrent.TimeUnit;\n\nimport rx.Observable;\ni"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/BaseCleanArchitectureActivity.java",
    "chars": 928,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui;\n\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivit"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/TweeterActivityMVP.java",
    "chars": 6113,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVP;\n\nimport android.content.Context;\nimport android.content.Intent;\nimpor"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/TweeterMVPPresenterImpl.java",
    "chars": 3335,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVP;\n\nimport io.patrykpoborca.cleanarchitecture.network.TweeterApi;\nimport"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/base/BasePresenterActivity.java",
    "chars": 964,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVP.base;\n\nimport android.os.Bundle;\n\nimport io.patrykpoborca.cleanarchite"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/base/Interfaces/PView.java",
    "chars": 236,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces;\n\n/**\n * Created by Patryk on 7/28/2015.\n */\npublic in"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/base/Interfaces/Presenter.java",
    "chars": 258,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfaces;\n\n/**\n * Created by Patryk on 7/28/2015.\n */\npublic in"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/interfaces/TweeterMVPPView.java",
    "chars": 495,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces;\n\nimport java.util.List;\n\nimport io.patrykpoborca.cleanarch"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVP/interfaces/TweeterMVPPresenter.java",
    "chars": 444,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces;\n\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.base.Int"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/TweeterActivityMVPCI.java",
    "chars": 6583,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVPCI;\n\nimport android.content.Context;\nimport android.content.Intent;\nimp"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/TweeterMVPCIPresenter.java",
    "chars": 3159,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVPCI;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\nimport javax.i"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/base/BasePresenterActivityMVPCI.java",
    "chars": 811,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVPCI.base;\n\nimport android.os.Bundle;\n\nimport io.patrykpoborca.cleanarchi"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/base/BasePresenterMVPCI.java",
    "chars": 418,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVPCI.base;\n\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.base.Interfa"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/interfaces/TweeterActivityMVPCIPview.java",
    "chars": 389,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVPCI.interfaces;\n\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.base.I"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVPCI/models/UserProfile.java",
    "chars": 516,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVPCI.models;\n\n/**\n * Created by Patryk on 7/29/2015.\n */\npublic class Use"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/MainViewmodel.java",
    "chars": 2048,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVVM;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\n\nimport io.patr"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/TweeterActivityMVVM.java",
    "chars": 6904,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVVM;\n\nimport android.content.Context;\nimport android.content.Intent;\nimpo"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/base/BaseViewModel.java",
    "chars": 162,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVVM.base;\n\npublic class BaseViewModel {\n\n    public void onAttach(){\n\n   "
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/MVVM/base/BaseViewModelActivity.java",
    "chars": 688,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui.MVVM.base;\n\nimport android.os.Bundle;\n\nimport io.patrykpoborca.cleanarchit"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/PlainTweeterActivity.java",
    "chars": 7227,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport an"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/ui/RouterActivity.java",
    "chars": 2106,
    "preview": "package io.patrykpoborca.cleanarchitecture.ui;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/util/Constants.java",
    "chars": 138,
    "preview": "package io.patrykpoborca.cleanarchitecture.util;\n\npublic class Constants {\n\n    public static final String MAIN_THREAD ="
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/util/LoadingFragment.java",
    "chars": 568,
    "preview": "package io.patrykpoborca.cleanarchitecture.util;\n\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\n"
  },
  {
    "path": "app/src/main/java/io/patrykpoborca/cleanarchitecture/util/utility.java",
    "chars": 1288,
    "preview": "package io.patrykpoborca.cleanarchitecture.util;\n\nimport android.support.v4.app.Fragment;\nimport android.support.v7.app."
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "chars": 5833,
    "preview": "<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            xmlns:tools=\"http://schemas.android.c"
  },
  {
    "path": "app/src/main/res/layout/activity_router.xml",
    "chars": 1954,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\n         "
  },
  {
    "path": "app/src/main/res/layout/fragment_progress.xml",
    "chars": 562,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n         "
  },
  {
    "path": "app/src/main/res/menu/menu_main.xml",
    "chars": 392,
    "preview": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n      xmlns:app=\"http://schemas.android.com/apk/res-aut"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "chars": 211,
    "preview": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "chars": 779,
    "preview": "<resources>\n    <string name=\"app_name\">CleanArchitecture</string>\n\n    <string name=\"hello_world\">Hello world!</string>"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "chars": 194,
    "preview": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "chars": 358,
    "preview": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as s"
  },
  {
    "path": "app/src/test/java/dagger/TestClassInjector.java",
    "chars": 527,
    "preview": "package dagger;\n\nimport dagger.mockmodules.MockTestModule;\nimport io.patrykpoborca.cleanarchitecture.dagger.components.B"
  },
  {
    "path": "app/src/test/java/dagger/mockmodules/MockLocalModule.java",
    "chars": 436,
    "preview": "package dagger.mockmodules;\n\nimport android.app.Application;\n\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.L"
  },
  {
    "path": "app/src/test/java/dagger/mockmodules/MockNetworkModule.java",
    "chars": 619,
    "preview": "package dagger.mockmodules;\n\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.NetworkModule;\nimport io.patrykpob"
  },
  {
    "path": "app/src/test/java/dagger/mockmodules/MockTestModule.java",
    "chars": 1635,
    "preview": "package dagger.mockmodules;\n\nimport javax.inject.Named;\n\nimport dagger.Module;\nimport dagger.Provides;\nimport io.patrykp"
  },
  {
    "path": "app/src/test/java/dagger/mockmodules/MockThreadingModule.java",
    "chars": 323,
    "preview": "package dagger.mockmodules;\n\nimport io.patrykpoborca.cleanarchitecture.dagger.modules.ThreadingModule;\nimport rx.Schedul"
  },
  {
    "path": "app/src/test/java/helper/TestHelper.java",
    "chars": 2733,
    "preview": "package helper;\n\nimport android.app.Application;\n\nimport dagger.DaggerTestClassInjector;\nimport dagger.TestClassInjector"
  },
  {
    "path": "app/src/test/java/mockimpl/MockLocalDataCache.java",
    "chars": 813,
    "preview": "package mockimpl;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport java.util.ArrayList;\nimport java.uti"
  },
  {
    "path": "app/src/test/java/mockimpl/MockMVPCIPview.java",
    "chars": 757,
    "preview": "package mockimpl;\n\nimport io.patrykpoborca.cleanarchitecture.ui.MVPCI.interfaces.TweeterActivityMVPCIPview;\nimport io.pa"
  },
  {
    "path": "app/src/test/java/mockimpl/MockOkHTTP.java",
    "chars": 220,
    "preview": "package mockimpl;\n\nimport io.patrykpoborca.cleanarchitecture.network.base.OKHttp;\n\npublic class MockOkHTTP extends OKHtt"
  },
  {
    "path": "app/src/test/java/mockimpl/MockRetrofit.java",
    "chars": 859,
    "preview": "package mockimpl;\n\nimport java.util.concurrent.TimeUnit;\n\nimport io.patrykpoborca.cleanarchitecture.network.base.OKHttp;"
  },
  {
    "path": "app/src/test/java/mockimpl/MockTweeterActivityPview.java",
    "chars": 1275,
    "preview": "package mockimpl;\n\nimport java.util.List;\n\nimport io.patrykpoborca.cleanarchitecture.ui.MVP.interfaces.TweeterMVPPView;\n"
  },
  {
    "path": "app/src/test/java/mockimpl/MockTweeterApi.java",
    "chars": 911,
    "preview": "package mockimpl;\n\nimport android.util.Log;\n\nimport io.patrykpoborca.cleanarchitecture.localdata.LocalDataCache;\nimport "
  },
  {
    "path": "app/src/test/java/tests/MVPCITest.java",
    "chars": 3048,
    "preview": "package tests;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith"
  },
  {
    "path": "app/src/test/java/tests/MVPTest.java",
    "chars": 2465,
    "preview": "package tests;\n\n\nimport junit.framework.Assert;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner"
  },
  {
    "path": "app/src/test/java/tests/MVVMTest.java",
    "chars": 2869,
    "preview": "package tests;\n\nimport junit.framework.Assert;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner."
  },
  {
    "path": "build.gradle",
    "chars": 835,
    "preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    r"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 231,
    "preview": "#Tue Mar 29 10:09:27 CDT 2016\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "gradle.properties",
    "chars": 855,
    "preview": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will o"
  },
  {
    "path": "gradlew",
    "chars": 5080,
    "preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start "
  },
  {
    "path": "gradlew.bat",
    "chars": 2314,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
  },
  {
    "path": "settings.gradle",
    "chars": 15,
    "preview": "include ':app'\n"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the patrykpoborca/CleanArchitecture GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 102 files (135.7 KB), approximately 34.2k tokens, and a symbol index with 322 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!