diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 000000000..fb7f4a8a4
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
new file mode 100644
index 000000000..579b0c6c9
--- /dev/null
+++ b/.idea/deploymentTargetDropDown.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 7ac24c777..a9f4e522a 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -3,6 +3,7 @@
-
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 000000000..d2ce72d10
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 703e5d4b8..f00c32884 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -5,7 +5,16 @@
-
+
+
+
+
+
+
diff --git a/app/build.gradle b/app/build.gradle
index a7fbdc0e9..7e55d0130 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,17 +1,14 @@
apply plugin: 'com.android.application'
-
apply plugin: 'kotlin-android'
-
-apply plugin: 'kotlin-android-extensions'
-
+apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
android {
- compileSdkVersion 29
+ compileSdkVersion 32
defaultConfig {
applicationId "com.picpay.desafio.android"
minSdkVersion 21
- targetSdkVersion 29
+ targetSdkVersion 32
versionCode 1
versionName "1.0"
@@ -37,26 +34,23 @@ android {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
+
+ buildFeatures {
+ dataBinding true
+ viewBinding true
+ }
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
-
implementation "androidx.core:core-ktx:$core_ktx_version"
-
implementation "androidx.appcompat:appcompat:$appcompat_version"
implementation "androidx.constraintlayout:constraintlayout:$constraintlayout_version"
-
implementation "com.google.android.material:material:$material_version"
- implementation "org.koin:koin-core:$koin_version"
- implementation "org.koin:koin-android:$koin_version"
- implementation "org.koin:koin-androidx-viewmodel:$koin_version"
-
- implementation "com.google.dagger:dagger:$dagger_version"
- kapt "com.google.dagger:dagger-compiler:$dagger_version"
+ implementation "io.insert-koin:koin-android:$koin_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
@@ -69,11 +63,12 @@ dependencies {
implementation "io.reactivex.rxjava2:rxjava:$rxjava_version"
implementation "io.reactivex.rxjava2:rxandroid:$rxandroid_version"
- implementation 'com.google.code.gson:gson:2.8.6'
+ implementation 'com.google.code.gson:gson: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"
+
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
implementation "com.squareup.okhttp3:mockwebserver:$okhttp_version"
@@ -84,7 +79,6 @@ dependencies {
testImplementation "org.mockito:mockito-core:$mockito_version"
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:$mockito_kotlin_version"
testImplementation "androidx.arch.core:core-testing:$core_testing_version"
- implementation "org.koin:koin-test:$koin_version"
androidTestImplementation "androidx.test:runner:$test_runner_version"
androidTestImplementation "androidx.test.espresso:espresso-core:$espresso_version"
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..f2e1d5301 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.view.ui.MainActivity
import okhttp3.mockwebserver.Dispatcher
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7bdf2ce38..35182b63e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -6,6 +6,7 @@
-
+
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..d8116cba5
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/AppApplication.kt
@@ -0,0 +1,30 @@
+package com.picpay.desafio.android
+
+import android.app.Application
+import com.picpay.desafio.android.modules.RetrofitModule
+import com.picpay.desafio.android.modules.repositoryModule
+import com.picpay.desafio.android.modules.uiModule
+import com.picpay.desafio.android.modules.viewModelModule
+import org.koin.android.ext.koin.androidContext
+import org.koin.core.context.startKoin
+
+class AppApplication : Application() {
+ override fun onCreate() {
+ super.onCreate()
+ startKoinConfig()
+ }
+
+ private fun startKoinConfig(){
+ startKoin {
+ androidContext(this@AppApplication)
+ RetrofitModule.load()
+ modules(
+ listOf(
+ viewModelModule,
+ repositoryModule,
+ uiModule
+ )
+ )
+ }
+ }
+}
\ No newline at end of file
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()!!
- }
- })
- }
-}
diff --git a/app/src/main/java/com/picpay/desafio/android/PicPayService.kt b/app/src/main/java/com/picpay/desafio/android/PicPayService.kt
deleted file mode 100644
index c26edac1f..000000000
--- a/app/src/main/java/com/picpay/desafio/android/PicPayService.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.picpay.desafio.android
-
-import retrofit2.Call
-import retrofit2.http.GET
-
-
-interface PicPayService {
-
- @GET("users")
- fun getUsers(): Call>
-}
\ No newline at end of file
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/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
diff --git a/app/src/main/java/com/picpay/desafio/android/core/Resource.kt b/app/src/main/java/com/picpay/desafio/android/core/Resource.kt
new file mode 100644
index 000000000..a603c5410
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/core/Resource.kt
@@ -0,0 +1,7 @@
+package com.picpay.desafio.android.core
+
+sealed class Resource(val data: T? = null, val message: String? = null) {
+ class Success(data: T?): Resource(data)
+ class Error(message: String?, data: T? = null): Resource(data, message)
+ class Loading(data: T? = null): Resource(data)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/picpay/desafio/android/core/UseCase.kt b/app/src/main/java/com/picpay/desafio/android/core/UseCase.kt
new file mode 100644
index 000000000..79bf14c6d
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/core/UseCase.kt
@@ -0,0 +1,5 @@
+package com.picpay.desafio.android.core
+
+abstract class UseCase {
+ abstract suspend fun execute(): Source
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/picpay/desafio/android/data/response/User.kt b/app/src/main/java/com/picpay/desafio/android/data/response/User.kt
new file mode 100644
index 000000000..cab8e2292
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/data/response/User.kt
@@ -0,0 +1,14 @@
+package com.picpay.desafio.android.data.response
+
+import com.google.gson.annotations.SerializedName
+
+data class User(
+ @SerializedName("img")
+ val img: String,
+ @SerializedName("name")
+ val name: String,
+ @SerializedName("id")
+ val id: Int,
+ @SerializedName("username")
+ val username: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/picpay/desafio/android/data/service/PicPayService.kt b/app/src/main/java/com/picpay/desafio/android/data/service/PicPayService.kt
new file mode 100644
index 000000000..de1b29d1f
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/data/service/PicPayService.kt
@@ -0,0 +1,10 @@
+package com.picpay.desafio.android.data.service
+
+import com.picpay.desafio.android.data.response.User
+import retrofit2.http.GET
+
+
+interface PicPayService {
+ @GET("users")
+ suspend fun getUsers(): List
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/picpay/desafio/android/data/source/UserSource.kt b/app/src/main/java/com/picpay/desafio/android/data/source/UserSource.kt
new file mode 100644
index 000000000..3a0e2c96c
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/data/source/UserSource.kt
@@ -0,0 +1,10 @@
+package com.picpay.desafio.android.data.source
+
+import com.picpay.desafio.android.data.response.User
+import com.picpay.desafio.android.data.service.PicPayService
+
+class UserSource(private val picPayService: PicPayService) {
+ suspend fun load(): List {
+ return picPayService.getUsers()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/picpay/desafio/android/domain/repository/GetUserCase.kt b/app/src/main/java/com/picpay/desafio/android/domain/repository/GetUserCase.kt
new file mode 100644
index 000000000..e1f08c110
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/domain/repository/GetUserCase.kt
@@ -0,0 +1,8 @@
+package com.picpay.desafio.android.domain.repository
+
+import com.picpay.desafio.android.core.UseCase
+import com.picpay.desafio.android.data.response.User
+
+class GetUserCase(private val repository: PicPayRepository) : UseCase>() {
+ override suspend fun execute(): List = repository.getUsers()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/picpay/desafio/android/domain/repository/PicPayRepository.kt b/app/src/main/java/com/picpay/desafio/android/domain/repository/PicPayRepository.kt
new file mode 100644
index 000000000..90fc8d6c0
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/domain/repository/PicPayRepository.kt
@@ -0,0 +1,7 @@
+package com.picpay.desafio.android.domain.repository
+
+import com.picpay.desafio.android.data.response.User
+
+interface PicPayRepository {
+ suspend fun getUsers() : List
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/picpay/desafio/android/domain/repository/PicPayRepositoryImpl.kt b/app/src/main/java/com/picpay/desafio/android/domain/repository/PicPayRepositoryImpl.kt
new file mode 100644
index 000000000..5295292db
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/domain/repository/PicPayRepositoryImpl.kt
@@ -0,0 +1,17 @@
+package com.picpay.desafio.android.domain.repository
+
+import com.picpay.desafio.android.data.response.User
+import com.picpay.desafio.android.data.service.PicPayService
+import com.picpay.desafio.android.data.source.UserSource
+import java.lang.Exception
+
+class PicPayRepositoryImpl(private val picPayService: PicPayService): PicPayRepository {
+
+ override suspend fun getUsers(): List {
+ return try {
+ UserSource(picPayService).load()
+ }catch (e: Exception){
+ throw e
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/picpay/desafio/android/modules/AppModules.kt b/app/src/main/java/com/picpay/desafio/android/modules/AppModules.kt
new file mode 100644
index 000000000..2a9d49247
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/modules/AppModules.kt
@@ -0,0 +1,19 @@
+package com.picpay.desafio.android.modules
+
+import com.picpay.desafio.android.domain.repository.GetUserCase
+import com.picpay.desafio.android.view.ui.MainActivity
+import com.picpay.desafio.android.view.viewModel.ListUsersViewModel
+import org.koin.androidx.viewmodel.dsl.viewModel
+import org.koin.dsl.module
+
+val viewModelModule = module {
+ viewModel { ListUsersViewModel(get()) }
+}
+
+val repositoryModule = module {
+ single { GetUserCase(get()) }
+}
+
+val uiModule = module {
+ factory { MainActivity() }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/picpay/desafio/android/modules/RetrofitModule.kt b/app/src/main/java/com/picpay/desafio/android/modules/RetrofitModule.kt
new file mode 100644
index 000000000..9bfbabfec
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/modules/RetrofitModule.kt
@@ -0,0 +1,51 @@
+package com.picpay.desafio.android.modules
+
+import com.google.gson.GsonBuilder
+import com.picpay.desafio.android.data.service.PicPayService
+import com.picpay.desafio.android.domain.repository.PicPayRepository
+import com.picpay.desafio.android.domain.repository.PicPayRepositoryImpl
+import okhttp3.OkHttpClient
+import org.koin.core.context.loadKoinModules
+import org.koin.core.module.Module
+import org.koin.dsl.module
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+
+object RetrofitModule {
+ private const val URL = "https://609a908e0f5a13001721b74e.mockapi.io/picpay/api/"
+ private val gsonBuilder = GsonBuilder()
+
+ fun load() {
+ loadKoinModules(repositoryModule() + networkModule())
+ }
+
+ private fun repositoryModule(): Module {
+ return module {
+ single { PicPayRepositoryImpl(get()) }
+ }
+ }
+
+ private fun networkModule(): Module {
+ return module {
+ single { createService(URL, get()) }
+ single { createOkHttpBuilder() }
+ }
+ }
+
+ private inline fun createService(
+ url: String,
+ client: OkHttpClient
+ ): T {
+ return Retrofit.Builder()
+ .baseUrl(url)
+ .addConverterFactory(GsonConverterFactory.create(gsonBuilder.create()))
+ .client(client)
+ .build()
+ .create(T::class.java)
+ }
+
+ private fun createOkHttpBuilder(): OkHttpClient {
+ return OkHttpClient.Builder()
+ .build()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/picpay/desafio/android/view/adapter/UserListAdapter.kt b/app/src/main/java/com/picpay/desafio/android/view/adapter/UserListAdapter.kt
new file mode 100644
index 000000000..e22579da8
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/view/adapter/UserListAdapter.kt
@@ -0,0 +1,21 @@
+package com.picpay.desafio.android.view.adapter
+
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.picpay.desafio.android.data.response.User
+import com.picpay.desafio.android.view.viewHolder.UserListItemViewHolder
+
+class UserListAdapter(private var results: List) : RecyclerView.Adapter() {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserListItemViewHolder {
+ return UserListItemViewHolder.inflate(parent)
+ }
+
+ override fun onBindViewHolder(holder: UserListItemViewHolder, position: Int) {
+ holder.bind(results[position])
+ }
+
+ override fun getItemCount(): Int {
+ return results.size
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/picpay/desafio/android/view/ui/MainActivity.kt b/app/src/main/java/com/picpay/desafio/android/view/ui/MainActivity.kt
new file mode 100644
index 000000000..82cacec3d
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/view/ui/MainActivity.kt
@@ -0,0 +1,73 @@
+package com.picpay.desafio.android.view.ui
+
+import android.os.Bundle
+import android.view.View
+import androidx.appcompat.app.AppCompatActivity
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.picpay.desafio.android.core.Resource
+import com.picpay.desafio.android.data.response.User
+import com.picpay.desafio.android.databinding.ActivityMainBinding
+import com.picpay.desafio.android.view.adapter.UserListAdapter
+import com.picpay.desafio.android.view.viewModel.ListUsersViewModel
+import org.koin.androidx.viewmodel.ext.android.viewModel
+
+class MainActivity : AppCompatActivity() {
+
+ private lateinit var adapter: UserListAdapter
+ private lateinit var binding: ActivityMainBinding
+ private val viewModel: ListUsersViewModel by viewModel()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ val view = binding.root
+
+ binding.viewModel = viewModel
+ setContentView(view)
+ }
+
+ override fun onResume() {
+ super.onResume()
+ initObservers()
+ }
+
+ private fun initObservers() {
+ viewModel.allUsers.observe(this) { state ->
+ when (state) {
+ is Resource.Success<*> -> {
+ goneImageError()
+ state.data?.let { setAdapter(it) }
+ }
+ is Resource.Error<*> -> {
+ setImageError()
+ }
+ is Resource.Loading<*> -> {
+ binding.userListProgressBar.visibility = View.VISIBLE
+ }
+ }
+ }
+ }
+
+ private fun setImageError(){
+ binding.run {
+ userListProgressBar.visibility = View.GONE
+ title.visibility = View.GONE
+ constraintError.visibility = View.VISIBLE
+ }
+ }
+
+ private fun goneImageError(){
+ binding.run {
+ userListProgressBar.visibility = View.GONE
+ title.visibility = View.VISIBLE
+ constraintError.visibility = View.GONE
+ }
+ }
+
+ private fun setAdapter(data: List) {
+ adapter = UserListAdapter(data)
+ binding.recyclerView.layoutManager =
+ LinearLayoutManager(this@MainActivity, LinearLayoutManager.VERTICAL, false)
+ binding.recyclerView.adapter = adapter
+ }
+}
diff --git a/app/src/main/java/com/picpay/desafio/android/view/viewHolder/UserListItemViewHolder.kt b/app/src/main/java/com/picpay/desafio/android/view/viewHolder/UserListItemViewHolder.kt
new file mode 100644
index 000000000..e3885d652
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/view/viewHolder/UserListItemViewHolder.kt
@@ -0,0 +1,43 @@
+package com.picpay.desafio.android.view.viewHolder
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.picpay.desafio.android.R
+import com.picpay.desafio.android.data.response.User
+import com.picpay.desafio.android.databinding.ListItemUserBinding
+import com.squareup.picasso.Callback
+import com.squareup.picasso.Picasso
+
+class UserListItemViewHolder(private var binding: ListItemUserBinding) : RecyclerView.ViewHolder(binding.root) {
+
+ fun bind(user: User) {
+ binding.name.text = user.name
+ binding.username.text = user.username
+ binding.progressBar.visibility = View.VISIBLE
+
+ Picasso.get()
+ .load(user.img)
+ .error(R.drawable.ic_round_account_circle)
+ .into(binding.picture, object : Callback {
+ override fun onSuccess() {
+ binding.progressBar.visibility = View.GONE
+ }
+
+ override fun onError(e: Exception?) {
+ binding.progressBar.visibility = View.GONE
+ }
+ })
+ }
+
+ companion object {
+ fun inflate(parent: ViewGroup) = UserListItemViewHolder(
+ ListItemUserBinding.inflate(
+ LayoutInflater.from(parent.context),
+ parent,
+ false
+ )
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/picpay/desafio/android/view/viewModel/ListUsersViewModel.kt b/app/src/main/java/com/picpay/desafio/android/view/viewModel/ListUsersViewModel.kt
new file mode 100644
index 000000000..98411b7c3
--- /dev/null
+++ b/app/src/main/java/com/picpay/desafio/android/view/viewModel/ListUsersViewModel.kt
@@ -0,0 +1,35 @@
+package com.picpay.desafio.android.view.viewModel
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.picpay.desafio.android.core.Resource
+import com.picpay.desafio.android.data.response.User
+import com.picpay.desafio.android.domain.repository.GetUserCase
+import kotlinx.coroutines.launch
+
+class ListUsersViewModel(private val getUserCase: GetUserCase): ViewModel() {
+ private val _users = MutableLiveData>>()
+ val allUsers: MutableLiveData>>
+ get() = _users
+
+ init {
+ getAllUsers()
+ }
+
+ fun clickRefresh(){
+ getAllUsers()
+ }
+
+ private fun getAllUsers(){
+ _users.postValue(Resource.Loading())
+ viewModelScope.launch {
+ try {
+ val it = getUserCase.execute()
+ _users.postValue(Resource.Success(it))
+ }catch (e: Exception){
+ _users.postValue(Resource.Error(e.message))
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable-hdpi/server_error.png b/app/src/main/res/drawable-hdpi/server_error.png
new file mode 100644
index 000000000..cfab243d8
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/server_error.png differ
diff --git a/app/src/main/res/drawable-ldpi/server_error.png b/app/src/main/res/drawable-ldpi/server_error.png
new file mode 100644
index 000000000..70228dbe2
Binary files /dev/null and b/app/src/main/res/drawable-ldpi/server_error.png differ
diff --git a/app/src/main/res/drawable-mdpi/server_error.png b/app/src/main/res/drawable-mdpi/server_error.png
new file mode 100644
index 000000000..4e08b5574
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/server_error.png differ
diff --git a/app/src/main/res/drawable-xhdpi/server_error.png b/app/src/main/res/drawable-xhdpi/server_error.png
new file mode 100644
index 000000000..6572b43ee
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/server_error.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/server_error.png b/app/src/main/res/drawable-xxhdpi/server_error.png
new file mode 100644
index 000000000..1e65662c8
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/server_error.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/server_error.png b/app/src/main/res/drawable-xxxhdpi/server_error.png
new file mode 100644
index 000000000..894d48ef6
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/server_error.png differ
diff --git a/app/src/main/res/drawable/ic_round_account_circle.xml b/app/src/main/res/drawable/ic_round_account_circle.xml
index b9664bae4..defd55151 100644
--- a/app/src/main/res/drawable/ic_round_account_circle.xml
+++ b/app/src/main/res/drawable/ic_round_account_circle.xml
@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 487ac549e..d9a452ca2 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,60 +1,106 @@
-
-
-
+
+
+
+
+
+
-
-
+ android:layout_height="match_parent"
+ android:background="@color/colorVariant"
+ tools:context=".view.ui.MainActivity">
-
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:orientation="vertical">
-
+ app:layout_constraintTop_toTopOf="parent" />
-
+
+
+
+
+
+
+
-
+
-
+
-
\ No newline at end of file
+
+
+
+
+
diff --git a/app/src/main/res/layout/list_item_user.xml b/app/src/main/res/layout/list_item_user.xml
index 587d40cc8..9860cf426 100644
--- a/app/src/main/res/layout/list_item_user.xml
+++ b/app/src/main/res/layout/list_item_user.xml
@@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@color/colorPrimaryDark"
+ android:background="@color/colorVariant"
android:orientation="vertical">
+
+ #2B2C2F
+ #1D1E20
+ #11C76F
+ #ACB1BD
+ #80FFFFFF
+ #1D1E20
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml
new file mode 100644
index 000000000..21a551c1a
--- /dev/null
+++ b/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index fe7f39aca..ef48afb86 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -5,4 +5,6 @@
#11C76F
#ACB1BD
#80FFFFFF
+ #FFFFFFFF
+ #1D1E20
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 39df3169e..7564d26dc 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.
+ Retry
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index edde96c27..ba6beeedb 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,5 +1,4 @@
-
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..57132d0a9 100644
--- a/app/src/test/java/com/picpay/desafio/android/ExampleService.kt
+++ b/app/src/test/java/com/picpay/desafio/android/ExampleService.kt
@@ -1,12 +1,13 @@
package com.picpay.desafio.android
+import com.picpay.desafio.android.data.response.User
+import com.picpay.desafio.android.data.service.PicPayService
+
class ExampleService(
private val service: PicPayService
) {
- fun example(): List {
- val users = service.getUsers().execute()
-
- return users.body() ?: emptyList()
+ suspend fun example(): List {
+ return service.getUsers()
}
}
\ No newline at end of file
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..33e0ff49c 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.data.response.User
+import com.picpay.desafio.android.data.service.PicPayService
import junit.framework.Assert.assertEquals
import org.junit.Test
import retrofit2.Call
@@ -14,13 +16,13 @@ class ExampleServiceTest {
private val service = ExampleService(api)
@Test
- fun exampleTest() {
+ suspend fun exampleTest() {
// given
val call = mock>>()
val expectedUsers = emptyList()
whenever(call.execute()).thenReturn(Response.success(expectedUsers))
- whenever(api.getUsers()).thenReturn(call)
+ whenever(api.getUsers())
// when
val users = service.example()
diff --git a/build.gradle b/build.gradle
index 7d1b94f34..d9843b2e4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,53 +2,53 @@
buildscript {
ext {
- kotlin_version = '1.3.61'
+ kotlin_version = '1.6.21'
- appcompat_version = '1.1.0'
- core_ktx_version = '1.2.0'
+ appcompat_version = '1.4.2'
+ core_ktx_version = '1.8.0'
core_testing_version = '2.1.0'
- constraintlayout_version = '1.1.3'
- material_version = "1.1.0"
+ constraintlayout_version = '2.1.4'
+ material_version = "1.6.1"
moshi_version = '1.8.0'
- retrofit_version = '2.7.1'
- okhttp_version = '4.3.1'
+ retrofit_version = '2.9.0'
+ okhttp_version = '4.10.0'
picasso_version = '2.71828'
circleimageview_version = '3.0.0'
- junit_version = '4.12'
+ junit_version = '4.13.2'
mockito_version = '2.27.0'
mockito_kotlin_version = '2.1.0'
- test_runner_version = '1.1.1'
- espresso_version = '3.1.1'
+ test_runner_version = '1.4.0'
+ espresso_version = '3.4.0'
- koin_version = "2.0.1"
- dagger_version = "2.23.2"
- lifecycle_version = "2.2.0"
- coroutines_version = "1.3.3"
+ koin_version = "3.1.5"
+ dagger_version = "2.4.1"
+ lifecycle_version = "2.4.1"
+ coroutines_version = "1.6.1"
rxjava_version = "2.2.17"
rxandroid_version = "2.1.1"
- core_ktx_test_version = "1.2.0"
+ core_ktx_test_version = "1.4.0"
}
repositories {
google()
- jcenter()
+ mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.5.3'
+ classpath 'com.android.tools.build:gradle:7.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
+
}
allprojects {
repositories {
google()
- jcenter()
-
+ mavenCentral()
}
}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 31680f1d6..be491bb72 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sun Feb 16 19:36:17 BRT 2020
+#Tue Jun 14 16:09:57 BRT 2022
distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
+zipStoreBase=GRADLE_USER_HOME