app: reinstate API wrapper to hide client implementation

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
Harsh Shandilya 2020-11-08 16:41:02 +05:30
parent 5b77fdf54b
commit 276877119d
No known key found for this signature in database
GPG key ID: 366D7BBAD1031E80
6 changed files with 75 additions and 23 deletions

View file

@ -8,3 +8,11 @@
-keepclasseswithmembers class dev.msfjarvis.lobsters.model.** { -keepclasseswithmembers class dev.msfjarvis.lobsters.model.** {
kotlinx.serialization.KSerializer serializer(...); kotlinx.serialization.KSerializer serializer(...);
} }
# Workaround for https://github.com/ktorio/ktor/issues/1354
-keepclassmembers class io.ktor.** { volatile <fields>; }
# Workaround for https://github.com/Kotlin/kotlinx.coroutines/issues/1564
-keepclassmembers class kotlinx.** {
volatile <fields>;
}

View file

@ -0,0 +1,16 @@
package dev.msfjarvis.lobsters.data.api
import dev.msfjarvis.lobsters.data.api.LobstersApi.Companion.BASE_URL
import dev.msfjarvis.lobsters.model.LobstersPost
import io.ktor.client.HttpClient
import io.ktor.client.request.get
import javax.inject.Inject
/**
* Ktor backed implementation of [LobstersApi]
*/
class KtorLobstersApi @Inject constructor(private val client: HttpClient) : LobstersApi {
override suspend fun getHottestPosts(page: Int): List<LobstersPost> {
return client.get("${BASE_URL}/hottest.json?page=$page")
}
}

View file

@ -0,0 +1,15 @@
package dev.msfjarvis.lobsters.data.api
import dev.msfjarvis.lobsters.model.LobstersPost
/**
* Simple interface defining an API for lobste.rs
*/
interface LobstersApi {
suspend fun getHottestPosts(page: Int): List<LobstersPost>
companion object {
const val BASE_URL = "https://lobste.rs"
}
}

View file

@ -1,26 +1,14 @@
package dev.msfjarvis.lobsters.injection package dev.msfjarvis.lobsters.injection
import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.components.ApplicationComponent import dagger.hilt.android.components.ActivityComponent
import io.ktor.client.HttpClient import dev.msfjarvis.lobsters.data.api.KtorLobstersApi
import io.ktor.client.engine.okhttp.OkHttp import dev.msfjarvis.lobsters.data.api.LobstersApi
import io.ktor.client.features.json.JsonFeature
import io.ktor.client.features.json.serializer.KotlinxSerializer
@Module @Module
@InstallIn(ApplicationComponent::class) @InstallIn(ActivityComponent::class)
object KtorApiModule { abstract class KtorApiModule {
@Provides @Binds abstract fun bindLobstersApi(realApi: KtorLobstersApi): LobstersApi
fun provideClient() = HttpClient(OkHttp) {
install(JsonFeature) {
serializer = KotlinxSerializer()
}
engine {
config {
followSslRedirects(true)
}
}
}
} }

View file

@ -0,0 +1,26 @@
package dev.msfjarvis.lobsters.injection
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ApplicationComponent
import io.ktor.client.HttpClient
import io.ktor.client.engine.okhttp.OkHttp
import io.ktor.client.features.json.JsonFeature
import io.ktor.client.features.json.serializer.KotlinxSerializer
@Module
@InstallIn(ApplicationComponent::class)
object KtorClientModule {
@Provides
fun provideClient() = HttpClient(OkHttp) {
install(JsonFeature) {
serializer = KotlinxSerializer()
}
engine {
config {
followSslRedirects(true)
}
}
}
}

View file

@ -3,10 +3,9 @@ package dev.msfjarvis.lobsters.ui.viewmodel
import androidx.hilt.lifecycle.ViewModelInject import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dev.msfjarvis.lobsters.data.api.LobstersApi
import dev.msfjarvis.lobsters.data.source.PostsDatabase import dev.msfjarvis.lobsters.data.source.PostsDatabase
import dev.msfjarvis.lobsters.model.LobstersPost import dev.msfjarvis.lobsters.model.LobstersPost
import io.ktor.client.HttpClient
import io.ktor.client.request.get
import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@ -16,7 +15,7 @@ import java.net.SocketTimeoutException
import java.net.UnknownHostException import java.net.UnknownHostException
class LobstersViewModel @ViewModelInject constructor( class LobstersViewModel @ViewModelInject constructor(
private val client: HttpClient, private val lobstersApi: LobstersApi,
database: PostsDatabase, database: PostsDatabase,
) : ViewModel() { ) : ViewModel() {
private var apiPage = 1 private var apiPage = 1
@ -57,7 +56,7 @@ class LobstersViewModel @ViewModelInject constructor(
private fun getMorePostsInternal(firstLoad: Boolean) { private fun getMorePostsInternal(firstLoad: Boolean) {
viewModelScope.launch(coroutineExceptionHandler) { viewModelScope.launch(coroutineExceptionHandler) {
val newPosts = client.get<List<LobstersPost>>("https://lobste.rs/hottest.json?page=$apiPage") val newPosts = lobstersApi.getHottestPosts(apiPage)
if (firstLoad) { if (firstLoad) {
_posts.value = newPosts _posts.value = newPosts
postsDao.deleteAllPosts() postsDao.deleteAllPosts()