diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..293d9aeac
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.idea
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..1d233faca
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Mohanraj K.M.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 000000000..796b96d1c
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/README.md b/app/README.md
new file mode 100644
index 000000000..19a14cbe9
--- /dev/null
+++ b/app/README.md
@@ -0,0 +1,9 @@
+Para executar o projeto basta clonar esse repositório, da seguinte forma:
+
+1. Execute o GitBash na basta destino e digite o comando : git clone https://github.com/netogdn999/TesteAndroidv2.git
+
+2. Sincronize o gradle para baixar as dependencias
+
+3. Caso deseje executar os testes unitários, clique com o botão direito do mouse em cima do diretório de teste: com.example.testeandroidv2, em seguida clique em: 'Run Tests in 'com.example.testeandroidv2'' with Covarage
+
+4. Execute o projeto no emulador ou em um dispositivo do seu desejo, clicando em 'Run' ou Shift+f10 (caso esteja utilizando o windows)
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 000000000..54e573d53
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,57 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 29
+ buildToolsVersion '29.0.2'
+
+ defaultConfig {
+ applicationId "com.testeandroidv2"
+ minSdkVersion 19
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+ vectorDrawables.useSupportLibrary = true
+ testInstrumentationRunner 'org.robolectric.RobolectricTestRunner'
+ testFunctionalTest true
+ }
+ configurations {
+ cleanedAnnotations
+ compile.exclude group: 'org.jetbrains' , module:'annotations'
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions{
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ testOptions {
+ unitTests {
+ includeAndroidResources true
+ returnDefaultValues true
+ }
+ }
+
+ buildFeatures {
+ dataBinding true
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ testImplementation 'junit:junit:4.13'
+ testImplementation "androidx.test:core:1.2.0"
+ implementation 'com.squareup.retrofit:retrofit:2.0.0-beta2'
+ implementation 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.7.2'
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta7'
+ implementation 'org.jetbrains:annotations-java5:15.0'
+ implementation 'androidx.recyclerview:recyclerview:1.1.0'
+ testImplementation 'org.robolectric:robolectric:4.3.1'
+}
+
diff --git a/app/gradle/wrapper/gradle-wrapper.jar b/app/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..f6b961fd5
Binary files /dev/null and b/app/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/app/gradle/wrapper/gradle-wrapper.properties b/app/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..23ff7e2cd
--- /dev/null
+++ b/app/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Jun 17 14:37:35 GFT 2020
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
diff --git a/app/gradlew b/app/gradlew
new file mode 100644
index 000000000..cccdd3d51
--- /dev/null
+++ b/app/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# 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\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# 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
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+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" -a "$nonstop" = "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"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # 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
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/app/gradlew.bat b/app/gradlew.bat
new file mode 100644
index 000000000..f9553162f
--- /dev/null
+++ b/app/gradlew.bat
@@ -0,0 +1,84 @@
+@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
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@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=
+
+@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 Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_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=%*
+
+: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
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# 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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..4d22b773f
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/testeandroidv2/Service/Api.java b/app/src/main/java/com/example/testeandroidv2/Service/Api.java
new file mode 100644
index 000000000..69bd7ab76
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/Service/Api.java
@@ -0,0 +1,16 @@
+package com.example.testeandroidv2.Service;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import retrofit.GsonConverterFactory;
+import retrofit.Retrofit;
+
+public class Api {
+
+ public static Retrofit getRetrofitInstance(String path){
+ return new Retrofit.Builder().baseUrl(path)
+ .addConverterFactory(GsonConverterFactory.create())
+ .build();
+ }
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/Service/LoginService.java b/app/src/main/java/com/example/testeandroidv2/Service/LoginService.java
new file mode 100644
index 000000000..65260dfc2
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/Service/LoginService.java
@@ -0,0 +1,15 @@
+package com.example.testeandroidv2.Service;
+
+import com.google.gson.JsonObject;
+
+import retrofit.Call;
+import retrofit.http.Field;
+import retrofit.http.FormUrlEncoded;
+import retrofit.http.POST;
+
+public interface LoginService {
+
+ @FormUrlEncoded
+ @POST("login")
+ Call authentication(@Field("user") String user, @Field("password") String password);
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/Service/StatementService.java b/app/src/main/java/com/example/testeandroidv2/Service/StatementService.java
new file mode 100644
index 000000000..4607f6db1
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/Service/StatementService.java
@@ -0,0 +1,16 @@
+package com.example.testeandroidv2.Service;
+
+import com.google.gson.JsonObject;
+
+import java.util.List;
+
+import retrofit.Call;
+import retrofit.http.FormUrlEncoded;
+import retrofit.http.GET;
+import retrofit.http.Path;
+
+public interface StatementService {
+
+ @GET("statements/{id}")
+ Call getStatements(@Path("id") int userId);
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginActivity.java b/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginActivity.java
new file mode 100644
index 000000000..3222c18c0
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginActivity.java
@@ -0,0 +1,83 @@
+package com.example.testeandroidv2.loginScreen;
+
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import com.example.testeandroidv2.R;
+import com.example.testeandroidv2.databinding.LoginScreenBinding;
+import com.google.gson.Gson;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.databinding.DataBindingUtil;
+
+interface LoginActivityInput {
+ void displayLoginData(UserViewModel userViewModel);
+ void displayLoginErro(Object erro);
+}
+
+public class LoginActivity extends AppCompatActivity implements LoginActivityInput {
+
+ LoginInteractorInput output;
+ List listOfLoginViewModel = new ArrayList<>();
+ LoginRouter router;
+ Object error;
+ LoginModel login = new LoginModel("", "");
+
+ private LoginScreenBinding binding;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ binding = DataBindingUtil.setContentView(this, R.layout.login_screen);
+ binding.setActivity(this);
+
+ binding.setLogin(login);
+ setIsErroVisible(false);
+
+ LoginConfigurator.INSTANCE.configure(this);
+ UserViewModel userViewModel = checkSharedPreferences();
+ if(userViewModel != null)
+ displayLoginData(userViewModel);
+ }
+
+ private void setIsErroVisible(Boolean isVisible){
+ binding.setIsErroVisible(isVisible);
+ }
+
+ public void login(){
+ setIsErroVisible(false);
+ binding.setBtnText(getString(R.string.loginScreenBtnWaitMessage));
+ fetchMetaData();
+ }
+
+ public void fetchMetaData(){
+ LoginRequest aLoginRequest = new LoginRequest();
+ aLoginRequest.user = login.login;
+ aLoginRequest.password = login.password;
+ output.fetchLoginData(aLoginRequest);
+ }
+
+ @Override
+ public void displayLoginData(UserViewModel userViewModel) {
+ listOfLoginViewModel.add(userViewModel);
+ router.onItemClick(null, null, 0, 0);
+ }
+
+ @Override
+ public void displayLoginErro(Object erro){
+ this.error = erro;
+ binding.setErroMessage(this.error.toString());
+ binding.setBtnText(null);
+ setIsErroVisible(true);
+ }
+
+ private UserViewModel checkSharedPreferences(){
+ SharedPreferences preferences = getSharedPreferences("user_preferences", MODE_PRIVATE);
+ String jsonUserModel = preferences.getString("user_login", null);
+ if(jsonUserModel != null)
+ return new Gson().fromJson(jsonUserModel, UserViewModel.class);
+ return null;
+ }
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginConfigurator.java b/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginConfigurator.java
new file mode 100644
index 000000000..9f9aa4afa
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginConfigurator.java
@@ -0,0 +1,27 @@
+package com.example.testeandroidv2.loginScreen;
+
+import java.lang.ref.WeakReference;
+
+
+public enum LoginConfigurator {
+ INSTANCE;
+
+ public void configure(LoginActivity activity) {
+
+ LoginRouter router = new LoginRouter();
+ router.activity = new WeakReference<>(activity);
+
+ LoginPresenter presenter = new LoginPresenter();
+ presenter.output = new WeakReference<>(activity);
+
+ LoginInteractor interactor = new LoginInteractor();
+ interactor.output = presenter;
+
+ if (activity.output == null) {
+ activity.output = interactor;
+ }
+ if (activity.router == null) {
+ activity.router = router;
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginInteractor.java b/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginInteractor.java
new file mode 100644
index 000000000..6c0f55437
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginInteractor.java
@@ -0,0 +1,90 @@
+package com.example.testeandroidv2.loginScreen;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.regex.Pattern;
+
+import retrofit.Callback;
+import retrofit.Response;
+import retrofit.Retrofit;
+
+interface LoginInteractorInput {
+ void fetchLoginData(LoginRequest request);
+}
+
+public class LoginInteractor implements LoginInteractorInput {
+
+ LoginPresenterInput output;
+ private LoginWorkerInput aLoginWorkerInput;
+
+ Callback callback = new Callback() {
+ LoginResponse loginResponse;
+ @Override
+ public void onResponse(Response response, Retrofit retrofit) {
+ loginResponse = new Gson().fromJson(response.body(), LoginResponse.class);
+ response(loginResponse);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ loginResponse.error = t;
+ response(loginResponse);
+ }
+ };
+
+ private LoginWorkerInput getLoginWorkerInput() {
+ if (aLoginWorkerInput == null) return new LoginWorker();
+ return aLoginWorkerInput;
+ }
+
+ void setLoginWorkerInput(LoginWorkerInput aLoginWorkerInput) {
+ this.aLoginWorkerInput = aLoginWorkerInput;
+ }
+
+ @Override
+ public void fetchLoginData(@NotNull LoginRequest request) {
+ aLoginWorkerInput = getLoginWorkerInput();
+ LoginResponse loginResponse = new LoginResponse();
+
+ if(isCpf(request.user) || isEmail(request.user)) {
+ if(isPasswordValid(request.password)) {
+ aLoginWorkerInput.buildRequest(request);
+ loginResponse = aLoginWorkerInput.getLoginResponse(callback);
+ if(loginResponse != null) response(loginResponse);
+ }else{
+ loginResponse.error = "A senha deve ter uma letra maiuscula, um caracter especial e um caracter alfanumérico";
+ response(loginResponse);
+ }
+ }else{
+ loginResponse.error = "Por favor digite um CPF ou E-mail válido";
+ response(loginResponse);
+ }
+ }
+
+ private void response(LoginResponse response){
+ output.presentLoginData(response);
+ }
+
+ @NotNull
+ private Boolean isCpf(String user){
+ Pattern pattern = Pattern.compile("(^(\\d{3}.\\d{3}.\\d{3}-\\d{2})|(\\d{11})$)");
+ return pattern.matcher(user).find();
+ }
+
+ @NotNull
+ private Boolean isEmail(String user){
+ Pattern pattern = Pattern.compile("(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)])");
+ return pattern.matcher(user).find();
+ }
+
+ @NotNull
+ private Boolean isPasswordValid(String password){
+ Pattern patternUppercase = Pattern.compile("[A-Z]+");
+ Pattern patternSpecialChar = Pattern.compile("\\W+");
+ Pattern patternAlphanumericChar = Pattern.compile("\\w+");
+ return patternUppercase.matcher(password).find() && patternSpecialChar.matcher(password).find() && patternAlphanumericChar.matcher(password).find();
+ }
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginModel.java b/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginModel.java
new file mode 100644
index 000000000..7dfdd901f
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginModel.java
@@ -0,0 +1,81 @@
+package com.example.testeandroidv2.loginScreen;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+public class LoginModel {
+ String login;
+ String password;
+
+ public LoginModel(String login, String password) {
+ this.login = login;
+ this.password = password;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "{\n\tlogin: "+login+",\n\tpassword: "+password+"\n}";
+ }
+
+ public String getLogin() {
+ return login;
+ }
+
+ public void setLogin(String login) {
+ this.login = login;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+}
+
+class LoginViewModel implements Parcelable {
+ String login;
+ String password;
+
+ protected LoginViewModel(Parcel in) {
+ login = in.readString();
+ password = in.readString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(login);
+ dest.writeString(password);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public LoginViewModel createFromParcel(Parcel in) {
+ return new LoginViewModel(in);
+ }
+
+ @Override
+ public LoginViewModel[] newArray(int size) {
+ return new LoginViewModel[size];
+ }
+ };
+}
+
+class LoginRequest {
+ String user;
+ String password;
+}
+
+class LoginResponse {
+ UserModel userAccount;
+ Object error;
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginPresenter.java b/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginPresenter.java
new file mode 100644
index 000000000..146d653b9
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginPresenter.java
@@ -0,0 +1,33 @@
+package com.example.testeandroidv2.loginScreen;
+
+import java.lang.ref.WeakReference;
+
+interface LoginPresenterInput {
+ void presentLoginData(LoginResponse response);
+}
+
+
+public class LoginPresenter implements LoginPresenterInput {
+
+ public WeakReference output;
+
+ @Override
+ public void presentLoginData(LoginResponse response) {
+ if(response.userAccount != null) {
+ UserModel userModel = response.userAccount;
+ output.get().displayLoginData(getUserViewModel(userModel));
+ }else{
+ output.get().displayLoginErro(response.error);
+ }
+ }
+
+ private UserViewModel getUserViewModel(UserModel userModel){
+ UserViewModel userViewModel = new UserViewModel();
+ userViewModel.name = userModel.name;
+ userViewModel.agency = userModel.agency;
+ userViewModel.bankAccount = userModel.bankAccount;
+ userViewModel.balance = userModel.balance;
+ return userViewModel;
+ }
+
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginRouter.java b/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginRouter.java
new file mode 100644
index 000000000..13c100b43
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginRouter.java
@@ -0,0 +1,53 @@
+package com.example.testeandroidv2.loginScreen;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.view.View;
+import android.widget.AdapterView;
+
+import com.example.testeandroidv2.statementScreen.StatementActivity;
+import com.google.gson.Gson;
+
+import java.lang.ref.WeakReference;
+
+import androidx.annotation.NonNull;
+
+interface LoginRouterInput {
+ Intent navigateToSomeWhere(int position);
+ void passDataToNextScene(int position, Intent intent);
+}
+
+public class LoginRouter implements LoginRouterInput, AdapterView.OnItemClickListener {
+
+ WeakReference activity;
+
+ @NonNull
+ @Override
+ public Intent navigateToSomeWhere(int position) {
+ return new Intent(activity.get(), StatementActivity.class);
+ }
+
+ @Override
+ public void passDataToNextScene(int position, Intent intent) {
+ UserViewModel user = activity.get().listOfLoginViewModel.get(position);
+ intent.putExtra("user",user);
+ }
+
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ Intent intent = navigateToSomeWhere(position);
+ passDataToNextScene(position, intent);
+ safeLoginOnSharedPreferences();
+ activity.get().startActivity(intent);
+ }
+
+ private void safeLoginOnSharedPreferences(){
+ String jsonLogin = new Gson().toJson(activity.get().listOfLoginViewModel.get(0));
+ SharedPreferences preferences = activity.get().getSharedPreferences("user_preferences", Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = preferences.edit();
+ editor.putString("user_login",jsonLogin);
+ editor.apply();
+ }
+
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginWorker.java b/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginWorker.java
new file mode 100644
index 000000000..69bf2d947
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/loginScreen/LoginWorker.java
@@ -0,0 +1,42 @@
+package com.example.testeandroidv2.loginScreen;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.example.testeandroidv2.Service.Api;
+import com.example.testeandroidv2.Service.LoginService;
+
+import java.io.IOException;
+
+import retrofit.Call;
+import retrofit.Callback;
+import retrofit.Retrofit;
+
+interface LoginWorkerInput {
+ void buildRequest(LoginRequest request);
+ LoginResponse getLoginResponse(Callback callback);
+}
+
+public class LoginWorker implements LoginWorkerInput {
+
+ private Call call;
+
+ @Override
+ public void buildRequest(LoginRequest request) {
+ Retrofit api = Api.getRetrofitInstance("https://bank-app-test.herokuapp.com/api/");
+ LoginService loginService = api.create(LoginService.class);
+ call = loginService.authentication(request.user, request.password);
+ }
+
+ @Override
+ public LoginResponse getLoginResponse(Callback callback) {
+ try {
+ if(callback == null)
+ return new Gson().fromJson(call.execute().body(), LoginResponse.class);
+ else
+ call.enqueue(callback);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/loginScreen/UserModel.java b/app/src/main/java/com/example/testeandroidv2/loginScreen/UserModel.java
new file mode 100644
index 000000000..346f529ba
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/loginScreen/UserModel.java
@@ -0,0 +1,96 @@
+package com.example.testeandroidv2.loginScreen;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+public class UserModel {
+ int userId;
+ String name;
+ String bankAccount;
+ String agency;
+ double balance;
+
+ public UserModel(int userId, String name, String bankAccount, String agency, double balance) {
+ this.userId = userId;
+ this.name = name;
+ this.bankAccount = bankAccount;
+ this.agency = agency;
+ this.balance = balance;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "{\n\tuserId: "+userId+",\n\tname: "+name+",\n\tbankAccount: "+bankAccount+",\n\tagency: "+agency+",\n\tbalance: "+balance+"\n}";
+ }
+
+ public int getUserId() {
+ return userId;
+ }
+
+ public void setUserId(int userId) {
+ this.userId = userId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getBankAccount() {
+ return bankAccount;
+ }
+
+ public String getAgency() {
+ return agency;
+ }
+
+ public double getBalance() {
+ return balance;
+ }
+}
+
+class UserViewModel implements Parcelable {
+ private int userId;
+ String name;
+ String bankAccount;
+ String agency;
+ double balance;
+
+ public UserViewModel(){ }
+
+ protected UserViewModel(Parcel in) {
+ userId = in.readInt();
+ name = in.readString();
+ bankAccount = in.readString();
+ agency = in.readString();
+ balance = in.readDouble();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public UserViewModel createFromParcel(Parcel in) {
+ return new UserViewModel(in);
+ }
+
+ @Override
+ public UserViewModel[] newArray(int size) {
+ return new UserViewModel[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ parcel.writeInt(userId);
+ parcel.writeString(name);
+ parcel.writeString(bankAccount);
+ parcel.writeString(agency);
+ parcel.writeDouble(balance);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/testeandroidv2/statementScreen/ClientModel.java b/app/src/main/java/com/example/testeandroidv2/statementScreen/ClientModel.java
new file mode 100644
index 000000000..94558824c
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/statementScreen/ClientModel.java
@@ -0,0 +1,99 @@
+package com.example.testeandroidv2.statementScreen;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+import com.example.testeandroidv2.loginScreen.UserModel;
+
+public class ClientModel {
+ String name;
+ String account;
+ String balance;
+
+ public ClientModel(){
+ super();
+ }
+
+ public ClientModel(String name, String account, String balance) {
+ this.name = name;
+ this.account = account;
+ this.balance = balance;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "{\n\tname: "+name+",\n\taccount: "+account+",\n\tbalance: "+balance+"\n}";
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAccount() {
+ return account;
+ }
+
+ public void setAccount(String account) {
+ this.account = account;
+ }
+
+ public String getBalance() {
+ return balance;
+ }
+
+ public void setBalance(String balance) {
+ this.balance = balance;
+ }
+}
+
+class ClientViewModel implements Parcelable {
+ String name;
+ String account;
+ String balance;
+
+ protected ClientViewModel(Parcel in) {
+ name = in.readString();
+ account = in.readString();
+ balance = in.readString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(name);
+ dest.writeString(account);
+ dest.writeString(balance);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public ClientViewModel createFromParcel(Parcel in) {
+ return new ClientViewModel(in);
+ }
+
+ @Override
+ public ClientViewModel[] newArray(int size) {
+ return new ClientViewModel[size];
+ }
+ };
+}
+
+class ClientRequest {
+ UserModel userModel;
+}
+
+class ClientResponse{
+ UserModel userModel;
+ Object error;
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementActivity.java b/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementActivity.java
new file mode 100644
index 000000000..66dfe8daf
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementActivity.java
@@ -0,0 +1,101 @@
+package com.example.testeandroidv2.statementScreen;
+
+import android.os.Bundle;
+
+import com.example.testeandroidv2.loginScreen.UserModel;
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.example.testeandroidv2.R;
+import com.example.testeandroidv2.databinding.StatementScreenBinding;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.databinding.DataBindingUtil;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+interface StatementActivityInput {
+ void displayStatementData(List statementModels);
+ void displayStatementError(Object error);
+ void displayClientData(ClientModel clientModel);
+ void displayClientError(Object error);
+}
+
+public class StatementActivity extends AppCompatActivity implements StatementActivityInput {
+
+// public static String TAG = StatementActivity.class.getSimpleName();
+ private StatementScreenBinding binding;
+ private TransactionHistoryAdapter adapter;
+ StatementInteractorInput output;
+ UserModel userModel;
+ List statementModelList = new ArrayList<>();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ binding = DataBindingUtil.setContentView(this, R.layout.statement_screen);
+ binding.setActivity(this);
+ toggleLoading(true);
+
+ StatementConfigurator.INSTANCE.configure(this);
+ Bundle bundle = getIntent().getExtras();
+ if(bundle != null) {
+ JsonObject object = new Gson().toJsonTree(bundle.get("user")).getAsJsonObject();
+ userModel = new Gson().fromJson(object, UserModel.class);
+ }
+
+ RecyclerView rv = findViewById(R.id.transactionHistory);
+ adapter = new TransactionHistoryAdapter(statementModelList);
+ rv.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
+ rv.setHasFixedSize(true);
+ rv.setAdapter(adapter);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ fetchMetaData();
+ }
+
+ public void fetchMetaData(){
+ ClientRequest clientRequest = new ClientRequest();
+ StatementRequest statementRequest = new StatementRequest();
+ clientRequest.userModel = userModel;
+ statementRequest.user = userModel;
+ if(clientRequest.userModel != null) {
+ output.fetchClientData(clientRequest);
+ output.fetchStatementData(statementRequest);
+ }
+ }
+
+ private void toggleLoading(Boolean isVisible){
+ binding.setLoadingIsVisible(isVisible);
+ }
+
+ @Override
+ public void displayStatementData(List statementModels) {
+ toggleLoading(false);
+ adapter.setListOfStatement(statementModels);
+ }
+
+ @Override
+ public void displayStatementError(Object error) {
+
+ }
+
+ @Override
+ public void displayClientData(ClientModel clientModel) {
+ binding.setClient(clientModel);
+ }
+
+ @Override
+ public void displayClientError(Object error) {
+
+ }
+
+ public void logout(){
+ finish();
+ }
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementConfigurator.java b/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementConfigurator.java
new file mode 100644
index 000000000..446be05bc
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementConfigurator.java
@@ -0,0 +1,19 @@
+package com.example.testeandroidv2.statementScreen;
+
+import java.lang.ref.WeakReference;
+
+public enum StatementConfigurator {
+ INSTANCE;
+
+ public void configure(StatementActivity activity) {
+ StatementPresenter presenter = new StatementPresenter();
+ presenter.output = new WeakReference<>(activity);
+
+ StatementInteractor interactor = new StatementInteractor();
+ interactor.output = presenter;
+
+ if (activity.output == null) {
+ activity.output = interactor;
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementInteractor.java b/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementInteractor.java
new file mode 100644
index 000000000..f24936585
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementInteractor.java
@@ -0,0 +1,73 @@
+package com.example.testeandroidv2.statementScreen;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+
+import retrofit.Callback;
+import retrofit.Response;
+import retrofit.Retrofit;
+
+interface StatementInteractorInput {
+ void fetchStatementData(StatementRequest request);
+ void fetchClientData(ClientRequest clientRequest);
+}
+
+public class StatementInteractor implements StatementInteractorInput {
+
+ StatementPresenterInput output;
+ private StatementWorkerInput aStatementWorkerInput;
+
+ Callback callback = new Callback() {
+ StatementResponse statementResponse;
+ @Override
+ public void onResponse(Response response, Retrofit retrofit) {
+ statementResponse = new Gson().fromJson(response.body(), StatementResponse.class);
+ response(statementResponse);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ statementResponse.error = t;
+ response(statementResponse);
+ }
+ };
+
+ private StatementWorkerInput getStatementWorkerInput() {
+ if (aStatementWorkerInput == null) return new StatementWorker();
+ return aStatementWorkerInput;
+ }
+
+ void setStatementWorkerInput(StatementWorkerInput aStatementWorkerInput) {
+ this.aStatementWorkerInput = aStatementWorkerInput;
+ }
+
+ @Override
+ public void fetchStatementData(StatementRequest request) {
+ StatementResponse statementResponse = new StatementResponse();
+ aStatementWorkerInput = getStatementWorkerInput();
+ if(request.user != null) {
+ aStatementWorkerInput.buildRequest(request);
+ statementResponse = aStatementWorkerInput.getStatementsResponse(callback);
+ if(statementResponse != null && statementResponse.statementList != null && !statementResponse.statementList.isEmpty())
+ response(statementResponse);
+ }else{
+ statementResponse.error = "Erro interno, usuário não logado";
+ response(statementResponse);
+ }
+ }
+
+ @Override
+ public void fetchClientData(ClientRequest clientRequest) {
+ ClientResponse clientResponse = new ClientResponse();
+ if(clientRequest.userModel != null) {
+ clientResponse.userModel = clientRequest.userModel;
+ }else{
+ clientResponse.error = "Erro interno, usuário não logado";
+ }
+ output.presentClientData(clientResponse);
+ }
+
+ private void response(StatementResponse statementResponse){
+ output.presentStatementData(statementResponse);
+ }
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementModel.java b/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementModel.java
new file mode 100644
index 000000000..ec53b67ec
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementModel.java
@@ -0,0 +1,110 @@
+package com.example.testeandroidv2.statementScreen;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+import androidx.annotation.NonNull;
+
+import com.example.testeandroidv2.loginScreen.UserModel;
+
+public class StatementModel {
+ String title;
+ String desc;
+ String date;
+ String value;
+
+ public StatementModel(String title, String desc, String date, String value) {
+ this.title = title;
+ this.desc = desc;
+ this.date = date;
+ this.value = value;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "{\n\ttitle: "+title+",\n\tdesc: "+desc+",\n\tdate: "+date+",\n\tvalue: "+value+"\n}";
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public String getDate() {
+ return date;
+ }
+
+ public void setDate(String date) {
+ this.date = date;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+}
+
+class StatementViewModel implements Parcelable {
+ String title;
+ String desc;
+ String date;
+ String value;
+
+ protected StatementViewModel(Parcel in) {
+ title = in.readString();
+ desc = in.readString();
+ date = in.readString();
+ value = in.readString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(title);
+ dest.writeString(desc);
+ dest.writeString(date);
+ dest.writeString(value);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public StatementViewModel createFromParcel(Parcel in) {
+ return new StatementViewModel(in);
+ }
+
+ @Override
+ public StatementViewModel[] newArray(int size) {
+ return new StatementViewModel[size];
+ }
+ };
+}
+
+class StatementRequest {
+ UserModel user;
+}
+
+class StatementResponse {
+ List statementList;
+ Object error;
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementPresenter.java b/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementPresenter.java
new file mode 100644
index 000000000..e21f92de9
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/statementScreen/StatementPresenter.java
@@ -0,0 +1,74 @@
+package com.example.testeandroidv2.statementScreen;
+
+import com.example.testeandroidv2.loginScreen.UserModel;
+
+import java.lang.ref.WeakReference;
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+interface StatementPresenterInput {
+ void presentStatementData(StatementResponse response);
+ void presentClientData(ClientResponse response);
+}
+
+public class StatementPresenter implements StatementPresenterInput {
+
+ public WeakReference output;
+
+ @Override
+ public void presentStatementData(StatementResponse response) {
+ if(response.statementList != null && !response.statementList.isEmpty()){
+ for(int i=0; i callback);
+}
+
+public class StatementWorker implements StatementWorkerInput {
+
+ private Call call;
+
+ @Override
+ public void buildRequest(StatementRequest request) {
+ Retrofit api = Api.getRetrofitInstance("https://bank-app-test.herokuapp.com/api/");
+ StatementService statementService = api.create(StatementService.class);
+ call = statementService.getStatements(request.user.getUserId());
+ }
+
+ @Override
+ public StatementResponse getStatementsResponse(Callback callback) {
+ try {
+ if(callback == null){
+ return new Gson().fromJson(call.execute().body(), StatementResponse.class);
+ }else {
+ call.enqueue(callback);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/com/example/testeandroidv2/statementScreen/TransactionHistoryAdapter.java b/app/src/main/java/com/example/testeandroidv2/statementScreen/TransactionHistoryAdapter.java
new file mode 100644
index 000000000..1623b72c9
--- /dev/null
+++ b/app/src/main/java/com/example/testeandroidv2/statementScreen/TransactionHistoryAdapter.java
@@ -0,0 +1,57 @@
+package com.example.testeandroidv2.statementScreen;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.example.testeandroidv2.R;
+import com.example.testeandroidv2.databinding.TransactionHistoryItemBinding;
+
+import java.util.List;
+
+import androidx.annotation.NonNull;
+import androidx.databinding.DataBindingUtil;
+import androidx.recyclerview.widget.RecyclerView;
+
+public class TransactionHistoryAdapter extends RecyclerView.Adapter {
+ private List listOfStatement;
+
+ public TransactionHistoryAdapter(List listOfStatement){
+ this.listOfStatement = listOfStatement;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
+ return new ViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.transaction_history_item, viewGroup, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
+ viewHolder.bind(listOfStatement.get(i));
+ }
+
+ @Override
+ public int getItemCount() {
+ return listOfStatement.size();
+ }
+
+ public void setListOfStatement(List listOfStatement){
+ this.listOfStatement = listOfStatement;
+ notifyDataSetChanged();
+ }
+}
+
+class ViewHolder extends RecyclerView.ViewHolder{
+
+ private final TransactionHistoryItemBinding binding;
+
+ ViewHolder(@NonNull View itemView) {
+ super(itemView);
+ binding = DataBindingUtil.bind(itemView);
+ }
+
+ void bind(StatementModel statement){
+ binding.setStatement(statement);
+ }
+}
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 000000000..2b068d114
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/custom_edit_text_bg.xml b/app/src/main/res/drawable/custom_edit_text_bg.xml
new file mode 100644
index 000000000..3419eb92f
--- /dev/null
+++ b/app/src/main/res/drawable/custom_edit_text_bg.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 000000000..07d5da9cb
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/login_button_bg.xml b/app/src/main/res/drawable/login_button_bg.xml
new file mode 100644
index 000000000..34070d4cb
--- /dev/null
+++ b/app/src/main/res/drawable/login_button_bg.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/logo.png b/app/src/main/res/drawable/logo.png
new file mode 100644
index 000000000..66bdc8d5d
Binary files /dev/null and b/app/src/main/res/drawable/logo.png differ
diff --git a/app/src/main/res/drawable/logout.png b/app/src/main/res/drawable/logout.png
new file mode 100644
index 000000000..de1e4ae3c
Binary files /dev/null and b/app/src/main/res/drawable/logout.png differ
diff --git a/app/src/main/res/drawable/message_erro_bg.xml b/app/src/main/res/drawable/message_erro_bg.xml
new file mode 100644
index 000000000..e05ca46da
--- /dev/null
+++ b/app/src/main/res/drawable/message_erro_bg.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/transaction_history_item_bg.xml b/app/src/main/res/drawable/transaction_history_item_bg.xml
new file mode 100644
index 000000000..8d25dd4cd
--- /dev/null
+++ b/app/src/main/res/drawable/transaction_history_item_bg.xml
@@ -0,0 +1,65 @@
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/font/helveticaneue.ttf b/app/src/main/res/font/helveticaneue.ttf
new file mode 100644
index 000000000..cac3b75d8
Binary files /dev/null and b/app/src/main/res/font/helveticaneue.ttf differ
diff --git a/app/src/main/res/layout/login_screen.xml b/app/src/main/res/layout/login_screen.xml
new file mode 100644
index 000000000..d561943c7
--- /dev/null
+++ b/app/src/main/res/layout/login_screen.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/statement_screen.xml b/app/src/main/res/layout/statement_screen.xml
new file mode 100644
index 000000000..b35ef4508
--- /dev/null
+++ b/app/src/main/res/layout/statement_screen.xml
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/transaction_history_item.xml b/app/src/main/res/layout/transaction_history_item.xml
new file mode 100644
index 000000000..05d1f67a7
--- /dev/null
+++ b/app/src/main/res/layout/transaction_history_item.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 000000000..eca70cfe5
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 000000000..eca70cfe5
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..cde69bccc
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 000000000..61da551c5
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..c133a0cbd
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 000000000..db5080a75
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..bfa42f0e7
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..da31a871c
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..324e72cdd
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..b216f2d31
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..aee44e138
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..e96783ccc
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 000000000..8ef95d9aa
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,28 @@
+
+
+
+ #FFFFFF
+ #DCE2EE
+ #DCE2EE
+ #ADF17575
+ #BD3030
+ #4A4A4A
+ #00000000
+
+
+ #FFFFFF
+ #3B48EE
+ #FFFFFF
+
+
+ #FFFFFF
+ #3B49EE
+ #3B49EE
+ #FFFFFF
+ #485465
+ #A8B4C4
+ #485465
+ #FFFFFF
+ #DBDFE3
+
+
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 000000000..47c822467
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,5 @@
+
+
+ 16dp
+ 16dp
+
diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml
new file mode 100644
index 000000000..a9975f83c
--- /dev/null
+++ b/app/src/main/res/values/ids.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 000000000..25de54aa3
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,22 @@
+
+ Bank
+
+
+ User
+ Password
+ Login
+ Aguarde…
+ Erro
+
+
+ Jose da Silva Teste
+ Conta
+ 2050 / 01.111222–4
+ Saldo
+ R$1.000,00
+ Recentes
+ Pagamento
+ Descrição
+ 12/12/2018
+ R$1.000,00
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 000000000..f18c97b91
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/app/src/test/java/com/example/testeandroidv2/loginScreen/LoginActivityUnitTest.java b/app/src/test/java/com/example/testeandroidv2/loginScreen/LoginActivityUnitTest.java
new file mode 100644
index 000000000..ca9f653d3
--- /dev/null
+++ b/app/src/test/java/com/example/testeandroidv2/loginScreen/LoginActivityUnitTest.java
@@ -0,0 +1,91 @@
+package com.example.testeandroidv2.loginScreen;
+
+import org.junit.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.lang.ref.WeakReference;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk=19)
+public class LoginActivityUnitTest {
+
+ private LoginActivity activity;
+ @Before
+ public void setUp(){
+ activity = Robolectric.buildActivity(LoginActivity.class).create().resume().get();
+ }
+
+ @Test
+ public void loginActivity_ShouldNOT_be_Null(){
+ Assert.assertNotNull(activity);
+ }
+
+ @Test
+ public void login_shouldCall_fetchMetaData(){
+ // Given
+ LoginActivityOutputSpy loginActivityOutputSpy = new LoginActivityOutputSpy();
+ activity.output = loginActivityOutputSpy;
+ // When
+ activity.login();
+ // Then
+ Assert.assertTrue(loginActivityOutputSpy.fetchLoginMetaDataIsCalled);
+ }
+
+ @Test
+ public void login_with_validInput_shouldCall_displayLoginData_listOfLoginViewModel_shouldNOT_Empty_And_error_should_Null(){
+ // Given
+ LoginInteractor loginInteractor = new LoginInteractor();
+ LoginPresenter loginPresenter = new LoginPresenter();
+
+ // Setup Double Test
+ activity.login = new LoginModel("111.111.111-11", "A@s");
+ loginPresenter.output = new WeakReference<>(activity);
+ loginInteractor.callback = null;
+ loginInteractor.output = loginPresenter;
+
+ // When
+ activity.output = loginInteractor;
+ activity.login();
+
+ // Then
+ Assert.assertNull(activity.error);
+ Assert.assertTrue(activity.listOfLoginViewModel.size() > 0);
+ }
+
+ @Test
+ public void login_with_invalidInput_shouldCall_displayLoginData_listOfLoginViewModel_should_Empty_And_error_shouldNOT_Null(){
+ // Given
+ LoginInteractor loginInteractor = new LoginInteractor();
+ LoginPresenter loginPresenter = new LoginPresenter();
+
+ // Setup Double Test
+ activity.login = new LoginModel("aaaaaa", "A@s");
+ loginPresenter.output = new WeakReference<>(activity);
+ loginInteractor.callback = null;
+ loginInteractor.output = loginPresenter;
+
+ // When
+ activity.output = loginInteractor;
+ activity.login();
+
+ // Then
+ Assert.assertNotNull(activity.error);
+ Assert.assertFalse(activity.listOfLoginViewModel.size() > 0);
+ }
+}
+
+class LoginActivityOutputSpy implements LoginInteractorInput {
+
+ boolean fetchLoginMetaDataIsCalled = false;
+
+ @Override
+ public void fetchLoginData(LoginRequest request) {
+ fetchLoginMetaDataIsCalled = true;
+ }
+}
diff --git a/app/src/test/java/com/example/testeandroidv2/loginScreen/LoginInteractorUnitTest.java b/app/src/test/java/com/example/testeandroidv2/loginScreen/LoginInteractorUnitTest.java
new file mode 100644
index 000000000..d465c7a29
--- /dev/null
+++ b/app/src/test/java/com/example/testeandroidv2/loginScreen/LoginInteractorUnitTest.java
@@ -0,0 +1,284 @@
+package com.example.testeandroidv2.loginScreen;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.example.testeandroidv2.Service.Api;
+import com.example.testeandroidv2.Service.LoginService;
+import com.google.gson.internal.LinkedTreeMap;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import retrofit.Call;
+import retrofit.Callback;
+import retrofit.Retrofit;
+
+public class LoginInteractorUnitTest {
+
+ @Test
+ public void fetchLoginData_with_validInput_Login_shouldCall_Worker_buildRequest(){
+ // Given
+ LoginInteractor loginInteractor = new LoginInteractor();
+ LoginRequest loginRequest = new LoginRequest();
+ loginRequest.user = "111.111.111-11";
+ loginRequest.password = "A12-345B";
+
+ // Setup Test Double
+ loginInteractor.output = new LoginPresenterInputSpy();
+ LoginWorkerInputSpy loginWorkerInputSpy = new LoginWorkerInputSpy();
+ loginInteractor.setLoginWorkerInput(loginWorkerInputSpy);
+
+ // When
+ loginInteractor.fetchLoginData(loginRequest);
+
+ // Then
+ Assert.assertTrue(loginWorkerInputSpy.isBuildRequestIsCalled);
+ }
+
+ @Test
+ public void fetchLoginData_with_validInput_Login_shouldCall_Worker_getLoginResponse(){
+ // Given
+ LoginInteractor loginInteractor = new LoginInteractor();
+ LoginRequest loginRequest = new LoginRequest();
+ loginRequest.user = "111.111.111-11";
+ loginRequest.password = "A12-345B";
+
+ // Setup Test Double
+ loginInteractor.output = new LoginPresenterInputSpy();
+ LoginWorkerInputSpy loginWorkerInputSpy = new LoginWorkerInputSpy();
+ loginInteractor.setLoginWorkerInput(loginWorkerInputSpy);
+
+ // When
+ loginInteractor.fetchLoginData(loginRequest);
+
+ // Then
+ Assert.assertTrue(loginWorkerInputSpy.isGetLoginResponseIsCalled);
+ }
+
+ @Test
+ public void fetchLoginData_with_validInput_Login_shouldReturn_NOT_be_Null(){
+ // Given
+ LoginInteractor loginInteractor = new LoginInteractor();
+ LoginRequest loginRequest = new LoginRequest();
+ loginRequest.user = "111.111.111-11";
+ loginRequest.password = "A12-345B";
+
+ // Setup Test Double
+ loginInteractor.output = new LoginPresenterInputSpy();
+ LoginWorkerInputSpy loginWorkerInputSpy = new LoginWorkerInputSpy();
+ loginInteractor.setLoginWorkerInput(loginWorkerInputSpy);
+
+ // When
+ loginInteractor.fetchLoginData(loginRequest);
+
+ // Then
+ Assert.assertNotNull(loginWorkerInputSpy.response.userAccount);
+ }
+
+ @Test
+ public void fetchLoginData_with_invalidInputUser_Login_shouldNOT_Call_Worker_buildRequest(){
+ // Given
+ LoginInteractor loginInteractor = new LoginInteractor();
+ LoginRequest loginRequest = new LoginRequest();
+ loginRequest.user = "111.111.111-1";
+ loginRequest.password = "A@s";
+
+ // Setup Test Double
+ loginInteractor.output = new LoginPresenterInputSpy();
+ LoginWorkerInputSpy loginWorkerInputSpy = new LoginWorkerInputSpy();
+ loginInteractor.setLoginWorkerInput(loginWorkerInputSpy);
+
+ // When
+ loginInteractor.fetchLoginData(loginRequest);
+
+ // Then
+ Assert.assertFalse(loginWorkerInputSpy.isBuildRequestIsCalled);
+ }
+
+ @Test
+ public void fetchLoginData_with_invalidInputPassword_Login_shouldNOT_Call_Worker_buildRequest(){
+ // Given
+ LoginInteractor loginInteractor = new LoginInteractor();
+ LoginRequest loginRequest = new LoginRequest();
+ loginRequest.user = "111.111.111-11";
+ loginRequest.password = "1111";
+
+ // Setup Test Double
+ loginInteractor.output = new LoginPresenterInputSpy();
+ LoginWorkerInputSpy loginWorkerInputSpy = new LoginWorkerInputSpy();
+ loginInteractor.setLoginWorkerInput(loginWorkerInputSpy);
+
+ // When
+ loginInteractor.fetchLoginData(loginRequest);
+
+ // Then
+ Assert.assertFalse(loginWorkerInputSpy.isBuildRequestIsCalled);
+ }
+
+ @Test
+ public void fetchLoginData_with_invalidInputUser_Login_shouldNOT_Call_Worker_getLoginResponse(){
+ // Given
+ LoginInteractor loginInteractor = new LoginInteractor();
+ LoginRequest loginRequest = new LoginRequest();
+ loginRequest.user = "111.111.111-1";
+ loginRequest.password = "A@s";
+
+ // Setup Test Double
+ loginInteractor.output = new LoginPresenterInputSpy();
+ LoginWorkerInputSpy loginWorkerInputSpy = new LoginWorkerInputSpy();
+ loginInteractor.setLoginWorkerInput(loginWorkerInputSpy);
+
+ // When
+ loginInteractor.fetchLoginData(loginRequest);
+
+ // Then
+ Assert.assertFalse(loginWorkerInputSpy.isGetLoginResponseIsCalled);
+ }
+
+ @Test
+ public void fetchLoginData_with_invalidInputPassword_Login_shouldNOT_Call_Worker_getLoginResponse(){
+ // Given
+ LoginInteractor loginInteractor = new LoginInteractor();
+ LoginRequest loginRequest = new LoginRequest();
+ loginRequest.user = "111.111.111-11";
+ loginRequest.password = "1111";
+
+ // Setup Test Double
+ loginInteractor.output = new LoginPresenterInputSpy();
+ LoginWorkerInputSpy loginWorkerInputSpy = new LoginWorkerInputSpy();
+ loginInteractor.setLoginWorkerInput(loginWorkerInputSpy);
+
+ // When
+ loginInteractor.fetchLoginData(loginRequest);
+
+ // Then
+ Assert.assertFalse(loginWorkerInputSpy.isGetLoginResponseIsCalled);
+ }
+
+ @Test
+ public void fetchLoginData_with_validInput_shouldCall_presentLoginData(){
+ // When
+ LoginInteractor loginInteractor = new LoginInteractor();
+ LoginRequest loginRequest = new LoginRequest();
+ loginRequest.user = "111.111.111-11";
+ loginRequest.password = "A12-345B";
+
+ // Setup Test Double
+ LoginPresenterInputSpy loginPresenterInputSpy = new LoginPresenterInputSpy();
+ loginInteractor.callback = null;
+ loginInteractor.output = loginPresenterInputSpy;
+
+ // When
+ loginInteractor.fetchLoginData(loginRequest);
+
+ // Then
+ Assert.assertTrue("When the valid input is passed to LoginInteractor Then presentLoginData should be called with erro null", loginPresenterInputSpy.presenterLoginDataIsCalled);
+ }
+
+ @Test
+ public void fetchLoginData_with_validInput_shouldCall_presentLoginData_without_error(){
+ // When
+ LoginInteractor loginInteractor = new LoginInteractor();
+ LoginRequest loginRequest = new LoginRequest();
+ loginRequest.user = "111.111.111-11";
+ loginRequest.password = "A12-345B";
+
+ // Setup Test Double
+ LoginPresenterInputSpy loginPresenterInputSpy = new LoginPresenterInputSpy();
+ loginInteractor.callback = null;
+ loginInteractor.output = loginPresenterInputSpy;
+
+ // When
+ loginInteractor.fetchLoginData(loginRequest);
+
+ // Then
+ Object error = loginPresenterInputSpy.loginResponse.error;
+ if(error instanceof LinkedTreeMap)
+ //noinspection rawtypes
+ Assert.assertEquals(0, ((LinkedTreeMap) loginPresenterInputSpy.loginResponse.error).size());
+ else
+ Assert.assertNull(loginPresenterInputSpy.loginResponse.error);
+ }
+
+ @Test
+ public void fetchLoginData_with_invalidInputUser_shouldCall_presentLoginData_with_error(){
+ // When
+ LoginInteractor loginInteractor = new LoginInteractor();
+ LoginRequest loginRequest = new LoginRequest();
+ loginRequest.user = "111.111.111-1";
+ loginRequest.password = "A12-345B";
+
+ // Setup Test Double
+ LoginPresenterInputSpy loginPresenterInputSpy = new LoginPresenterInputSpy();
+ loginInteractor.callback = null;
+ loginInteractor.output = loginPresenterInputSpy;
+
+ // When
+ loginInteractor.fetchLoginData(loginRequest);
+
+ // Then
+ Assert.assertNotNull(loginPresenterInputSpy.loginResponse.error);
+ }
+
+ @Test
+ public void fetchLoginData_with_invalidInputPassword_shouldCall_presentLoginData_with_error(){
+ // When
+ LoginInteractor loginInteractor = new LoginInteractor();
+ LoginRequest loginRequest = new LoginRequest();
+ loginRequest.user = "111.111.111-11";
+ loginRequest.password = "1111";
+
+ // Setup Test Double
+ LoginPresenterInputSpy loginPresenterInputSpy = new LoginPresenterInputSpy();
+ loginInteractor.callback = null;
+ loginInteractor.output = loginPresenterInputSpy;
+
+ // When
+ loginInteractor.fetchLoginData(loginRequest);
+
+ // Then
+ Assert.assertNotNull(loginPresenterInputSpy.loginResponse.error);
+ }
+}
+
+class LoginWorkerInputSpy implements LoginWorkerInput {
+
+ boolean isBuildRequestIsCalled = false;
+ boolean isGetLoginResponseIsCalled = false;
+ private Call call;
+ LoginResponse response;
+
+ @Override
+ public void buildRequest(LoginRequest request) {
+ isBuildRequestIsCalled = true;
+ Retrofit api = Api.getRetrofitInstance("https://bank-app-test.herokuapp.com/api/");
+ LoginService loginService = api.create(LoginService.class);
+ call = loginService.authentication(request.user, request.password);
+ }
+
+ @Override
+ public LoginResponse getLoginResponse(Callback callback) {
+ isGetLoginResponseIsCalled = true;
+ try {
+ response = new Gson().fromJson(call.execute().body(), LoginResponse.class);
+ return response;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
+
+class LoginPresenterInputSpy implements LoginPresenterInput {
+
+ boolean presenterLoginDataIsCalled = false;
+ LoginResponse loginResponse;
+
+ @Override
+ public void presentLoginData(LoginResponse response) {
+ presenterLoginDataIsCalled = true;
+ loginResponse = response;
+ }
+}
diff --git a/app/src/test/java/com/example/testeandroidv2/loginScreen/LoginPresentUnitTest.java b/app/src/test/java/com/example/testeandroidv2/loginScreen/LoginPresentUnitTest.java
new file mode 100644
index 000000000..b7700a488
--- /dev/null
+++ b/app/src/test/java/com/example/testeandroidv2/loginScreen/LoginPresentUnitTest.java
@@ -0,0 +1,68 @@
+package com.example.testeandroidv2.loginScreen;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.ref.WeakReference;
+
+public class LoginPresentUnitTest {
+
+ @Test
+ public void presentLoginData_with_userAccountNot_empty_shouldCall_displayLoginData(){
+ // Given
+ LoginPresenter loginPresenter = new LoginPresenter();
+ LoginResponse loginResponse = new LoginResponse();
+ LoginRequest loginRequest = new LoginRequest();
+ LoginWorker loginWorker = new LoginWorker();
+ LoginActivityInputSpy loginActivityInputSpy = new LoginActivityInputSpy();
+
+ // Setup Test Double
+ loginWorker.buildRequest(loginRequest);
+ loginWorker.getLoginResponse(null);
+ loginResponse.userAccount = new UserModel(1, "Teste", "123", "45678", 3.33);
+ loginPresenter.output = new WeakReference<>(loginActivityInputSpy);
+
+ // When
+ loginPresenter.presentLoginData(loginResponse);
+
+ // Then
+ Assert.assertTrue(loginActivityInputSpy.isDisplayLoginDataIsCalled);
+ }
+
+ @Test
+ public void presentLoginData_with_userAccount_empty_shouldCall_displayLoginError(){
+ // Given
+ LoginPresenter loginPresenter = new LoginPresenter();
+ LoginResponse loginResponse = new LoginResponse();
+ LoginRequest loginRequest = new LoginRequest();
+ LoginWorker loginWorker = new LoginWorker();
+ LoginActivityInputSpy loginActivityInputSpy = new LoginActivityInputSpy();
+
+ // Setup Test Double
+ loginWorker.buildRequest(loginRequest);
+ loginWorker.getLoginResponse(null);
+ loginPresenter.output = new WeakReference<>(loginActivityInputSpy);
+
+ // When
+ loginPresenter.presentLoginData(loginResponse);
+
+ // Then
+ Assert.assertTrue(loginActivityInputSpy.isDisplayLoginErrorIsCalled);
+ }
+}
+
+class LoginActivityInputSpy implements LoginActivityInput{
+
+ boolean isDisplayLoginDataIsCalled = false;
+ boolean isDisplayLoginErrorIsCalled = false;
+
+ @Override
+ public void displayLoginData(UserViewModel userViewModel) {
+ isDisplayLoginDataIsCalled = true;
+ }
+
+ @Override
+ public void displayLoginErro(Object erro) {
+ isDisplayLoginErrorIsCalled = true;
+ }
+}
diff --git a/app/src/test/java/com/example/testeandroidv2/loginScreen/LoginRouterUnitTest.java b/app/src/test/java/com/example/testeandroidv2/loginScreen/LoginRouterUnitTest.java
new file mode 100644
index 000000000..123cb13d1
--- /dev/null
+++ b/app/src/test/java/com/example/testeandroidv2/loginScreen/LoginRouterUnitTest.java
@@ -0,0 +1,40 @@
+package com.example.testeandroidv2.loginScreen;
+
+import android.content.Intent;
+
+import com.example.testeandroidv2.statementScreen.StatementActivity;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.lang.ref.WeakReference;
+import java.util.Objects;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk=19)
+public class LoginRouterUnitTest {
+
+ @Test
+ public void loginRouter_determineNextScreen_when_Authentication_valid(){
+ // Given
+ LoginRouter loginRouter = new LoginRouter();
+ LoginModel loginModel = new LoginModel("111.111.111-11", "A@s");
+
+ // Setup Double Test
+ LoginActivity activity = Robolectric.buildActivity(LoginActivity.class).create().resume().get();
+ activity.login = loginModel;
+ activity.router = loginRouter;
+ loginRouter.activity = new WeakReference<>(activity);
+
+ // When
+ Intent intent = loginRouter.navigateToSomeWhere(0);
+
+ // Then
+ String targetActivityName = Objects.requireNonNull(intent.getComponent()).getClassName();
+ Assert.assertEquals("When the login authentication is valided then next Intent should be statementActivity", targetActivityName, StatementActivity.class.getName());
+ }
+}
diff --git a/app/src/test/java/com/example/testeandroidv2/statementScreen/StatementActivityUnitTest.java b/app/src/test/java/com/example/testeandroidv2/statementScreen/StatementActivityUnitTest.java
new file mode 100644
index 000000000..ea1c6ecb2
--- /dev/null
+++ b/app/src/test/java/com/example/testeandroidv2/statementScreen/StatementActivityUnitTest.java
@@ -0,0 +1,111 @@
+package com.example.testeandroidv2.statementScreen;
+
+import com.example.testeandroidv2.loginScreen.UserModel;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk=19)
+public class StatementActivityUnitTest {
+ StatementActivity activity;
+
+ @Before
+ public void setUp() {
+ activity = Robolectric.buildActivity(StatementActivity.class).get();
+ }
+
+ @After
+ public void setDown(){
+ activity.finish();
+ }
+
+ @Test
+ public void StatementActivity_ShouldNOT_be_null(){
+ Assert.assertNotNull(activity);
+ }
+
+ @Test
+ public void fetchMetaData_with_userModelNOT_Null_ShouldCall_fetchClientData(){
+ // Given
+ StatementActivityOutputSpy outputSpy = new StatementActivityOutputSpy();
+
+ // Setup Double Test
+ activity.userModel = new UserModel(1, "Teste", "123", "456789", 3.3345);
+ activity.output = outputSpy;
+
+ // When
+ activity.fetchMetaData();
+
+ // Then
+ Assert.assertTrue(outputSpy.fetchClientDataIsCalled);
+ }
+
+ @Test
+ public void fetchMetaData_with_userModel_Null_ShouldNOT_Call_fetchClientData(){
+ // Given
+ StatementActivityOutputSpy outputSpy = new StatementActivityOutputSpy();
+
+ // Setup Double Test
+ activity.output = outputSpy;
+
+ // When
+ activity.fetchMetaData();
+
+ // Then
+ Assert.assertFalse(outputSpy.fetchClientDataIsCalled);
+ }
+
+ @Test
+ public void fetchMetaData_with_userModelNOT_Null_ShouldCall_fetchStatementData(){
+ // Given
+ StatementActivityOutputSpy outputSpy = new StatementActivityOutputSpy();
+
+ // Setup Double Test
+ activity.userModel = new UserModel(1, "Teste", "123", "456789", 3.3345);
+ activity.output = outputSpy;
+
+ // When
+ activity.fetchMetaData();
+
+ // Then
+ Assert.assertTrue(outputSpy.fetchStatementDataIsCalled);
+ }
+
+ @Test
+ public void fetchMetaData_with_userModel_Null_ShouldNOT_Call_fetchStatementData(){
+ // Given
+ StatementActivityOutputSpy outputSpy = new StatementActivityOutputSpy();
+
+ // Setup Double Test
+ activity.output = outputSpy;
+
+ // When
+ activity.fetchMetaData();
+
+ // Then
+ Assert.assertFalse(outputSpy.fetchStatementDataIsCalled);
+ }
+}
+
+class StatementActivityOutputSpy implements StatementInteractorInput {
+
+ Boolean fetchStatementDataIsCalled = false;
+ Boolean fetchClientDataIsCalled = false;
+
+ @Override
+ public void fetchStatementData(StatementRequest request) {
+ fetchStatementDataIsCalled = true;
+ }
+
+ @Override
+ public void fetchClientData(ClientRequest clientRequest) {
+ fetchClientDataIsCalled = true;
+ }
+}
diff --git a/app/src/test/java/com/example/testeandroidv2/statementScreen/StatementInteractorUnitTest.java b/app/src/test/java/com/example/testeandroidv2/statementScreen/StatementInteractorUnitTest.java
new file mode 100644
index 000000000..6cfeeafd2
--- /dev/null
+++ b/app/src/test/java/com/example/testeandroidv2/statementScreen/StatementInteractorUnitTest.java
@@ -0,0 +1,215 @@
+package com.example.testeandroidv2.statementScreen;
+
+import com.example.testeandroidv2.Service.Api;
+import com.example.testeandroidv2.Service.StatementService;
+import com.example.testeandroidv2.loginScreen.UserModel;
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import retrofit.Call;
+import retrofit.Callback;
+import retrofit.Retrofit;
+
+public class StatementInteractorUnitTest {
+
+ @Test
+ public void fetchStatementData_with_validInput_shouldCall_StatementPresenterInput_presentStatementData(){
+ // Given
+ StatementInteractor statementInteractor = new StatementInteractor();
+ StatementRequest statementRequest = new StatementRequest();
+ statementRequest.user = new UserModel(1, "Teste", "123", "456789", 3.3345);
+ StatementPresenterInputSpy statementPresenterInputSpy = new StatementPresenterInputSpy();
+
+ // Setup Test Double
+ statementInteractor.output = statementPresenterInputSpy;
+ StatementWorkerInputSpy statementWorkerInputSpy = new StatementWorkerInputSpy();
+ statementInteractor.setStatementWorkerInput(statementWorkerInputSpy);
+
+ // When
+ statementInteractor.fetchStatementData(statementRequest);
+
+ // Then
+ Assert.assertTrue(statementPresenterInputSpy.presentStatementDataIsCalled);
+ }
+
+ @Test
+ public void fetchClientData_with_validInput_shouldCall_StatementPresenterInput_presentClientData(){
+ // Given
+ StatementInteractor statementInteractor = new StatementInteractor();
+ ClientRequest clientRequest = new ClientRequest();
+ clientRequest.userModel = new UserModel(1, "Teste", "123", "456789", 3.3345);
+ StatementPresenterInputSpy statementPresenterInputSpy = new StatementPresenterInputSpy();
+
+ // Setup Test Double
+ statementInteractor.output = statementPresenterInputSpy;
+ StatementWorkerInputSpy statementWorkerInputSpy = new StatementWorkerInputSpy();
+ statementInteractor.setStatementWorkerInput(statementWorkerInputSpy);
+
+ // When
+ statementInteractor.fetchClientData(clientRequest);
+
+ // Then
+ Assert.assertTrue(statementPresenterInputSpy.presentClientDataIsCalled);
+ }
+
+ @Test
+ public void fetchStatementData_with_invalidInput_shouldCall_StatementPresenterInput_presentStatementData(){
+ // Given
+ StatementInteractor statementInteractor = new StatementInteractor();
+ StatementRequest statementRequest = new StatementRequest();
+ StatementPresenterInputSpy statementPresenterInputSpy = new StatementPresenterInputSpy();
+
+ // Setup Test Double
+ statementInteractor.output = statementPresenterInputSpy;
+ StatementWorkerInputSpy statementWorkerInputSpy = new StatementWorkerInputSpy();
+ statementInteractor.setStatementWorkerInput(statementWorkerInputSpy);
+
+ // When
+ statementInteractor.fetchStatementData(statementRequest);
+
+ // Then
+ Assert.assertTrue(statementPresenterInputSpy.presentStatementDataIsCalled);
+ }
+
+ @Test
+ public void fetchClientData_with_invalidInput_shouldCall_StatementPresenterInput_presentClientData(){
+ // Given
+ StatementInteractor statementInteractor = new StatementInteractor();
+ ClientRequest clientRequest = new ClientRequest();
+ StatementPresenterInputSpy statementPresenterInputSpy = new StatementPresenterInputSpy();
+
+ // Setup Test Double
+ statementInteractor.output = statementPresenterInputSpy;
+ StatementWorkerInputSpy statementWorkerInputSpy = new StatementWorkerInputSpy();
+ statementInteractor.setStatementWorkerInput(statementWorkerInputSpy);
+
+ // When
+ statementInteractor.fetchClientData(clientRequest);
+
+ // Then
+ Assert.assertTrue(statementPresenterInputSpy.presentClientDataIsCalled);
+ }
+
+ @Test
+ public void fetchStatementData_with_validInput_shouldCall_Worker_buildRequest(){
+ // Given
+ StatementInteractor statementInteractor = new StatementInteractor();
+ StatementRequest statementRequest = new StatementRequest();
+ statementRequest.user = new UserModel(1, "Teste", "123", "456789", 3.3345);
+
+ // Setup Test Double
+ statementInteractor.output = new StatementPresenterInputSpy();
+ StatementWorkerInputSpy statementWorkerInputSpy = new StatementWorkerInputSpy();
+ statementInteractor.setStatementWorkerInput(statementWorkerInputSpy);
+
+ // When
+ statementInteractor.fetchStatementData(statementRequest);
+
+ // Then
+ Assert.assertTrue(statementWorkerInputSpy.buildRequestIsCalled);
+ }
+
+ @Test
+ public void fetchStatementData_with_validInput_shouldCall_Worker_getStatements(){
+ // Given
+ StatementInteractor statementInteractor = new StatementInteractor();
+ StatementRequest statementRequest = new StatementRequest();
+ statementRequest.user = new UserModel(1, "Teste", "123", "456789", 3.3345);
+
+ // Setup Test Double
+ statementInteractor.output = new StatementPresenterInputSpy();
+ StatementWorkerInputSpy statementWorkerInputSpy = new StatementWorkerInputSpy();
+ statementInteractor.setStatementWorkerInput(statementWorkerInputSpy);
+
+ // When
+ statementInteractor.fetchStatementData(statementRequest);
+
+ // Then
+ Assert.assertTrue(statementWorkerInputSpy.getStatementResponseIsCalled);
+ }
+
+ @Test
+ public void fetchStatementData_with_invalidInput_shouldNOT_Call_Worker_buildRequest(){
+ // Given
+ StatementInteractor statementInteractor = new StatementInteractor();
+ StatementRequest statementRequest = new StatementRequest();
+
+ // Setup Test Double
+ statementInteractor.output = new StatementPresenterInputSpy();
+ StatementWorkerInputSpy statementWorkerInputSpy = new StatementWorkerInputSpy();
+ statementInteractor.setStatementWorkerInput(statementWorkerInputSpy);
+
+ // When
+ statementInteractor.fetchStatementData(statementRequest);
+
+ // Then
+ Assert.assertFalse(statementWorkerInputSpy.buildRequestIsCalled);
+ }
+
+ @Test
+ public void fetchStatementData_with_invalidInput_shouldNOT_Call_Worker_getStatements(){
+ // Given
+ StatementInteractor statementInteractor = new StatementInteractor();
+ StatementRequest statementRequest = new StatementRequest();
+
+ // Setup Test Double
+ statementInteractor.output = new StatementPresenterInputSpy();
+ StatementWorkerInputSpy statementWorkerInputSpy = new StatementWorkerInputSpy();
+ statementInteractor.setStatementWorkerInput(statementWorkerInputSpy);
+
+ // When
+ statementInteractor.fetchStatementData(statementRequest);
+
+ // Then
+ Assert.assertFalse(statementWorkerInputSpy.getStatementResponseIsCalled);
+ }
+}
+
+class StatementPresenterInputSpy implements StatementPresenterInput{
+
+ Boolean presentStatementDataIsCalled = false;
+ Boolean presentClientDataIsCalled = false;
+
+ @Override
+ public void presentStatementData(StatementResponse response) {
+ presentStatementDataIsCalled = true;
+ }
+
+ @Override
+ public void presentClientData(ClientResponse response) {
+ presentClientDataIsCalled = true;
+ }
+}
+
+class StatementWorkerInputSpy implements StatementWorkerInput{
+
+ Boolean buildRequestIsCalled = false;
+ Boolean getStatementResponseIsCalled = false;
+ private Call call;
+ StatementResponse response;
+
+ @Override
+ public void buildRequest(StatementRequest request) {
+ buildRequestIsCalled = true;
+ Retrofit api = Api.getRetrofitInstance("https://bank-app-test.herokuapp.com/api/");
+ StatementService statementService = api.create(StatementService.class);
+ call = statementService.getStatements(request.user.getUserId());
+ }
+
+ @Override
+ public StatementResponse getStatementsResponse(Callback callback) {
+ getStatementResponseIsCalled = true;
+ try {
+ response = new Gson().fromJson(call.execute().body(), StatementResponse.class);
+ return response;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/app/src/test/java/com/example/testeandroidv2/statementScreen/StatementPresenterUnitTest.java b/app/src/test/java/com/example/testeandroidv2/statementScreen/StatementPresenterUnitTest.java
new file mode 100644
index 000000000..fbacab305
--- /dev/null
+++ b/app/src/test/java/com/example/testeandroidv2/statementScreen/StatementPresenterUnitTest.java
@@ -0,0 +1,130 @@
+package com.example.testeandroidv2.statementScreen;
+
+import com.example.testeandroidv2.loginScreen.UserModel;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+public class StatementPresenterUnitTest {
+
+ @Test
+ public void presentStatementData_ShouldCall_displayStatementData(){
+ // Given
+ StatementPresenter statementPresenter = new StatementPresenter();
+ StatementResponse statementResponse = new StatementResponse();
+ statementResponse.statementList = new ArrayList<>();
+ statementResponse.statementList.add(new StatementModel("Teste", "Teste", "1999-01-01", "1000"));
+ StatementActivityInputSpy statementActivityInputSpy = new StatementActivityInputSpy();
+
+ // Setup Double Test
+ statementPresenter.output = new WeakReference<>(statementActivityInputSpy);
+
+ // When
+ statementPresenter.presentStatementData(statementResponse);
+
+ // Then
+ Assert.assertTrue(statementActivityInputSpy.displayStatementDataIsCalled);
+ }
+
+ @Test
+ public void presentStatementError_ShouldCall_displayStatementError(){
+ // Given
+ StatementPresenter statementPresenter = new StatementPresenter();
+ StatementResponse statementResponse = new StatementResponse();
+ StatementActivityInputSpy statementActivityInputSpy = new StatementActivityInputSpy();
+
+ // Setup Double Test
+ statementPresenter.output = new WeakReference<>(statementActivityInputSpy);
+
+ // When
+ statementPresenter.presentStatementData(statementResponse);
+
+ // Then
+ Assert.assertTrue(statementActivityInputSpy.displayStatementErrorIsCalled);
+ }
+
+ @Test
+ public void presentClientData_with_validInput_ShouldCall_displayClientData(){
+ // Given
+ StatementPresenter statementPresenter = new StatementPresenter();
+ ClientResponse clientResponse = new ClientResponse();
+ clientResponse.userModel = new UserModel(1, "Teste", "1234", "01235064", 3.3345);
+ StatementActivityInputSpy statementActivityInputSpy = new StatementActivityInputSpy();
+
+ // Setup Double Test
+ statementPresenter.output = new WeakReference<>(statementActivityInputSpy);
+
+ // When
+ statementPresenter.presentClientData(clientResponse);
+
+ // Then
+ Assert.assertTrue(statementActivityInputSpy.displayClientDataIsCalled);
+ }
+
+ @Test
+ public void presentClientData_with_invalidInput_ShouldNOT_Call_displayClientData(){
+ // Given
+ StatementPresenter statementPresenter = new StatementPresenter();
+ ClientResponse clientResponse = new ClientResponse();
+ StatementActivityInputSpy statementActivityInputSpy = new StatementActivityInputSpy();
+
+ // Setup Double Test
+ statementPresenter.output = new WeakReference<>(statementActivityInputSpy);
+
+ // When
+ statementPresenter.presentClientData(clientResponse);
+
+ // Then
+ Assert.assertFalse(statementActivityInputSpy.displayClientDataIsCalled);
+ }
+
+ @Test
+ public void presentClientError_ShouldCall_displayClientError(){
+ // Given
+ StatementPresenter statementPresenter = new StatementPresenter();
+ ClientResponse clientResponse = new ClientResponse();
+ StatementActivityInputSpy statementActivityInputSpy = new StatementActivityInputSpy();
+
+ // Setup Double Test
+ statementPresenter.output = new WeakReference<>(statementActivityInputSpy);
+
+ // When
+ statementPresenter.presentClientData(clientResponse);
+
+ // Then
+ Assert.assertTrue(statementActivityInputSpy.displayClientErrorIsCalled);
+ }
+
+}
+
+class StatementActivityInputSpy implements StatementActivityInput{
+
+ Boolean displayStatementDataIsCalled = false;
+ Boolean displayStatementErrorIsCalled = false;
+ Boolean displayClientDataIsCalled = false;
+ Boolean displayClientErrorIsCalled = false;
+
+ @Override
+ public void displayStatementData(List statementModels) {
+ displayStatementDataIsCalled = true;
+ }
+
+ @Override
+ public void displayStatementError(Object error) {
+ displayStatementErrorIsCalled = true;
+ }
+
+ @Override
+ public void displayClientData(ClientModel clientModel) {
+ displayClientDataIsCalled= true;
+ }
+
+ @Override
+ public void displayClientError(Object error) {
+ displayClientErrorIsCalled = true;
+ }
+}
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 000000000..2a76051ca
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,24 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath "com.android.tools.build:gradle:4.2.0-alpha01"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 000000000..52f5917cb
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,19 @@
+# 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.
+org.gradle.jvmargs=-Xmx2048m -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
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app"s APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..f6b961fd5
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..64b70d50a
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Thu Jun 18 19:55:53 GFT 2020
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-rc-1-all.zip
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 000000000..66aee6998
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = "testeandroidv2"
+include ':app'