Add LobstersRepo to handle DB operations

Signed-off-by: Aditya Wasan <adityawasan55@gmail.com>
This commit is contained in:
Aditya Wasan 2020-12-20 16:21:18 +05:30 committed by Harsh Shandilya
parent 4f9d0c09ef
commit 3bcdcbdac7
No known key found for this signature in database
GPG key ID: 366D7BBAD1031E80
8 changed files with 99 additions and 7 deletions

View file

@ -44,6 +44,7 @@ dependencies {
implementation(Dependencies.Kotlin.Coroutines.android) implementation(Dependencies.Kotlin.Coroutines.android)
implementation(Dependencies.ThirdParty.accompanist) implementation(Dependencies.ThirdParty.accompanist)
implementation(Dependencies.ThirdParty.Moshi.lib) implementation(Dependencies.ThirdParty.Moshi.lib)
implementation(Dependencies.ThirdParty.SQLDelight.androidDriver)
testImplementation(Dependencies.Testing.junit) testImplementation(Dependencies.Testing.junit)
androidTestImplementation(Dependencies.Testing.daggerHilt) androidTestImplementation(Dependencies.Testing.daggerHilt)
androidTestImplementation(Dependencies.Testing.uiTest) androidTestImplementation(Dependencies.Testing.uiTest)

View file

@ -3,16 +3,21 @@ package dev.msfjarvis.lobsters.data.remote
import androidx.paging.PagingSource import androidx.paging.PagingSource
import dev.msfjarvis.lobsters.data.api.LobstersApi import dev.msfjarvis.lobsters.data.api.LobstersApi
import dev.msfjarvis.lobsters.data.local.LobstersPost import dev.msfjarvis.lobsters.data.local.LobstersPost
import dev.msfjarvis.lobsters.data.repo.LobstersRepository
import javax.inject.Inject import javax.inject.Inject
class LobstersPagingSource @Inject constructor( class LobstersPagingSource @Inject constructor(
private val lobstersApi: LobstersApi, private val lobstersApi: LobstersApi,
private val lobstersRepository: LobstersRepository,
) : PagingSource<Int, LobstersPost>() { ) : PagingSource<Int, LobstersPost>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, LobstersPost> { override suspend fun load(params: LoadParams<Int>): LoadResult<Int, LobstersPost> {
return try { return try {
val page = params.key ?: 1 val page = params.key ?: 1
val posts = lobstersApi.getHottestPosts(page) val savedPosts = lobstersRepository.getCachedPosts()
val posts = lobstersApi.getHottestPosts(page).map { post ->
post.copy(is_saved = savedPosts.contains(post.short_id))
}
LoadResult.Page( LoadResult.Page(
data = posts, data = posts,

View file

@ -0,0 +1,39 @@
package dev.msfjarvis.lobsters.data.repo
import dev.msfjarvis.lobsters.data.local.LobstersPost
import dev.msfjarvis.lobsters.database.LobstersDatabase
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject
class LobstersRepository @Inject constructor(private val lobstersDatabase: LobstersDatabase) {
private var savedPostCache: MutableSet<String>? = null
fun isPostSaved(postId: String): Boolean {
savedPostCache ?: return false
return requireNotNull(savedPostCache).contains(postId)
}
suspend fun savePost(post: LobstersPost) = withContext(Dispatchers.IO) {
val isElementAdded = getCachedPosts().add(post.short_id)
if (isElementAdded) {
lobstersDatabase.postQueries.savePost(post.short_id)
}
}
suspend fun removeSavedPost(post: LobstersPost) = withContext(Dispatchers.IO) {
val isElementRemoved = getCachedPosts().remove(post.short_id)
if (isElementRemoved) {
lobstersDatabase.postQueries.removeSavedPost(post.short_id)
}
}
suspend fun getCachedPosts(): MutableSet<String> = withContext(Dispatchers.IO) {
if (savedPostCache != null) return@withContext requireNotNull(savedPostCache)
val dbPosts = lobstersDatabase.postQueries.selectSavedPosts().executeAsList()
savedPostCache = dbPosts.filter { it.is_saved ?: false }.map { it.short_id }.toMutableSet()
return@withContext requireNotNull(savedPostCache)
}
}

View file

@ -0,0 +1,29 @@
package dev.msfjarvis.lobsters.injection
import android.content.Context
import com.squareup.sqldelight.android.AndroidSqliteDriver
import com.squareup.sqldelight.db.SqlDriver
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import dev.msfjarvis.lobsters.data.local.LobstersPost
import dev.msfjarvis.lobsters.database.LobstersDatabase
import dev.msfjarvis.lobsters.model.SubmitterAdapter
import dev.msfjarvis.lobsters.model.TagsAdapter
@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
@Provides
fun providesSqlDriver(@ApplicationContext context: Context): SqlDriver {
return AndroidSqliteDriver(LobstersDatabase.Schema, context)
}
@Provides
fun providesLobstersDatabase(sqlDriver: SqlDriver): LobstersDatabase {
return LobstersDatabase(sqlDriver, LobstersPost.Adapter(SubmitterAdapter(), TagsAdapter()))
}
}

View file

@ -78,14 +78,14 @@ fun LobstersApp() {
HottestPosts( HottestPosts(
posts = hottestPosts, posts = hottestPosts,
listState = hottestPostsListState, listState = hottestPostsListState,
saveAction = viewModel::savePost, saveAction = viewModel::toggleSave,
modifier = Modifier.padding(bottom = innerPadding.bottom), modifier = Modifier.padding(bottom = innerPadding.bottom),
) )
} }
composable(Destination.Saved.route) { composable(Destination.Saved.route) {
SavedPosts( SavedPosts(
posts = savedPosts, posts = savedPosts,
saveAction = viewModel::removeSavedPost, saveAction = viewModel::toggleSave,
modifier = Modifier.padding(bottom = innerPadding.bottom), modifier = Modifier.padding(bottom = innerPadding.bottom),
) )
} }

View file

@ -121,7 +121,7 @@ fun LobstersItem(
}, },
) )
IconResource( IconResource(
resourceId = R.drawable.ic_favorite_border_24px, resourceId = if (post.is_saved == true) R.drawable.ic_favorite_24px else R.drawable.ic_favorite_border_24px,
modifier = Modifier modifier = Modifier
.padding(8.dp) .padding(8.dp)
.clickable( .clickable(

View file

@ -5,8 +5,9 @@ import androidx.lifecycle.viewModelScope
import androidx.paging.Pager import androidx.paging.Pager
import androidx.paging.PagingConfig import androidx.paging.PagingConfig
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import dev.msfjarvis.lobsters.data.remote.LobstersPagingSource
import dev.msfjarvis.lobsters.data.local.LobstersPost import dev.msfjarvis.lobsters.data.local.LobstersPost
import dev.msfjarvis.lobsters.data.remote.LobstersPagingSource
import dev.msfjarvis.lobsters.data.repo.LobstersRepository
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -15,6 +16,7 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class LobstersViewModel @Inject constructor( class LobstersViewModel @Inject constructor(
private val pagingSource: LobstersPagingSource, private val pagingSource: LobstersPagingSource,
private val lobstersRepository: LobstersRepository,
) : ViewModel() { ) : ViewModel() {
private val _savedPosts = MutableStateFlow<List<LobstersPost>>(emptyList()) private val _savedPosts = MutableStateFlow<List<LobstersPost>>(emptyList())
val savedPosts = _savedPosts.asStateFlow() val savedPosts = _savedPosts.asStateFlow()
@ -22,13 +24,24 @@ class LobstersViewModel @Inject constructor(
pagingSource pagingSource
}.flow }.flow
fun savePost(post: LobstersPost) { fun toggleSave(post: LobstersPost) {
viewModelScope.launch { viewModelScope.launch {
val isSaved = lobstersRepository.isPostSaved(post.short_id)
if (isSaved) removeSavedPost(post) else savePost(post)
} }
} }
fun removeSavedPost(post: LobstersPost) { private fun savePost(post: LobstersPost) {
viewModelScope.launch { viewModelScope.launch {
lobstersRepository.savePost(post)
_savedPosts.value = _savedPosts.value + post
}
}
private fun removeSavedPost(post: LobstersPost) {
viewModelScope.launch {
lobstersRepository.removeSavedPost(post)
_savedPosts.value = _savedPosts.value - post
} }
} }
} }

View file

@ -22,6 +22,11 @@ selectAllPosts:
SELECT * SELECT *
FROM LobstersPost; FROM LobstersPost;
selectSavedPosts:
SELECT *
FROM LobstersPost
WHERE is_saved = 1;
selectPost: selectPost:
SELECT * SELECT *
FROM LobstersPost FROM LobstersPost