Skip to content

Commit 1257eed

Browse files
authored
Merge pull request #1 from Njumbi/dev
Dev
2 parents c951633 + a59d4fd commit 1257eed

File tree

15 files changed

+348
-2
lines changed

15 files changed

+348
-2
lines changed

app/build.gradle

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
plugins {
22
id 'com.android.application'
33
id 'org.jetbrains.kotlin.android'
4+
id 'kotlin-kapt'
5+
id("dagger.hilt.android.plugin")
46
}
57

68
android {
@@ -29,6 +31,9 @@ android {
2931
kotlinOptions {
3032
jvmTarget = '1.8'
3133
}
34+
buildFeatures {
35+
viewBinding = true
36+
}
3237
}
3338

3439
dependencies {
@@ -40,6 +45,42 @@ dependencies {
4045
testImplementation 'junit:junit:4.13.2'
4146
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
4247
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
48+
4349
//circular image
4450
implementation 'de.hdodenhof:circleimageview:3.1.0'
51+
52+
// di
53+
implementation "com.google.dagger:hilt-android:2.38.1"
54+
kapt "com.google.dagger:hilt-compiler:2.38.1"
55+
56+
//glide
57+
implementation 'com.github.bumptech.glide:glide:4.12.0'
58+
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
59+
60+
// coroutines
61+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
62+
implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
63+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
64+
65+
// lifecycle
66+
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0"
67+
implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03"
68+
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"
69+
70+
// network
71+
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
72+
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
73+
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
74+
implementation 'com.google.code.gson:gson:2.8.9'
75+
76+
//glide
77+
implementation 'com.github.bumptech.glide:glide:4.13.0'
78+
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.0'
79+
80+
// activity
81+
implementation "androidx.activity:activity-ktx:1.4.0"
82+
83+
//lifecycle
84+
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.4.1")
85+
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1")
4586
}

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
package="com.example.diff_utils_recyclerview_example">
4+
<uses-permission android:name="android.permission.INTERNET"/>
45

56
<application
7+
android:name=".App"
68
android:allowBackup="true"
79
android:icon="@mipmap/ic_launcher"
810
android:label="@string/app_name"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.example.diff_utils_recyclerview_example
2+
3+
import android.app.Application
4+
import dagger.hilt.android.HiltAndroidApp
5+
6+
@HiltAndroidApp
7+
class App:Application() {
8+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.example.diff_utils_recyclerview_example.data.di
2+
3+
import com.example.diff_utils_recyclerview_example.data.remote.ApiService
4+
import com.example.diff_utils_recyclerview_example.data.repository.CharactersRepo
5+
import com.example.diff_utils_recyclerview_example.data.repository.CharactersRepoImpl
6+
import com.example.diff_utils_recyclerview_example.ui.BASE_URL
7+
import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
8+
import dagger.Module
9+
import dagger.Provides
10+
import dagger.hilt.InstallIn
11+
import dagger.hilt.components.SingletonComponent
12+
import de.hdodenhof.circleimageview.BuildConfig
13+
import okhttp3.OkHttpClient
14+
import okhttp3.logging.HttpLoggingInterceptor
15+
import retrofit2.Retrofit
16+
import retrofit2.converter.gson.GsonConverterFactory
17+
import javax.inject.Singleton
18+
19+
@Module
20+
@InstallIn(SingletonComponent::class)
21+
object AppModule {
22+
23+
@Provides
24+
fun providesOkhttp():OkHttpClient{
25+
val okhhtp = OkHttpClient.Builder()
26+
27+
if (BuildConfig.DEBUG) {
28+
val logger = HttpLoggingInterceptor()
29+
logger.setLevel(HttpLoggingInterceptor.Level.BODY)
30+
31+
okhhtp.addInterceptor(logger)
32+
}
33+
return okhhtp.build()
34+
}
35+
36+
@Provides
37+
@Singleton
38+
fun providesRetrofit(okHttpClient: OkHttpClient):Retrofit = Retrofit
39+
.Builder()
40+
.addConverterFactory(GsonConverterFactory.create())
41+
.addCallAdapterFactory(CoroutineCallAdapterFactory())
42+
.client(okHttpClient)
43+
.baseUrl(BASE_URL)
44+
.build()
45+
46+
@Provides
47+
@Singleton
48+
fun apiService(retrofit: Retrofit): ApiService = retrofit.create(ApiService::class.java)
49+
50+
@Provides
51+
@Singleton
52+
fun providesCharactersRepo(apiService: ApiService):CharactersRepo= CharactersRepoImpl(apiService)
53+
54+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.example.diff_utils_recyclerview_example.data.remote
2+
3+
4+
import com.example.diff_utils_recyclerview_example.data.responses.CharactersResponse
5+
import retrofit2.http.GET
6+
7+
interface ApiService {
8+
9+
@GET("characters")
10+
suspend fun fetchCharacters(): CharactersResponse
11+
12+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.example.diff_utils_recyclerview_example.data.repository
2+
3+
import android.util.Log
4+
import com.example.diff_utils_recyclerview_example.data.remote.ApiService
5+
import com.example.diff_utils_recyclerview_example.data.responses.ApiResource
6+
import com.example.diff_utils_recyclerview_example.data.responses.CharactersResponse
7+
import com.example.diff_utils_recyclerview_example.data.responses.DataResponse
8+
import com.example.diff_utils_recyclerview_example.data.responses.safeApiCall
9+
import java.lang.reflect.Constructor
10+
import javax.inject.Inject
11+
12+
interface CharactersRepo{
13+
suspend fun getCharacters(): ApiResource<CharactersResponse>
14+
}
15+
class CharactersRepoImpl @Inject constructor(val apiService: ApiService):CharactersRepo{
16+
override suspend fun getCharacters() = safeApiCall {
17+
apiService.fetchCharacters()
18+
}
19+
20+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.example.diff_utils_recyclerview_example.data.responses
2+
3+
import com.bumptech.glide.load.HttpException
4+
import kotlinx.coroutines.Dispatchers
5+
import kotlinx.coroutines.withContext
6+
7+
sealed class ApiResource<out T> {
8+
data class Success<out T>(val value: T) : ApiResource<T>()
9+
data class Error(
10+
val isNetworkError: Boolean?,
11+
val errorCode: Int?,
12+
val errorBody: String?
13+
) : ApiResource<Nothing>()
14+
15+
object Loading : ApiResource<Nothing>()
16+
17+
}
18+
19+
suspend fun <T : Any> safeApiCall(
20+
apiCall: suspend () -> T,
21+
) : ApiResource<T> {
22+
return withContext(Dispatchers.IO) {
23+
try {
24+
val response = apiCall.invoke()
25+
ApiResource.Success(response)
26+
} catch (throwable: Throwable) {
27+
when(throwable){
28+
is HttpException -> {
29+
ApiResource.Error(false, throwable.statusCode, throwable.message)
30+
}
31+
else -> {
32+
ApiResource.Error(true, null, throwable.message)
33+
}
34+
}
35+
}
36+
}
37+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.example.diff_utils_recyclerview_example.data.responses
2+
3+
data class CharactersResponse(
4+
val count: Int,
5+
val `data`: List<DataResponse>,
6+
val nextPage: String,
7+
val totalPages: Int
8+
)
9+
10+
data class DataResponse(
11+
var id: Int,
12+
val allies: List<Any>,
13+
val enemies: List<Any>,
14+
val films: List<Any>,
15+
val imageUrl: String,
16+
val name: String,
17+
val parkAttractions: List<Any>,
18+
val shortFilms: List<Any>,
19+
val tvShows: List<Any>,
20+
val url: String,
21+
val videoGames: List<Any>
22+
)
23+
24+

app/src/main/java/com/example/diff_utils_recyclerview_example/ui/MainActivity.kt

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,43 @@ package com.example.diff_utils_recyclerview_example.ui
22

33
import androidx.appcompat.app.AppCompatActivity
44
import android.os.Bundle
5+
import android.view.LayoutInflater
6+
import android.widget.Toast
7+
import android.widget.Toast.makeText
8+
import androidx.activity.viewModels
9+
import androidx.lifecycle.ViewModel
10+
import androidx.lifecycle.lifecycleScope
11+
import androidx.recyclerview.widget.LinearLayoutManager
12+
import androidx.recyclerview.widget.RecyclerView
513
import com.example.diff_utils_recyclerview_example.R
14+
import com.example.diff_utils_recyclerview_example.databinding.ActivityMainBinding
15+
import com.example.diff_utils_recyclerview_example.ui.adapters.CharactersAdapter
16+
import com.example.diff_utils_recyclerview_example.ui.viewmodel.fetchCharactersViewModel
17+
import com.google.android.material.snackbar.Snackbar
18+
import dagger.hilt.android.AndroidEntryPoint
619

20+
@AndroidEntryPoint
721
class MainActivity : AppCompatActivity() {
22+
private lateinit var binding: ActivityMainBinding
23+
private lateinit var charactersAdapter:CharactersAdapter
24+
private val charactersViewModel: fetchCharactersViewModel by viewModels()
25+
826
override fun onCreate(savedInstanceState: Bundle?) {
927
super.onCreate(savedInstanceState)
10-
setContentView(R.layout.activity_main)
28+
binding = ActivityMainBinding.inflate(layoutInflater)
29+
setContentView(binding.root)
30+
31+
charactersAdapter = CharactersAdapter()
32+
var recyclerView = binding.rvCharacters
33+
recyclerView.layoutManager = LinearLayoutManager(this,RecyclerView.VERTICAL,false)
34+
recyclerView.adapter = charactersAdapter
35+
36+
charactersViewModel.fetchCharacters.observe(this){
37+
charactersAdapter.saveData(it.data)
38+
}
39+
charactersViewModel.errorResponse.observe(this){errorMessage ->
40+
Snackbar.make(binding.root,errorMessage.toString(),Snackbar.LENGTH_SHORT).show()
41+
}
42+
charactersViewModel.getCharacters()
1143
}
1244
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.example.diff_utils_recyclerview_example.ui
2+
3+
const val BASE_URL ="https://api.disneyapi.dev/"
4+

0 commit comments

Comments
 (0)