diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..603b14077 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..208c0a5c4 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,50 @@ +image: openjdk:8-jdk + +variables: + ANDROID_COMPILE_SDK: "29" + ANDROID_BUILD_TOOLS: "29.3.0" + ANDROID_SDK_TOOLS: "6514223" + +before_script: + + # installing packages + - apt-get --quiet update --yes + - apt-get --quiet install --yes wget tar unzip lib32stdc++6 lib32z1 + + # install android sdk + - wget --quiet --output-document=android-sdk.zip https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_TOOLS}.zip + - unzip -d android-sdk-linux android-sdk.zip + - echo y | android-sdk-linux/tools/bin/sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}" >/dev/null + - echo y | android-sdk-linux/tools/bin/sdkmanager "platform-tools" >/dev/null + - echo y | android-sdk-linux/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS}" >/dev/null + + # setup environment + - export ANDROID_HOME=$PWD/android-sdk-linux + - export PATH=$PATH:$PWD/android-sdk-linux/platform-tools/ + - chmod +x ./gradlew + # temporarily disable checking for EPIPE error and use yes to accept all licenses + - set +o pipefail + - yes | android-sdk-linux/tools/bin/sdkmanager --licenses + - set -o pipefail + +stages: + - build + - test + +lintDebug: + stage: build + script: + - ./gradlew -Pci --console=plain :app:lintDebug -PbuildDir=lint + +assembleDebug: + stage: build + script: + - ./gradlew assembleDebug + artifacts: + paths: + - app/build/outputs/ + +debugTests: + stage: test + script: + - ./gradlew -Pci --console=plain :app:testDebug diff --git a/.idea/$CACHE_FILE$ b/.idea/$CACHE_FILE$ new file mode 100644 index 000000000..ebf0f060e --- /dev/null +++ b/.idea/$CACHE_FILE$ @@ -0,0 +1,31 @@ + + + + + + + + + + + Groovy + + + Java + + + Potentially confusing code constructsGroovy + + + Threading issuesJava + + + + + Android + + + + + + \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 000000000..866f33f0a --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Teste Santander \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 000000000..88ea3aa1e --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,122 @@ + + + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+ + +
+
\ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 000000000..79ee123c2 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 000000000..40ed93785 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 000000000..97626ba45 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 000000000..8ae288524 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 000000000..a5f05cd8c --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..8a8f75bfe --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 000000000..7f68460d8 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..6c0b86358 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Bank_App.postman_collection.json b/Bank_App.postman_collection.json deleted file mode 100644 index 53882a1c6..000000000 --- a/Bank_App.postman_collection.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "info": { - "_postman_id": "b90c97e1-4261-4a34-a348-a0604f0264a7", - "name": "Bank App", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "Login", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "name": "Content-Type", - "value": "application/x-www-form-urlencoded", - "type": "text" - } - ], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "user", - "value": "test_user", - "type": "text" - }, - { - "key": "password", - "value": "Test@1", - "type": "text" - } - ] - }, - "url": { - "raw": "https://bank-app-test.herokuapp.com/api/login", - "protocol": "https", - "host": [ - "bank-app-test", - "herokuapp", - "com" - ], - "path": [ - "api", - "login" - ] - } - }, - "response": [] - }, - { - "name": "Statements", - "request": { - "method": "GET", - "header": [ - { - "key": "Content-Type", - "name": "Content-Type", - "value": "application/x-www-form-urlencoded", - "type": "text" - } - ], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "user", - "value": "4", - "type": "text" - }, - { - "key": "password", - "value": "asdfa", - "type": "text" - } - ] - }, - "url": { - "raw": "https://bank-app-test.herokuapp.com/api/statements/1", - "protocol": "https", - "host": [ - "bank-app-test", - "herokuapp", - "com" - ], - "path": [ - "api", - "statements", - "1" - ] - } - }, - "response": [] - } - ] -} \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index bd73feb5f..000000000 --- a/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Show me the code - -Esse repositório contem todo o material necessário para realizar o teste: -- A especificação do layout está na pasta 'bank_app_layout' abrindo o index.html, utilizar os Styles do Android - -- Os dados da Api estão mockados, os exemplos e a especificação dos serviços (login e statements) se encontram no arquivo BankApp.postman_collection.json ( é necessário instalar o postman e importar a colection https://www.getpostman.com/apps) - -![Image of Yaktocat](https://github.com/SantanderTecnologia/TesteiOS/blob/new_test/telas.png) - -### # DESAFIO: - -Na primeira tela teremos um formulario de login, o campo user deve aceitar email ou cpf, -o campo password deve validar se a senha tem pelo menos uma letra maiuscula, um caracter especial e um caracter alfanumérico. -Apos a validação, realizar o login no endpoint https://bank-app-test.herokuapp.com/api/login e exibir os dados de retorno na próxima tela. -O ultimo usuário logado deve ser salvo de forma segura localmente, e exibido na tela de login se houver algum salvo. - -Na segunda tela será exibido os dados formatados do retorno do login e será necessário fazer um segundo request para obter os lançamentos do usuário, no endpoint https://bank-app-test.herokuapp.com/api/statements/{idUser} que retornará uma lista de lançamentos - -### # Avaliação - -Você será avaliado pela usabilidade, por respeitar o design e pela arquitetura do app. É esperado que você consiga explicar as decisões que tomou durante o desenvolvimento através de commits. - -Obrigatórios: - -* Java ou Kotlin -* Material Design -* O app deve funcionar a partir do android 4.4 -* Testes unitários, pode usar a ferramenta que você tem mais experiência, só nos explique o que ele tem de bom. -* Arquitetura a ser utilizada: Android Clean Code (https://github.com/kmmraj/android-clean-code && https://medium.com/@kmmraj/android-clean-code-part-1-c66da6551d1) -* Uso do git. - -### # Observações gerais - -Adicione um arquivo [README.md](http://README.md) com os procedimentos para executar o projeto. -Pedimos que trabalhe sozinho e não divulgue o resultado na internet. - -Faça um fork desse desse repositório em seu Github e ao finalizar nos envie um Pull Request com o resultado, por favor informe por qual empresa você esta se candidatando. - -# Importante: não há prazo de entrega, faça com qualidade! - -# BOA SORTE! diff --git a/_config.yml b/_config.yml deleted file mode 100644 index 2f7efbeab..000000000 --- a/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-minimal \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 000000000..0c6479d9b --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,52 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 29 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + applicationId "br.com.cauejannini.testesantander" + minSdkVersion 19 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + testOptions { + unitTests { + includeAndroidResources = true + } + } +} + +dependencies { + implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation 'androidx.core:core-ktx:1.3.0' + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'com.google.android.material:material:1.1.0' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' + testImplementation 'org.robolectric:robolectric:4.3' + + implementation 'com.squareup.retrofit2:retrofit:2.8.1' + implementation 'com.squareup.retrofit2:converter-gson:2.8.1' +} \ No newline at end of file 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/androidTest/java/br/com/cauejannini/testesantander/ExampleInstrumentedTest.kt b/app/src/androidTest/java/br/com/cauejannini/testesantander/ExampleInstrumentedTest.kt new file mode 100644 index 000000000..cbb0b0bc0 --- /dev/null +++ b/app/src/androidTest/java/br/com/cauejannini/testesantander/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package br.com.cauejannini.testesantander + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("br.com.cauejannini.testesantander", appContext.packageName) + } +} \ 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..4ab7c3c18 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/SharedPreferencesHelper.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/SharedPreferencesHelper.kt new file mode 100644 index 000000000..affb58b9a --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/SharedPreferencesHelper.kt @@ -0,0 +1,38 @@ +package br.com.cauejannini.testesantander.commons + +import android.content.Context +import android.content.SharedPreferences +import android.preference.PreferenceManager +import br.com.cauejannini.testesantander.login.UserAccount +import com.google.gson.Gson + +object SharedPreferencesHelper { + + private val SP_KEY_USER_ACCOUNT = "SP_KEY_USER_ACCOUNT" + private val SP_KEY_USER_NAME = "SP_KEY_USER_NAME" + + fun getSP(context: Context): SharedPreferences? { + return PreferenceManager.getDefaultSharedPreferences(context) + } + + fun saveLoggedUser(context: Context, username: String) { + getSP(context)?.edit()?.putString(SP_KEY_USER_NAME, username)?.apply() + } + + fun getLastLoggedUser(context: Context): String? { + return getSP(context)?.getString(SP_KEY_USER_NAME, null) + } + +// fun saveUserAccount(context: Context, userAccount: UserAccount) { +// val json = Gson().toJson(userAccount) +// getSP(context)?.edit()?.putString(SP_KEY_USER_ACCOUNT, json)?.apply() +// } +// +// fun getUserAccount(context: Context): UserAccount? { +// getSP(context)?.getString(SP_KEY_USER_ACCOUNT, null)?.let { +// return Gson().fromJson(it, UserAccount::class.java) +// } +// return null +// } + +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/Utils.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/Utils.kt new file mode 100644 index 000000000..5c0498a12 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/Utils.kt @@ -0,0 +1,71 @@ +package br.com.cauejannini.testesantander.commons + +import android.content.Context +import android.widget.Toast +import java.text.DecimalFormat +import java.text.DecimalFormatSymbols +import java.text.NumberFormat +import java.text.ParseException +import java.util.* + +object Utils { + + fun showToast(context: Context?, text: String?) { + + if (context != null && text != null) { + Toast.makeText(context, text, Toast.LENGTH_SHORT).show() + } + } + + fun valorMonetarioParaDouble(valor: String?): Double? { + if (valor != null) { + + val df = DecimalFormat("#,##0.00") + try { + val number = df.parse(valor) + number?.let{ + return it.toDouble() + } + } catch (e: ParseException) { + e.printStackTrace() + } + } + return null + } + + fun doubleParaValorMonetario(valor: Double?): String { + valor?.let{ + val df = DecimalFormat("#,##0.00") + return df.format(it) + } + return "-" + } + + fun dataApiParaApp(data: String?): String { + data?.let{ + val array = data.split("-") + if (array.size == 3) { + return String.format("%s/%s/%s", array.get(2), array.get(1),array.get(0)) + } + } + return "-" + } + + fun doisDecimais(valor: Double?): String? { + if (valor != null) { + val decimalFormat = DecimalFormat( + "#,##0.00", + DecimalFormatSymbols(Locale("pt", "BR")) + ) + return decimalFormat.format(valor) + } + return "-" + } + + fun currencyBrazil(valor: Double?): String { + val doisDecimais = doisDecimais(valor) + + return "R$ $doisDecimais" + } + +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/form/AppButton.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/AppButton.kt new file mode 100644 index 000000000..11997608a --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/AppButton.kt @@ -0,0 +1,65 @@ +package br.com.cauejannini.testesantander.commons.form + +import android.content.Context +import android.graphics.PorterDuff +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.LinearLayout +import android.widget.ProgressBar +import android.widget.TextView +import androidx.core.content.ContextCompat +import br.com.cauejannini.testesantander.R + +class AppButton(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) { + + var textView: TextView + var progressBar: ProgressBar + var text: String? = null + + init { + initializeAttrs(attrs) + orientation = VERTICAL + background = resources.getDrawable(R.drawable.app_button) + + // Adicionar view + val child = LayoutInflater.from(context).inflate(R.layout.app_button, this, true) + + // Configurar estado inicial + textView = child.findViewWithTag("textView") + progressBar = child.findViewWithTag("progressBar") + progressBar.indeterminateDrawable.setColorFilter(ContextCompat.getColor(context!!, R.color.white), PorterDuff.Mode.SRC_IN) + + text?.let { textView.text = it } + } + + fun updateText(text: String) { + this.text = text + textView.text = text + } + + private fun initializeAttrs(attrs: AttributeSet?) { + + val typedArray = context.obtainStyledAttributes(attrs, R.styleable.AppButton) + + text = typedArray.getString(R.styleable.AppButton_text) + typedArray.recycle() + } + + override fun setEnabled(enabled: Boolean) { + super.setEnabled(enabled) + isClickable = enabled + } + + fun setLoading(loading: Boolean) { + if (loading) { + isClickable = false + textView.visibility = View.INVISIBLE + progressBar.visibility = View.VISIBLE + } else { + progressBar.visibility = View.INVISIBLE + textView.visibility = View.VISIBLE + isClickable = true + } + } +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/form/Form.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/Form.kt new file mode 100644 index 000000000..4e9c16746 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/Form.kt @@ -0,0 +1,64 @@ +package br.com.cauejannini.testesantander.commons.form + +import android.view.View +import java.util.* + +/** + * Created by cauejannini on 16/01/2018. + */ +class Form (private val btAction: View?) { + + private val fields = ArrayList() + + init { + checkButtonStatus() + } + + fun addValidatable(field: Validatable) { + fields.add(field) + field.form = this + checkButtonStatus() + } + + fun removeValidatable(fieldToRemove: Validatable?) { + if (fieldToRemove != null) { + val iter = fields.iterator() + while (iter.hasNext()) { + val field = iter.next() + if (field == fieldToRemove) { + field.form = null + iter.remove() + } + } + checkButtonStatus() + } + } + + private fun checkButtonStatus() { + if (btAction != null) btAction.isEnabled = isValid + } + + val isValid: Boolean + get() { + for (item in fields) { + if (!item.isValid) { + return false + } + } + return true + } + + fun validadeReceiver(valido: Boolean) { + if (valido) { + checkButtonStatus() + } else { + if (btAction != null) btAction.isEnabled = false + } + } + + interface Validatable { + var form: Form? + val isValid: Boolean + } + +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/form/InputTextField.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/InputTextField.kt new file mode 100644 index 000000000..8578efd0c --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/InputTextField.kt @@ -0,0 +1,204 @@ +package br.com.cauejannini.testesantander.commons.form + +import android.content.Context +import android.text.Editable +import android.text.InputType +import android.text.TextWatcher +import android.text.method.PasswordTransformationMethod +import android.util.AttributeSet +import android.util.TypedValue +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View.OnFocusChangeListener +import android.view.inputmethod.EditorInfo +import android.view.inputmethod.InputMethodManager +import android.widget.EditText +import android.widget.LinearLayout +import android.widget.TextView.OnEditorActionListener +import br.com.cauejannini.testesantander.R +import br.com.cauejannini.testesantander.commons.form.textwatchers.ValidatorTextWatcher +import br.com.cauejannini.testesantander.commons.form.validators.ValidationResult +import br.com.cauejannini.testesantander.commons.form.validators.Validator + +class InputTextField(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs), + ValidatorTextWatcher.WatchableField, + Form.Validatable { + + override lateinit var editText: EditText + + var text: String + get() = editText.text.toString() + set(text) { + editText.setText(text) + } + + var hint: String + get() = editText.hint.toString() + set(hint) { + editText.hint = hint + } + + var inputType = 0 + var imeOptions = 0 + var customTextAlignment = 0 + var maxLines = 0 + var textSize = 0f + var textWatcher: TextWatcher? = null + var myValidator: Validator? = null + var afterTextChangedListener: AfterTextChangedListener? = null + + override var form: Form? = null + + var onEditTextFocusChangeValidator = OnFocusChangeListener { view, isFocused -> + if (isFocused) { + onFocused() + } else { + onUnfocused() + val imm = getContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(view.windowToken, 0) + } + } + + init { + + val child = LayoutInflater.from(context).inflate(R.layout.field_input_text, this, true) + editText = child.findViewWithTag("et") + + background = resources.getDrawable(R.drawable.input_text_bg) + + initAttrs(attrs) + + if (inputType != -1) { + editText.inputType = inputType or InputType.TYPE_TEXT_FLAG_MULTI_LINE or InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE + if (inputType == InputType.TYPE_TEXT_VARIATION_PASSWORD) { + editText.transformationMethod = PasswordTransformationMethod.getInstance() + } + } + + editText.imeOptions = imeOptions + + editText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) + + if (maxLines > 0) editText.maxLines = maxLines + + editText.gravity = Gravity.TOP or customTextAlignment + + editText.onFocusChangeListener = onEditTextFocusChangeValidator + + editText.setHintTextColor(resources.getColor(R.color.hintColor)) + + if (textWatcher == null) { + editText.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {} + + override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {} + + override fun afterTextChanged(editable: Editable) { + this@InputTextField.afterTextChanged(true, editable.toString()) + } + }) + } + } + + private fun initAttrs(attrs: AttributeSet?) { + + val typedArray = context.obtainStyledAttributes(attrs, R.styleable.InputTextField) + + var hint = typedArray.getString(R.styleable.InputTextField_hint) + if (hint == null) hint = "" + this.hint = hint + + inputType = typedArray.getInt(R.styleable.InputTextField_inputType, -1) + textSize = typedArray.getDimension(R.styleable.InputTextField_textSize, resources.getDimension(R.dimen.ts)) + customTextAlignment = typedArray.getInt(R.styleable.InputTextField_textAlignment, Gravity.START) + maxLines = typedArray.getInt(R.styleable.InputTextField_maxLines, -1) + imeOptions = typedArray.getInt(R.styleable.InputTextField_imeOptions, EditorInfo.IME_ACTION_NEXT) + + typedArray.recycle() + } + + override fun setEnabled(enabled: Boolean) { + if (enabled) { + editText.isEnabled = true + editText.alpha = 1f + } else { + editText.isEnabled = false + editText.alpha = .5f + } + } + + fun setOnEditorActionListener(onEditorActionListener: OnEditorActionListener) { + editText.setOnEditorActionListener(onEditorActionListener) + } + + override val isValid: Boolean + get() = myValidator == null || myValidator!!.validate(text).isValid + + override fun afterTextChanged(valid: Boolean, text: String) { + runValidation(text, false) + if (afterTextChangedListener != null) afterTextChangedListener!!.afterTextChanged(text) + } + + fun runValidation(text: String?, reflectLayout: Boolean) { + val validationResult = if (myValidator != null) myValidator!!.validate(text) else ValidationResult(true, "") + + if (text!!.trim { it <= ' ' }.isEmpty() || !reflectLayout) { + layoutNeutral() + } else { + if (validationResult.isValid) { + layoutValid() + } else { + layoutError(validationResult.getMessage()) + } + } + form?.validadeReceiver(validationResult.isValid) + } + + private fun layoutNeutral() { + editText.setTextColor(resources.getColor(R.color.textColor)) + } + + private fun layoutError(message: String) { + editText.setTextColor(resources.getColor(R.color.red)) + editText.error = message + } + + private fun layoutValid() { + editText.setTextColor(resources.getColor(R.color.textColor)) + } + + fun setValidator(validationInterface: Validator?) { + myValidator = validationInterface + runValidation(text, true) + } + + fun showErrorOnFocusLost(shouldShow: Boolean) { + if (shouldShow) { + editText.onFocusChangeListener = onEditTextFocusChangeValidator + } else { + editText.onFocusChangeListener = null + } + } + + fun setCustomTextWatcher(textWatcher: TextWatcher?) { + if (textWatcher != null) { + this.textWatcher = textWatcher + editText.addTextChangedListener(this.textWatcher) + } else { + editText.removeTextChangedListener(this.textWatcher) + this.textWatcher = null + } + } + + private fun onFocused() { + layoutNeutral() + } + + private fun onUnfocused() { + runValidation(text, true) + } + + interface AfterTextChangedListener { + fun afterTextChanged(text: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/form/textwatchers/ValidatorTextWatcher.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/textwatchers/ValidatorTextWatcher.kt new file mode 100644 index 000000000..72a65f080 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/textwatchers/ValidatorTextWatcher.kt @@ -0,0 +1,51 @@ +package br.com.cauejannini.testesantander.commons.form.textwatchers + +import android.text.Editable +import android.text.TextWatcher +import android.widget.EditText + +/** + * Created by user on 16/01/18. + */ +abstract class ValidatorTextWatcher : TextWatcher { + + private var formInterface: WatchableField? = null + protected var editText: EditText + private var lastValidated: String? = null + + constructor(editText: EditText) { + this.editText = editText + } + + constructor(formInterface: WatchableField) { + this.formInterface = formInterface + editText = this.formInterface!!.editText + + val valor = editText.text.toString() + val valido = valida(valor) + this.formInterface!!.afterTextChanged(valido, valor) + } + + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} + + override fun afterTextChanged(s: Editable) { + if (formInterface != null) { + val current = s.toString() + if (current != lastValidated) { + lastValidated = current + val valido = valida(current) + formInterface!!.afterTextChanged(valido, current) + } + } + } + + + protected abstract fun valida(valor: String): Boolean + + interface WatchableField { + var editText: EditText + fun afterTextChanged(valid: Boolean, text: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/form/textwatchers/ValorMonetarioTextWatcher.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/textwatchers/ValorMonetarioTextWatcher.kt new file mode 100644 index 000000000..7c2fd1201 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/textwatchers/ValorMonetarioTextWatcher.kt @@ -0,0 +1,86 @@ +package br.com.cauejannini.testesantander.commons.form.textwatchers + +import android.text.Editable +import android.widget.EditText +import br.com.cauejannini.testesantander.commons.form.validators.Validations + +/** + * Created by cauejannini on 24/04/17. + */ +class ValorMonetarioTextWatcher : ValidatorTextWatcher { + + var cifrao: String? = null + + constructor (editText: EditText) : super(editText) {} + + constructor (formInterface: WatchableField) : super(formInterface) {} + + constructor (formInterface: WatchableField, cifrao: String?) : super(formInterface) { + this.cifrao = cifrao + } + + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} + + override fun afterTextChanged(editable: Editable) { + + var str = editable.toString() + + if (cifrao != null) { + str = str.replace(cifrao!!, "").trim { it <= ' ' } + str = str.replace(cifrao!!.substring(0, cifrao!!.length - 1), "").trim { it <= ' ' } + } + + if (str != "") { + + var clean = str.replace(".", "").replace(",", "") + + val stringBuilder = StringBuilder(clean) + + while (stringBuilder.length > 0 && stringBuilder[0] == '0') { + stringBuilder.deleteCharAt(0) + } + + clean = stringBuilder.toString() + val countChar = clean.length + + str = if (countChar > 19) { + clean.substring(countChar - 19, countChar - 17) + "." + clean.substring(countChar - 17, countChar - 14) + "." + clean.substring(countChar - 14, countChar - 11) + "." + clean.substring(countChar - 11, countChar - 8) + "." + clean.substring(countChar - 8, countChar - 5) + "." + clean.substring(countChar - 5, countChar - 2) + "," + clean.substring(countChar - 2) + } else if (countChar > 17) { + clean.substring(0, countChar - 17) + "." + clean.substring(countChar - 17, countChar - 14) + "." + clean.substring(countChar - 14, countChar - 11) + "." + clean.substring(countChar - 11, countChar - 8) + "." + clean.substring(countChar - 8, countChar - 5) + "." + clean.substring(countChar - 5, countChar - 2) + "," + clean.substring(countChar - 2) + } else if (countChar > 14) { + clean.substring(0, countChar - 14) + "." + clean.substring(countChar - 14, countChar - 11) + "." + clean.substring(countChar - 11, countChar - 8) + "." + clean.substring(countChar - 8, countChar - 5) + "." + clean.substring(countChar - 5, countChar - 2) + "," + clean.substring(countChar - 2) + } else if (countChar > 11) { + clean.substring(0, countChar - 11) + "." + clean.substring(countChar - 11, countChar - 8) + "." + clean.substring(countChar - 8, countChar - 5) + "." + clean.substring(countChar - 5, countChar - 2) + "," + clean.substring(countChar - 2) + } else if (countChar > 8) { + clean.substring(0, countChar - 8) + "." + clean.substring(countChar - 8, countChar - 5) + "." + clean.substring(countChar - 5, countChar - 2) + "," + clean.substring(countChar - 2) + } else if (countChar > 5) { + clean.substring(0, countChar - 5) + "." + clean.substring(countChar - 5, countChar - 2) + "," + clean.substring(countChar - 2) + } else if (countChar > 2) { + clean.substring(0, countChar - 2) + "," + clean.substring(countChar - 2) + } else if (countChar == 2) { + "0,$clean" + } else if (countChar == 1) { + "0,0$clean" + } else { + "0,00" + } + } + + editText.removeTextChangedListener(this) + val filters = editable.filters + editable.filters = arrayOf() + val newString = if (cifrao != null) "$cifrao $str" else str + editable.replace(0, editable.length, newString) + editable.filters = filters + editText.setSelection(editText.length()) + editText.addTextChangedListener(this) + + super.afterTextChanged(editable) + } + + override fun valida(valor: String): Boolean { + return Validations.validarValorMonetario(valor).isValid + } +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/PasswordValidator.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/PasswordValidator.kt new file mode 100644 index 000000000..2f1120d66 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/PasswordValidator.kt @@ -0,0 +1,14 @@ +package br.com.cauejannini.testesantander.commons.form.validators + +import br.com.cauejannini.testesantander.commons.Utils + +/** + * Created by cauejannini on 14/03/2018. + */ +class PasswordValidator : Validator { + + override fun validate(text: String?): ValidationResult { + + return Validations.validarSenha(text) + } +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/UsernameValidator.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/UsernameValidator.kt new file mode 100644 index 000000000..92280d30c --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/UsernameValidator.kt @@ -0,0 +1,14 @@ +package br.com.cauejannini.testesantander.commons.form.validators + +import br.com.cauejannini.testesantander.commons.Utils + +/** + * Created by cauejannini on 14/03/2018. + */ +class UsernameValidator : Validator { + + override fun validate(text: String?): ValidationResult { + + return Validations.validarUsuario(text) + } +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/ValidationResult.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/ValidationResult.kt new file mode 100644 index 000000000..190c95dbc --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/ValidationResult.kt @@ -0,0 +1,12 @@ +package br.com.cauejannini.testesantander.commons.form.validators + +/** + * Created by cauejannini on 14/03/2018. + */ +class ValidationResult(val isValid: Boolean, private val message: String?) { + + fun getMessage(): String { + return message ?: if (isValid) "Campo válido" else "Campo inválido" + } + +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/Validations.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/Validations.kt new file mode 100644 index 000000000..ddf65d3ba --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/Validations.kt @@ -0,0 +1,100 @@ +package br.com.cauejannini.testesantander.commons.form.validators + +/** + * Created by cauejannini on 23/02/17. + */ +object Validations { + + + fun validarSenha(senha: String?): ValidationResult { + return if (senha != null && + senha.isNotEmpty() && + // Checar se tem pelo menos um dígito + senha.matches("(?=.*[0-9]).*".toRegex()) && + + // Checar se tem pelo menos uma letra maiúscula + senha.matches("(?=.*[A-Z]).*".toRegex()) && + + // Checar se tem pelo menos um caractere especial + senha.matches("(?=.*[~!@#$%^&*()_-]).*".toRegex())) { + ValidationResult(true, "Senha OK") + } else { + ValidationResult(false, "Deve conter um número, uma maiúscula e um caractere especial") + } + } + + fun validarUsuario(usuario: String?): ValidationResult { + + return if (validarCpf(usuario) || validarEmail(usuario)) { + ValidationResult(true, "Usuário OK") + } else { + ValidationResult(false, "Usuário deve ser email ou CPF") + } + } + + fun validarEmail(email: String?): Boolean { + return (email != null && email.matches("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}$".toRegex())) + } + + fun validarCpf(cpfString: String?): Boolean { + try { + val cpf = cpfString!!.replace("-", "").replace(".", "") + if (cpf == "00000000000" || cpf == "11111111111" || cpf == "22222222222" || cpf == "33333333333" || cpf == "44444444444" || cpf == "55555555555" || cpf == "66666666666" || cpf == "77777777777" || cpf == "88888888888" || cpf == "99999999999") { + return false + } + if (cpf.length < 11) { + return false + } else if (cpf.length == 11) { + + // VALIDAR PRIMEIRO DIGITO + val d1 = cpf[0].toInt() - 48 + val d2 = cpf[1].toInt() - 48 + val d3 = cpf[2].toInt() - 48 + val d4 = cpf[3].toInt() - 48 + val d5 = cpf[4].toInt() - 48 + val d6 = cpf[5].toInt() - 48 + val d7 = cpf[6].toInt() - 48 + val d8 = cpf[7].toInt() - 48 + val d9 = cpf[8].toInt() - 48 + val d10 = cpf[9].toInt() - 48 + val d11 = cpf[10].toInt() - 48 + val totalSum1 = d1 * 10 + d2 * 9 + d3 * 8 + d4 * 7 + d5 * 6 + d6 * 5 + d7 * 4 + d8 * 3 + d9 * 2 + + val remainder1 = totalSum1 % 11 + var firstDigitCorret = 0 + if (remainder1 >= 2) { + firstDigitCorret = 11 - remainder1 + } + if (d10 == firstDigitCorret) { + + // VALIDAR SEGUNDO DÍGITO + val totalSum2 = + totalSum1 + d1 + d2 + d3 + d4 + d5 + d6 + d7 + d8 + d9 + d10 * 2 + val remainder2 = totalSum2 % 11 + var secondDigitCorrect = 0 + if (remainder2 >= 2) { + secondDigitCorrect = 11 - remainder2 + } + if (secondDigitCorrect == d11) { + return true + } + } + } + } catch (ignored: Exception) { + } + return false + } + + fun validarValorMonetario(renda: String): ValidationResult { + + val rendaJustNumbers = renda.replace(".", "").replace("R$", "").trim { it <= ' ' } + val arrayRenda = rendaJustNumbers.split(",".toRegex()).toTypedArray() + val rendaSemDecimal = arrayRenda[0] + + return if (rendaSemDecimal.matches("[0-9]+".toRegex())) { + ValidationResult(true, "Valor ok") + } else { + ValidationResult(false, "Valor inválido") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/Validator.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/Validator.kt new file mode 100644 index 000000000..6d5aa47b0 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/Validator.kt @@ -0,0 +1,8 @@ +package br.com.cauejannini.testesantander.commons.form.validators + +/** + * Created by cauejannini on 14/03/2018. + */ +interface Validator { + fun validate(text: String?): ValidationResult +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/ValorMonetarioValidator.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/ValorMonetarioValidator.kt new file mode 100644 index 000000000..2d784afd8 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/form/validators/ValorMonetarioValidator.kt @@ -0,0 +1,45 @@ +package br.com.cauejannini.testesantander.commons.form.validators + +import br.com.cauejannini.testesantander.commons.Utils + +/** + * Created by cauejannini on 14/03/2018. + */ +class ValorMonetarioValidator : Validator { + + var min: Double? = null + var max: Double? = null + + constructor() {} + + constructor(min: Double?, max: Double?) { + this.min = min + this.max = max + } + + override fun validate(text: String?): ValidationResult { + + val validationResult = Validations.validarValorMonetario(text!!) + if (validationResult.isValid) { + if (min != null || max != null) { + + if (min != null && max != null && min!! > max!!) { + return ValidationResult(false, "Valor inválido") + } + + val valorDouble = Utils.valorMonetarioParaDouble(text) + + if (valorDouble != null) { + if (min != null && valorDouble < min!!) { + return ValidationResult(false, "O valor mínimo é de " + Utils.doisDecimais(min)) + } + + return if (max != null && valorDouble > max!!) { + ValidationResult(false, "O valor máximo é de " + Utils.doisDecimais(max)) + } else ValidationResult(true, "Válido") + } + } + } + return validationResult + } +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/integracao/Api.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/integracao/Api.kt new file mode 100644 index 000000000..2adf2f4ae --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/integracao/Api.kt @@ -0,0 +1,16 @@ +package br.com.cauejannini.testesantander.commons.integracao + +import br.com.cauejannini.testesantander.login.LoginResponseModel +import br.com.cauejannini.testesantander.statements.StatementsResponseModel +import retrofit2.Call +import retrofit2.http.* + +interface Api { + + @FormUrlEncoded + @POST("login") + fun login(@Field("user") user: String, @Field("password") password: String): Call + + @GET("statements/{userId}") + fun getStatements(@Path("userId") userId: Int): Call +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/integracao/ApiRepository.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/integracao/ApiRepository.kt new file mode 100644 index 000000000..5fb940f76 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/integracao/ApiRepository.kt @@ -0,0 +1,11 @@ +package br.com.cauejannini.testesantander.commons.integracao + +import android.content.Context + +class ApiRepository() { + + fun get(): Api { + return RetrofitService().createService(Api::class.java) + } + +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/integracao/NetworkUtils.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/integracao/NetworkUtils.kt new file mode 100644 index 000000000..dfadded66 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/integracao/NetworkUtils.kt @@ -0,0 +1,20 @@ +package br.com.cauejannini.testesantander.commons.integracao + +import android.content.Context +import android.net.ConnectivityManager +import android.net.NetworkInfo + +object NetworkUtils { + + fun isConnected(context: Context?): Boolean { + context?.let { contextNonNull -> + val connectivityManager = contextNonNull.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + connectivityManager.activeNetworkInfo?.let { networkInfo -> + return networkInfo.isConnected + } + return false + } + return true + } + +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/commons/integracao/RetrofitService.kt b/app/src/main/java/br/com/cauejannini/testesantander/commons/integracao/RetrofitService.kt new file mode 100644 index 000000000..610ef1339 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/commons/integracao/RetrofitService.kt @@ -0,0 +1,58 @@ +package br.com.cauejannini.testesantander.commons.integracao + +import android.content.Context +import br.com.cauejannini.testesantander.commons.integracao.NetworkUtils +import okhttp3.HttpUrl +import okhttp3.Interceptor +import okhttp3.OkHttpClient +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import java.io.IOException + +class RetrofitService() { + + val baseUrl = "https://bank-app-test.herokuapp.com/api/" + + val retrofit: Retrofit = Retrofit.Builder() + .baseUrl(baseUrl) + .addConverterFactory(GsonConverterFactory.create()) + .client(buildClient()) + .build() + + fun createService(serviceClass: Class): T { + + return retrofit.create(serviceClass) + } + + fun buildClient() : OkHttpClient { + +// val connectionCheckerInterface = Interceptor { chain -> +// +// if (!NetworkUtils.isConnected(context)) { +// throw IOException("Você parece estar offline") +// } +// chain.proceed(chain.request().newBuilder().build()) +// +// } + +// val authInterceptor = Interceptor { chain -> +// +// val apiKey = BuildConfig.API_KEY +// +// var request = chain.request() +// val url: HttpUrl = request.url().newBuilder() +// .addQueryParameter("access_key", apiKey) +// .build() +// request = request.newBuilder().url(url).build() +// +// chain.proceed(request) +// +// } + + return OkHttpClient.Builder() +// .addInterceptor(connectionCheckerInterface) +// .addInterceptor(authInterceptor) + .build() + } + +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/login/LoginActivity.kt b/app/src/main/java/br/com/cauejannini/testesantander/login/LoginActivity.kt new file mode 100644 index 000000000..4ab8d729c --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/login/LoginActivity.kt @@ -0,0 +1,87 @@ +package br.com.cauejannini.testesantander.login + +import android.app.Activity +import android.content.Context +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.util.Log +import android.view.View +import android.view.inputmethod.InputMethodManager +import android.widget.TextView +import br.com.cauejannini.testesantander.R +import br.com.cauejannini.testesantander.commons.SharedPreferencesHelper +import br.com.cauejannini.testesantander.commons.Utils +import br.com.cauejannini.testesantander.commons.form.Form +import br.com.cauejannini.testesantander.commons.form.validators.PasswordValidator +import br.com.cauejannini.testesantander.commons.form.validators.UsernameValidator +import br.com.cauejannini.testesantander.statements.StatementsActivity +import com.google.gson.Gson +import kotlinx.android.synthetic.main.activity_login.* + +interface LoginActivityInput { + fun onLoggedIn(userAccount: UserAccount) + fun onLoginError(message: String) +} + +class LoginActivity : AppCompatActivity(), LoginActivityInput { + + lateinit var output: LoginInteractorInput + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_login) + + LoginConfigurator.configure(this) + + inputUser.setValidator(UsernameValidator()) + inputPassword.setValidator(PasswordValidator()) + + val form = Form(btLogin) + form.addValidatable(inputUser) + form.addValidatable(inputPassword) + + btLogin.setOnClickListener { + login() + } + + inputPassword.setOnEditorActionListener(TextView.OnEditorActionListener { textView, i, keyEvent -> + hideKeyboard() + login() + true + }) + + SharedPreferencesHelper.getLastLoggedUser(this)?.let { + inputUser.text = it + } + } + + fun login() { + val user = inputUser.text + val password = inputPassword.text + output.login(LoginRequest(user, password)) + btLogin.setLoading(true) + } + + override fun onLoggedIn(userAccount: UserAccount) { + Log.i("userAccount", Gson().toJson(userAccount)) + btLogin.setLoading(false) + + SharedPreferencesHelper.saveLoggedUser(this, inputUser.text) + + val intent = Intent(this, StatementsActivity::class.java) + intent.putExtra(StatementsActivity.EXTRA_KEY_USER_ACCOUNT, userAccount) + startActivity(intent) + } + + override fun onLoginError(message: String) { + Utils.showToast(this, message) + btLogin.setLoading(false) + } + + fun AppCompatActivity.hideKeyboard() { + val view = currentFocus ?: View(this) + val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager + inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0) + } +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/login/LoginConfigurator.kt b/app/src/main/java/br/com/cauejannini/testesantander/login/LoginConfigurator.kt new file mode 100644 index 000000000..e4f079385 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/login/LoginConfigurator.kt @@ -0,0 +1,19 @@ +package br.com.cauejannini.testesantander.login + +import java.lang.ref.WeakReference + +object LoginConfigurator { + + fun configure(loginActivity: LoginActivity) { + + val presenter = LoginPresenter() + presenter.output = WeakReference(loginActivity) + + val interactor = LoginInteractor() + interactor.output = presenter + + loginActivity.output = interactor + + } + +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/login/LoginInteractor.kt b/app/src/main/java/br/com/cauejannini/testesantander/login/LoginInteractor.kt new file mode 100644 index 000000000..10f839c3c --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/login/LoginInteractor.kt @@ -0,0 +1,43 @@ +package br.com.cauejannini.testesantander.login + +import android.content.Context +import br.com.cauejannini.testesantander.commons.integracao.ApiRepository +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +interface LoginInteractorInput { + fun login(request: LoginRequest) +} + +class LoginInteractor: LoginInteractorInput { + + var output: LoginPresenterInput? = null + val api = ApiRepository().get() + + override fun login(request: LoginRequest) { + + val user = request.user + val password = request.password + + api.login(user, password).enqueue(object: Callback { + + override fun onFailure(call: Call, t: Throwable) { + output?.onLoginFailed(if (t.message != null) t.message!! else "Erro") + } + + override fun onResponse(call: Call, response: Response) { + val loginResponse = response.body() + if (loginResponse != null) { + output?.onLoginResponse(loginResponse) + } else { + output?.onLoginFailed(response.message()) + } + } + + }) + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/login/LoginModels.kt b/app/src/main/java/br/com/cauejannini/testesantander/login/LoginModels.kt new file mode 100644 index 000000000..6b38835e2 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/login/LoginModels.kt @@ -0,0 +1,20 @@ +package br.com.cauejannini.testesantander.login + +import java.io.Serializable + +data class LoginRequest(val user: String, val password: String) {} + +class LoginResponseModel { + + var userAccount: UserAccount? = null + var error: Any? = null +} + +class UserAccount: Serializable { + + var userId: Int? = null + var name: String? = null + var bankAccount: String? = null + var agency: String? = null + var balance: Double? = null +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/login/LoginPresenter.kt b/app/src/main/java/br/com/cauejannini/testesantander/login/LoginPresenter.kt new file mode 100644 index 000000000..e260c0492 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/login/LoginPresenter.kt @@ -0,0 +1,27 @@ +package br.com.cauejannini.testesantander.login + +import java.lang.ref.WeakReference + +interface LoginPresenterInput { + fun onLoginResponse(loginResponse: LoginResponseModel) + fun onLoginFailed(message: String) +} + +class LoginPresenter: LoginPresenterInput { + + var output: WeakReference? = null + + override fun onLoginResponse(loginResponse: LoginResponseModel) { + val userAccount = loginResponse.userAccount + if (userAccount != null) { + output?.get()?.onLoggedIn(userAccount) + } else { + output?.get()?.onLoginError(loginResponse.error.toString()) + } + } + + override fun onLoginFailed(message: String) { + output?.get()?.onLoginError(message) + } + +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsActivity.kt b/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsActivity.kt new file mode 100644 index 000000000..fc3bb20cd --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsActivity.kt @@ -0,0 +1,64 @@ +package br.com.cauejannini.testesantander.statements + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import androidx.recyclerview.widget.LinearLayoutManager +import br.com.cauejannini.testesantander.R +import br.com.cauejannini.testesantander.commons.Utils +import br.com.cauejannini.testesantander.login.UserAccount +import kotlinx.android.synthetic.main.activity_statements.* + +interface StatementsActivityInput { + fun displayStatements(statements: List) + fun displayStatementsError(message: String) + fun displayUserData(userDataModel: UserDataModel) +} + +class StatementsActivity : AppCompatActivity(), StatementsActivityInput { + + companion object { + val EXTRA_KEY_USER_ACCOUNT = "EXTRA_KEY_USER_ACCOUNT" + } + + lateinit var output: StatementsInteractorInput + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_statements) + + StatementsConfigurator.configure(this) + + val userAccount = intent.getSerializableExtra(EXTRA_KEY_USER_ACCOUNT) as UserAccount? + + fetchStatements(userAccount) + + swipeRefreshLayout.setOnRefreshListener { + fetchStatements(userAccount) + } + + } + + fun fetchStatements(userAccount: UserAccount?) { + + output.fetchStatements(userAccount) + swipeRefreshLayout.isRefreshing = true + } + + override fun displayStatements(statements: List) { + rvStatements.layoutManager = LinearLayoutManager(this) + rvStatements.adapter = StatementsRecyclerViewAdapter(statements) + swipeRefreshLayout.isRefreshing = false + } + + override fun displayStatementsError(message: String) { + Utils.showToast(this, message) + swipeRefreshLayout.isRefreshing = false + } + + override fun displayUserData(userDataModel: UserDataModel) { + tvUserName.text = userDataModel.userName + tvContaNumero.text = userDataModel.agenciaConta + tvSaldo.text = userDataModel.saldo + } + +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsConfigurator.kt b/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsConfigurator.kt new file mode 100644 index 000000000..d8fb59f64 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsConfigurator.kt @@ -0,0 +1,19 @@ +package br.com.cauejannini.testesantander.statements + +import java.lang.ref.WeakReference + +object StatementsConfigurator { + + fun configure(statementsActivity: StatementsActivity) { + + val presenter = StatementsPresenter() + presenter.output = WeakReference(statementsActivity) + + val interactor = StatementsInteractor() + interactor.output = presenter + + statementsActivity.output = interactor + + } + +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsInteractor.kt b/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsInteractor.kt new file mode 100644 index 000000000..851c18024 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsInteractor.kt @@ -0,0 +1,48 @@ +package br.com.cauejannini.testesantander.statements + +import android.content.Context +import br.com.cauejannini.testesantander.commons.integracao.ApiRepository +import br.com.cauejannini.testesantander.login.UserAccount +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +interface StatementsInteractorInput { + fun fetchStatements(userAccount: UserAccount?) +} + +class StatementsInteractor: StatementsInteractorInput{ + + var output: StatementsPresenterInput? = null + val api = ApiRepository().get() + + override fun fetchStatements(userAccount: UserAccount?) { + + output?.presentUserAccount(userAccount) + + val userId = userAccount?.userId + if (userId != null) { + + api.getStatements(userId).enqueue(object: Callback { + + override fun onFailure(call: Call, t: Throwable) { + output?.presentStatementsFailed(if (t.message != null) t.message!! else "Erro") + } + + override fun onResponse(call: Call, response: Response) { + val statementsResponse = response.body() + if (statementsResponse != null) { + output?.presentStatementsResponse(statementsResponse) + } else { + output?.presentStatementsFailed(response.message()) + } + } + }) + + } else { + output?.presentStatementsFailed("User id nulo") + } + + + } +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsModels.kt b/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsModels.kt new file mode 100644 index 000000000..7a53508c4 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsModels.kt @@ -0,0 +1,34 @@ +package br.com.cauejannini.testesantander.statements + +data class StatementsRequestModel(val userId: String) {} + +class StatementsResponseModel { + + var statementList: List? = null + var error: Any? = null +} + + +class UserDataModel { + + var userName: String? = null + var agenciaConta: String? = null + var saldo: String? = null +} + +class Statement { + + constructor() {} + + constructor(title: String?, desc: String?, date: String?, value: Double?) { + this.title = title + this.desc = desc + this.date = date + this.value = value + } + + var title: String? = null + var desc: String? = null + var date: String? = null + var value: Double? = null +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsPresenter.kt b/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsPresenter.kt new file mode 100644 index 000000000..09dc4e5db --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsPresenter.kt @@ -0,0 +1,53 @@ +package br.com.cauejannini.testesantander.statements + +import br.com.cauejannini.testesantander.commons.Utils +import br.com.cauejannini.testesantander.login.UserAccount +import java.lang.ref.WeakReference + +interface StatementsPresenterInput { + fun presentStatementsResponse(statementsResponse: StatementsResponseModel) + fun presentStatementsFailed(message: String) + fun presentUserAccount (userAccount: UserAccount?) +} + +class StatementsPresenter: StatementsPresenterInput { + + var output: WeakReference? = null + + override fun presentStatementsResponse(statementsResponse: StatementsResponseModel) { + val statementList = statementsResponse.statementList + if (statementList != null) { + output?.get()?.displayStatements(statementList) + } else { + output?.get()?.displayStatementsError(statementsResponse.error.toString()) + } + } + + override fun presentStatementsFailed(message: String) { + output?.get()?.displayStatementsError(message) + } + + override fun presentUserAccount(userAccount: UserAccount?) { + + val userDataModel = UserDataModel() + + if (userAccount != null) { + + userDataModel.userName = if (userAccount.name != null) userAccount.name else "-" + val agencia = if (userAccount.agency != null) userAccount.agency else "-" + val conta = if (userAccount.bankAccount != null) userAccount.bankAccount else "-" + userDataModel.agenciaConta = "$conta / $agencia" + + val saldo = if (userAccount.balance != null) Utils.currencyBrazil(userAccount.balance) else "-" + userDataModel.saldo = saldo + + } else { + userDataModel.userName = "-" + userDataModel.agenciaConta = "- / -" + userDataModel.saldo = "-" + } + + output?.get()?.displayUserData(userDataModel) + } + +} \ No newline at end of file diff --git a/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsRecyclerViewAdapter.kt b/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsRecyclerViewAdapter.kt new file mode 100644 index 000000000..110e109d2 --- /dev/null +++ b/app/src/main/java/br/com/cauejannini/testesantander/statements/StatementsRecyclerViewAdapter.kt @@ -0,0 +1,42 @@ +package br.com.cauejannini.testesantander.statements + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import br.com.cauejannini.testesantander.R +import br.com.cauejannini.testesantander.commons.Utils +import kotlinx.android.synthetic.main.list_item_statement.view.* + +class StatementsRecyclerViewAdapter(val statementList: List): + RecyclerView.Adapter() { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StatementItemViewHolder { + val view = LayoutInflater.from(parent.context).inflate(R.layout.list_item_statement, parent, false) + return StatementItemViewHolder(view) + } + + override fun getItemCount(): Int { + return statementList.size + } + + override fun onBindViewHolder(holder: StatementItemViewHolder, position: Int) { + val statement = statementList.get(position) + holder.tvTitle.text = statement.title + holder.tvDate.text = Utils.dataApiParaApp(statement.date) + holder.tvDesc.text = statement.desc + + val value = Utils.doisDecimais(statement.value) + holder.tvValue.text = "R$ $value" + } + + class StatementItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + + val tvTitle = itemView.tvTitle + val tvDesc = itemView.tvDesc + val tvDate = itemView.tvDate + val tvValue = itemView.tvValue + + } + +} \ No newline at end of file diff --git a/app/src/main/res/drawable/app_button.xml b/app/src/main/res/drawable/app_button.xml new file mode 100644 index 000000000..3ed3d526c --- /dev/null +++ b/app/src/main/res/drawable/app_button.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/app_button_disabled.xml b/app/src/main/res/drawable/app_button_disabled.xml new file mode 100644 index 000000000..dfa1270df --- /dev/null +++ b/app/src/main/res/drawable/app_button_disabled.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/app_button_np.xml b/app/src/main/res/drawable/app_button_np.xml new file mode 100644 index 000000000..2c6f71bca --- /dev/null +++ b/app/src/main/res/drawable/app_button_np.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/app_button_p.xml b/app/src/main/res/drawable/app_button_p.xml new file mode 100644 index 000000000..7fc07bd3c --- /dev/null +++ b/app/src/main/res/drawable/app_button_p.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ 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/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 000000000..2b068d114 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/bank_app_layout/assets/logout 2.png b/app/src/main/res/drawable/ic_logout.png similarity index 100% rename from bank_app_layout/assets/logout 2.png rename to app/src/main/res/drawable/ic_logout.png diff --git a/app/src/main/res/drawable/input_text_bg.xml b/app/src/main/res/drawable/input_text_bg.xml new file mode 100644 index 000000000..4579d8b2b --- /dev/null +++ b/app/src/main/res/drawable/input_text_bg.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/item_list_bg.xml b/app/src/main/res/drawable/item_list_bg.xml new file mode 100644 index 000000000..f26b435a5 --- /dev/null +++ b/app/src/main/res/drawable/item_list_bg.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/bank_app_layout/assets/Logo.png b/app/src/main/res/drawable/logo.png similarity index 100% rename from bank_app_layout/assets/Logo.png rename to app/src/main/res/drawable/logo.png diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml new file mode 100644 index 000000000..3f21c564f --- /dev/null +++ b/app/src/main/res/layout/activity_login.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_statements.xml b/app/src/main/res/layout/activity_statements.xml new file mode 100644 index 000000000..aa5006224 --- /dev/null +++ b/app/src/main/res/layout/activity_statements.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/app_button.xml b/app/src/main/res/layout/app_button.xml new file mode 100644 index 000000000..a2a4beec2 --- /dev/null +++ b/app/src/main/res/layout/app_button.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/field_input_text.xml b/app/src/main/res/layout/field_input_text.xml new file mode 100644 index 000000000..1b890f94c --- /dev/null +++ b/app/src/main/res/layout/field_input_text.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/list_item_statement.xml b/app/src/main/res/layout/list_item_statement.xml new file mode 100644 index 000000000..ddfd0fe9a --- /dev/null +++ b/app/src/main/res/layout/list_item_statement.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + \ 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..a571e6009 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..c41dd2853 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..6dba46dab 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..15ac68172 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..f25a41974 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/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 000000000..fc4dadfd6 --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 000000000..ddfec5f79 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,17 @@ + + + #111 + #000 + #3434ec + #5454ff + #333 + + #bbb + #555 + #fff + #f9f9f9 + #7fff + #777 + #ddd + #f66 + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 000000000..37b5b24bd --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,15 @@ + + + 8dp + 16dp + 32dp + 48dp + + 12sp + 16sp + 24sp + + 4dp + 1dp + + \ 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..52ff143dc --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,9 @@ + + Teste Santander + Login + User + Password + Conta + Saldo + Recentes + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..eec57e753 --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/test/java/br/com/cauejannini/testesantander/LoginActivityUnitTest.kt b/app/src/test/java/br/com/cauejannini/testesantander/LoginActivityUnitTest.kt new file mode 100644 index 000000000..03dbad7e7 --- /dev/null +++ b/app/src/test/java/br/com/cauejannini/testesantander/LoginActivityUnitTest.kt @@ -0,0 +1,177 @@ +package br.com.cauejannini.testesantander + +import android.content.Context +import android.content.Intent +import android.os.Build +import br.com.cauejannini.testesantander.commons.form.AppButton +import br.com.cauejannini.testesantander.commons.form.InputTextField +import br.com.cauejannini.testesantander.commons.form.validators.PasswordValidator +import br.com.cauejannini.testesantander.commons.form.validators.UsernameValidator +import br.com.cauejannini.testesantander.login.LoginActivity +import br.com.cauejannini.testesantander.login.LoginInteractorInput +import br.com.cauejannini.testesantander.login.LoginRequest +import br.com.cauejannini.testesantander.login.UserAccount +import br.com.cauejannini.testesantander.statements.StatementsActivity +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.Robolectric +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment +import org.robolectric.Shadows +import org.robolectric.annotation.Config + +@Config(sdk = [Build.VERSION_CODES.O_MR1]) +@RunWith(RobolectricTestRunner::class) +class LoginActivityUnitTest { + + @Test + fun loginActivity_shouldNot_beNull() { + val activity = Robolectric.setupActivity(LoginActivity::class.java) + + Assert.assertNotNull(activity) + } + + @Test + fun onCreate_shouldAdd_inputValidation() { + + val activity = Robolectric.setupActivity(LoginActivity::class.java) + + val inputUser = activity.findViewById(R.id.inputUser) + val inputPassword = activity.findViewById(R.id.inputPassword) + + Assert.assertTrue(inputUser.myValidator is UsernameValidator) + Assert.assertTrue(inputPassword.myValidator is PasswordValidator) + } + + @Test + fun inputUser_shouldOnly_acceptValidUsers() { + val activity = Robolectric.setupActivity(LoginActivity::class.java) + + val inputUser = activity.findViewById(R.id.inputUser) + + // Emails inválidos + inputUser.text = "" + Assert.assertFalse(inputUser.isValid) + + inputUser.text = "a" + Assert.assertFalse(inputUser.isValid) + + inputUser.text = "abcdefg123" + Assert.assertFalse(inputUser.isValid) + + inputUser.text = "abcdefg123@domain" + Assert.assertFalse(inputUser.isValid) + + inputUser.text = "abcdefg123@domain." + Assert.assertFalse(inputUser.isValid) + + // Email válido + inputUser.text = "abcdefg123@domain.com" + Assert.assertTrue(inputUser.isValid) + + // CPFs inválidos + inputUser.text = "406361858" + Assert.assertFalse(inputUser.isValid) + + inputUser.text = "40636185875" + Assert.assertFalse(inputUser.isValid) + + // CPFs válido + inputUser.text = "40636185877" + Assert.assertTrue(inputUser.isValid) + + } + + @Test + fun inputPassword_shouldOnly_acceptValidPasswords() { + val activity = Robolectric.setupActivity(LoginActivity::class.java) + + val inputPassword = activity.findViewById(R.id.inputPassword) + + // Passwords inválidos + inputPassword.text = "" + Assert.assertFalse(inputPassword.isValid) + + inputPassword.text = "a" + Assert.assertFalse(inputPassword.isValid) + + inputPassword.text = "a1" + Assert.assertFalse(inputPassword.isValid) + + inputPassword.text = "a1@" + Assert.assertFalse(inputPassword.isValid) + + // Password válido + inputPassword.text = "a1@B" + Assert.assertTrue(inputPassword.isValid) + + } + + @Test + fun btLoginClick_callsLogin_withCorrectData() { + + val activity = Robolectric.setupActivity(LoginActivity::class.java) + val outputSpy = LoginActivityOutputSpy() + activity.output = outputSpy + + val inputUser = activity.findViewById(R.id.inputUser) + val inputPassword = activity.findViewById(R.id.inputPassword) + val btLogin = activity.findViewById(R.id.btLogin) + + inputUser.text = "user@domain.com" + inputPassword.text = "b2#C" + + btLogin.performClick() + + // Assert login is called in spy + Assert.assertTrue(outputSpy.loginCalled) + + // Assert request passed is not null and correct + Assert.assertNotNull(outputSpy.loginRequestCopy) + Assert.assertTrue(outputSpy.loginRequestCopy.user == inputUser.text) + Assert.assertTrue(outputSpy.loginRequestCopy.password == inputPassword.text) + } + + @Test + fun successfullLogin_shouldCall_statementsActivityWithIntent() { + val activity = Robolectric.setupActivity(LoginActivity::class.java) + + val userAccount = UserAccount() + userAccount.userId = 1 + userAccount.name = "Lucio dos Santos Teste" + userAccount.agency = "1234" + userAccount.bankAccount = "567890" + userAccount.balance = 990.34 + + activity.onLoggedIn(userAccount) + + val intentEsperado = Intent(activity, StatementsActivity::class.java) + intentEsperado.putExtra(StatementsActivity.EXTRA_KEY_USER_ACCOUNT, userAccount) + + val intentEnviado = Shadows.shadowOf(RuntimeEnvironment.application).nextStartedActivity + + // Assert redirecting to correct Activity + Assert.assertEquals(intentEnviado.component?.className, StatementsActivity::class.java.name) + + // Assert that has added extra with correct key + Assert.assertTrue(intentEnviado.hasExtra(StatementsActivity.EXTRA_KEY_USER_ACCOUNT)) + + // Assert that extra type is correct + Assert.assertTrue(intentEnviado.getSerializableExtra(StatementsActivity.EXTRA_KEY_USER_ACCOUNT) is UserAccount) + + } + + private class LoginActivityOutputSpy: LoginInteractorInput { + + var loginCalled = false + lateinit var loginRequestCopy: LoginRequest + + override fun login(request: LoginRequest) { + loginCalled = true + loginRequestCopy = request + + } + } + +} \ No newline at end of file diff --git a/app/src/test/java/br/com/cauejannini/testesantander/LoginPresenterUnitTest.kt b/app/src/test/java/br/com/cauejannini/testesantander/LoginPresenterUnitTest.kt new file mode 100644 index 000000000..c2d3444e4 --- /dev/null +++ b/app/src/test/java/br/com/cauejannini/testesantander/LoginPresenterUnitTest.kt @@ -0,0 +1,108 @@ +package br.com.cauejannini.testesantander + +import android.os.Build +import br.com.cauejannini.testesantander.login.* +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import java.lang.ref.WeakReference + +@Config(sdk = [Build.VERSION_CODES.O_MR1]) +@RunWith(RobolectricTestRunner::class) +class LoginPresenterUnitTest { + + @Test + fun present_correctData_onLoginSuccessfull() { + + val loginPresenter = LoginPresenter() + val outputSpy = LoginActivityInputSpy() + loginPresenter.output = WeakReference(outputSpy) + + val loginResponseModel = LoginResponseModel() + + val userAccount = UserAccount() + userAccount.userId = 1 + userAccount.name = "Lucio dos Santos Teste" + userAccount.agency = "1234" + userAccount.bankAccount = "567890" + userAccount.balance = 990.34 + + loginResponseModel.userAccount = userAccount + loginResponseModel.error = null + + loginPresenter.onLoginResponse(loginResponseModel) + + Assert.assertTrue(outputSpy.onLoggedInCalled) + Assert.assertEquals(outputSpy.userAccountCopy, userAccount) + + Assert.assertFalse(outputSpy.onLoginErrorCalled) + Assert.assertNull(outputSpy.errorMessageCopy) + + } + + @Test + fun present_correctData_onLoginResponseError() { + + val loginPresenter = LoginPresenter() + val outputSpy = LoginActivityInputSpy() + loginPresenter.output = WeakReference(outputSpy) + + val loginResponseModel = LoginResponseModel() + + loginResponseModel.userAccount = null + + val errorMessage = "Erro retornado no LoginResponseModel" + loginResponseModel.error = errorMessage + + loginPresenter.onLoginResponse(loginResponseModel) + + Assert.assertTrue(outputSpy.onLoginErrorCalled) + Assert.assertEquals(outputSpy.errorMessageCopy, errorMessage) + + Assert.assertFalse(outputSpy.onLoggedInCalled) + Assert.assertNull(outputSpy.userAccountCopy) + + } + + @Test + fun present_correctData_onLoginFailed() { + + val loginPresenter = LoginPresenter() + val outputSpy = LoginActivityInputSpy() + loginPresenter.output = WeakReference(outputSpy) + + val errorMessage = "Erro de integração" + + loginPresenter.onLoginFailed(errorMessage) + + Assert.assertTrue(outputSpy.onLoginErrorCalled) + Assert.assertEquals(outputSpy.errorMessageCopy, errorMessage) + + Assert.assertFalse(outputSpy.onLoggedInCalled) + Assert.assertNull(outputSpy.userAccountCopy) + + } + + private class LoginActivityInputSpy: LoginActivityInput { + + var onLoggedInCalled = false + var userAccountCopy: UserAccount? = null + + var onLoginErrorCalled = false + var errorMessageCopy: String? = null + + override fun onLoggedIn(userAccount: UserAccount) { + onLoggedInCalled = true + userAccountCopy = userAccount + } + + override fun onLoginError(message: String) { + onLoginErrorCalled = true + errorMessageCopy = message + } + + } + +} \ No newline at end of file diff --git a/app/src/test/java/br/com/cauejannini/testesantander/StatementsActivityUnitTest.kt b/app/src/test/java/br/com/cauejannini/testesantander/StatementsActivityUnitTest.kt new file mode 100644 index 000000000..9dcaa51b6 --- /dev/null +++ b/app/src/test/java/br/com/cauejannini/testesantander/StatementsActivityUnitTest.kt @@ -0,0 +1,70 @@ +package br.com.cauejannini.testesantander + +import android.content.Context +import android.content.Intent +import android.os.Build +import br.com.cauejannini.testesantander.commons.form.AppButton +import br.com.cauejannini.testesantander.commons.form.InputTextField +import br.com.cauejannini.testesantander.commons.form.validators.PasswordValidator +import br.com.cauejannini.testesantander.commons.form.validators.UsernameValidator +import br.com.cauejannini.testesantander.login.LoginActivity +import br.com.cauejannini.testesantander.login.LoginInteractorInput +import br.com.cauejannini.testesantander.login.LoginRequest +import br.com.cauejannini.testesantander.login.UserAccount +import br.com.cauejannini.testesantander.statements.StatementsActivity +import br.com.cauejannini.testesantander.statements.StatementsInteractorInput +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.Robolectric +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment +import org.robolectric.Shadows +import org.robolectric.annotation.Config + +@Config(sdk = [Build.VERSION_CODES.O_MR1]) +@RunWith(RobolectricTestRunner::class) +class StatementsActivityUnitTest { + + @Test + fun statementsActivity_shouldNot_beNull() { + val activity = Robolectric.setupActivity(StatementsActivity::class.java) + + Assert.assertNotNull(activity) + } + + @Test + fun onCreate_fetchStatements_withCorrectData() { + + val activity = Robolectric.setupActivity(StatementsActivity::class.java) + val outputSpy = StatementsInteractorInputSpy() + activity.output = outputSpy + + val userAccount = UserAccount() + userAccount.userId = 1 + userAccount.name = "Lucio dos Santos Teste" + userAccount.agency = "1234" + userAccount.bankAccount = "567890" + userAccount.balance = 990.34 + + activity.fetchStatements(userAccount) + + // Assert login is called in spy + Assert.assertTrue(outputSpy.fetchStatementsCalled) + + // Assert request passed is not null and correct + Assert.assertEquals(outputSpy.userAccountCopy, userAccount) + } + + private class StatementsInteractorInputSpy: StatementsInteractorInput { + + var fetchStatementsCalled = false + var userAccountCopy: UserAccount? = null + + override fun fetchStatements(userAccount: UserAccount?) { + fetchStatementsCalled = true + userAccountCopy = userAccount + } + } + +} \ No newline at end of file diff --git a/app/src/test/java/br/com/cauejannini/testesantander/StatementsPresenterUnitTest.kt b/app/src/test/java/br/com/cauejannini/testesantander/StatementsPresenterUnitTest.kt new file mode 100644 index 000000000..bec9d3f7a --- /dev/null +++ b/app/src/test/java/br/com/cauejannini/testesantander/StatementsPresenterUnitTest.kt @@ -0,0 +1,139 @@ +package br.com.cauejannini.testesantander + +import android.os.Build +import br.com.cauejannini.testesantander.commons.Utils +import br.com.cauejannini.testesantander.login.* +import br.com.cauejannini.testesantander.statements.* +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import java.lang.ref.WeakReference + +@Config(sdk = [Build.VERSION_CODES.O_MR1]) +@RunWith(RobolectricTestRunner::class) +class StatementsPresenterUnitTest { + + @Test + fun present_correctData_onGetStatementsSuccessfull() { + + val presenter = StatementsPresenter() + val outputSpy = StatementsActivityInputSpy() + presenter.output = WeakReference(outputSpy) + + val responseModel = StatementsResponseModel() + + val list = ArrayList() + list.add(Statement("Crédito", "Transferência TED", "2020-05-30", 120.50)) + list.add(Statement("Débito", "Supermercado", "2020-05-29", 80.0)) + list.add(Statement("Débito", "Padaria", "2020-05-28", 30.90)) + + responseModel.statementList = list + responseModel.error = null + + presenter.presentStatementsResponse(responseModel) + + Assert.assertTrue(outputSpy.displayStatementsCalled) + Assert.assertEquals(outputSpy.statementsListCopy, list) + + Assert.assertFalse(outputSpy.displayStatementsErrorCalled) + Assert.assertNull(outputSpy.statementsErrorMessageCopy) + + } + + @Test + fun present_correctData_onGetStatementsResponseError() { + + val presenter = StatementsPresenter() + val outputSpy = StatementsActivityInputSpy() + presenter.output = WeakReference(outputSpy) + + val responseModel = StatementsResponseModel() + responseModel.statementList = null + val errorMessage = "Erro devolvido pelo StatementsResponse" + responseModel.error = errorMessage + + presenter.presentStatementsResponse(responseModel) + + Assert.assertTrue(outputSpy.displayStatementsErrorCalled) + Assert.assertEquals(outputSpy.statementsErrorMessageCopy, errorMessage) + + Assert.assertFalse(outputSpy.displayStatementsCalled) + Assert.assertNull(outputSpy.statementsListCopy) + + } + + @Test + fun present_correctData_onGetStatementsError() { + + val presenter = StatementsPresenter() + val outputSpy = StatementsActivityInputSpy() + presenter.output = WeakReference(outputSpy) + + val errorMessage = "Erro de integração" + + presenter.presentStatementsFailed(errorMessage) + + Assert.assertTrue(outputSpy.displayStatementsErrorCalled) + Assert.assertEquals(outputSpy.statementsErrorMessageCopy, errorMessage) + + Assert.assertFalse(outputSpy.displayStatementsCalled) + Assert.assertNull(outputSpy.statementsListCopy) + + } + + @Test + fun present_userData_withCorrectData() { + + val presenter = StatementsPresenter() + val outputSpy = StatementsActivityInputSpy() + presenter.output = WeakReference(outputSpy) + + val userAccount = UserAccount() + userAccount.name = "João da Silva" + userAccount.balance = 120.3 + userAccount.bankAccount = "1234" + userAccount.agency = "567890" + userAccount.userId = 1 + + presenter.presentUserAccount(userAccount) + + Assert.assertTrue(outputSpy.displayUserDataCalled) + Assert.assertEquals(outputSpy.userDataModelCopy.userName, userAccount.name) + Assert.assertEquals(outputSpy.userDataModelCopy.saldo, Utils.currencyBrazil(userAccount.balance)) + + val conta = userAccount.bankAccount + val agencia = userAccount.agency + Assert.assertEquals(outputSpy.userDataModelCopy.agenciaConta, "$conta / $agencia") + + } + + private class StatementsActivityInputSpy: StatementsActivityInput { + + var displayStatementsCalled = false + var displayStatementsErrorCalled = false + var displayUserDataCalled = false + + var statementsListCopy: List? = null + var statementsErrorMessageCopy: String? = null + lateinit var userDataModelCopy: UserDataModel + + override fun displayStatements(statements: List) { + displayStatementsCalled = true + statementsListCopy = statements + } + + override fun displayStatementsError(message: String) { + displayStatementsErrorCalled = true + statementsErrorMessageCopy = message + } + + override fun displayUserData(userDataModel: UserDataModel) { + displayUserDataCalled = true + userDataModelCopy = userDataModel + } + + } + +} \ No newline at end of file diff --git a/bank_app.sketch b/bank_app.sketch deleted file mode 100644 index d4ed8cafc..000000000 Binary files a/bank_app.sketch and /dev/null differ diff --git a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/3817562E-CBB6-4CAD-BBCF-FD468BAA446F@0.5x.png b/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/3817562E-CBB6-4CAD-BBCF-FD468BAA446F@0.5x.png deleted file mode 100644 index 53a1cdeb7..000000000 Binary files a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/3817562E-CBB6-4CAD-BBCF-FD468BAA446F@0.5x.png and /dev/null differ diff --git a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/3817562E-CBB6-4CAD-BBCF-FD468BAA446F@1x.png b/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/3817562E-CBB6-4CAD-BBCF-FD468BAA446F@1x.png deleted file mode 100644 index fb33afda6..000000000 Binary files a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/3817562E-CBB6-4CAD-BBCF-FD468BAA446F@1x.png and /dev/null differ diff --git a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/3817562E-CBB6-4CAD-BBCF-FD468BAA446F@2x.png b/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/3817562E-CBB6-4CAD-BBCF-FD468BAA446F@2x.png deleted file mode 100644 index 5f7313021..000000000 Binary files a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/3817562E-CBB6-4CAD-BBCF-FD468BAA446F@2x.png and /dev/null differ diff --git a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/3817562E-CBB6-4CAD-BBCF-FD468BAA446F@3x.png b/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/3817562E-CBB6-4CAD-BBCF-FD468BAA446F@3x.png deleted file mode 100644 index 1eda7465e..000000000 Binary files a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/3817562E-CBB6-4CAD-BBCF-FD468BAA446F@3x.png and /dev/null differ diff --git a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/B27D4452-A3F9-4F53-991A-9E914520B88A@0.5x.png b/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/B27D4452-A3F9-4F53-991A-9E914520B88A@0.5x.png deleted file mode 100644 index b79e2ecfb..000000000 Binary files a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/B27D4452-A3F9-4F53-991A-9E914520B88A@0.5x.png and /dev/null differ diff --git a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/B27D4452-A3F9-4F53-991A-9E914520B88A@1x.png b/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/B27D4452-A3F9-4F53-991A-9E914520B88A@1x.png deleted file mode 100644 index b961132ed..000000000 Binary files a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/B27D4452-A3F9-4F53-991A-9E914520B88A@1x.png and /dev/null differ diff --git a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/B27D4452-A3F9-4F53-991A-9E914520B88A@2x.png b/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/B27D4452-A3F9-4F53-991A-9E914520B88A@2x.png deleted file mode 100644 index a9483ea0f..000000000 Binary files a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/B27D4452-A3F9-4F53-991A-9E914520B88A@2x.png and /dev/null differ diff --git a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/B27D4452-A3F9-4F53-991A-9E914520B88A@3x.png b/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/B27D4452-A3F9-4F53-991A-9E914520B88A@3x.png deleted file mode 100644 index af2a6f7bb..000000000 Binary files a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/B27D4452-A3F9-4F53-991A-9E914520B88A@3x.png and /dev/null differ diff --git a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/CA2B476F-0F1E-42F9-B119-2A2B3380A4D4@0.5x.png b/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/CA2B476F-0F1E-42F9-B119-2A2B3380A4D4@0.5x.png deleted file mode 100644 index 08ae82bd9..000000000 Binary files a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/CA2B476F-0F1E-42F9-B119-2A2B3380A4D4@0.5x.png and /dev/null differ diff --git a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/CA2B476F-0F1E-42F9-B119-2A2B3380A4D4@1x.png b/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/CA2B476F-0F1E-42F9-B119-2A2B3380A4D4@1x.png deleted file mode 100644 index 66948cabd..000000000 Binary files a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/CA2B476F-0F1E-42F9-B119-2A2B3380A4D4@1x.png and /dev/null differ diff --git a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/CA2B476F-0F1E-42F9-B119-2A2B3380A4D4@2x.png b/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/CA2B476F-0F1E-42F9-B119-2A2B3380A4D4@2x.png deleted file mode 100644 index 0d20e8026..000000000 Binary files a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/CA2B476F-0F1E-42F9-B119-2A2B3380A4D4@2x.png and /dev/null differ diff --git a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/CA2B476F-0F1E-42F9-B119-2A2B3380A4D4@3x.png b/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/CA2B476F-0F1E-42F9-B119-2A2B3380A4D4@3x.png deleted file mode 100644 index 8d42293ac..000000000 Binary files a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/CA2B476F-0F1E-42F9-B119-2A2B3380A4D4@3x.png and /dev/null differ diff --git a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/artboard.png b/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/artboard.png deleted file mode 100644 index 20c1aa4bb..000000000 Binary files a/bank_app_layout/83F6DA3D-9F1B-4816-92B9-A74AAED40206/artboard.png and /dev/null differ diff --git a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/39D04EF6-4A67-4ED6-A6AC-624922CFD8A1@0.5x.png b/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/39D04EF6-4A67-4ED6-A6AC-624922CFD8A1@0.5x.png deleted file mode 100644 index fed7233bc..000000000 Binary files a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/39D04EF6-4A67-4ED6-A6AC-624922CFD8A1@0.5x.png and /dev/null differ diff --git a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/39D04EF6-4A67-4ED6-A6AC-624922CFD8A1@1x.png b/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/39D04EF6-4A67-4ED6-A6AC-624922CFD8A1@1x.png deleted file mode 100644 index 5899f020f..000000000 Binary files a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/39D04EF6-4A67-4ED6-A6AC-624922CFD8A1@1x.png and /dev/null differ diff --git a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/39D04EF6-4A67-4ED6-A6AC-624922CFD8A1@2x.png b/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/39D04EF6-4A67-4ED6-A6AC-624922CFD8A1@2x.png deleted file mode 100644 index 2315098f8..000000000 Binary files a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/39D04EF6-4A67-4ED6-A6AC-624922CFD8A1@2x.png and /dev/null differ diff --git a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/39D04EF6-4A67-4ED6-A6AC-624922CFD8A1@3x.png b/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/39D04EF6-4A67-4ED6-A6AC-624922CFD8A1@3x.png deleted file mode 100644 index e47f46018..000000000 Binary files a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/39D04EF6-4A67-4ED6-A6AC-624922CFD8A1@3x.png and /dev/null differ diff --git a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/4F2CC5EF-170E-45CA-94D1-9BCD2FA4A805@0.5x.png b/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/4F2CC5EF-170E-45CA-94D1-9BCD2FA4A805@0.5x.png deleted file mode 100644 index 242c3fdaf..000000000 Binary files a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/4F2CC5EF-170E-45CA-94D1-9BCD2FA4A805@0.5x.png and /dev/null differ diff --git a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/4F2CC5EF-170E-45CA-94D1-9BCD2FA4A805@1x.png b/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/4F2CC5EF-170E-45CA-94D1-9BCD2FA4A805@1x.png deleted file mode 100644 index 23ff4626f..000000000 Binary files a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/4F2CC5EF-170E-45CA-94D1-9BCD2FA4A805@1x.png and /dev/null differ diff --git a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/4F2CC5EF-170E-45CA-94D1-9BCD2FA4A805@2x.png b/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/4F2CC5EF-170E-45CA-94D1-9BCD2FA4A805@2x.png deleted file mode 100644 index 35d07a14f..000000000 Binary files a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/4F2CC5EF-170E-45CA-94D1-9BCD2FA4A805@2x.png and /dev/null differ diff --git a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/4F2CC5EF-170E-45CA-94D1-9BCD2FA4A805@3x.png b/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/4F2CC5EF-170E-45CA-94D1-9BCD2FA4A805@3x.png deleted file mode 100644 index 97b68a58f..000000000 Binary files a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/4F2CC5EF-170E-45CA-94D1-9BCD2FA4A805@3x.png and /dev/null differ diff --git a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/68A7CB4F-8C7B-480B-B544-271AB428EE8A@0.5x.png b/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/68A7CB4F-8C7B-480B-B544-271AB428EE8A@0.5x.png deleted file mode 100644 index 117de969e..000000000 Binary files a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/68A7CB4F-8C7B-480B-B544-271AB428EE8A@0.5x.png and /dev/null differ diff --git a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/68A7CB4F-8C7B-480B-B544-271AB428EE8A@1x.png b/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/68A7CB4F-8C7B-480B-B544-271AB428EE8A@1x.png deleted file mode 100644 index 5ff77a675..000000000 Binary files a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/68A7CB4F-8C7B-480B-B544-271AB428EE8A@1x.png and /dev/null differ diff --git a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/68A7CB4F-8C7B-480B-B544-271AB428EE8A@2x.png b/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/68A7CB4F-8C7B-480B-B544-271AB428EE8A@2x.png deleted file mode 100644 index 73b2edbac..000000000 Binary files a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/68A7CB4F-8C7B-480B-B544-271AB428EE8A@2x.png and /dev/null differ diff --git a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/68A7CB4F-8C7B-480B-B544-271AB428EE8A@3x.png b/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/68A7CB4F-8C7B-480B-B544-271AB428EE8A@3x.png deleted file mode 100644 index beba6c0cf..000000000 Binary files a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/68A7CB4F-8C7B-480B-B544-271AB428EE8A@3x.png and /dev/null differ diff --git a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/artboard.png b/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/artboard.png deleted file mode 100644 index 9befa0cc5..000000000 Binary files a/bank_app_layout/CCA3949D-B416-466A-8949-425E5DCD35B5/artboard.png and /dev/null differ diff --git a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/05376719-28C6-4537-A0B4-097E3C72AB41@0.5x.png b/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/05376719-28C6-4537-A0B4-097E3C72AB41@0.5x.png deleted file mode 100644 index 10ad360f4..000000000 Binary files a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/05376719-28C6-4537-A0B4-097E3C72AB41@0.5x.png and /dev/null differ diff --git a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/05376719-28C6-4537-A0B4-097E3C72AB41@1x.png b/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/05376719-28C6-4537-A0B4-097E3C72AB41@1x.png deleted file mode 100644 index 5fbb12417..000000000 Binary files a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/05376719-28C6-4537-A0B4-097E3C72AB41@1x.png and /dev/null differ diff --git a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/05376719-28C6-4537-A0B4-097E3C72AB41@2x.png b/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/05376719-28C6-4537-A0B4-097E3C72AB41@2x.png deleted file mode 100644 index fde4b9b75..000000000 Binary files a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/05376719-28C6-4537-A0B4-097E3C72AB41@2x.png and /dev/null differ diff --git a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/05376719-28C6-4537-A0B4-097E3C72AB41@3x.png b/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/05376719-28C6-4537-A0B4-097E3C72AB41@3x.png deleted file mode 100644 index af0e0ac72..000000000 Binary files a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/05376719-28C6-4537-A0B4-097E3C72AB41@3x.png and /dev/null differ diff --git a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/372B9348-D602-4A3B-8E91-A66250670461@0.5x.png b/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/372B9348-D602-4A3B-8E91-A66250670461@0.5x.png deleted file mode 100644 index ec991238a..000000000 Binary files a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/372B9348-D602-4A3B-8E91-A66250670461@0.5x.png and /dev/null differ diff --git a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/372B9348-D602-4A3B-8E91-A66250670461@1x.png b/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/372B9348-D602-4A3B-8E91-A66250670461@1x.png deleted file mode 100644 index 7307b9e13..000000000 Binary files a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/372B9348-D602-4A3B-8E91-A66250670461@1x.png and /dev/null differ diff --git a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/372B9348-D602-4A3B-8E91-A66250670461@2x.png b/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/372B9348-D602-4A3B-8E91-A66250670461@2x.png deleted file mode 100644 index 1178f890d..000000000 Binary files a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/372B9348-D602-4A3B-8E91-A66250670461@2x.png and /dev/null differ diff --git a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/372B9348-D602-4A3B-8E91-A66250670461@3x.png b/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/372B9348-D602-4A3B-8E91-A66250670461@3x.png deleted file mode 100644 index f0d400bea..000000000 Binary files a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/372B9348-D602-4A3B-8E91-A66250670461@3x.png and /dev/null differ diff --git a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/D78AA366-D361-4FA8-AACE-0B91A0581654@0.5x.png b/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/D78AA366-D361-4FA8-AACE-0B91A0581654@0.5x.png deleted file mode 100644 index 5066a058b..000000000 Binary files a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/D78AA366-D361-4FA8-AACE-0B91A0581654@0.5x.png and /dev/null differ diff --git a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/D78AA366-D361-4FA8-AACE-0B91A0581654@1x.png b/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/D78AA366-D361-4FA8-AACE-0B91A0581654@1x.png deleted file mode 100644 index 831e7bb47..000000000 Binary files a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/D78AA366-D361-4FA8-AACE-0B91A0581654@1x.png and /dev/null differ diff --git a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/D78AA366-D361-4FA8-AACE-0B91A0581654@2x.png b/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/D78AA366-D361-4FA8-AACE-0B91A0581654@2x.png deleted file mode 100644 index d857b805a..000000000 Binary files a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/D78AA366-D361-4FA8-AACE-0B91A0581654@2x.png and /dev/null differ diff --git a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/D78AA366-D361-4FA8-AACE-0B91A0581654@3x.png b/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/D78AA366-D361-4FA8-AACE-0B91A0581654@3x.png deleted file mode 100644 index d91b98e6d..000000000 Binary files a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/D78AA366-D361-4FA8-AACE-0B91A0581654@3x.png and /dev/null differ diff --git a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/artboard.png b/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/artboard.png deleted file mode 100644 index 2acdd074b..000000000 Binary files a/bank_app_layout/D66AAA24-D61F-44D2-8D53-8B219D009DBF/artboard.png and /dev/null differ diff --git a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/CDEBC6CD-73C4-47CB-B879-8A426D8163E1@0.5x.png b/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/CDEBC6CD-73C4-47CB-B879-8A426D8163E1@0.5x.png deleted file mode 100644 index 535dafe15..000000000 Binary files a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/CDEBC6CD-73C4-47CB-B879-8A426D8163E1@0.5x.png and /dev/null differ diff --git a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/CDEBC6CD-73C4-47CB-B879-8A426D8163E1@1x.png b/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/CDEBC6CD-73C4-47CB-B879-8A426D8163E1@1x.png deleted file mode 100644 index 466ef1c09..000000000 Binary files a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/CDEBC6CD-73C4-47CB-B879-8A426D8163E1@1x.png and /dev/null differ diff --git a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/CDEBC6CD-73C4-47CB-B879-8A426D8163E1@2x.png b/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/CDEBC6CD-73C4-47CB-B879-8A426D8163E1@2x.png deleted file mode 100644 index cb118e91b..000000000 Binary files a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/CDEBC6CD-73C4-47CB-B879-8A426D8163E1@2x.png and /dev/null differ diff --git a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/CDEBC6CD-73C4-47CB-B879-8A426D8163E1@3x.png b/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/CDEBC6CD-73C4-47CB-B879-8A426D8163E1@3x.png deleted file mode 100644 index a650b8199..000000000 Binary files a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/CDEBC6CD-73C4-47CB-B879-8A426D8163E1@3x.png and /dev/null differ diff --git a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/E3013759-B45A-4E98-8B34-278A50F98591@0.5x.png b/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/E3013759-B45A-4E98-8B34-278A50F98591@0.5x.png deleted file mode 100644 index de8e4b18f..000000000 Binary files a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/E3013759-B45A-4E98-8B34-278A50F98591@0.5x.png and /dev/null differ diff --git a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/E3013759-B45A-4E98-8B34-278A50F98591@1x.png b/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/E3013759-B45A-4E98-8B34-278A50F98591@1x.png deleted file mode 100644 index d720a4f0d..000000000 Binary files a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/E3013759-B45A-4E98-8B34-278A50F98591@1x.png and /dev/null differ diff --git a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/E3013759-B45A-4E98-8B34-278A50F98591@2x.png b/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/E3013759-B45A-4E98-8B34-278A50F98591@2x.png deleted file mode 100644 index 9f57e7902..000000000 Binary files a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/E3013759-B45A-4E98-8B34-278A50F98591@2x.png and /dev/null differ diff --git a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/E3013759-B45A-4E98-8B34-278A50F98591@3x.png b/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/E3013759-B45A-4E98-8B34-278A50F98591@3x.png deleted file mode 100644 index fee69c198..000000000 Binary files a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/E3013759-B45A-4E98-8B34-278A50F98591@3x.png and /dev/null differ diff --git a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/artboard.png b/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/artboard.png deleted file mode 100644 index c620ef44d..000000000 Binary files a/bank_app_layout/E822A087-B20C-42DD-8665-FE03A4AA8211/artboard.png and /dev/null differ diff --git a/bank_app_layout/data.js b/bank_app_layout/data.js deleted file mode 100644 index a692702f5..000000000 --- a/bank_app_layout/data.js +++ /dev/null @@ -1 +0,0 @@ -var pageData = {"exportEveryLayer":1,"sketchName":"","language":"en","I18N":{"UNIT":"Unit","SIZE":"Size","SHOWSLICE":"Show slices","DRAGTOSAVE":"Drag to desktop to save.","WIDTH":"Width","HEIGHT":"Height","BORDER":"Border","COLOR":"Color","FILLCOLOR":"Fill","RADIUS":"Radius","LAYERTEXT":"Content","FONTSIZE":"Font Size","CODE":"Code","EXPORT":"Export","FORMAT":"Format","EXPORTLAYER":"Export Activity Layer","COPYSUCCESS":"Copy Success","TEXTSHAREDSTYLE":"Text Styles","SHAPESHAREDSTYLE":"Layer Styles"},"pageOrder":["E1DD8600-6E88-4482-9447-55D03DD87354","6774A219-5AFB-46B1-8AD2-8BE278B93378"],"pageData":{"E1DD8600-6E88-4482-9447-55D03DD87354":{"pageId":"E1DD8600-6E88-4482-9447-55D03DD87354","name":"Symbols","artboardId":["D66AAA24-D61F-44D2-8D53-8B219D009DBF","CCA3949D-B416-466A-8949-425E5DCD35B5"]},"6774A219-5AFB-46B1-8AD2-8BE278B93378":{"pageId":"6774A219-5AFB-46B1-8AD2-8BE278B93378","name":"Page%201","artboardId":["E822A087-B20C-42DD-8665-FE03A4AA8211","83F6DA3D-9F1B-4816-92B9-A74AAED40206"]}},"artboard":{"D66AAA24-D61F-44D2-8D53-8B219D009DBF":{"id":"D66AAA24-D61F-44D2-8D53-8B219D009DBF","src":"D66AAA24-D61F-44D2-8D53-8B219D009DBF","name":"Status%20Bar%2FBlack%2F100%25","type":"MSSymbolMaster","x":100,"y":0,"zIndex":0,"width":375,"height":20,"sharedStyleType":"","sharedStyle":"","symbolId":"8F28FC9A-816F-4541-8734-BC8EF14D685F","slice":[],"layer":[{"id":"372B9348-D602-4A3B-8E91-A66250670461","src":"372B9348-D602-4A3B-8E91-A66250670461","name":"Battery","type":"MSShapeGroup","x":445,"y":6,"zIndex":1,"width":25,"height":10,"sharedStyleType":"","sharedStyle":"","style":{"background":"#030303","border-radius":"1.5px","width":"25px","height":"10px"},"radius":"1.5","background":"#030303"},{"id":"6CE93654-D8D2-4BD3-85AF-C2D9A33E8979","src":"6CE93654-D8D2-4BD3-85AF-C2D9A33E8979","name":"100%25","type":"MSTextLayer","x":409,"y":4,"zIndex":2,"width":33,"height":14,"sharedStyleType":"","sharedStyle":"","html":"100%25","style":{"font-family":"Helvetica","font-size":"12px","color":"#030303","letter-spacing":"0","text-align":"right"}},{"id":"5DE5A561-10FF-40B7-864C-B93F09A30B82","src":"5DE5A561-10FF-40B7-864C-B93F09A30B82","name":"9%3A41%20AM","type":"MSTextLayer","x":263,"y":4,"zIndex":3,"width":49,"height":14,"sharedStyleType":"","sharedStyle":"","html":"9%3A41%20AM","style":{"font-family":"Helvetica","font-size":"12px","color":"#030303","letter-spacing":"0","text-align":"center"}},{"id":"05376719-28C6-4537-A0B4-097E3C72AB41","src":"05376719-28C6-4537-A0B4-097E3C72AB41","name":"Wi-Fi","type":"MSShapeGroup","x":188,"y":6,"zIndex":4,"width":13,"height":10,"sharedStyleType":"","sharedStyle":"","style":{"background":"#030303","width":"13px","height":"10px"},"background":"#030303"},{"id":"5B618E12-BBE6-411D-85B1-8668F4646AC1","src":"5B618E12-BBE6-411D-85B1-8668F4646AC1","name":"Carrier","type":"MSTextLayer","x":144,"y":4,"zIndex":5,"width":40,"height":14,"sharedStyleType":"","sharedStyle":"","html":"Sketch","style":{"font-family":"Helvetica","font-size":"12px","color":"#030303","letter-spacing":"0","text-align":"left"}},{"id":"D78AA366-D361-4FA8-AACE-0B91A0581654","src":"D78AA366-D361-4FA8-AACE-0B91A0581654","name":"Mobile%20Signal","type":"MSShapeGroup","x":107,"y":8,"zIndex":6,"width":34,"height":6,"sharedStyleType":"","sharedStyle":"","style":{"background":"#030303","width":"34px","height":"6px"},"background":"#030303"}],"mask":{}},"CCA3949D-B416-466A-8949-425E5DCD35B5":{"id":"CCA3949D-B416-466A-8949-425E5DCD35B5","src":"CCA3949D-B416-466A-8949-425E5DCD35B5","name":"Status%20Bar%2FWhite%2F100%25","type":"MSSymbolMaster","x":100,"y":120,"zIndex":0,"width":375,"height":20,"sharedStyleType":"","sharedStyle":"","symbolId":"FC386540-E94F-407E-88AC-44E4621D13CF","slice":[],"layer":[{"id":"68A7CB4F-8C7B-480B-B544-271AB428EE8A","src":"68A7CB4F-8C7B-480B-B544-271AB428EE8A","name":"Battery","type":"MSShapeGroup","x":445,"y":126,"zIndex":1,"width":25,"height":10,"sharedStyleType":"","sharedStyle":"","style":{"background":"#ffffff","border-radius":"1.5px","width":"25px","height":"10px"},"radius":"1.5","background":"#ffffff"},{"id":"D4D25776-86EB-4EB6-8037-476B91D3D811","src":"D4D25776-86EB-4EB6-8037-476B91D3D811","name":"100%25","type":"MSTextLayer","x":409,"y":124,"zIndex":2,"width":33,"height":14,"sharedStyleType":"","sharedStyle":"","html":"100%25","style":{"font-family":"Helvetica","font-size":"12px","color":"#ffffff","letter-spacing":"0","text-align":"right"}},{"id":"A14DAE1C-2900-467F-B2EA-41189DAF5B7D","src":"A14DAE1C-2900-467F-B2EA-41189DAF5B7D","name":"9%3A41%20AM","type":"MSTextLayer","x":263,"y":124,"zIndex":3,"width":49,"height":14,"sharedStyleType":"","sharedStyle":"","html":"9%3A41%20AM","style":{"font-family":"Helvetica","font-size":"12px","color":"#ffffff","letter-spacing":"0","text-align":"center"}},{"id":"39D04EF6-4A67-4ED6-A6AC-624922CFD8A1","src":"39D04EF6-4A67-4ED6-A6AC-624922CFD8A1","name":"Wi-Fi","type":"MSShapeGroup","x":188,"y":126,"zIndex":4,"width":13,"height":10,"sharedStyleType":"","sharedStyle":"","style":{"background":"#ffffff","width":"13px","height":"10px"},"background":"#ffffff"},{"id":"FDA2694C-D63C-41E9-A93A-4BF70C3F3364","src":"FDA2694C-D63C-41E9-A93A-4BF70C3F3364","name":"Carrier","type":"MSTextLayer","x":144,"y":124,"zIndex":5,"width":40,"height":14,"sharedStyleType":"","sharedStyle":"","html":"Sketch","style":{"font-family":"Helvetica","font-size":"12px","color":"#ffffff","letter-spacing":"0","text-align":"left"}},{"id":"4F2CC5EF-170E-45CA-94D1-9BCD2FA4A805","src":"4F2CC5EF-170E-45CA-94D1-9BCD2FA4A805","name":"Mobile%20Signal","type":"MSShapeGroup","x":107,"y":128,"zIndex":6,"width":34,"height":6,"sharedStyleType":"","sharedStyle":"","style":{"background":"#ffffff","width":"34px","height":"6px"},"background":"#ffffff"}],"mask":{}},"E822A087-B20C-42DD-8665-FE03A4AA8211":{"id":"E822A087-B20C-42DD-8665-FE03A4AA8211","src":"E822A087-B20C-42DD-8665-FE03A4AA8211","name":"Location","type":"MSArtboardGroup","x":513,"y":55,"zIndex":0,"width":375,"height":667,"sharedStyleType":"","sharedStyle":"","slice":[],"layer":[{"id":"12DBC3B3-F637-40BB-AE47-0B1653A29FFC","src":"12DBC3B3-F637-40BB-AE47-0B1653A29FFC","name":"login","type":"MSTextLayer","x":680,"y":644,"zIndex":0,"width":42,"height":36,"sharedStyleType":"","sharedStyle":"","html":"Login%0A","style":{"font-family":"HelveticaNeue","font-size":"16px","color":"#ffffff","letter-spacing":"0.44px","text-align":"left"}},{"id":"A9F8A6FB-8379-4EF3-A6A9-B93581CF3A25","src":"A9F8A6FB-8379-4EF3-A6A9-B93581CF3A25","name":"Password","type":"MSTextLayer","x":543,"y":370,"zIndex":1,"width":69,"height":23,"sharedStyleType":"","sharedStyle":"","html":"Password","style":{"font-family":"HelveticaNeue","font-size":"15px","color":"#a8b4c4","letter-spacing":"0.29px","text-align":"center","line-height":"23px"}},{"id":"4D1D953A-F49D-42D4-AC1B-051E802681E8","src":"4D1D953A-F49D-42D4-AC1B-051E802681E8","name":"User","type":"MSTextLayer","x":543,"y":298,"zIndex":2,"width":33,"height":23,"sharedStyleType":"","sharedStyle":"","html":"User","style":{"font-family":"HelveticaNeue","font-size":"15px","color":"#a8b4c4","letter-spacing":"0.29px","text-align":"center","line-height":"23px"}},{"id":"CDEBC6CD-73C4-47CB-B879-8A426D8163E1","src":"CDEBC6CD-73C4-47CB-B879-8A426D8163E1","name":"Screen%20Shot%202018-10-18%20at%2022.49.51","type":"MSBitmapLayer","x":639,"y":111,"zIndex":3,"width":125,"height":70,"sharedStyleType":"","sharedStyle":""},{"id":"E3013759-B45A-4E98-8B34-278A50F98591","src":"E3013759-B45A-4E98-8B34-278A50F98591","name":"Status%20Bar%2FBlack%2F100%25","type":"MSSymbolInstance","x":513,"y":55,"zIndex":4,"width":375,"height":20,"sharedStyleType":"","sharedStyle":"","symbolId":"8F28FC9A-816F-4541-8734-BC8EF14D685F"}],"mask":{}},"83F6DA3D-9F1B-4816-92B9-A74AAED40206":{"id":"83F6DA3D-9F1B-4816-92B9-A74AAED40206","src":"83F6DA3D-9F1B-4816-92B9-A74AAED40206","name":"Currency","type":"MSArtboardGroup","x":988,"y":55,"zIndex":0,"width":375,"height":667,"sharedStyleType":"","sharedStyle":"","slice":[],"layer":[{"id":"09BAE240-CC06-46A5-B01E-A15117109EAC","src":"09BAE240-CC06-46A5-B01E-A15117109EAC","name":"Find%20out%20where","type":"MSTextLayer","x":1127,"y":491,"zIndex":0,"width":118,"height":18,"sharedStyleType":"","sharedStyle":"","html":"Find%20out%20where%20","style":{"font-family":"HelveticaNeue","font-size":"16px","color":"#ffffff","letter-spacing":"0.44px","text-align":"left"}},{"id":"2E3D38C9-2ED3-499B-BF39-008733AAE30C","src":"2E3D38C9-2ED3-499B-BF39-008733AAE30C","name":"Market%20rate%3A%201%20USD%20%3D","type":"MSTextLayer","x":1064,"y":420,"zIndex":1,"width":212,"height":17,"sharedStyleType":"","sharedStyle":"","html":"Market%20rate%3A%201%20USD%20%3D%200.8900%20EUR","style":{"font-family":"HelveticaNeue","font-size":"14px","color":"#a8b4c4","text-align":"center"}},{"id":"07B6D69B-B539-432D-A0F1-45428FCF5C13","src":"07B6D69B-B539-432D-A0F1-45428FCF5C13","name":"890%2C10","type":"MSTextLayer","x":1239,"y":351,"zIndex":2,"width":89,"height":33,"sharedStyleType":"","sharedStyle":"","html":"890%2C10","style":{"font-family":"HelveticaNeue-Light","font-size":"28px","color":"#485465","letter-spacing":"0.5px","text-align":"center"}},{"id":"99544A31-44A6-4BAD-B88E-99DDD345E9EA","src":"99544A31-44A6-4BAD-B88E-99DDD345E9EA","name":"1%20EUR%20%3D%201.123%20USD","type":"MSTextLayer","x":1216,"y":331,"zIndex":3,"width":110,"height":14,"sharedStyleType":"","sharedStyle":"","html":"1%20EUR%20%3D%201.123%20USD","style":{"font-family":"HelveticaNeue","font-size":"12px","color":"#a8b4c4","letter-spacing":"0.2px","text-align":"center"}},{"id":"66E60EFF-B648-4673-85F3-323550B705D3","src":"66E60EFF-B648-4673-85F3-323550B705D3","name":"EUR","type":"MSTextLayer","x":1065,"y":356,"zIndex":4,"width":49,"height":29,"sharedStyleType":"","sharedStyle":"","html":"EUR","style":{"font-family":"HelveticaNeue-Light","font-size":"25px","color":"#485465","text-align":"center"}},{"id":"B9A6B04C-614B-4F9E-8BD4-E59A0D050361","src":"B9A6B04C-614B-4F9E-8BD4-E59A0D050361","name":"I%20want","type":"MSTextLayer","x":1024,"y":325,"zIndex":5,"width":44,"height":18,"sharedStyleType":"","sharedStyle":"","html":"I%20want","style":{"font-family":"HelveticaNeue","font-size":"16px","color":"#a8b4c4","text-align":"center"}},{"id":"2B156AE2-C7CC-403A-AD6A-8414CCB60279","src":"2B156AE2-C7CC-403A-AD6A-8414CCB60279","name":"1%20000%2C00","type":"MSTextLayer","x":1214,"y":245,"zIndex":6,"width":113,"height":33,"sharedStyleType":"","sharedStyle":"","html":"1%20000%2C00","style":{"font-family":"HelveticaNeue-Light","font-size":"28px","color":"#485465","letter-spacing":"0.5px","text-align":"center"}},{"id":"246AE036-104B-41CF-B0F4-FCAEDF1CFC25","src":"246AE036-104B-41CF-B0F4-FCAEDF1CFC25","name":"1%20USD%20%3D%200.8900%20EUR","type":"MSTextLayer","x":1209,"y":224,"zIndex":7,"width":117,"height":14,"sharedStyleType":"","sharedStyle":"","html":"1%20USD%20%3D%200.8900%20EUR","style":{"font-family":"HelveticaNeue","font-size":"12px","color":"#a8b4c4","letter-spacing":"0.2px","text-align":"center"}},{"id":"3817562E-CBB6-4CAD-BBCF-FD468BAA446F","src":"3817562E-CBB6-4CAD-BBCF-FD468BAA446F","name":"Shape","type":"MSShapeGroup","x":1025,"y":247,"zIndex":8,"width":15,"height":15,"sharedStyleType":"","sharedStyle":"","style":{"background":"#0052b4","width":"15px","height":"15px"},"background":"#0052b4"},{"id":"D8815B79-8031-4DBF-AC66-0A035AD9905D","src":"D8815B79-8031-4DBF-AC66-0A035AD9905D","name":"USD","type":"MSTextLayer","x":1065,"y":248,"zIndex":9,"width":50,"height":29,"sharedStyleType":"","sharedStyle":"","html":"USD","style":{"font-family":"HelveticaNeue-Light","font-size":"25px","color":"#485465","text-align":"center"}},{"id":"4D7068B6-0C46-4E07-A300-CF23125F168C","src":"4D7068B6-0C46-4E07-A300-CF23125F168C","name":"I%20have","type":"MSTextLayer","x":1024,"y":218,"zIndex":10,"width":43,"height":18,"sharedStyleType":"","sharedStyle":"","html":"I%20have","style":{"font-family":"HelveticaNeue","font-size":"16px","color":"#a8b4c4","text-align":"center"}},{"id":"B27D4452-A3F9-4F53-991A-9E914520B88A","src":"B27D4452-A3F9-4F53-991A-9E914520B88A","name":"Shape","type":"MSShapeGroup","x":1016,"y":142,"zIndex":11,"width":11,"height":16,"sharedStyleType":"","sharedStyle":"","style":{"background":"#485465","width":"11px","height":"16px"},"background":"#485465"},{"id":"904C402D-FC98-45E0-9270-068D9717010D","src":"904C402D-FC98-45E0-9270-068D9717010D","name":"Paris%2C%20France","type":"MSTextLayer","x":1042,"y":143,"zIndex":12,"width":100,"height":20,"sharedStyleType":"","sharedStyle":"","html":"Paris%2C%20France","style":{"font-family":"HelveticaNeue","font-size":"17px","color":"#485465","text-align":"center"}},{"id":"4EE21DE4-3DDC-4464-B264-4223F0236C08","src":"4EE21DE4-3DDC-4464-B264-4223F0236C08","name":"Looking%20for%20the%20best","type":"MSTextLayer","x":1012,"y":168,"zIndex":13,"width":284,"height":16,"sharedStyleType":"","sharedStyle":"","html":"Looking%20for%20the%20best%20exchange%20rates%20in%20Paris%3F","style":{"font-family":"HelveticaNeue","font-size":"14px","color":"#a8b4c4","text-align":"center"}},{"id":"45B169DE-B3B5-4D12-B1B3-25F826B339CB","src":"45B169DE-B3B5-4D12-B1B3-25F826B339CB","name":"Currency","type":"MSTextLayer","x":1142,"y":87,"zIndex":14,"width":67,"height":20,"sharedStyleType":"","sharedStyle":"","html":"Currency","style":{"font-family":".SFNSText","font-size":"17px","color":"#ffffff","letter-spacing":"-0.41px","text-align":"center"}},{"id":"CA2B476F-0F1E-42F9-B119-2A2B3380A4D4","src":"CA2B476F-0F1E-42F9-B119-2A2B3380A4D4","name":"Status%20Bar%2FWhite%2F100%25","type":"MSSymbolInstance","x":988,"y":55,"zIndex":15,"width":375,"height":20,"sharedStyleType":"","sharedStyle":"","symbolId":"FC386540-E94F-407E-88AC-44E4621D13CF"}],"mask":{}}}} \ No newline at end of file diff --git a/bank_app_layout/index.html b/bank_app_layout/index.html deleted file mode 100644 index 28125fac2..000000000 --- a/bank_app_layout/index.html +++ /dev/null @@ -1,1569 +0,0 @@ - - - - - - - Spec Export - Sketch Measure 2.4 - - - - - - - diff --git a/bank_app_layout/links/page-1-currency.html b/bank_app_layout/links/page-1-currency.html deleted file mode 100644 index 5652fa211..000000000 --- a/bank_app_layout/links/page-1-currency.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/bank_app_layout/links/page-1-location.html b/bank_app_layout/links/page-1-location.html deleted file mode 100644 index 5ca1854a1..000000000 --- a/bank_app_layout/links/page-1-location.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/bank_app_layout/preview/page-1-currency.png b/bank_app_layout/preview/page-1-currency.png deleted file mode 100644 index d0c171355..000000000 Binary files a/bank_app_layout/preview/page-1-currency.png and /dev/null differ diff --git a/bank_app_layout/preview/page-1-location.png b/bank_app_layout/preview/page-1-location.png deleted file mode 100644 index c620ef44d..000000000 Binary files a/bank_app_layout/preview/page-1-location.png and /dev/null differ diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..71b78e029 --- /dev/null +++ b/build.gradle @@ -0,0 +1,26 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + ext.kotlin_version = "1.3.72" + repositories { + google() + jcenter() + } + dependencies { + classpath "com.android.tools.build:gradle:4.0.0" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + + // 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..4d15d015f --- /dev/null +++ b/gradle.properties @@ -0,0 +1,21 @@ +# 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 +# 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 +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official \ 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..7b2de5d33 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sat Jun 06 19:49:37 BRT 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/gradlew b/gradlew new file mode 100755 index 000000000..cccdd3d51 --- /dev/null +++ b/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/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..e95643d6a --- /dev/null +++ b/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/settings.gradle b/settings.gradle new file mode 100644 index 000000000..f80fb383f --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +include ':app' +rootProject.name = "Teste Santander" \ No newline at end of file diff --git a/telas.png b/telas.png deleted file mode 100644 index 783374440..000000000 Binary files a/telas.png and /dev/null differ