From 5d0fa31de3f92ccc67d25000c8edef33451fee90 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sat, 12 Mar 2022 23:43:35 -0300 Subject: [PATCH 01/32] add textView, rename id --- ...tivity_main.xml => activity_user_list.xml} | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) rename app/src/main/res/layout/{activity_main.xml => activity_user_list.xml} (65%) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_user_list.xml similarity index 65% rename from app/src/main/res/layout/activity_main.xml rename to app/src/main/res/layout/activity_user_list.xml index 487ac549e..80b8a81ae 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_user_list.xml @@ -5,7 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorPrimaryDark" - tools:context=".MainActivity"> + tools:context=".ui.UserListActivity"> + android:layout_height="match_parent"> + + + + app:layout_constraintEnd_toEndOf="@+id/user_list_recyclerView" + app:layout_constraintStart_toStartOf="@+id/user_list_recyclerView" + app:layout_constraintTop_toTopOf="@+id/user_list_recyclerView" + app:layout_constraintVertical_bias="0.52" /> From 659c90612970353619039ca8dabb15a355995250 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sat, 12 Mar 2022 23:45:33 -0300 Subject: [PATCH 02/32] create dependencies using koin --- .../picpay/desafio/android/AppApplication.kt | 20 +++++ .../picpay/desafio/android/di/AppModule.kt | 83 +++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 app/src/main/java/com/picpay/desafio/android/AppApplication.kt create mode 100644 app/src/main/java/com/picpay/desafio/android/di/AppModule.kt diff --git a/app/src/main/java/com/picpay/desafio/android/AppApplication.kt b/app/src/main/java/com/picpay/desafio/android/AppApplication.kt new file mode 100644 index 000000000..4d5482b88 --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/AppApplication.kt @@ -0,0 +1,20 @@ +package com.picpay.desafio.android + +import android.app.Application +import com.picpay.desafio.android.di.appModules +import org.koin.android.ext.koin.androidContext +import org.koin.android.ext.koin.androidLogger +import org.koin.core.context.startKoin + +class AppApplication : Application() { + override fun onCreate() { + super.onCreate() + + startKoin { + androidContext(this@AppApplication) + androidLogger() + modules(appModules) + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/android/di/AppModule.kt b/app/src/main/java/com/picpay/desafio/android/di/AppModule.kt new file mode 100644 index 000000000..980c4128a --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/di/AppModule.kt @@ -0,0 +1,83 @@ +package com.picpay.desafio.android.di + +import androidx.room.Room +import com.picpay.desafio.android.database.dao.UserDao +import com.picpay.desafio.android.database.UserDatabase +import com.picpay.desafio.android.repository.local.UserLocalDataSource +import com.picpay.desafio.android.repository.local.UserLocalDataSourceImp +import com.picpay.desafio.android.repository.remote.UserRemoteDataSource +import com.picpay.desafio.android.repository.remote.UserRemoteDataSourceImp +import com.picpay.desafio.android.repository.UserRepository +import com.picpay.desafio.android.repository.UserRepositoryImp +import com.picpay.desafio.android.ui.UserListViewModel +import com.picpay.desafio.android.repository.remote.webclient.PicPayService +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.dsl.module +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +private val URL_BASE = "https://609a908e0f5a13001721b74e.mockapi.io/picpay/api/" +private const val NOME_BANCO_DE_DADOS = "user.db" + +val retrofitModule = module { + single { + Retrofit.Builder() + .baseUrl(URL_BASE) + .client(get()) + .addConverterFactory(GsonConverterFactory.create()) + .build() + } + + single { get().create(PicPayService::class.java) } + + single { + val logging = HttpLoggingInterceptor() + logging.level = HttpLoggingInterceptor.Level.BODY + OkHttpClient.Builder() + .addInterceptor(logging) + .build() + } +} + +val databaseModule = module { + single { + Room.databaseBuilder( + get(), + UserDatabase::class.java, + NOME_BANCO_DE_DADOS + ).build() + } +} + +val daoModule = module { +single { get().userDao()} +} + +val viewModule = module { + viewModel { UserListViewModel(get())} +} + +val repositoryModule = module { + single { UserRepositoryImp(get(), get())} +} + +val localModule = module { + single { UserLocalDataSourceImp(get())} +} + +val remoteModule = module { + single { UserRemoteDataSourceImp(get())} +} + +val appModules = listOf( + retrofitModule, + viewModule, + repositoryModule, + daoModule, + databaseModule, + localModule, + remoteModule +) + From fbbc274b3a623b288cc8626d2f50c19ef8c6ab0d Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sat, 12 Mar 2022 23:46:27 -0300 Subject: [PATCH 03/32] add dependencies in the project --- app/build.gradle | 11 +++++++++++ build.gradle | 1 + 2 files changed, 12 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index a7fbdc0e9..073069b5e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -89,4 +89,15 @@ dependencies { androidTestImplementation "androidx.test:runner:$test_runner_version" androidTestImplementation "androidx.test.espresso:espresso-core:$espresso_version" androidTestImplementation "androidx.test:core-ktx:$core_ktx_test_version" + + implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1' + + def room_version = "2.4.2" + implementation "androidx.room:room-runtime:$room_version" + kapt "androidx.room:room-compiler:2.4.2" + annotationProcessor "androidx.room:room-compiler:2.4.2" + + testImplementation "io.mockk:mockk:1.11.0" + + testImplementation 'org.hamcrest:hamcrest-all:1.3' } diff --git a/build.gradle b/build.gradle index 7d1b94f34..f07ec2e6e 100644 --- a/build.gradle +++ b/build.gradle @@ -34,6 +34,7 @@ buildscript { repositories { google() jcenter() + mavenCentral() } dependencies { From 44c1abdf4399f189e158ca347844dfb25cd0096f Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sat, 12 Mar 2022 23:47:20 -0300 Subject: [PATCH 04/32] add AppApplication --- app/src/main/AndroidManifest.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7bdf2ce38..94a6ad7a9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ - + From e8fde667a4cfcc0628634a08559d43a1b2a2aa71 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sat, 12 Mar 2022 23:48:50 -0300 Subject: [PATCH 05/32] project downloaded file --- .idea/compiler.xml | 6 ++++++ .idea/jarRepositories.xml | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 .idea/compiler.xml create mode 100644 .idea/jarRepositories.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 000000000..61a9130cd --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ 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 From f6165ba6ab93df9e10f7e8318f48e4836cd16e46 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sat, 12 Mar 2022 23:50:41 -0300 Subject: [PATCH 06/32] class example downloaded from project --- app/src/test/java/com/picpay/desafio/android/ExampleService.kt | 3 +++ .../test/java/com/picpay/desafio/android/ExampleServiceTest.kt | 2 ++ 2 files changed, 5 insertions(+) diff --git a/app/src/test/java/com/picpay/desafio/android/ExampleService.kt b/app/src/test/java/com/picpay/desafio/android/ExampleService.kt index 0199c5e4a..2d8413b35 100644 --- a/app/src/test/java/com/picpay/desafio/android/ExampleService.kt +++ b/app/src/test/java/com/picpay/desafio/android/ExampleService.kt @@ -1,5 +1,8 @@ package com.picpay.desafio.android +import com.picpay.desafio.android.repository.model.User +import com.picpay.desafio.android.repository.remote.webclient.PicPayService + class ExampleService( private val service: PicPayService ) { diff --git a/app/src/test/java/com/picpay/desafio/android/ExampleServiceTest.kt b/app/src/test/java/com/picpay/desafio/android/ExampleServiceTest.kt index 843c0e776..c80af1fb6 100644 --- a/app/src/test/java/com/picpay/desafio/android/ExampleServiceTest.kt +++ b/app/src/test/java/com/picpay/desafio/android/ExampleServiceTest.kt @@ -2,6 +2,8 @@ package com.picpay.desafio.android import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.whenever +import com.picpay.desafio.android.repository.model.User +import com.picpay.desafio.android.repository.remote.webclient.PicPayService import junit.framework.Assert.assertEquals import org.junit.Test import retrofit2.Call From 0da5e8eb11d11ac50dea42f28852d1dde99d6d14 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sat, 12 Mar 2022 23:53:58 -0300 Subject: [PATCH 07/32] project downloaded files --- .idea/codeStyles/Project.xml | 3 --- .idea/gradle.xml | 2 ++ .idea/misc.xml | 10 +++++++++- .idea/runConfigurations.xml | 12 ------------ app/src/main/res/values/strings.xml | 1 + 5 files changed, 12 insertions(+), 16 deletions(-) delete mode 100644 .idea/runConfigurations.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 45b565415..88ea3aa1e 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,8 +1,5 @@ - - diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 7ac24c777..526b4c25c 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,8 +1,10 @@ + - + + + + diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 7f68460d8..000000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 39df3169e..555d2d856 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,5 +2,6 @@ PicPay Contatos Ocorreu um erro. Tente novamente. + Lista de contatos vazia From fe368283ba4c1686a2aeaea336eb466389faa52c Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sat, 12 Mar 2022 23:54:57 -0300 Subject: [PATCH 08/32] rename activity --- .../desafio/android/MainActivityTest.kt | 5 +- .../picpay/desafio/android/MainActivity.kt | 75 ------------------- 2 files changed, 3 insertions(+), 77 deletions(-) delete mode 100644 app/src/main/java/com/picpay/desafio/android/MainActivity.kt diff --git a/app/src/androidTest/java/com/picpay/desafio/android/MainActivityTest.kt b/app/src/androidTest/java/com/picpay/desafio/android/MainActivityTest.kt index e4a4978eb..50c7cb436 100644 --- a/app/src/androidTest/java/com/picpay/desafio/android/MainActivityTest.kt +++ b/app/src/androidTest/java/com/picpay/desafio/android/MainActivityTest.kt @@ -7,6 +7,7 @@ import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.platform.app.InstrumentationRegistry +import com.picpay.desafio.android.ui.UserListActivity import okhttp3.mockwebserver.Dispatcher import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer @@ -22,7 +23,7 @@ class MainActivityTest { @Test fun shouldDisplayTitle() { - launchActivity().apply { + launchActivity().apply { val expectedTitle = context.getString(R.string.title) moveToState(Lifecycle.State.RESUMED) @@ -44,7 +45,7 @@ class MainActivityTest { server.start(serverPort) - launchActivity().apply { + launchActivity().apply { // TODO("validate if list displays items returned by server") } diff --git a/app/src/main/java/com/picpay/desafio/android/MainActivity.kt b/app/src/main/java/com/picpay/desafio/android/MainActivity.kt deleted file mode 100644 index 2447de98d..000000000 --- a/app/src/main/java/com/picpay/desafio/android/MainActivity.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.picpay.desafio.android - -import android.view.View -import android.widget.ProgressBar -import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.google.gson.Gson -import com.google.gson.GsonBuilder -import okhttp3.OkHttpClient -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response -import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory - -class MainActivity : AppCompatActivity(R.layout.activity_main) { - - private lateinit var recyclerView: RecyclerView - private lateinit var progressBar: ProgressBar - private lateinit var adapter: UserListAdapter - - private val url = "https://609a908e0f5a13001721b74e.mockapi.io/picpay/api/" - - private val gson: Gson by lazy { GsonBuilder().create() } - - private val okHttp: OkHttpClient by lazy { - OkHttpClient.Builder() - .build() - } - - private val retrofit: Retrofit by lazy { - Retrofit.Builder() - .baseUrl(url) - .client(okHttp) - .addConverterFactory(GsonConverterFactory.create(gson)) - .build() - } - - private val service: PicPayService by lazy { - retrofit.create(PicPayService::class.java) - } - - override fun onResume() { - super.onResume() - - recyclerView = findViewById(R.id.recyclerView) - progressBar = findViewById(R.id.user_list_progress_bar) - - adapter = UserListAdapter() - recyclerView.adapter = adapter - recyclerView.layoutManager = LinearLayoutManager(this) - - progressBar.visibility = View.VISIBLE - service.getUsers() - .enqueue(object : Callback> { - override fun onFailure(call: Call>, t: Throwable) { - val message = getString(R.string.error) - - progressBar.visibility = View.GONE - recyclerView.visibility = View.GONE - - Toast.makeText(this@MainActivity, message, Toast.LENGTH_SHORT) - .show() - } - - override fun onResponse(call: Call>, response: Response>) { - progressBar.visibility = View.GONE - - adapter.users = response.body()!! - } - }) - } -} From 54c2f6b68ada62702a88b92c8fd68a415fd87ae5 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sat, 12 Mar 2022 23:56:13 -0300 Subject: [PATCH 09/32] refactor class user --- .../main/java/com/picpay/desafio/android/User.kt | 13 ------------- .../picpay/desafio/android/repository/model/User.kt | 13 +++++++++++++ .../remote/webclient}/PicPayService.kt | 3 ++- 3 files changed, 15 insertions(+), 14 deletions(-) delete mode 100644 app/src/main/java/com/picpay/desafio/android/User.kt create mode 100644 app/src/main/java/com/picpay/desafio/android/repository/model/User.kt rename app/src/main/java/com/picpay/desafio/android/{ => repository/remote/webclient}/PicPayService.kt (52%) diff --git a/app/src/main/java/com/picpay/desafio/android/User.kt b/app/src/main/java/com/picpay/desafio/android/User.kt deleted file mode 100644 index aa28171c9..000000000 --- a/app/src/main/java/com/picpay/desafio/android/User.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.picpay.desafio.android - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.android.parcel.Parcelize - -@Parcelize -data class User( - @SerializedName("img") val img: String, - @SerializedName("name") val name: String, - @SerializedName("id") val id: Int, - @SerializedName("username") val username: String -) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/android/repository/model/User.kt b/app/src/main/java/com/picpay/desafio/android/repository/model/User.kt new file mode 100644 index 000000000..ec0de15e0 --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/repository/model/User.kt @@ -0,0 +1,13 @@ +package com.picpay.desafio.android.repository.model + +import android.os.Parcelable +import com.google.gson.annotations.SerializedName +import kotlinx.android.parcel.Parcelize + +@Parcelize +data class User( + @SerializedName("img") val img: String?, + @SerializedName("name") val name: String?, + @SerializedName("id") val id: Int?, + @SerializedName("username") val username: String? +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/android/PicPayService.kt b/app/src/main/java/com/picpay/desafio/android/repository/remote/webclient/PicPayService.kt similarity index 52% rename from app/src/main/java/com/picpay/desafio/android/PicPayService.kt rename to app/src/main/java/com/picpay/desafio/android/repository/remote/webclient/PicPayService.kt index c26edac1f..68f7ba87b 100644 --- a/app/src/main/java/com/picpay/desafio/android/PicPayService.kt +++ b/app/src/main/java/com/picpay/desafio/android/repository/remote/webclient/PicPayService.kt @@ -1,5 +1,6 @@ -package com.picpay.desafio.android +package com.picpay.desafio.android.repository.remote.webclient +import com.picpay.desafio.android.repository.model.User import retrofit2.Call import retrofit2.http.GET From e49ccd9a49d3ff9fbc73104e321fcd48daa0d271 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sat, 12 Mar 2022 23:57:02 -0300 Subject: [PATCH 10/32] create database and dao --- .../desafio/android/database/UserDatabase.kt | 15 +++++++++++++++ .../desafio/android/database/dao/UserDao.kt | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 app/src/main/java/com/picpay/desafio/android/database/UserDatabase.kt create mode 100644 app/src/main/java/com/picpay/desafio/android/database/dao/UserDao.kt diff --git a/app/src/main/java/com/picpay/desafio/android/database/UserDatabase.kt b/app/src/main/java/com/picpay/desafio/android/database/UserDatabase.kt new file mode 100644 index 000000000..4fab33f03 --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/database/UserDatabase.kt @@ -0,0 +1,15 @@ +package com.picpay.desafio.android.database + +import androidx.room.Database +import androidx.room.RoomDatabase +import com.picpay.desafio.android.database.dao.UserDao +import com.picpay.desafio.android.repository.model.UserLocal + +@Database(entities = [UserLocal::class], version = 1, exportSchema = false) +abstract class UserDatabase : RoomDatabase() { + + abstract fun userDao() : UserDao + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/android/database/dao/UserDao.kt b/app/src/main/java/com/picpay/desafio/android/database/dao/UserDao.kt new file mode 100644 index 000000000..7afc82483 --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/database/dao/UserDao.kt @@ -0,0 +1,17 @@ +package com.picpay.desafio.android.database.dao +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy.REPLACE +import androidx.room.Query +import com.picpay.desafio.android.repository.model.UserLocal + +@Dao +interface UserDao { + + @Insert(onConflict = REPLACE) + fun insert(user: List) + + @Query("SELECT * from userlocal ") + fun getUser() : LiveData?> +} \ No newline at end of file From 8787f7ff64287afa4acdade4ca9aff929c0a2824 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sat, 12 Mar 2022 23:57:45 -0300 Subject: [PATCH 11/32] create activity and adapter --- .../desafio/android/ui/UserListActivity.kt | 67 ++++++++++++++++ .../android/ui/adapter/UserListAdapter.kt | 76 +++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 app/src/main/java/com/picpay/desafio/android/ui/UserListActivity.kt create mode 100644 app/src/main/java/com/picpay/desafio/android/ui/adapter/UserListAdapter.kt diff --git a/app/src/main/java/com/picpay/desafio/android/ui/UserListActivity.kt b/app/src/main/java/com/picpay/desafio/android/ui/UserListActivity.kt new file mode 100644 index 000000000..f80fcf2cd --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/ui/UserListActivity.kt @@ -0,0 +1,67 @@ +package com.picpay.desafio.android.ui + +import android.view.View +import android.widget.ProgressBar +import android.widget.TextView +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.RecyclerView +import com.picpay.desafio.android.R +import com.picpay.desafio.android.ui.adapter.UserListAdapter +import com.picpay.desafio.android.repository.model.UserResponse +import org.koin.androidx.viewmodel.ext.android.viewModel + +class UserListActivity : AppCompatActivity(R.layout.activity_user_list) { + + private lateinit var recyclerView: RecyclerView + private val progressBar by lazy { + findViewById(R.id.user_list_progress_bar) + } + private val userListEmpty by lazy { + findViewById(R.id.user_list_empty) + } + private lateinit var adapter: UserListAdapter + private val viewModel: UserListViewModel by viewModel() + + override fun onResume() { + super.onResume() + configureRecyclerView() + getUsers() + } + + private fun getUsers() { + tryLoadListaLocal() + tryLoadListaApi() + } + + private fun tryLoadListaLocal() { + viewModel.getUser().observe(this, Observer { + if (it.isNullOrEmpty()) { + userListEmpty.visibility = View.VISIBLE + userListEmpty.text = getString(R.string.listaVazia) + } else { + adapter.differ.submitList(it) + } + }) + } + + private fun tryLoadListaApi() { + viewModel.liveData.observe(this, Observer { + when (it) { + is UserResponse.Failure -> { + progressBar.visibility = View.GONE + Toast.makeText(this, it.error, Toast.LENGTH_LONG).show() + } + is UserResponse.Loading -> progressBar.visibility = View.VISIBLE + is UserResponse.Success -> progressBar.visibility = View.GONE + } + }) + } + + private fun configureRecyclerView() { + recyclerView = findViewById(R.id.user_list_recyclerView) + adapter = UserListAdapter() + recyclerView.adapter = adapter + } +} diff --git a/app/src/main/java/com/picpay/desafio/android/ui/adapter/UserListAdapter.kt b/app/src/main/java/com/picpay/desafio/android/ui/adapter/UserListAdapter.kt new file mode 100644 index 000000000..d83a1b550 --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/ui/adapter/UserListAdapter.kt @@ -0,0 +1,76 @@ +package com.picpay.desafio.android.ui.adapter + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.AsyncListDiffer +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView +import com.picpay.desafio.android.R +import com.picpay.desafio.android.repository.model.UserLocal +import com.squareup.picasso.Callback +import com.squareup.picasso.Picasso +import kotlinx.android.synthetic.main.list_item_user.view.* + +class UserListAdapter : RecyclerView.Adapter() { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder { + return ArticleViewHolder( + LayoutInflater.from(parent.context).inflate(R.layout.list_item_user, parent, false) + ) + } + + override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) { + + val user = differ.currentList[position] + holder.bind(user) + } + + override fun getItemCount(): Int { + return differ.currentList.size + } + + inner class ArticleViewHolder(itemVew: View) : RecyclerView.ViewHolder(itemVew) { + + fun bind(user: UserLocal) { + showName(user) + configureImage(user) + } + + private fun configureImage(user: UserLocal) { + itemView.progressBar.visibility = View.VISIBLE + Picasso.get() + .load(user.img) + .error(R.drawable.ic_round_account_circle) + .into(itemView.picture, object : Callback { + override fun onSuccess() { + itemView.progressBar.visibility = View.GONE + } + + override fun onError(e: Exception?) { + itemView.progressBar.visibility = View.GONE + } + }) + } + + private fun showName(user: UserLocal) { + itemView.name.text = user.name + itemView.username.text = user.username + } + } + + + private val differCallback = object : DiffUtil.ItemCallback() { + + override fun areItemsTheSame(oldItem: UserLocal, newItem: UserLocal): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: UserLocal, newItem: UserLocal): Boolean { + return oldItem.equals(newItem) + } + + } + + val differ = AsyncListDiffer(this, differCallback) +} From d170ff323195d58e8e436cce3215555f658af20e Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sat, 12 Mar 2022 23:58:37 -0300 Subject: [PATCH 12/32] remove class no used --- .../picpay/desafio/android/UserListAdapter.kt | 34 ------------------- .../desafio/android/UserListDiffCallback.kt | 26 -------------- .../desafio/android/UserListItemViewHolder.kt | 30 ---------------- 3 files changed, 90 deletions(-) delete mode 100644 app/src/main/java/com/picpay/desafio/android/UserListAdapter.kt delete mode 100644 app/src/main/java/com/picpay/desafio/android/UserListDiffCallback.kt delete mode 100644 app/src/main/java/com/picpay/desafio/android/UserListItemViewHolder.kt diff --git a/app/src/main/java/com/picpay/desafio/android/UserListAdapter.kt b/app/src/main/java/com/picpay/desafio/android/UserListAdapter.kt deleted file mode 100644 index 538c98a4a..000000000 --- a/app/src/main/java/com/picpay/desafio/android/UserListAdapter.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.picpay.desafio.android - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.RecyclerView - -class UserListAdapter : RecyclerView.Adapter() { - - var users = emptyList() - set(value) { - val result = DiffUtil.calculateDiff( - UserListDiffCallback( - field, - value - ) - ) - result.dispatchUpdatesTo(this) - field = value - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserListItemViewHolder { - val view = LayoutInflater.from(parent.context) - .inflate(R.layout.list_item_user, parent, false) - - return UserListItemViewHolder(view) - } - - override fun onBindViewHolder(holder: UserListItemViewHolder, position: Int) { - holder.bind(users[position]) - } - - override fun getItemCount(): Int = users.size -} \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/android/UserListDiffCallback.kt b/app/src/main/java/com/picpay/desafio/android/UserListDiffCallback.kt deleted file mode 100644 index 7c734d37b..000000000 --- a/app/src/main/java/com/picpay/desafio/android/UserListDiffCallback.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.picpay.desafio.android - -import androidx.recyclerview.widget.DiffUtil -import com.picpay.desafio.android.User - -class UserListDiffCallback( - private val oldList: List, - private val newList: List -) : DiffUtil.Callback() { - - override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { - return oldList[oldItemPosition].username.equals(newList[newItemPosition].username) - } - - override fun getOldListSize(): Int { - return oldList.size - } - - override fun getNewListSize(): Int { - return newList.size - } - - override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { - return true - } -} \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/android/UserListItemViewHolder.kt b/app/src/main/java/com/picpay/desafio/android/UserListItemViewHolder.kt deleted file mode 100644 index 1d8240eb3..000000000 --- a/app/src/main/java/com/picpay/desafio/android/UserListItemViewHolder.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.picpay.desafio.android - -import android.view.View -import androidx.recyclerview.widget.RecyclerView -import com.squareup.picasso.Callback -import com.squareup.picasso.Picasso -import kotlinx.android.synthetic.main.list_item_user.view.* - -class UserListItemViewHolder( - itemView: View -) : RecyclerView.ViewHolder(itemView) { - - fun bind(user: User) { - itemView.name.text = user.name - itemView.username.text = user.username - itemView.progressBar.visibility = View.VISIBLE - Picasso.get() - .load(user.img) - .error(R.drawable.ic_round_account_circle) - .into(itemView.picture, object : Callback { - override fun onSuccess() { - itemView.progressBar.visibility = View.GONE - } - - override fun onError(e: Exception?) { - itemView.progressBar.visibility = View.GONE - } - }) - } -} \ No newline at end of file From d72f4417e1a3e10cdedb3787d779f60a9831f383 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sat, 12 Mar 2022 23:59:18 -0300 Subject: [PATCH 13/32] create viewmodel --- .../desafio/android/ui/UserListViewModel.kt | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 app/src/main/java/com/picpay/desafio/android/ui/UserListViewModel.kt diff --git a/app/src/main/java/com/picpay/desafio/android/ui/UserListViewModel.kt b/app/src/main/java/com/picpay/desafio/android/ui/UserListViewModel.kt new file mode 100644 index 000000000..871843460 --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/ui/UserListViewModel.kt @@ -0,0 +1,26 @@ +package com.picpay.desafio.android.ui + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.picpay.desafio.android.repository.model.UserLocal +import com.picpay.desafio.android.repository.UserRepository +import com.picpay.desafio.android.repository.model.UserResponse + +class UserListViewModel(private val repository: UserRepository) : ViewModel() { + + private val _userResponseLiveData = MutableLiveData(UserResponse.Loading) + val liveData: LiveData = _userResponseLiveData + + init { + repository.getUsers(success = { + _userResponseLiveData.postValue(UserResponse.Success) + }, failure = { + _userResponseLiveData.postValue(UserResponse.Failure(it)) + }) + } + + fun getUser(): LiveData?> { + return repository.getUserDao() + } +} \ No newline at end of file From 25619098c599471e11b59ee644ce892f4c56e094 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sat, 12 Mar 2022 23:59:50 -0300 Subject: [PATCH 14/32] create class userLocal --- .../desafio/android/repository/model/UserLocal.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 app/src/main/java/com/picpay/desafio/android/repository/model/UserLocal.kt diff --git a/app/src/main/java/com/picpay/desafio/android/repository/model/UserLocal.kt b/app/src/main/java/com/picpay/desafio/android/repository/model/UserLocal.kt new file mode 100644 index 000000000..b0277e0cd --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/repository/model/UserLocal.kt @@ -0,0 +1,11 @@ +package com.picpay.desafio.android.repository.model + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity +data class UserLocal(val img: String?, + @PrimaryKey + val id: Int?, + val name: String?, + val username: String?) \ No newline at end of file From f7118dc1e4620a45bff497abf3c609d9a61ff67c Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sun, 13 Mar 2022 00:00:21 -0300 Subject: [PATCH 15/32] create local data source --- .../repository/local/UserLocalDataSource.kt | 10 ++++++ .../local/UserLocalDataSourceImp.kt | 33 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 app/src/main/java/com/picpay/desafio/android/repository/local/UserLocalDataSource.kt create mode 100644 app/src/main/java/com/picpay/desafio/android/repository/local/UserLocalDataSourceImp.kt diff --git a/app/src/main/java/com/picpay/desafio/android/repository/local/UserLocalDataSource.kt b/app/src/main/java/com/picpay/desafio/android/repository/local/UserLocalDataSource.kt new file mode 100644 index 000000000..b5a13e555 --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/repository/local/UserLocalDataSource.kt @@ -0,0 +1,10 @@ +package com.picpay.desafio.android.repository.local + +import androidx.lifecycle.LiveData +import com.picpay.desafio.android.repository.model.User +import com.picpay.desafio.android.repository.model.UserLocal + +interface UserLocalDataSource { + fun insert(users: List) + fun getUser(): LiveData?> +} \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/android/repository/local/UserLocalDataSourceImp.kt b/app/src/main/java/com/picpay/desafio/android/repository/local/UserLocalDataSourceImp.kt new file mode 100644 index 000000000..d773e4a7d --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/repository/local/UserLocalDataSourceImp.kt @@ -0,0 +1,33 @@ +package com.picpay.desafio.android.repository.local + +import androidx.lifecycle.LiveData +import com.picpay.desafio.android.database.dao.UserDao +import com.picpay.desafio.android.repository.model.User +import com.picpay.desafio.android.repository.model.UserLocal +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +class UserLocalDataSourceImp(private val dao: UserDao) : UserLocalDataSource { + + override fun insert(users: List) { + CoroutineScope(Dispatchers.IO).launch { + dao.insert(convertForUserLocalList(users)) + } + } + + override fun getUser(): LiveData?> { + return dao.getUser() + } + + fun convertForUserLocalList(users: List): List { + return users.map { user -> + UserLocal( + img = user.img, + name = user.name, + id = user.id, + username = user.username + ) + } + } +} \ No newline at end of file From 7f1e6644348c222bd8eff4471d9b222e336b89fd Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sun, 13 Mar 2022 00:00:44 -0300 Subject: [PATCH 16/32] create remote data source --- .../repository/remote/UserRemoteDataSource.kt | 8 +++++ .../remote/UserRemoteDataSourceImp.kt | 32 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 app/src/main/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSource.kt create mode 100644 app/src/main/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImp.kt diff --git a/app/src/main/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSource.kt b/app/src/main/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSource.kt new file mode 100644 index 000000000..dede56a17 --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSource.kt @@ -0,0 +1,8 @@ +package com.picpay.desafio.android.repository.remote + +import com.picpay.desafio.android.repository.model.User + +interface UserRemoteDataSource { + + fun getUser(success: (List)-> Unit, failure: (String) -> Unit) +} \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImp.kt b/app/src/main/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImp.kt new file mode 100644 index 000000000..08f38b37d --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImp.kt @@ -0,0 +1,32 @@ +package com.picpay.desafio.android.repository.remote + +import com.picpay.desafio.android.repository.model.User +import com.picpay.desafio.android.repository.remote.webclient.PicPayService +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class UserRemoteDataSourceImp(private val service: PicPayService) : UserRemoteDataSource { + + override fun getUser(success: (List) -> Unit, failure: (String) -> Unit) { + val call = service.getUsers() + call.enqueue(object : Callback> { + override fun onResponse(call: Call>, response: Response>) { + if (response.isSuccessful) { + val user = response.body() + if (user != null) { + success(user) + } + }else{ + failure(response.message()) + } + } + override fun onFailure(call: Call>, t: Throwable) { + t.message?.let { + failure(it) + } + } + + }) + } +} \ No newline at end of file From ad6685d74d5ecd8e6dd0f67662c58eb54d327912 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sun, 13 Mar 2022 00:01:08 -0300 Subject: [PATCH 17/32] create test --- .../repository/UserRepositoryImpTest.kt | 58 ++++++++++++ .../local/UserLocalDataSourceImpTest.kt | 40 ++++++++ .../remote/UserRemoteDataSourceImpTest.kt | 94 +++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 app/src/test/java/com/picpay/desafio/android/repository/UserRepositoryImpTest.kt create mode 100644 app/src/test/java/com/picpay/desafio/android/repository/local/UserLocalDataSourceImpTest.kt create mode 100644 app/src/test/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImpTest.kt diff --git a/app/src/test/java/com/picpay/desafio/android/repository/UserRepositoryImpTest.kt b/app/src/test/java/com/picpay/desafio/android/repository/UserRepositoryImpTest.kt new file mode 100644 index 000000000..48d2d83fc --- /dev/null +++ b/app/src/test/java/com/picpay/desafio/android/repository/UserRepositoryImpTest.kt @@ -0,0 +1,58 @@ +package com.picpay.desafio.android.repository + +import com.picpay.desafio.android.database.dao.UserDao +import com.picpay.desafio.android.repository.local.UserLocalDataSource +import com.picpay.desafio.android.repository.local.UserLocalDataSourceImp +import com.picpay.desafio.android.repository.model.User +import com.picpay.desafio.android.repository.remote.UserRemoteDataSource +import com.picpay.desafio.android.repository.remote.UserRemoteDataSourceImp +import com.picpay.desafio.android.repository.remote.webclient.PicPayService +import io.mockk.* +import kotlinx.coroutines.runBlocking +import org.junit.Test + +class UserRepositoryImpTest { + + private var picPayServiceMock: PicPayService = mockk() + private var userDaoMock: UserDao = mockk() + + private val userRemoteDataSource: UserRemoteDataSource = spyk(UserRemoteDataSourceImp(picPayServiceMock)) + private val userLocalDataSource: UserLocalDataSource = spyk(UserLocalDataSourceImp(userDaoMock)) + + private val repository: UserRepository = spyk(UserRepositoryImp(userRemoteDataSource, userLocalDataSource)) + + @Test + fun deve_inserir_lista_quando_api_retornar_sucesso() { + val sucess: () -> Unit = {} + val sucessSlot = slot<() -> Unit>() + val failure: (String) -> Unit = {} + + every { userRemoteDataSource.getUser(success = any(), failure = any()) } answers { + firstArg<(List) -> Unit>().invoke(listOf()) + } + coEvery { userLocalDataSource.insert(any()) } answers {} + + runBlocking { repository.getUsers(success = sucess, failure = failure) } + + coVerify { userLocalDataSource.insert(any()) } + verify { repository.getUsers(success = capture(sucessSlot), failure = any()) } + + } + + @Test + fun deve_notificar_falha_quando_api_retornar_falha() { + val sucess: () -> Unit = {} + val failure: (String) -> Unit = {} + val failureSlot = slot<(String) -> Unit>() + failureSlot.captured = failure + + every { userRemoteDataSource.getUser(any(), any()) } answers { + secondArg<(String) -> Unit>().invoke("teste") + } + + runBlocking { repository.getUsers(success = sucess, failure = failure) } + + verify { repository.getUsers(success = any(), failure = capture(failureSlot)) } + + } +} \ No newline at end of file diff --git a/app/src/test/java/com/picpay/desafio/android/repository/local/UserLocalDataSourceImpTest.kt b/app/src/test/java/com/picpay/desafio/android/repository/local/UserLocalDataSourceImpTest.kt new file mode 100644 index 000000000..a10c7a55b --- /dev/null +++ b/app/src/test/java/com/picpay/desafio/android/repository/local/UserLocalDataSourceImpTest.kt @@ -0,0 +1,40 @@ +package com.picpay.desafio.android.repository.local + + +import com.picpay.desafio.android.database.dao.UserDao +import com.picpay.desafio.android.repository.model.User +import com.picpay.desafio.android.repository.model.UserLocal +import io.mockk.mockk +import org.hamcrest.Matchers.contains +import org.junit.Assert +import org.junit.Test + + +class UserLocalDataSourceImpTest { + + private val userList = arrayListOf() + private val userListLocal = arrayListOf() + private val daoMock: UserDao = mockk() + + private val userLocalDataSourceImp: UserLocalDataSourceImp = (UserLocalDataSourceImp(daoMock)) + + @Test + fun deve_devolver_lista_user_local_quando_recebe_lista_user() { + //userList.add(User(img = "", name = "Roberta", id = 1, username = "Maria")) + //userListLocal.add(UserLocal(img = "", name = "Roberta", id = 1, username = "Maria")) + + userList.add(User(img = "", name = "Roberta", id = 1, username = "Maria")) + userListLocal.add(UserLocal(img = "", name = "Roberta", id = 1, username = "Maria")) + + //every { userList. } answers { listOf(User(img = "", name = "Roberta", id = 1, username = "Maria"))} + + + val listConverted = userLocalDataSourceImp.convertForUserLocalList(userList) + +// MatcherAssert.assertThat(listConverted, CoreMatchers.both(Matchers.hasSize(1)).and( +// Matchers.contains(UserLocal(img = "", name = "Roberta", id = 1, username = "Maria")))) + + Assert.assertEquals(listConverted, contains + (UserLocal(img = "", name = "Roberta", id = 1, username = "Maria"))) + } +} \ No newline at end of file diff --git a/app/src/test/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImpTest.kt b/app/src/test/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImpTest.kt new file mode 100644 index 000000000..4a7c8c973 --- /dev/null +++ b/app/src/test/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImpTest.kt @@ -0,0 +1,94 @@ +package com.picpay.desafio.android.repository.remote + +import com.picpay.desafio.android.repository.model.User +import com.picpay.desafio.android.repository.remote.webclient.PicPayService +import io.mockk.* +import kotlinx.coroutines.runBlocking +import org.junit.Test +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class UserRemoteDataSourceImpTest{ + private var picPayServiceMock: PicPayService = mockk() + private val userRemoteDataSource: UserRemoteDataSource = spyk(UserRemoteDataSourceImp(picPayServiceMock)) + + @Test + fun deve_usar_sucesso_quando_api_retornar_sucesso() { + val success: (List) -> Unit = {} + val successSlot = slot<(List) -> Unit>() + val failure: (String) -> Unit = {} + + val callMock: Call> = mockk() + val responseMock: Response> = mockk() + + every { picPayServiceMock.getUsers() } returns callMock + every { callMock.enqueue(any()) } answers { + (args[0] as Callback>).apply { + onResponse(mockk(), responseMock) + } + } + + responseMock.apply { + every { isSuccessful } answers { true } + every { body() } returns mockk() + } + + runBlocking { userRemoteDataSource.getUser(success, failure) } + + verify { userRemoteDataSource.getUser(capture(successSlot), failure) } + } + + @Test + fun deve_notificar_falha_quando_api_retornar_falha() { + val success: (List) -> Unit = {} + val failure: (String) -> Unit = {} + val failureSlot = slot<(String) -> Unit>() + failureSlot.captured = failure + + val callMock: Call> = mockk() + val responseMock: Response> = mockk() + + every { picPayServiceMock.getUsers() } returns callMock + every { callMock.enqueue(any()) } answers { + (args[0] as Callback>).apply { + onResponse(mockk(), responseMock) + } + } + + responseMock.apply { + every { isSuccessful } answers { false } + every { message() } answers {""} + } + + runBlocking { userRemoteDataSource.getUser(success = success, failure = failure) } + + verify { userRemoteDataSource.getUser(success = any(), failure = capture(failureSlot)) } + } + + @Test + fun deve_devolver_falha_quando_api_retornar_falha(){ + val success : (List) -> Unit = {} + val failure : (String) -> Unit = {} + val failureSlot = slot<(String) -> Unit>() + failureSlot.captured = failure + + val callMock: Call> = mockk() + val failureMock: Throwable = mockk() + + every { picPayServiceMock.getUsers() } returns callMock + every { callMock.enqueue(any()) } answers { + (args[0] as Callback>).apply { + onFailure(mockk(), failureMock) + } + } + + failureMock.apply { + every { message } answers {""} + } + + runBlocking { userRemoteDataSource.getUser(success, failure) } + verify { userRemoteDataSource.getUser(any(), capture(failureSlot)) } + + } +} \ No newline at end of file From e04a56244ed676b2fccc240ee11f4d07c559c7fa Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sun, 13 Mar 2022 00:01:33 -0300 Subject: [PATCH 18/32] create repository --- .../android/repository/UserRepository.kt | 9 +++++++ .../android/repository/UserRepositoryImp.kt | 25 +++++++++++++++++++ .../android/repository/model/UserResponse.kt | 7 ++++++ 3 files changed, 41 insertions(+) create mode 100644 app/src/main/java/com/picpay/desafio/android/repository/UserRepository.kt create mode 100644 app/src/main/java/com/picpay/desafio/android/repository/UserRepositoryImp.kt create mode 100644 app/src/main/java/com/picpay/desafio/android/repository/model/UserResponse.kt diff --git a/app/src/main/java/com/picpay/desafio/android/repository/UserRepository.kt b/app/src/main/java/com/picpay/desafio/android/repository/UserRepository.kt new file mode 100644 index 000000000..c70056e0b --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/repository/UserRepository.kt @@ -0,0 +1,9 @@ +package com.picpay.desafio.android.repository + +import androidx.lifecycle.LiveData +import com.picpay.desafio.android.repository.model.UserLocal + +interface UserRepository { + fun getUsers(success: () -> Unit, failure: (String) -> Unit) + fun getUserDao(): LiveData?> +} \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/android/repository/UserRepositoryImp.kt b/app/src/main/java/com/picpay/desafio/android/repository/UserRepositoryImp.kt new file mode 100644 index 000000000..f008911fb --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/repository/UserRepositoryImp.kt @@ -0,0 +1,25 @@ +package com.picpay.desafio.android.repository + +import androidx.lifecycle.LiveData +import com.picpay.desafio.android.repository.local.UserLocalDataSource +import com.picpay.desafio.android.repository.model.UserLocal +import com.picpay.desafio.android.repository.remote.UserRemoteDataSource + +class UserRepositoryImp( + private val userRemoteDataSource: UserRemoteDataSource, + private val userLocalDataSource: UserLocalDataSource +) : UserRepository { + + override fun getUsers(success: () -> Unit, failure: (String) -> Unit) { + + userRemoteDataSource.getUser(success = { users -> + userLocalDataSource.insert(users) + success() + }, failure = failure) + + } + + override fun getUserDao(): LiveData?> { + return userLocalDataSource.getUser() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/android/repository/model/UserResponse.kt b/app/src/main/java/com/picpay/desafio/android/repository/model/UserResponse.kt new file mode 100644 index 000000000..a3f8f8951 --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/android/repository/model/UserResponse.kt @@ -0,0 +1,7 @@ +package com.picpay.desafio.android.repository.model + +sealed class UserResponse{ + object Success : UserResponse() + data class Failure (val error: String): UserResponse() + object Loading: UserResponse() +} From 90341b48959314976f7b04ac5d8c35c993e429f9 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sun, 13 Mar 2022 17:10:50 -0300 Subject: [PATCH 19/32] create test --- .../local/UserLocalDataSourceImpTest.kt | 24 ++++--------------- .../remote/UserRemoteDataSourceImpTest.kt | 8 +++---- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/app/src/test/java/com/picpay/desafio/android/repository/local/UserLocalDataSourceImpTest.kt b/app/src/test/java/com/picpay/desafio/android/repository/local/UserLocalDataSourceImpTest.kt index a10c7a55b..c289780fb 100644 --- a/app/src/test/java/com/picpay/desafio/android/repository/local/UserLocalDataSourceImpTest.kt +++ b/app/src/test/java/com/picpay/desafio/android/repository/local/UserLocalDataSourceImpTest.kt @@ -1,40 +1,24 @@ package com.picpay.desafio.android.repository.local - import com.picpay.desafio.android.database.dao.UserDao import com.picpay.desafio.android.repository.model.User import com.picpay.desafio.android.repository.model.UserLocal import io.mockk.mockk -import org.hamcrest.Matchers.contains import org.junit.Assert import org.junit.Test - class UserLocalDataSourceImpTest { - private val userList = arrayListOf() - private val userListLocal = arrayListOf() private val daoMock: UserDao = mockk() - - private val userLocalDataSourceImp: UserLocalDataSourceImp = (UserLocalDataSourceImp(daoMock)) + private val userLocalDataSourceImp: UserLocalDataSourceImp = UserLocalDataSourceImp(daoMock) @Test fun deve_devolver_lista_user_local_quando_recebe_lista_user() { - //userList.add(User(img = "", name = "Roberta", id = 1, username = "Maria")) - //userListLocal.add(UserLocal(img = "", name = "Roberta", id = 1, username = "Maria")) - - userList.add(User(img = "", name = "Roberta", id = 1, username = "Maria")) - userListLocal.add(UserLocal(img = "", name = "Roberta", id = 1, username = "Maria")) - - //every { userList. } answers { listOf(User(img = "", name = "Roberta", id = 1, username = "Maria"))} - + val userList = arrayListOf(User(img = "", name = "Roberta", id = 1, username = "Maria")) + val userListLocal = arrayListOf(UserLocal(img = "", name = "Roberta", id = 1, username = "Maria")) val listConverted = userLocalDataSourceImp.convertForUserLocalList(userList) -// MatcherAssert.assertThat(listConverted, CoreMatchers.both(Matchers.hasSize(1)).and( -// Matchers.contains(UserLocal(img = "", name = "Roberta", id = 1, username = "Maria")))) - - Assert.assertEquals(listConverted, contains - (UserLocal(img = "", name = "Roberta", id = 1, username = "Maria"))) + Assert.assertEquals(userListLocal, listConverted) } } \ No newline at end of file diff --git a/app/src/test/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImpTest.kt b/app/src/test/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImpTest.kt index 4a7c8c973..bb1d1c0a1 100644 --- a/app/src/test/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImpTest.kt +++ b/app/src/test/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImpTest.kt @@ -67,23 +67,23 @@ class UserRemoteDataSourceImpTest{ } @Test - fun deve_devolver_falha_quando_api_retornar_falha(){ + fun deve_devolver_falha_quando_a_conexao_com_a_api_falhar(){ val success : (List) -> Unit = {} val failure : (String) -> Unit = {} val failureSlot = slot<(String) -> Unit>() failureSlot.captured = failure val callMock: Call> = mockk() - val failureMock: Throwable = mockk() + val throwableMock: Throwable = mockk() every { picPayServiceMock.getUsers() } returns callMock every { callMock.enqueue(any()) } answers { (args[0] as Callback>).apply { - onFailure(mockk(), failureMock) + onFailure(mockk(), throwableMock) } } - failureMock.apply { + throwableMock.apply { every { message } answers {""} } From a4e74b37e3ec74362180ff9a58707468defb70b6 Mon Sep 17 00:00:00 2001 From: RobertaMaria <90925988+RobertaMaria@users.noreply.github.com> Date: Sun, 13 Mar 2022 19:28:26 -0300 Subject: [PATCH 20/32] Create android.yml settings CI --- .github/workflows/android.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/android.yml diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 000000000..42bb1acbf --- /dev/null +++ b/.github/workflows/android.yml @@ -0,0 +1,30 @@ +name: Android CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: set up JDK 11 + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'temurin' + cache: gradle + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build with Gradle + run: ./gradlew build + + - name: execute tests in unity + run: ./gradlew test + From b7e38026a3640aeb810e76acaafa6e830f652f48 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sun, 13 Mar 2022 20:09:44 -0300 Subject: [PATCH 21/32] update test --- .../desafio/android/repository/UserRepositoryImpTest.kt | 5 ++--- .../repository/remote/UserRemoteDataSourceImpTest.kt | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/app/src/test/java/com/picpay/desafio/android/repository/UserRepositoryImpTest.kt b/app/src/test/java/com/picpay/desafio/android/repository/UserRepositoryImpTest.kt index 48d2d83fc..bbb5a8d25 100644 --- a/app/src/test/java/com/picpay/desafio/android/repository/UserRepositoryImpTest.kt +++ b/app/src/test/java/com/picpay/desafio/android/repository/UserRepositoryImpTest.kt @@ -8,7 +8,6 @@ import com.picpay.desafio.android.repository.remote.UserRemoteDataSource import com.picpay.desafio.android.repository.remote.UserRemoteDataSourceImp import com.picpay.desafio.android.repository.remote.webclient.PicPayService import io.mockk.* -import kotlinx.coroutines.runBlocking import org.junit.Test class UserRepositoryImpTest { @@ -32,7 +31,7 @@ class UserRepositoryImpTest { } coEvery { userLocalDataSource.insert(any()) } answers {} - runBlocking { repository.getUsers(success = sucess, failure = failure) } + run { repository.getUsers(success = sucess, failure = failure) } coVerify { userLocalDataSource.insert(any()) } verify { repository.getUsers(success = capture(sucessSlot), failure = any()) } @@ -50,7 +49,7 @@ class UserRepositoryImpTest { secondArg<(String) -> Unit>().invoke("teste") } - runBlocking { repository.getUsers(success = sucess, failure = failure) } + run { repository.getUsers(success = sucess, failure = failure) } verify { repository.getUsers(success = any(), failure = capture(failureSlot)) } diff --git a/app/src/test/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImpTest.kt b/app/src/test/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImpTest.kt index bb1d1c0a1..c5da00e67 100644 --- a/app/src/test/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImpTest.kt +++ b/app/src/test/java/com/picpay/desafio/android/repository/remote/UserRemoteDataSourceImpTest.kt @@ -3,7 +3,6 @@ package com.picpay.desafio.android.repository.remote import com.picpay.desafio.android.repository.model.User import com.picpay.desafio.android.repository.remote.webclient.PicPayService import io.mockk.* -import kotlinx.coroutines.runBlocking import org.junit.Test import retrofit2.Call import retrofit2.Callback @@ -34,7 +33,7 @@ class UserRemoteDataSourceImpTest{ every { body() } returns mockk() } - runBlocking { userRemoteDataSource.getUser(success, failure) } + run { userRemoteDataSource.getUser(success, failure) } verify { userRemoteDataSource.getUser(capture(successSlot), failure) } } @@ -61,7 +60,7 @@ class UserRemoteDataSourceImpTest{ every { message() } answers {""} } - runBlocking { userRemoteDataSource.getUser(success = success, failure = failure) } + run { userRemoteDataSource.getUser(success = success, failure = failure) } verify { userRemoteDataSource.getUser(success = any(), failure = capture(failureSlot)) } } @@ -87,7 +86,7 @@ class UserRemoteDataSourceImpTest{ every { message } answers {""} } - runBlocking { userRemoteDataSource.getUser(success, failure) } + run { userRemoteDataSource.getUser(success, failure) } verify { userRemoteDataSource.getUser(any(), capture(failureSlot)) } } From e083e2ab21794e0520140b74d21b37d1728959e5 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sun, 13 Mar 2022 20:11:09 -0300 Subject: [PATCH 22/32] extend PagingDataAdapter --- .../android/ui/adapter/UserListAdapter.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/picpay/desafio/android/ui/adapter/UserListAdapter.kt b/app/src/main/java/com/picpay/desafio/android/ui/adapter/UserListAdapter.kt index d83a1b550..6cc1bb797 100644 --- a/app/src/main/java/com/picpay/desafio/android/ui/adapter/UserListAdapter.kt +++ b/app/src/main/java/com/picpay/desafio/android/ui/adapter/UserListAdapter.kt @@ -3,6 +3,7 @@ package com.picpay.desafio.android.ui.adapter import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.paging.PagingDataAdapter import androidx.recyclerview.widget.AsyncListDiffer import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView @@ -12,7 +13,7 @@ import com.squareup.picasso.Callback import com.squareup.picasso.Picasso import kotlinx.android.synthetic.main.list_item_user.view.* -class UserListAdapter : RecyclerView.Adapter() { +class UserListAdapter : PagingDataAdapter(differCallback) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder { return ArticleViewHolder( @@ -59,18 +60,17 @@ class UserListAdapter : RecyclerView.Adapter( } } + val differ = AsyncListDiffer(this, differCallback) +} - private val differCallback = object : DiffUtil.ItemCallback() { - - override fun areItemsTheSame(oldItem: UserLocal, newItem: UserLocal): Boolean { - return oldItem.id == newItem.id - } +private val differCallback = object : DiffUtil.ItemCallback() { - override fun areContentsTheSame(oldItem: UserLocal, newItem: UserLocal): Boolean { - return oldItem.equals(newItem) - } + override fun areItemsTheSame(oldItem: UserLocal, newItem: UserLocal): Boolean { + return oldItem.id == newItem.id + } + override fun areContentsTheSame(oldItem: UserLocal, newItem: UserLocal): Boolean { + return oldItem.equals(newItem) } - val differ = AsyncListDiffer(this, differCallback) } From 6edc45c5db343f8ffc7b95473ce705205c0528d4 Mon Sep 17 00:00:00 2001 From: RobertaMaria Date: Sun, 13 Mar 2022 20:12:23 -0300 Subject: [PATCH 23/32] add constraintlayout, update dependency gradle --- .idea/misc.xml | 2 ++ app/build.gradle | 4 ++++ app/src/main/res/layout/activity_user_list.xml | 10 +++++++--- build.gradle | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index db32ab146..f51a8b73c 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -8,6 +8,8 @@