diff --git a/Safrando/.gitignore b/Safrando/.gitignore new file mode 100644 index 000000000..aa724b770 --- /dev/null +++ b/Safrando/.gitignore @@ -0,0 +1,15 @@ +*.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 +local.properties diff --git a/Safrando/.idea/.gitignore b/Safrando/.idea/.gitignore new file mode 100644 index 000000000..26d33521a --- /dev/null +++ b/Safrando/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/Safrando/.idea/compiler.xml b/Safrando/.idea/compiler.xml new file mode 100644 index 000000000..b589d56e9 --- /dev/null +++ b/Safrando/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Safrando/.idea/gradle.xml b/Safrando/.idea/gradle.xml new file mode 100644 index 000000000..a2d7c2133 --- /dev/null +++ b/Safrando/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/Safrando/.idea/kotlinc.xml b/Safrando/.idea/kotlinc.xml new file mode 100644 index 000000000..69e86158b --- /dev/null +++ b/Safrando/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Safrando/.idea/misc.xml b/Safrando/.idea/misc.xml new file mode 100644 index 000000000..773fe0fbd --- /dev/null +++ b/Safrando/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/Safrando/.idea/vcs.xml b/Safrando/.idea/vcs.xml new file mode 100644 index 000000000..6c0b86358 --- /dev/null +++ b/Safrando/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Safrando/app/.gitignore b/Safrando/app/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/Safrando/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/Safrando/app/build.gradle b/Safrando/app/build.gradle new file mode 100644 index 000000000..c9fdb5808 --- /dev/null +++ b/Safrando/app/build.gradle @@ -0,0 +1,94 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' + id 'kotlin-kapt' + id 'kotlin-parcelize' + id 'com.google.dagger.hilt.android' +} + +android { + namespace 'com.nandoligeiro.safrando' + compileSdk 33 + + defaultConfig { + applicationId "com.nandoligeiro.safrando" + minSdk 19 + targetSdk 33 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = '17' + } + + buildFeatures { + viewBinding = true + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.10.1' + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.9.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation "androidx.activity:activity-ktx:1.7.2" + + def navigate_version = "2.6.0" + implementation "androidx.navigation:navigation-fragment-ktx:$navigate_version" + implementation "androidx.navigation:navigation-ui-ktx:$navigate_version" + + + def lifecycle_version = "2.6.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" + implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" + + def coroutines_version = "1.6.4" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:$coroutines_version" + testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" + + //DataStore + implementation "androidx.datastore:datastore-preferences:1.0.0" + + def retrofit_version = "2.9.0" + implementation "com.squareup.retrofit2:retrofit:$retrofit_version" + implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit_version" + implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" + + def okhttp_version = "5.0.0-alpha.3" + implementation "com.squareup.okhttp3:okhttp:$okhttp_version" + implementation "com.squareup.okhttp3:mockwebserver:$okhttp_version" + //HTTP LOG + implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version" + + // Hilt DI + def hilt_version = "2.44.2" + implementation "com.google.dagger:hilt-android:$hilt_version" + kapt "com.google.dagger:hilt-compiler:$hilt_version" + + def mockk_version = "1.13.5" + testImplementation "io.mockk:mockk:$mockk_version" + testImplementation "io.mockk:mockk-android:$mockk_version" + testImplementation "io.mockk:mockk-agent:$mockk_version" + + testImplementation 'junit:junit:4.13.2' + testImplementation 'androidx.arch.core:core-testing:2.2.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' +} diff --git a/Safrando/app/proguard-rules.pro b/Safrando/app/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/Safrando/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/Safrando/app/src/androidTest/java/com/nandoligeiro/safrando/ExampleInstrumentedTest.kt b/Safrando/app/src/androidTest/java/com/nandoligeiro/safrando/ExampleInstrumentedTest.kt new file mode 100644 index 000000000..bd1fb9f29 --- /dev/null +++ b/Safrando/app/src/androidTest/java/com/nandoligeiro/safrando/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.nandoligeiro.safrando + +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("com.nandoligeiro.safrando", appContext.packageName) + } +} \ No newline at end of file diff --git a/Safrando/app/src/main/AndroidManifest.xml b/Safrando/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..527d2e7b3 --- /dev/null +++ b/Safrando/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/SafrandoApp.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/SafrandoApp.kt new file mode 100644 index 000000000..bc9d83a0b --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/SafrandoApp.kt @@ -0,0 +1,7 @@ +package com.nandoligeiro.safrando + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + +@HiltAndroidApp +class SafrandoApp: Application() \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/api/SafrandoService.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/api/SafrandoService.kt new file mode 100755 index 000000000..a8c6d90eb --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/api/SafrandoService.kt @@ -0,0 +1,19 @@ +package com.nandoligeiro.safrando.data.api + +import com.nandoligeiro.safrando.datasource.bankstatement.entity.BankStatementEntity +import com.nandoligeiro.safrando.datasource.login.entity.LoginEntity +import okhttp3.ResponseBody +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Path + +interface SafrandoService { + + @POST("login") + suspend fun postLogin(@Body user: String, @Body password: String): LoginEntity + + @GET("statements/{id}") + suspend fun getBankStatements(@Path("id") userId: Int): List +} \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/bankstatement/datasource/BankStatementDataSource.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/bankstatement/datasource/BankStatementDataSource.kt new file mode 100644 index 000000000..2f3d43731 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/bankstatement/datasource/BankStatementDataSource.kt @@ -0,0 +1,7 @@ +package com.nandoligeiro.safrando.data.bankstatement.datasource + +import com.nandoligeiro.safrando.data.bankstatement.model.BankStatementData + +interface BankStatementDataSource { + suspend fun getBankStatement(userId: Int): List +} \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/bankstatement/mapper/BankStatementDataToDomainMapper.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/bankstatement/mapper/BankStatementDataToDomainMapper.kt new file mode 100644 index 000000000..0728d5ada --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/bankstatement/mapper/BankStatementDataToDomainMapper.kt @@ -0,0 +1,17 @@ +package com.nandoligeiro.safrando.data.bankstatement.mapper + +import com.nandoligeiro.safrando.data.bankstatement.model.BankStatementData +import com.nandoligeiro.safrando.domain.statements.model.BankStatementDomain + +class BankStatementDataToDomainMapper { + + fun toDomainBankStatement(statements: List) = + statements.map { statement -> + BankStatementDomain( + nameStatement = statement.nameStatement, + description = statement.description, + amount = statement.amount, + statementDate = statement.statementDate + ) + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/bankstatement/model/BankStatementData.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/bankstatement/model/BankStatementData.kt new file mode 100644 index 000000000..0cf09ce6e --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/bankstatement/model/BankStatementData.kt @@ -0,0 +1,8 @@ +package com.nandoligeiro.safrando.data.bankstatement.model + +data class BankStatementData( + val nameStatement: String, + val description: String, + val amount: String, + val statementDate: String +) diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/bankstatement/repository/BankStatementRepositoryImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/bankstatement/repository/BankStatementRepositoryImpl.kt new file mode 100644 index 000000000..3972fbd92 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/bankstatement/repository/BankStatementRepositoryImpl.kt @@ -0,0 +1,16 @@ +package com.nandoligeiro.safrando.data.bankstatement.repository + +import com.nandoligeiro.safrando.data.bankstatement.datasource.BankStatementDataSource +import com.nandoligeiro.safrando.data.bankstatement.mapper.BankStatementDataToDomainMapper +import com.nandoligeiro.safrando.domain.statements.repository.BankStatementRepository +import javax.inject.Inject + +class BankStatementRepositoryImpl @Inject constructor( + private val dataSource: BankStatementDataSource, + private val toDomainMapper: BankStatementDataToDomainMapper +) : BankStatementRepository { + override suspend fun getBankStatement( + userId: Int + ) = toDomainMapper.toDomainBankStatement(dataSource.getBankStatement(userId)) + +} \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/datasource/LocalLoginDataSource.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/datasource/LocalLoginDataSource.kt new file mode 100644 index 000000000..436303c80 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/datasource/LocalLoginDataSource.kt @@ -0,0 +1,8 @@ +package com.nandoligeiro.safrando.data.login.datasource + +import kotlinx.coroutines.flow.Flow + +interface LocalLoginDataSource { + suspend fun saveLogin(user: String) + suspend fun getLocalLogin(): Flow +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/datasource/RemoteLoginDataSource.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/datasource/RemoteLoginDataSource.kt new file mode 100644 index 000000000..10359f64d --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/datasource/RemoteLoginDataSource.kt @@ -0,0 +1,7 @@ +package com.nandoligeiro.safrando.data.login.datasource + +import com.nandoligeiro.safrando.data.login.model.LoginData + +interface RemoteLoginDataSource { + suspend fun postLogin(user: String, password: String): LoginData +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/mapper/LoginDataToDomainMapper.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/mapper/LoginDataToDomainMapper.kt new file mode 100644 index 000000000..a316f41ec --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/mapper/LoginDataToDomainMapper.kt @@ -0,0 +1,14 @@ +package com.nandoligeiro.safrando.data.login.mapper + +import com.nandoligeiro.safrando.data.login.model.LoginData +import com.nandoligeiro.safrando.domain.login.model.LoginDomain + +class LoginDataToDomainMapper { + fun toDomainLogin(login: LoginData) = LoginDomain( + id = 1, + name = login.name, + agency = login.agency, + account = login.account, + balance = login.balance + ) +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/model/LoginData.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/model/LoginData.kt new file mode 100644 index 000000000..70d14b4ed --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/model/LoginData.kt @@ -0,0 +1,9 @@ +package com.nandoligeiro.safrando.data.login.model + +data class LoginData( + val id: Int, + val name: String, + val agency: String, + val account: String, + val balance: String, +) diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/repository/LocalLoginRepositoryImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/repository/LocalLoginRepositoryImpl.kt new file mode 100644 index 000000000..3f64a47f2 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/repository/LocalLoginRepositoryImpl.kt @@ -0,0 +1,14 @@ +package com.nandoligeiro.safrando.data.login.repository + +import com.nandoligeiro.safrando.data.login.datasource.LocalLoginDataSource +import com.nandoligeiro.safrando.domain.login.repository.LocalLoginRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class LocalLoginRepositoryImpl @Inject constructor( + private val localLoginDataSource: LocalLoginDataSource, +) : LocalLoginRepository { + override suspend fun save(user: String) = localLoginDataSource.saveLogin(user) + + override suspend fun getUser() = localLoginDataSource.getLocalLogin() +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/repository/LoginRepositoryImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/repository/LoginRepositoryImpl.kt new file mode 100644 index 000000000..e10057cdc --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/data/login/repository/LoginRepositoryImpl.kt @@ -0,0 +1,18 @@ +package com.nandoligeiro.safrando.data.login.repository + +import com.nandoligeiro.safrando.data.login.datasource.LocalLoginDataSource +import com.nandoligeiro.safrando.data.login.datasource.RemoteLoginDataSource +import com.nandoligeiro.safrando.data.login.mapper.LoginDataToDomainMapper +import com.nandoligeiro.safrando.domain.login.repository.LoginRepository +import javax.inject.Inject + +class LoginRepositoryImpl @Inject constructor( + private val dataSource: RemoteLoginDataSource, + //private val localLoginDataSource: LocalLoginDataSource, + private val loginDataToDomainMapper: LoginDataToDomainMapper +) : LoginRepository { + override suspend fun postLogin( + user: String, password: String + ) = loginDataToDomainMapper.toDomainLogin(dataSource.postLogin(user, password)) + +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/bankstatement/entity/BankStatementEntity.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/bankstatement/entity/BankStatementEntity.kt new file mode 100644 index 000000000..f35ebfbd4 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/bankstatement/entity/BankStatementEntity.kt @@ -0,0 +1,8 @@ +package com.nandoligeiro.safrando.datasource.bankstatement.entity + +data class BankStatementEntity( + val nameStatement: String, + val description: String, + val amount: String, + val statementDate: String +) diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/bankstatement/local/LocalBankStatementDataSourceImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/bankstatement/local/LocalBankStatementDataSourceImpl.kt new file mode 100644 index 000000000..f199d4f3e --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/bankstatement/local/LocalBankStatementDataSourceImpl.kt @@ -0,0 +1,79 @@ +package com.nandoligeiro.safrando.datasource.bankstatement.local + +import com.nandoligeiro.safrando.data.api.SafrandoService +import com.nandoligeiro.safrando.data.bankstatement.datasource.BankStatementDataSource +import com.nandoligeiro.safrando.datasource.bankstatement.entity.BankStatementEntity +import com.nandoligeiro.safrando.datasource.bankstatement.mapper.BankStatementEntityToDataMapper +import javax.inject.Inject + +class LocalBankStatementDataSourceImpl @Inject constructor( + private val api: SafrandoService, + private val toDataMapper: BankStatementEntityToDataMapper +) : BankStatementDataSource { + override suspend fun getBankStatement( + userId: Int + ) = toDataMapper.toData(mockBankStatement()) //(api.getBankStatements(userId)) + private fun mockBankStatement() = listOf( + BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), + BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), + BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), + BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), + BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), + BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ) + ) +} \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/bankstatement/mapper/BankStatementEntityToDataMapper.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/bankstatement/mapper/BankStatementEntityToDataMapper.kt new file mode 100644 index 000000000..32b6aff73 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/bankstatement/mapper/BankStatementEntityToDataMapper.kt @@ -0,0 +1,17 @@ +package com.nandoligeiro.safrando.datasource.bankstatement.mapper + +import com.nandoligeiro.safrando.data.bankstatement.model.BankStatementData +import com.nandoligeiro.safrando.datasource.bankstatement.entity.BankStatementEntity + +class BankStatementEntityToDataMapper { + + fun toData(statements: List) = + statements.map { statement -> + BankStatementData( + nameStatement = statement.nameStatement, + description = statement.description, + amount = statement.amount, + statementDate = statement.statementDate + ) + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/bankstatement/remote/BankStatementDataSourceImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/bankstatement/remote/BankStatementDataSourceImpl.kt new file mode 100644 index 000000000..3bc605f07 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/bankstatement/remote/BankStatementDataSourceImpl.kt @@ -0,0 +1,79 @@ +package com.nandoligeiro.safrando.datasource.bankstatement.remote + +import com.nandoligeiro.safrando.data.api.SafrandoService +import com.nandoligeiro.safrando.data.bankstatement.datasource.BankStatementDataSource +import com.nandoligeiro.safrando.datasource.bankstatement.entity.BankStatementEntity +import com.nandoligeiro.safrando.datasource.bankstatement.mapper.BankStatementEntityToDataMapper +import javax.inject.Inject + +class BankStatementDataSourceImpl @Inject constructor( + private val api: SafrandoService, + private val toDataMapper: BankStatementEntityToDataMapper +) : BankStatementDataSource { + override suspend fun getBankStatement( + userId: Int + ) = toDataMapper.toData(mockBankStatement()) //(api.getBankStatements(userId)) + private fun mockBankStatement() = listOf( + BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), + BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), + BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), + BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), + BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ), + BankStatementEntity( + nameStatement = "Pagamento", + description = "Conta de Luz", + amount = "1000", + statementDate = "12/12/2023" + ) + ) +} \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/login/entity/LoginEntity.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/login/entity/LoginEntity.kt new file mode 100644 index 000000000..57f26a877 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/login/entity/LoginEntity.kt @@ -0,0 +1,9 @@ +package com.nandoligeiro.safrando.datasource.login.entity + +data class LoginEntity( + val id: Int, + val name: String, + val agency: String, + val account: String, + val balance: String, +) diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/login/local/LocalLoginDataSourceImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/login/local/LocalLoginDataSourceImpl.kt new file mode 100644 index 000000000..d46d8a348 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/login/local/LocalLoginDataSourceImpl.kt @@ -0,0 +1,30 @@ +package com.nandoligeiro.safrando.datasource.login.local + +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.stringPreferencesKey +import com.nandoligeiro.safrando.data.login.datasource.LocalLoginDataSource +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +class LocalLoginDataSourceImpl @Inject constructor( + private val dataStore: DataStore +) : LocalLoginDataSource { + + companion object { + val USER = stringPreferencesKey("USER") + } + + override suspend fun saveLogin(user: String) { + + dataStore.edit { preferences -> + preferences[USER] = user + } + } + + override suspend fun getLocalLogin(): Flow = dataStore.data.map { preference -> + preference[USER] ?: "" + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/login/mapper/LoginEntityToDataMapper.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/login/mapper/LoginEntityToDataMapper.kt new file mode 100644 index 000000000..5ed3556bf --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/login/mapper/LoginEntityToDataMapper.kt @@ -0,0 +1,14 @@ +package com.nandoligeiro.safrando.datasource.login.mapper + +import com.nandoligeiro.safrando.data.login.model.LoginData +import com.nandoligeiro.safrando.datasource.login.entity.LoginEntity + +class LoginEntityToDataMapper { + fun toDataLogin(login: LoginEntity) = LoginData( + id = 1, + name = login.name, + agency = login.agency, + account = login.account, + balance = login.balance + ) +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/login/remote/LoginDataSourceImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/login/remote/LoginDataSourceImpl.kt new file mode 100644 index 000000000..49c9d14dc --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/datasource/login/remote/LoginDataSourceImpl.kt @@ -0,0 +1,23 @@ +package com.nandoligeiro.safrando.datasource.login.remote + +import com.nandoligeiro.safrando.data.api.SafrandoService +import com.nandoligeiro.safrando.data.login.datasource.RemoteLoginDataSource +import com.nandoligeiro.safrando.datasource.login.entity.LoginEntity +import com.nandoligeiro.safrando.datasource.login.mapper.LoginEntityToDataMapper +import javax.inject.Inject + +class LoginDataSourceImpl @Inject constructor( + private val api: SafrandoService, + private val toDataMapper: LoginEntityToDataMapper +) : RemoteLoginDataSource { + override suspend fun postLogin( + user: String, password: String + ) = toDataMapper.toDataLogin(mockApiLogin()) //(api.postLogin(user, password)) + private fun mockApiLogin() = LoginEntity( + id = 1, + name = "Jose da Silva Teste", + agency = "2050", + account = "01.11122-4", + balance = "10000" + ) +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/ApiModule.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/ApiModule.kt new file mode 100755 index 000000000..c7d7df04c --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/ApiModule.kt @@ -0,0 +1,71 @@ +package com.nandoligeiro.safrando.di + +import com.nandoligeiro.safrando.data.api.SafrandoService +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import okhttp3.Interceptor +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object ApiModule { + private const val BASE_URL = "https://bank-app-test.herokuapp.com/api/" + private const val ApiKey = "" + private const val API_KEY = "api-key" + + @Singleton + @Provides + fun providesHttpLoggingInterceptor() = HttpLoggingInterceptor() + .apply { + level = HttpLoggingInterceptor.Level.BODY + } + + @Singleton + @Provides + fun providesOkHttpClient(httpLoggingInterceptor: HttpLoggingInterceptor): OkHttpClient = + OkHttpClient + .Builder() + .addInterceptor { apiNoKey(it) } + .addInterceptor(httpLoggingInterceptor) + .build() + + @Singleton + @Provides + fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder() + .addConverterFactory(GsonConverterFactory.create()) + .baseUrl(BASE_URL) + .client(okHttpClient) + .build() + + @Singleton + @Provides + fun provideApiService(retrofit: Retrofit): SafrandoService = + retrofit.create(SafrandoService::class.java) + + private fun apiKeyAsQuery(chain: Interceptor.Chain) = chain.proceed( + chain.request() + .newBuilder() + .url(chain.request().url.newBuilder().addQueryParameter(API_KEY, ApiKey).build()) + .build() + ) + + private fun apiKeyAsHeader(it: Interceptor.Chain) = it.proceed( + it.request() + .newBuilder() + .addHeader(API_KEY, ApiKey) + .build() + ) + + private fun apiNoKey(it: Interceptor.Chain) = it.proceed( + it.request() + .newBuilder() + .build() + ) + +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/DataSourceModule.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/DataSourceModule.kt new file mode 100644 index 000000000..1da7d7cd8 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/DataSourceModule.kt @@ -0,0 +1,29 @@ +package com.nandoligeiro.safrando.di + + +import com.nandoligeiro.safrando.data.bankstatement.datasource.BankStatementDataSource +import com.nandoligeiro.safrando.data.login.datasource.LocalLoginDataSource +import com.nandoligeiro.safrando.data.login.datasource.RemoteLoginDataSource +import com.nandoligeiro.safrando.datasource.bankstatement.remote.BankStatementDataSourceImpl +import com.nandoligeiro.safrando.datasource.login.local.LocalLoginDataSourceImpl +import com.nandoligeiro.safrando.datasource.login.remote.LoginDataSourceImpl +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +interface DataSourceModule { + + @Binds + fun bindLoginDataSource(repository: LoginDataSourceImpl): RemoteLoginDataSource + + @Binds + fun bindLocalLoginDataSource(repository: LocalLoginDataSourceImpl): LocalLoginDataSource + + + @Binds + fun bindBankStatementDataSource(repository: BankStatementDataSourceImpl): BankStatementDataSource + +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/DataStoreModule.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/DataStoreModule.kt new file mode 100644 index 000000000..f55489953 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/DataStoreModule.kt @@ -0,0 +1,39 @@ +package com.nandoligeiro.safrando.di + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler +import androidx.datastore.preferences.SharedPreferencesMigration +import androidx.datastore.preferences.core.PreferenceDataStoreFactory +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.emptyPreferences +import androidx.datastore.preferences.preferencesDataStoreFile +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import javax.inject.Singleton + +private const val PREFERENCE_NAME = "preference_name" + +@Module +@InstallIn(SingletonComponent::class) +object DataStoreModule { + + @Singleton + @Provides + fun providePreferencesDataStore(@ApplicationContext context: Context): DataStore { + return PreferenceDataStoreFactory.create( + corruptionHandler = ReplaceFileCorruptionHandler( + produceNewData = { emptyPreferences() } + ), + migrations = listOf(SharedPreferencesMigration(context, PREFERENCE_NAME)), + scope = CoroutineScope(Dispatchers.IO + SupervisorJob()), + produceFile = { context.preferencesDataStoreFile(PREFERENCE_NAME) } + ) + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/DispatcherModule.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/DispatcherModule.kt new file mode 100644 index 000000000..7f3251405 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/DispatcherModule.kt @@ -0,0 +1,37 @@ +package com.nandoligeiro.safrando.di + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import javax.inject.Qualifier + +@Module +@InstallIn(SingletonComponent::class) +object DispatcherModule { + @DefaultDispatcher + @Provides + fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default + + @IoDispatcher + @Provides + fun providesIoDispatcher(): CoroutineDispatcher = Dispatchers.IO + + @MainDispatcher + @Provides + fun providesMainDispatcher(): CoroutineDispatcher = Dispatchers.Main +} + +@Retention(AnnotationRetention.BINARY) +@Qualifier +annotation class DefaultDispatcher + +@Retention(AnnotationRetention.BINARY) +@Qualifier +annotation class IoDispatcher + +@Retention(AnnotationRetention.BINARY) +@Qualifier +annotation class MainDispatcher \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/MapperModule.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/MapperModule.kt new file mode 100755 index 000000000..abf075dbf --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/MapperModule.kt @@ -0,0 +1,36 @@ +package com.nandoligeiro.safrando.di + +import com.nandoligeiro.safrando.data.bankstatement.mapper.BankStatementDataToDomainMapper +import com.nandoligeiro.safrando.data.login.mapper.LoginDataToDomainMapper +import com.nandoligeiro.safrando.datasource.bankstatement.mapper.BankStatementEntityToDataMapper +import com.nandoligeiro.safrando.datasource.login.mapper.LoginEntityToDataMapper +import com.nandoligeiro.safrando.presentation.login.mapper.LoginDomainToUiMapper +import com.nandoligeiro.safrando.presentation.statements.mapper.BankStatementDomainToUiMapper +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +class MapperModule { + + @Provides + fun providesLoginDomainToUiMapper() = LoginDomainToUiMapper() + + @Provides + fun providesBankStatementDomainToUiMapper() = BankStatementDomainToUiMapper() + + @Provides + fun providesLoginDataToDomainMapper() = LoginDataToDomainMapper() + + @Provides + fun providesLoginEntityToDataMapper() = LoginEntityToDataMapper() + + @Provides + fun providesBankStatementEntityToDataMapper() = BankStatementEntityToDataMapper() + + @Provides + fun providesBankStatementDataToDomainMapper() = BankStatementDataToDomainMapper() +} + diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/RepositoryModule.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/RepositoryModule.kt new file mode 100644 index 000000000..46f26aa6a --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/RepositoryModule.kt @@ -0,0 +1,34 @@ +package com.nandoligeiro.safrando.di + + +import com.nandoligeiro.safrando.data.bankstatement.repository.BankStatementRepositoryImpl +import com.nandoligeiro.safrando.data.login.repository.LocalLoginRepositoryImpl +import com.nandoligeiro.safrando.data.login.repository.LoginRepositoryImpl +import com.nandoligeiro.safrando.domain.login.repository.LocalLoginRepository +import com.nandoligeiro.safrando.domain.login.repository.LoginRepository +import com.nandoligeiro.safrando.domain.statements.repository.BankStatementRepository +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ViewModelComponent + +@Module +@InstallIn(ViewModelComponent::class) +interface RepositoryModule { + + @Binds + fun bindBankStatementRepository( + repository: BankStatementRepositoryImpl + ): BankStatementRepository + + @Binds + fun bindLoginRepository( + repository: LoginRepositoryImpl + ): LoginRepository + + @Binds + fun bindLocalLoginRepository( + repository: LocalLoginRepositoryImpl + ): LocalLoginRepository + +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/UseCaseModule.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/UseCaseModule.kt new file mode 100644 index 000000000..29b56d5a7 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/di/UseCaseModule.kt @@ -0,0 +1,83 @@ +package com.nandoligeiro.safrando.di + +import com.nandoligeiro.safrando.domain.common.checkCPF.CheckCPFUseCase +import com.nandoligeiro.safrando.domain.common.checkCPF.NewCheckCPFUseCaseImpl +import com.nandoligeiro.safrando.domain.common.checkEmail.CheckEmailUseCase +import com.nandoligeiro.safrando.domain.common.checkEmail.CheckEmailUseCaseImpl +import com.nandoligeiro.safrando.domain.common.currencyFormatter.CurrencyFormatterBrUseCaseImpl +import com.nandoligeiro.safrando.domain.common.currencyFormatter.CurrencyFormatterUseCase +import com.nandoligeiro.safrando.domain.localUser.usecase.saveLocalUser.SaveUserUseCase +import com.nandoligeiro.safrando.domain.localUser.usecase.saveLocalUser.SaveUserUseCaseImpl +import com.nandoligeiro.safrando.domain.common.dateFormatter.DateFormatterUseCase +import com.nandoligeiro.safrando.domain.common.dateFormatter.DateFormatterUseCaseImpl +import com.nandoligeiro.safrando.domain.localUser.usecase.getLocalUser.GetLocalUserUseCase +import com.nandoligeiro.safrando.domain.localUser.usecase.getLocalUser.GetLocalUserUseCaseImpl +import com.nandoligeiro.safrando.domain.login.usecase.checkLogin.CheckLoginUseCase +import com.nandoligeiro.safrando.domain.login.usecase.checkLogin.CheckLoginUseCaseImpl +import com.nandoligeiro.safrando.domain.login.usecase.checkPassword.CheckPasswordUseCase +import com.nandoligeiro.safrando.domain.login.usecase.checkPassword.CheckPasswordUseCaseImpl +import com.nandoligeiro.safrando.domain.login.usecase.postLogin.PostLoginUseCase +import com.nandoligeiro.safrando.domain.login.usecase.postLogin.PostLoginUseCaseImpl +import com.nandoligeiro.safrando.domain.statements.usecase.GetBankStatementUseCase +import com.nandoligeiro.safrando.domain.statements.usecase.GetBankStatementUseCaseImpl +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ViewModelComponent + +@Module +@InstallIn(ViewModelComponent::class) +interface UseCaseModule { + + + @Binds + fun bindCheckPasswordUseCase( + useCase: CheckPasswordUseCaseImpl + ): CheckPasswordUseCase + + @Binds + fun bindCheckEmailUseCase( + useCase: CheckEmailUseCaseImpl + ): CheckEmailUseCase + + @Binds + fun bindCheckCPFUseCaseUseCase( + useCase: NewCheckCPFUseCaseImpl + ): CheckCPFUseCase + + @Binds + fun bindDateFormatterUseCaseUseCase( + useCase: DateFormatterUseCaseImpl + ): DateFormatterUseCase + + @Binds + fun bindFormatCurrencyUseCaseUseCase( + useCase: CurrencyFormatterBrUseCaseImpl + ): CurrencyFormatterUseCase + + @Binds + fun bindGetBankStatementUseCase( + useCase: GetBankStatementUseCaseImpl + ): GetBankStatementUseCase + + @Binds + fun bindCheckLoginUseCase( + useCase: CheckLoginUseCaseImpl + ): CheckLoginUseCase + + @Binds + fun bindPostLoginUseCase( + useCase: PostLoginUseCaseImpl + ): PostLoginUseCase + + @Binds + fun bindSaveDataStoreUseCase( + useCase: SaveUserUseCaseImpl + ): SaveUserUseCase + + @Binds + fun bindGetLocalUserUseCase( + useCase: GetLocalUserUseCaseImpl + ): GetLocalUserUseCase + +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkCPF/CheckCPFUseCase.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkCPF/CheckCPFUseCase.kt new file mode 100644 index 000000000..adab93230 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkCPF/CheckCPFUseCase.kt @@ -0,0 +1,5 @@ +package com.nandoligeiro.safrando.domain.common.checkCPF + +interface CheckCPFUseCase { + operator fun invoke(value: String): Boolean +} \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkCPF/CheckCPFUseCaseImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkCPF/CheckCPFUseCaseImpl.kt new file mode 100644 index 000000000..4afb6facb --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkCPF/CheckCPFUseCaseImpl.kt @@ -0,0 +1,71 @@ +package com.nandoligeiro.safrando.domain.common.checkCPF + +import javax.inject.Inject + +class CheckCPFUseCaseImpl @Inject constructor() : CheckCPFUseCase { + override fun invoke(value: String): Boolean { + + val cpfClean = value.replace(".", "").replace("-", "") + + //## check if size is eleven + if (cpfClean.length != 11) + return false + + //## check if is number + try { + cpfClean.toLong() + } catch (e: Exception) { + return false + } + + //continue + val dvCurrent10 = cpfClean.substring(9, 10).toInt() + val dvCurrent11 = cpfClean.substring(10, 11).toInt() + + //the sum of the nine first digits determines the tenth digit + val cpfNineFirst = IntArray(9) + var i = 9 + while (i > 0) { + cpfNineFirst[i - 1] = cpfClean.substring(i - 1, i).toInt() + i-- + } + //multiple the nine digits for your weights: 10,9..2 + val sumProductNine = IntArray(9) + var weight = 10 + var position = 0 + while (weight >= 2) { + sumProductNine[position] = weight * cpfNineFirst[position] + weight-- + position++ + } + //Verify the nineth digit + var dvForTenthDigit = sumProductNine.sum() % 11 + dvForTenthDigit = 11 - dvForTenthDigit //rule for tenth digit + if (dvForTenthDigit > 9) + dvForTenthDigit = 0 + if (dvForTenthDigit != dvCurrent10) + return false + + //### verify tenth digit + val cpfTenFirst = cpfNineFirst.copyOf(10) + cpfTenFirst[9] = dvCurrent10 + //multiple the nine digits for your weights: 10,9..2 + val sumProductTen = IntArray(10) + var w = 11 + var p = 0 + while (w >= 2) { + sumProductTen[p] = w * cpfTenFirst[p] + w-- + p++ + } + //Verify the nineth digit + var dvForeleventhDigit = sumProductTen.sum() % 11 + dvForeleventhDigit = 11 - dvForeleventhDigit //rule for tenth digit + if (dvForeleventhDigit > 9) + dvForeleventhDigit = 0 + if (dvForeleventhDigit != dvCurrent11) + return false + + return true + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkCPF/NewCheckCPFUseCaseImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkCPF/NewCheckCPFUseCaseImpl.kt new file mode 100644 index 000000000..c65a2faaf --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkCPF/NewCheckCPFUseCaseImpl.kt @@ -0,0 +1,31 @@ +package com.nandoligeiro.safrando.domain.common.checkCPF + +import javax.inject.Inject + +class NewCheckCPFUseCaseImpl @Inject constructor() : CheckCPFUseCase { + + companion object { + private const val CPF_LENGTH = 11 + } + + override fun invoke(value: String): Boolean { + val formattedCPF = value.replace("[^0-9]".toRegex(), "") + if (formattedCPF.length != CPF_LENGTH || formattedCPF.all { it == formattedCPF[0] }) { + return false + } + val digits = formattedCPF.substring(0, 9).toCharArray() + val verifierDigit1 = calculateVerifierDigit(digits, 10) + val verifierDigit2 = + calculateVerifierDigit(digits.plus(verifierDigit1.toString().toCharArray()), 11) + return formattedCPF.substring(9, 11) == "$verifierDigit1$verifierDigit2" + } + + private fun calculateVerifierDigit(digits: CharArray, multiplier: Int): Int { + var sum = 0 + for (i in digits.indices) { + sum += Character.getNumericValue(digits[i]) * (multiplier - i) + } + val remainder = sum % 11 + return if (remainder < 2) 0 else 11 - remainder + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkEmail/CheckEmailUseCase.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkEmail/CheckEmailUseCase.kt new file mode 100644 index 000000000..b8f3b1fa6 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkEmail/CheckEmailUseCase.kt @@ -0,0 +1,5 @@ +package com.nandoligeiro.safrando.domain.common.checkEmail + +interface CheckEmailUseCase { + operator fun invoke(value: String): Boolean +} \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkEmail/CheckEmailUseCaseImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkEmail/CheckEmailUseCaseImpl.kt new file mode 100644 index 000000000..4341e9a87 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/checkEmail/CheckEmailUseCaseImpl.kt @@ -0,0 +1,17 @@ +package com.nandoligeiro.safrando.domain.common.checkEmail + +import java.util.regex.Pattern +import javax.inject.Inject + +class CheckEmailUseCaseImpl @Inject constructor() : CheckEmailUseCase { + override fun invoke(value: String): Boolean { + return Pattern.compile( + "^(([\\w-]+\\.)+[\\w-]+|([a-zA-Z]|[\\w-]{2,}))@" + + "((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\.([0-1]?" + + "[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\." + + "([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\.([0-1]?" + + "[0-9]{1,2}|25[0-5]|2[0-4][0-9]))|" + + "([a-zA-Z]+[\\w-]+\\.)+[a-zA-Z]{2,4})$" + ).matcher(value).matches() + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/currencyFormatter/CurrencyFormatterBrUseCaseImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/currencyFormatter/CurrencyFormatterBrUseCaseImpl.kt new file mode 100644 index 000000000..3b5bba0c2 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/currencyFormatter/CurrencyFormatterBrUseCaseImpl.kt @@ -0,0 +1,13 @@ +package com.nandoligeiro.safrando.domain.common.currencyFormatter + +import java.text.NumberFormat +import java.util.Locale +import javax.inject.Inject + +class CurrencyFormatterBrUseCaseImpl @Inject constructor(): CurrencyFormatterUseCase { + override fun invoke(amount: String): String { + val locale = Locale("pt", "BR") + val numberFormat: NumberFormat = NumberFormat.getCurrencyInstance(locale) + return numberFormat.format(amount.toDouble()) + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/currencyFormatter/CurrencyFormatterDefaultUseCaseImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/currencyFormatter/CurrencyFormatterDefaultUseCaseImpl.kt new file mode 100644 index 000000000..59e356b61 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/currencyFormatter/CurrencyFormatterDefaultUseCaseImpl.kt @@ -0,0 +1,12 @@ +package com.nandoligeiro.safrando.domain.common.currencyFormatter + +import java.text.NumberFormat +import java.util.Locale +import javax.inject.Inject + +class CurrencyFormatterDefaultUseCaseImpl @Inject constructor() : CurrencyFormatterUseCase { + override fun invoke(amount: String): String { + val numberFormat = NumberFormat.getCurrencyInstance(Locale.getDefault()) + return numberFormat.format(amount.toDouble()) + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/currencyFormatter/CurrencyFormatterUseCase.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/currencyFormatter/CurrencyFormatterUseCase.kt new file mode 100644 index 000000000..c5f7b7474 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/currencyFormatter/CurrencyFormatterUseCase.kt @@ -0,0 +1,5 @@ +package com.nandoligeiro.safrando.domain.common.currencyFormatter + +interface CurrencyFormatterUseCase { + operator fun invoke(amount: String): String +} \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/dateFormatter/DateFormatterUseCase.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/dateFormatter/DateFormatterUseCase.kt new file mode 100644 index 000000000..ee7029e03 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/dateFormatter/DateFormatterUseCase.kt @@ -0,0 +1,5 @@ +package com.nandoligeiro.safrando.domain.common.dateFormatter + +interface DateFormatterUseCase { + operator fun invoke(date: String): String +} \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/dateFormatter/DateFormatterUseCaseImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/dateFormatter/DateFormatterUseCaseImpl.kt new file mode 100644 index 000000000..76e36123b --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/common/dateFormatter/DateFormatterUseCaseImpl.kt @@ -0,0 +1,22 @@ +package com.nandoligeiro.safrando.domain.common.dateFormatter + +import java.text.SimpleDateFormat +import java.util.Locale +import javax.inject.Inject + +class DateFormatterUseCaseImpl @Inject constructor() : DateFormatterUseCase { + + companion object { + const val DATE_PATTERN = "dd/MM/yyyy" + const val LANG = "pt" + const val COUNTRY = "BR" + } + + override fun invoke(date: String): String { + + val locale = Locale(LANG, COUNTRY) + val sdf = SimpleDateFormat(DATE_PATTERN, locale) + + return sdf.format(date) + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/localUser/usecase/getLocalUser/GetLocalUserUseCase.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/localUser/usecase/getLocalUser/GetLocalUserUseCase.kt new file mode 100644 index 000000000..c6bb4f5db --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/localUser/usecase/getLocalUser/GetLocalUserUseCase.kt @@ -0,0 +1,7 @@ +package com.nandoligeiro.safrando.domain.localUser.usecase.getLocalUser + +import kotlinx.coroutines.flow.Flow + +interface GetLocalUserUseCase { + suspend operator fun invoke(): Flow +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/localUser/usecase/getLocalUser/GetLocalUserUseCaseImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/localUser/usecase/getLocalUser/GetLocalUserUseCaseImpl.kt new file mode 100644 index 000000000..52862108e --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/localUser/usecase/getLocalUser/GetLocalUserUseCaseImpl.kt @@ -0,0 +1,10 @@ +package com.nandoligeiro.safrando.domain.localUser.usecase.getLocalUser + +import com.nandoligeiro.safrando.domain.login.repository.LocalLoginRepository +import javax.inject.Inject + +class GetLocalUserUseCaseImpl @Inject constructor( + private val localLoginRepository: LocalLoginRepository +) : GetLocalUserUseCase { + override suspend fun invoke() = localLoginRepository.getUser() +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/localUser/usecase/saveLocalUser/SaveUserUseCase.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/localUser/usecase/saveLocalUser/SaveUserUseCase.kt new file mode 100644 index 000000000..c7a411517 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/localUser/usecase/saveLocalUser/SaveUserUseCase.kt @@ -0,0 +1,5 @@ +package com.nandoligeiro.safrando.domain.localUser.usecase.saveLocalUser + +interface SaveUserUseCase { + suspend operator fun invoke(data: String) +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/localUser/usecase/saveLocalUser/SaveUserUseCaseImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/localUser/usecase/saveLocalUser/SaveUserUseCaseImpl.kt new file mode 100644 index 000000000..4fe3e64ed --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/localUser/usecase/saveLocalUser/SaveUserUseCaseImpl.kt @@ -0,0 +1,13 @@ +package com.nandoligeiro.safrando.domain.localUser.usecase.saveLocalUser + +import com.nandoligeiro.safrando.domain.login.repository.LocalLoginRepository +import javax.inject.Inject + +class SaveUserUseCaseImpl @Inject constructor( + private val localLoginRepository: LocalLoginRepository +): SaveUserUseCase { + + override suspend fun invoke(user: String) { + localLoginRepository.save(user) + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/model/LoginDomain.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/model/LoginDomain.kt new file mode 100644 index 000000000..28bba4321 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/model/LoginDomain.kt @@ -0,0 +1,9 @@ +package com.nandoligeiro.safrando.domain.login.model + +data class LoginDomain( + val id: Int, + val name: String, + val agency: String, + val account: String, + val balance: String, +) diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/repository/LocalLoginRepository.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/repository/LocalLoginRepository.kt new file mode 100755 index 000000000..dceb1587e --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/repository/LocalLoginRepository.kt @@ -0,0 +1,8 @@ +package com.nandoligeiro.safrando.domain.login.repository + +import kotlinx.coroutines.flow.Flow + +interface LocalLoginRepository { + suspend fun save(user: String) + suspend fun getUser(): Flow +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/repository/LoginRepository.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/repository/LoginRepository.kt new file mode 100755 index 000000000..b5b91b828 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/repository/LoginRepository.kt @@ -0,0 +1,7 @@ +package com.nandoligeiro.safrando.domain.login.repository + +import com.nandoligeiro.safrando.domain.login.model.LoginDomain + +interface LoginRepository { + suspend fun postLogin(user: String, password: String): LoginDomain +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/result/LoginResult.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/result/LoginResult.kt new file mode 100755 index 000000000..af20aebc2 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/result/LoginResult.kt @@ -0,0 +1,7 @@ +package com.nandoligeiro.safrando.domain.login.result + +sealed class LoginResult { + data class Success(val data: T) : LoginResult() + data class Error(val t: Throwable) : LoginResult() + object CheckFieldError : LoginResult() +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/checkLogin/CheckLoginUseCase.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/checkLogin/CheckLoginUseCase.kt new file mode 100644 index 000000000..6e8708937 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/checkLogin/CheckLoginUseCase.kt @@ -0,0 +1,5 @@ +package com.nandoligeiro.safrando.domain.login.usecase.checkLogin + +interface CheckLoginUseCase { + operator fun invoke(user: String, password: String): Boolean +} \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/checkLogin/CheckLoginUseCaseImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/checkLogin/CheckLoginUseCaseImpl.kt new file mode 100644 index 000000000..267c87582 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/checkLogin/CheckLoginUseCaseImpl.kt @@ -0,0 +1,16 @@ +package com.nandoligeiro.safrando.domain.login.usecase.checkLogin + +import com.nandoligeiro.safrando.domain.common.checkCPF.CheckCPFUseCase +import com.nandoligeiro.safrando.domain.common.checkEmail.CheckEmailUseCase +import com.nandoligeiro.safrando.domain.login.usecase.checkPassword.CheckPasswordUseCase +import javax.inject.Inject + +class CheckLoginUseCaseImpl @Inject constructor( + private val checkCPFUseCase: CheckCPFUseCase, + private val checkEmailUseCase: CheckEmailUseCase, + private val checkPasswordUseCase: CheckPasswordUseCase +) : CheckLoginUseCase { + override fun invoke(user: String, password: String): Boolean { + return (checkCPFUseCase(user) || checkEmailUseCase(user)) && checkPasswordUseCase(password) + } +} \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/checkPassword/CheckPasswordUseCase.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/checkPassword/CheckPasswordUseCase.kt new file mode 100644 index 000000000..4cde5b08b --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/checkPassword/CheckPasswordUseCase.kt @@ -0,0 +1,5 @@ +package com.nandoligeiro.safrando.domain.login.usecase.checkPassword + +interface CheckPasswordUseCase { + operator fun invoke(password: String): Boolean +} \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/checkPassword/CheckPasswordUseCaseImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/checkPassword/CheckPasswordUseCaseImpl.kt new file mode 100644 index 000000000..9529930b2 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/checkPassword/CheckPasswordUseCaseImpl.kt @@ -0,0 +1,14 @@ +package com.nandoligeiro.safrando.domain.login.usecase.checkPassword + +import javax.inject.Inject + +class CheckPasswordUseCaseImpl @Inject constructor(): CheckPasswordUseCase { + override fun invoke(password: String): Boolean { + if (password.firstOrNull { it.isDigit() } == null) return false + if (password.filter { it.isLetter() }.firstOrNull { it.isUpperCase() } == null) return false + if (password.filter { it.isLetter() }.firstOrNull { it.isLowerCase() } == null) return false + if (password.firstOrNull { !it.isLetterOrDigit() } == null) return false + + return true + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/postLogin/PostLoginUseCase.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/postLogin/PostLoginUseCase.kt new file mode 100755 index 000000000..019bc6ee0 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/postLogin/PostLoginUseCase.kt @@ -0,0 +1,8 @@ +package com.nandoligeiro.safrando.domain.login.usecase.postLogin + +import com.nandoligeiro.safrando.domain.login.model.LoginDomain +import com.nandoligeiro.safrando.domain.login.result.LoginResult + +interface PostLoginUseCase { + suspend operator fun invoke(user: String, password: String ): LoginResult +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/postLogin/PostLoginUseCaseImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/postLogin/PostLoginUseCaseImpl.kt new file mode 100644 index 000000000..2e05b6fbf --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/login/usecase/postLogin/PostLoginUseCaseImpl.kt @@ -0,0 +1,38 @@ +package com.nandoligeiro.safrando.domain.login.usecase.postLogin + +import com.nandoligeiro.safrando.di.IoDispatcher +import com.nandoligeiro.safrando.domain.common.currencyFormatter.CurrencyFormatterUseCase +import com.nandoligeiro.safrando.domain.login.model.LoginDomain +import com.nandoligeiro.safrando.domain.login.repository.LoginRepository +import com.nandoligeiro.safrando.domain.login.result.LoginResult +import com.nandoligeiro.safrando.domain.login.usecase.checkLogin.CheckLoginUseCase +import com.nandoligeiro.safrando.domain.localUser.usecase.saveLocalUser.SaveUserUseCase +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class PostLoginUseCaseImpl @Inject constructor( + private val loginRepository: LoginRepository, + private val checkLoginUseCase: CheckLoginUseCase, + private val currencyFormatterUseCase: CurrencyFormatterUseCase, + private val saveDataStoreUseCase: SaveUserUseCase, + @IoDispatcher private val ioDispatcher: CoroutineDispatcher +) : PostLoginUseCase { + + override suspend fun invoke( + user: String, password: String + ): LoginResult = withContext(ioDispatcher) { + if (checkLoginUseCase(user, password)) { + try { + val result = loginRepository.postLogin(user, password) + val changedResult = result.copy(balance = currencyFormatterUseCase(result.balance)) + saveDataStoreUseCase(user) + LoginResult.Success(changedResult) + } catch (e: Exception) { + LoginResult.Error(e) + } + } else { + LoginResult.CheckFieldError + } + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/result/DomainResult.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/result/DomainResult.kt new file mode 100755 index 000000000..b55fd419c --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/result/DomainResult.kt @@ -0,0 +1,6 @@ +package com.nandoligeiro.safrando.domain.result + +sealed class DomainResult { + data class Success(val data: T) : DomainResult() + data class Error(val t: Throwable) : DomainResult() +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/statements/model/BankStatementDomain.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/statements/model/BankStatementDomain.kt new file mode 100644 index 000000000..a2494c7de --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/statements/model/BankStatementDomain.kt @@ -0,0 +1,8 @@ +package com.nandoligeiro.safrando.domain.statements.model + +data class BankStatementDomain( + val nameStatement: String, + val description: String, + val amount: String, + val statementDate: String +) diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/statements/repository/BankStatementRepository.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/statements/repository/BankStatementRepository.kt new file mode 100755 index 000000000..f1e322122 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/statements/repository/BankStatementRepository.kt @@ -0,0 +1,7 @@ +package com.nandoligeiro.safrando.domain.statements.repository + +import com.nandoligeiro.safrando.domain.statements.model.BankStatementDomain + +interface BankStatementRepository { + suspend fun getBankStatement(userId: Int): List +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/statements/usecase/GetBankStatementUseCase.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/statements/usecase/GetBankStatementUseCase.kt new file mode 100755 index 000000000..f96c49566 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/statements/usecase/GetBankStatementUseCase.kt @@ -0,0 +1,8 @@ +package com.nandoligeiro.safrando.domain.statements.usecase + +import com.nandoligeiro.safrando.domain.result.DomainResult +import com.nandoligeiro.safrando.domain.statements.model.BankStatementDomain + +interface GetBankStatementUseCase { + suspend operator fun invoke(userId: Int): DomainResult> +} \ No newline at end of file diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/statements/usecase/GetBankStatementUseCaseImpl.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/statements/usecase/GetBankStatementUseCaseImpl.kt new file mode 100644 index 000000000..74d404846 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/domain/statements/usecase/GetBankStatementUseCaseImpl.kt @@ -0,0 +1,32 @@ +package com.nandoligeiro.safrando.domain.statements.usecase + +import com.nandoligeiro.safrando.di.IoDispatcher +import com.nandoligeiro.safrando.domain.common.currencyFormatter.CurrencyFormatterUseCase +import com.nandoligeiro.safrando.domain.result.DomainResult +import com.nandoligeiro.safrando.domain.statements.model.BankStatementDomain +import com.nandoligeiro.safrando.domain.statements.repository.BankStatementRepository +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class GetBankStatementUseCaseImpl @Inject constructor( + private val bankStatementRepository: BankStatementRepository, + private val currencyFormatterUseCase: CurrencyFormatterUseCase, + @IoDispatcher private val ioDispatcher: CoroutineDispatcher +) : GetBankStatementUseCase { + + override suspend fun invoke(userId: Int): + DomainResult> = withContext(ioDispatcher) { + + try { + val statement = bankStatementRepository.getBankStatement(userId) + DomainResult.Success( + statement.map { + it.copy(amount = currencyFormatterUseCase(it.amount)) + } + ) + } catch (e: Exception) { + DomainResult.Error(e) + } + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/common/Constants.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/common/Constants.kt new file mode 100644 index 000000000..36178c362 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/common/Constants.kt @@ -0,0 +1,7 @@ +package com.nandoligeiro.safrando.presentation.common + +object Constants { + object KeyExtra{ + const val KEY_EXTRA_LOGIN = "userData" + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/helper/Mask.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/helper/Mask.kt new file mode 100644 index 000000000..1c431461d --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/helper/Mask.kt @@ -0,0 +1,72 @@ +package com.nandoligeiro.safrando.presentation.login.helper + +import android.text.Editable +import android.text.TextWatcher +import android.widget.EditText + +class Mask { + companion object { + const val CPF_MASK = "###.###.###-##" + private fun replaceChars(cpfFull: String): String { + return cpfFull.replace(".", "").replace("-", "") + .replace("(", "").replace(")", "") + .replace("/", "").replace(" ", "") + .replace("*", "") + } + + fun mask(mask: String, etCpf: EditText): TextWatcher { + + val textWatcher: TextWatcher = object : TextWatcher { + var isUpdating: Boolean = false + var oldString: String = "" + override fun beforeTextChanged( + charSequence: CharSequence, + i: Int, + i1: Int, + i2: Int + ) { + + } + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { + val str = replaceChars(s.toString()) + var cpfWithMask = "" + + if (count == 0)//is deleting + isUpdating = true + + if (isUpdating) { + oldString = str + isUpdating = false + return + } + + var i = 0 + for (m: Char in mask.toCharArray()) { + if (m != '#' && str.length > oldString.length) { + cpfWithMask += m + continue + } + try { + cpfWithMask += str.get(i) + } catch (e: Exception) { + break + } + i++ + } + + isUpdating = true + etCpf.setText(cpfWithMask) + etCpf.setSelection(cpfWithMask.length) + + } + + override fun afterTextChanged(editable: Editable) { + + } + } + + return textWatcher + } + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/mapper/LoginDomainToUiMapper.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/mapper/LoginDomainToUiMapper.kt new file mode 100644 index 000000000..d03ff372f --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/mapper/LoginDomainToUiMapper.kt @@ -0,0 +1,14 @@ +package com.nandoligeiro.safrando.presentation.login.mapper + +import com.nandoligeiro.safrando.domain.login.model.LoginDomain +import com.nandoligeiro.safrando.presentation.login.model.UiLoginModel + +class LoginDomainToUiMapper { + fun toUiLogin(login: LoginDomain) = UiLoginModel( + id = 1, + name = login.name, + agency = login.agency, + account = login.account, + balance = login.balance + ) +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/model/UiLoginModel.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/model/UiLoginModel.kt new file mode 100644 index 000000000..a60e5e897 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/model/UiLoginModel.kt @@ -0,0 +1,13 @@ +package com.nandoligeiro.safrando.presentation.login.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class UiLoginModel( + val id: Int, + val name: String = "", + val agency: String = "", + val account: String = "", + val balance: String = "", +): Parcelable diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/state/LoginState.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/state/LoginState.kt new file mode 100755 index 000000000..b1cacc187 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/state/LoginState.kt @@ -0,0 +1,9 @@ +package com.nandoligeiro.safrando.presentation.login.state + + +sealed class LoginState { + data class Success(val data: T) : LoginState() + object Default: LoginState() + object Error: LoginState() + object CheckFieldError: LoginState() +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/view/LoginActivity.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/view/LoginActivity.kt new file mode 100644 index 000000000..97e70a1aa --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/view/LoginActivity.kt @@ -0,0 +1,108 @@ +package com.nandoligeiro.safrando.presentation.login.view + +import android.content.Intent +import android.os.Bundle +import android.view.View +import android.widget.Toast +import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.nandoligeiro.safrando.databinding.ActivityLoginBinding +import com.nandoligeiro.safrando.presentation.common.Constants +import com.nandoligeiro.safrando.presentation.login.model.UiLoginModel +import com.nandoligeiro.safrando.presentation.login.state.LoginState +import com.nandoligeiro.safrando.presentation.login.viewmodel.LoginViewModel +import com.nandoligeiro.safrando.presentation.statements.view.StatementActivity +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch + +@AndroidEntryPoint +class LoginActivity : AppCompatActivity() { + + private lateinit var binding: ActivityLoginBinding + + private val viewModel: LoginViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityLoginBinding.inflate(layoutInflater) + setContentView(binding.root) + observeVMEvents() + observeUser() + actionSignIn() + actionGetLocalUser() + } + + private fun actionGetLocalUser() { + viewModel.getLocalUserSaved() + } + + private fun actionSignIn() { + binding.buttonLogin.setOnClickListener { + binding.run { + viewModel.signIn( + editTextUser.text.toString(), + editTextPassword.text.toString() + ) + } + } + } + + private fun toStatementActivity(userData: UiLoginModel) { + val intent = Intent(this, StatementActivity::class.java) + intent.putExtra(Constants.KeyExtra.KEY_EXTRA_LOGIN, userData) + startActivity(intent) + finish() + } + + private fun observeUser() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.localUser.collect { + binding.editTextUser.setText(it) + } + } + } + } + + private fun observeVMEvents() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.login.collect { loginState -> + when (loginState) { + is LoginState.Success -> { + toStatementActivity(loginState.data) + } + + is LoginState.Error -> { + //showError() //error server + hideCheckFieldError() + Toast.makeText( + this@LoginActivity, "Tente Novamente", + Toast.LENGTH_SHORT + ).show() + } + + is LoginState.Default -> { + hideCheckFieldError() + } + + is LoginState.CheckFieldError -> { + showCheckFieldError() + } + } + } + } + } + } + + private fun hideCheckFieldError() { + binding.warning.visibility = View.GONE + } + + private fun showCheckFieldError() { + binding.warning.visibility = View.VISIBLE + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/viewmodel/LoginViewModel.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/viewmodel/LoginViewModel.kt new file mode 100644 index 000000000..92736cb23 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/login/viewmodel/LoginViewModel.kt @@ -0,0 +1,58 @@ +package com.nandoligeiro.safrando.presentation.login.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.nandoligeiro.safrando.domain.localUser.usecase.getLocalUser.GetLocalUserUseCase +import com.nandoligeiro.safrando.domain.login.result.LoginResult +import com.nandoligeiro.safrando.domain.login.usecase.postLogin.PostLoginUseCase +import com.nandoligeiro.safrando.presentation.login.mapper.LoginDomainToUiMapper +import com.nandoligeiro.safrando.presentation.login.model.UiLoginModel +import com.nandoligeiro.safrando.presentation.login.state.LoginState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class LoginViewModel @Inject constructor( + private val postLoginUseCase: PostLoginUseCase, + private val getLocalUserUseCase: GetLocalUserUseCase, + private val loginDomainToUiMapper: LoginDomainToUiMapper +) : ViewModel() { + + private val mutableLogin = MutableStateFlow>(LoginState.Default) + val login: StateFlow> get() = mutableLogin + + private val mutableLocalUser = MutableStateFlow("") + val localUser: StateFlow get() = mutableLocalUser + fun signIn(user: String, password: String) { + viewModelScope.launch { + when (val result = postLoginUseCase(user, password)) { + is LoginResult.Success -> { + mutableLogin.value = LoginState.Success( + loginDomainToUiMapper.toUiLogin(result.data) + ) + } + + is LoginResult.Error -> { + mutableLogin.value = LoginState.Error + } + + else -> { + mutableLogin.value = LoginState.CheckFieldError + } + + } + } + } + + fun getLocalUserSaved() { + viewModelScope.launch { + mutableLocalUser.value = getLocalUserUseCase().first() + } + } + +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/mapper/BankStatementDomainToUiMapper.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/mapper/BankStatementDomainToUiMapper.kt new file mode 100644 index 000000000..15a66bb2d --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/mapper/BankStatementDomainToUiMapper.kt @@ -0,0 +1,17 @@ +package com.nandoligeiro.safrando.presentation.statements.mapper + +import com.nandoligeiro.safrando.domain.statements.model.BankStatementDomain +import com.nandoligeiro.safrando.presentation.statements.model.UiStatementModel + +class BankStatementDomainToUiMapper { + + fun toUiBankStatement(statements: List) = + statements.map { statement -> + UiStatementModel( + nameStatement = statement.nameStatement, + description = statement.description, + amount = statement.amount, + statementDate = statement.statementDate + ) + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/model/UiStatementModel.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/model/UiStatementModel.kt new file mode 100644 index 000000000..a10dfc6bb --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/model/UiStatementModel.kt @@ -0,0 +1,8 @@ +package com.nandoligeiro.safrando.presentation.statements.model + +data class UiStatementModel( + val nameStatement: String = "" , + val description: String = "", + val amount: String = "", + val statementDate: String = "" +) diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/state/UiState.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/state/UiState.kt new file mode 100755 index 000000000..2a8287df0 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/state/UiState.kt @@ -0,0 +1,7 @@ +package com.nandoligeiro.safrando.presentation.statements.state + +sealed class UiBankStatementState { + object Loading : UiBankStatementState() + data class Success(val data: T) : UiBankStatementState() + data class Error(val msg: String) : UiBankStatementState() +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/view/StatementActivity.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/view/StatementActivity.kt new file mode 100644 index 000000000..4c62df114 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/view/StatementActivity.kt @@ -0,0 +1,103 @@ +package com.nandoligeiro.safrando.presentation.statements.view + +import android.os.Build +import android.os.Bundle +import android.view.View +import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import com.nandoligeiro.safrando.databinding.ActivityStatementBinding +import com.nandoligeiro.safrando.presentation.common.Constants +import com.nandoligeiro.safrando.presentation.statements.state.UiBankStatementState +import com.nandoligeiro.safrando.presentation.login.model.UiLoginModel +import com.nandoligeiro.safrando.presentation.statements.model.UiStatementModel +import com.nandoligeiro.safrando.presentation.statements.view.adapter.BankStatementsAdapter +import com.nandoligeiro.safrando.presentation.statements.viewmodel.StatementViewModel +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch + +@AndroidEntryPoint +class StatementActivity : AppCompatActivity() { + + private lateinit var binding: ActivityStatementBinding + private val viewModel: StatementViewModel by viewModels() + private val bankStatementsAdapter by lazy { BankStatementsAdapter() } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityStatementBinding.inflate(layoutInflater) + setContentView(binding.root) + + bindView() + setRecyclerView() + observeVMEvents() + getBankStatement() + } + + private fun setRecyclerView() { + binding.recyclerView.run { + adapter = bankStatementsAdapter + layoutManager = LinearLayoutManager(this@StatementActivity) + isNestedScrollingEnabled = false + setHasFixedSize(false) + } + } + + private fun getBankStatement() { + getUiLoginModelExtra()?.let { + viewModel.getBankStatement(it.id) + } + } + + private fun observeVMEvents() { + lifecycleScope.launch { + viewModel.bankStatement.collect { uiState -> + when (uiState) { + is UiBankStatementState.Loading -> { + showLoading() + } + + is UiBankStatementState.Success -> { + notifyAdapter(uiState.data) + } + + is UiBankStatementState.Error -> { + //handleError() + } + } + } + } + } + + private fun getUiLoginModelExtra() = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + intent.getParcelableExtra(Constants.KeyExtra.KEY_EXTRA_LOGIN, UiLoginModel::class.java) + } else { + intent.getParcelableExtra(Constants.KeyExtra.KEY_EXTRA_LOGIN) + } + + private fun bindView() { + binding.run { + getUiLoginModelExtra()?.let { userData -> + val agencyAndAccount = "${userData.agency} / ${userData.account}" + headerName.text = userData.name + account.text = agencyAndAccount + balance.text = userData.balance + } + } + } + + private fun notifyAdapter(data: List) { + hideLoading() + bankStatementsAdapter.submitList(data) + } + + private fun showLoading() { + binding.userListProgressBar.visibility = View.VISIBLE + } + + private fun hideLoading() { + binding.userListProgressBar.visibility = View.GONE + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/view/adapter/BankStatementItemViewHolder.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/view/adapter/BankStatementItemViewHolder.kt new file mode 100755 index 000000000..c147e5719 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/view/adapter/BankStatementItemViewHolder.kt @@ -0,0 +1,30 @@ +package com.nandoligeiro.safrando.presentation.statements.view.adapter + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.nandoligeiro.safrando.databinding.StatementCardBinding +import com.nandoligeiro.safrando.presentation.statements.model.UiStatementModel + + +class BankStatementItemViewHolder( + private val binding: StatementCardBinding +) : RecyclerView.ViewHolder(binding.root) { + + companion object { + fun create(parent: ViewGroup): BankStatementItemViewHolder { + val binding = + StatementCardBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return BankStatementItemViewHolder(binding) + } + } + + fun bind(bankStatement: UiStatementModel) { + binding.run { + type.text = bankStatement.nameStatement + description.text = bankStatement.description + date.text = bankStatement.statementDate + amount.text = bankStatement.amount + } + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/view/adapter/BankStatementsAdapter.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/view/adapter/BankStatementsAdapter.kt new file mode 100755 index 000000000..eb70383f5 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/view/adapter/BankStatementsAdapter.kt @@ -0,0 +1,29 @@ +package com.nandoligeiro.safrando.presentation.statements.view.adapter + +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import com.nandoligeiro.safrando.presentation.statements.model.UiStatementModel + +class BankStatementsAdapter : + ListAdapter(DIFF_CALLBACK) { + companion object { + val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame( + oldItem: UiStatementModel, newItem: UiStatementModel + ) = oldItem.nameStatement == newItem.nameStatement + + override fun areContentsTheSame( + oldItem: UiStatementModel, newItem: UiStatementModel + ) = oldItem == newItem + } + } + + override fun onCreateViewHolder( + parent: ViewGroup, viewType: Int + ) = BankStatementItemViewHolder.create(parent) + + override fun onBindViewHolder(holder: BankStatementItemViewHolder, position: Int) { + holder.bind(getItem(position)) + } +} diff --git a/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/viewmodel/StatementViewModel.kt b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/viewmodel/StatementViewModel.kt new file mode 100644 index 000000000..48e51bec1 --- /dev/null +++ b/Safrando/app/src/main/java/com/nandoligeiro/safrando/presentation/statements/viewmodel/StatementViewModel.kt @@ -0,0 +1,43 @@ +package com.nandoligeiro.safrando.presentation.statements.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.nandoligeiro.safrando.domain.result.DomainResult +import com.nandoligeiro.safrando.domain.statements.usecase.GetBankStatementUseCase +import com.nandoligeiro.safrando.presentation.statements.mapper.BankStatementDomainToUiMapper +import com.nandoligeiro.safrando.presentation.statements.model.UiStatementModel +import com.nandoligeiro.safrando.presentation.statements.state.UiBankStatementState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class StatementViewModel @Inject constructor( + private val getBankStatementUseCase: GetBankStatementUseCase, + private val bankStatementDomainToUiMapper: BankStatementDomainToUiMapper +) : ViewModel() { + + private val mutableBankStatement = + MutableStateFlow>>(UiBankStatementState.Loading) + val bankStatement: StateFlow>> get() = mutableBankStatement + + fun getBankStatement(userId: Int) { + viewModelScope.launch { + + when (val result = getBankStatementUseCase(userId)) { + is DomainResult.Success -> { + mutableBankStatement.value = UiBankStatementState.Success( + bankStatementDomainToUiMapper.toUiBankStatement(result.data) + ) + } + + else -> { + mutableBankStatement.value = UiBankStatementState.Error("$result") + + } + } + } + } +} diff --git a/Safrando/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Safrando/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..2b068d114 --- /dev/null +++ b/Safrando/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Safrando/app/src/main/res/drawable/ic_launcher_background.xml b/Safrando/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..07d5da9cb --- /dev/null +++ b/Safrando/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Safrando/app/src/main/res/drawable/rounded_shape.xml b/Safrando/app/src/main/res/drawable/rounded_shape.xml new file mode 100644 index 000000000..7914e98e6 --- /dev/null +++ b/Safrando/app/src/main/res/drawable/rounded_shape.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/Safrando/app/src/main/res/layout/activity_login.xml b/Safrando/app/src/main/res/layout/activity_login.xml new file mode 100644 index 000000000..3fee3ec32 --- /dev/null +++ b/Safrando/app/src/main/res/layout/activity_login.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + +