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" /> - + + + + + + + - + - +