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'
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
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.