diff --git a/app/build.gradle b/app/build.gradle index a7fbdc0e9..17a13da65 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,10 +1,9 @@ -apply plugin: 'com.android.application' - -apply plugin: 'kotlin-android' - -apply plugin: 'kotlin-android-extensions' - -apply plugin: 'kotlin-kapt' +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'kotlin-android-extensions' + id 'kotlin-kapt' +} android { compileSdkVersion 29 @@ -43,12 +42,9 @@ 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" @@ -66,9 +62,6 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" - 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.squareup.retrofit2:retrofit:$retrofit_version" @@ -89,4 +82,39 @@ 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" + + // Architectural Components + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" + + // Coroutines + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8' + + // Coroutine Lifecycle Scopes + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" + implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0" + + // Retrofit + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + implementation 'com.squareup.retrofit2:converter-gson:2.9.0' + implementation "com.squareup.okhttp3:logging-interceptor:4.5.0" + + // Glide + implementation 'com.github.bumptech.glide:glide:4.11.0' + kapt 'com.github.bumptech.glide:compiler:4.11.0' + + // KTX + implementation 'androidx.core:core-ktx:1.3.1' + + // Lifecycles + implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' + kapt "android.arch.lifecycle:compiler:1.1.1" + + // GSON + implementation "com.google.code.gson:gson:2.8.6" + + // Navigation Components + implementation "androidx.navigation:navigation-fragment-ktx:2.3.0" + implementation "androidx.navigation:navigation-ui-ktx:2.3.0" + } diff --git a/app/src/androidTest/java/com/picpay/desafio/android/MainActivityTest.kt b/app/src/androidTest/java/com/picpay/desafio/android/UsersActivityTest.kt similarity index 92% rename from app/src/androidTest/java/com/picpay/desafio/android/MainActivityTest.kt rename to app/src/androidTest/java/com/picpay/desafio/android/UsersActivityTest.kt index e4a4978eb..31de98721 100644 --- a/app/src/androidTest/java/com/picpay/desafio/android/MainActivityTest.kt +++ b/app/src/androidTest/java/com/picpay/desafio/android/UsersActivityTest.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.ui.UsersActivity import okhttp3.mockwebserver.Dispatcher import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer @@ -14,7 +15,7 @@ import okhttp3.mockwebserver.RecordedRequest import org.junit.Test -class MainActivityTest { +class UsersActivityTest { private val server = 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/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7bdf2ce38..b590d9610 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,7 +14,7 @@ android:supportsRtl="true" android:theme="@style/AppTheme" tools:ignore="AllowBackup,GoogleAppIndexingWarning"> - + 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/api/ContactListApi.kt b/app/src/main/java/com/picpay/desafio/api/ContactListApi.kt new file mode 100644 index 000000000..fc630b814 --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/api/ContactListApi.kt @@ -0,0 +1,11 @@ +package com.picpay.desafio.api + +import com.picpay.desafio.models.ContactListResponse +import retrofit2.Response +import retrofit2.http.GET + +interface ContactListApi { + + @GET("users") + suspend fun getContactList(): Response +} \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/api/RetrofitInstance.kt b/app/src/main/java/com/picpay/desafio/api/RetrofitInstance.kt new file mode 100644 index 000000000..bbd612ebc --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/api/RetrofitInstance.kt @@ -0,0 +1,29 @@ +package com.picpay.desafio.api + +import com.picpay.desafio.util.Constants.Companion.BASE_URL +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +class RetrofitInstance { + companion object{ + + private val retrofit by lazy{ + val logging = HttpLoggingInterceptor() + logging.setLevel(HttpLoggingInterceptor.Level.BODY) + val client = OkHttpClient.Builder() + .addInterceptor(logging) + .build() + Retrofit.Builder() + .baseUrl(BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .client(client) + .build() + } + + val api by lazy { + retrofit.create(ContactListApi::class.java) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/models/Contact.kt b/app/src/main/java/com/picpay/desafio/models/Contact.kt new file mode 100644 index 000000000..8e26f071b --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/models/Contact.kt @@ -0,0 +1,8 @@ +package com.picpay.desafio.models + +data class Contact( + val id: String, + val img: String, + val name: String, + val username: String +) \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/models/ContactListResponse.kt b/app/src/main/java/com/picpay/desafio/models/ContactListResponse.kt new file mode 100644 index 000000000..9c8b8634c --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/models/ContactListResponse.kt @@ -0,0 +1,3 @@ +package com.picpay.desafio.models + +class ContactListResponse : ArrayList() \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/ui/SavedUserFragment.kt b/app/src/main/java/com/picpay/desafio/ui/SavedUserFragment.kt new file mode 100644 index 000000000..f95ffb73f --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/ui/SavedUserFragment.kt @@ -0,0 +1,7 @@ +package com.picpay.desafio.ui + +import androidx.fragment.app.Fragment +import com.picpay.desafio.android.R + +class SavedUserFragment : Fragment(R.layout.fragment_saved_user) { +} \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/ui/UserListFragment.kt b/app/src/main/java/com/picpay/desafio/ui/UserListFragment.kt new file mode 100644 index 000000000..79fe4cf61 --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/ui/UserListFragment.kt @@ -0,0 +1,7 @@ +package com.picpay.desafio.ui + +import androidx.fragment.app.Fragment +import com.picpay.desafio.android.R + +class UserListFragment : Fragment(R.layout.fragment_user_list) { +} \ No newline at end of file diff --git a/app/src/main/java/com/picpay/desafio/ui/UsersActivity.kt b/app/src/main/java/com/picpay/desafio/ui/UsersActivity.kt new file mode 100644 index 000000000..5e748bbc8 --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/ui/UsersActivity.kt @@ -0,0 +1,35 @@ +package com.picpay.desafio.ui + +import android.os.Bundle +import android.os.PersistableBundle +import android.view.View +import android.widget.ProgressBar +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.fragment.findNavController +import androidx.navigation.ui.setupWithNavController +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import com.picpay.desafio.android.PicPayService +import com.picpay.desafio.android.R +import com.picpay.desafio.android.User +import com.picpay.desafio.android.UserListAdapter +import kotlinx.android.synthetic.main.activity_users.* +import okhttp3.OkHttpClient +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +class UsersActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_users) + + bottom_navigation_view.setupWithNavController(users_nav_host_fragment.findNavController()) + } +} diff --git a/app/src/main/java/com/picpay/desafio/util/Constants.kt b/app/src/main/java/com/picpay/desafio/util/Constants.kt new file mode 100644 index 000000000..b5c045078 --- /dev/null +++ b/app/src/main/java/com/picpay/desafio/util/Constants.kt @@ -0,0 +1,8 @@ +package com.picpay.desafio.util + +class Constants { + + companion object { + const val BASE_URL = "https://609a908e0f5a13001721b74e.mockapi.io/picpay/api/" + } +} \ No newline at end of file diff --git a/app/src/main/res/anim/slide_in_left.xml b/app/src/main/res/anim/slide_in_left.xml new file mode 100644 index 000000000..0256aaf5a --- /dev/null +++ b/app/src/main/res/anim/slide_in_left.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_in_right.xml b/app/src/main/res/anim/slide_in_right.xml new file mode 100644 index 000000000..549c0f307 --- /dev/null +++ b/app/src/main/res/anim/slide_in_right.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_out_left.xml b/app/src/main/res/anim/slide_out_left.xml new file mode 100644 index 000000000..f3b0cc48f --- /dev/null +++ b/app/src/main/res/anim/slide_out_left.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_out_right.xml b/app/src/main/res/anim/slide_out_right.xml new file mode 100644 index 000000000..b740a48f0 --- /dev/null +++ b/app/src/main/res/anim/slide_out_right.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index 487ac549e..000000000 --- a/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_users.xml b/app/src/main/res/layout/activity_users.xml new file mode 100644 index 000000000..a52b1a49d --- /dev/null +++ b/app/src/main/res/layout/activity_users.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_saved_user.xml b/app/src/main/res/layout/fragment_saved_user.xml new file mode 100644 index 000000000..30e6cfc14 --- /dev/null +++ b/app/src/main/res/layout/fragment_saved_user.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_user_list.xml b/app/src/main/res/layout/fragment_user_list.xml new file mode 100644 index 000000000..1f24e4c3e --- /dev/null +++ b/app/src/main/res/layout/fragment_user_list.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/bottom_navigation_menu.xml b/app/src/main/res/menu/bottom_navigation_menu.xml new file mode 100644 index 000000000..46f32b0bc --- /dev/null +++ b/app/src/main/res/menu/bottom_navigation_menu.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/users_nav_graph.xml b/app/src/main/res/navigation/users_nav_graph.xml new file mode 100644 index 000000000..da80e8e3f --- /dev/null +++ b/app/src/main/res/navigation/users_nav_graph.xml @@ -0,0 +1,25 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index edde96c27..7dbaa7a8a 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -14,4 +14,9 @@ bold + +