add saved item flow in library view model
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
package app.omnivore.omnivore.core.data
|
||||
|
||||
import app.omnivore.omnivore.core.database.AppDatabase
|
||||
import app.omnivore.omnivore.core.database.OmnivoreDatabase
|
||||
import app.omnivore.omnivore.core.database.entities.SavedItem
|
||||
import app.omnivore.omnivore.core.network.Networker
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -11,11 +11,11 @@ import javax.inject.Inject
|
||||
|
||||
class DataService @Inject constructor(
|
||||
val networker: Networker,
|
||||
appDatabase: AppDatabase
|
||||
omnivoreDatabase: OmnivoreDatabase
|
||||
) {
|
||||
val savedItemSyncChannel = Channel<SavedItem>(capacity = Channel.UNLIMITED)
|
||||
|
||||
val db = appDatabase
|
||||
val db = omnivoreDatabase
|
||||
|
||||
init {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
|
||||
@ -19,25 +19,24 @@ import app.omnivore.omnivore.core.database.entities.Viewer
|
||||
import app.omnivore.omnivore.core.database.entities.ViewerDao
|
||||
|
||||
@Database(
|
||||
entities = [
|
||||
Viewer::class,
|
||||
SavedItem::class,
|
||||
SavedItemLabel::class,
|
||||
Highlight::class,
|
||||
HighlightChange::class,
|
||||
SavedItemAndSavedItemLabelCrossRef::class,
|
||||
SavedItemAndHighlightCrossRef::class
|
||||
],
|
||||
version = 24,
|
||||
exportSchema = false
|
||||
entities = [
|
||||
Viewer::class,
|
||||
SavedItem::class,
|
||||
SavedItemLabel::class,
|
||||
Highlight::class,
|
||||
HighlightChange::class,
|
||||
SavedItemAndSavedItemLabelCrossRef::class,
|
||||
SavedItemAndHighlightCrossRef::class],
|
||||
version = 24,
|
||||
exportSchema = true
|
||||
)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun viewerDao(): ViewerDao
|
||||
abstract fun savedItemDao(): SavedItemDao
|
||||
abstract fun highlightDao(): HighlightDao
|
||||
abstract fun highlightChangesDao(): HighlightChangesDao
|
||||
abstract fun savedItemLabelDao(): SavedItemLabelDao
|
||||
abstract fun savedItemWithLabelsAndHighlightsDao(): SavedItemWithLabelsAndHighlightsDao
|
||||
abstract fun savedItemAndSavedItemLabelCrossRefDao(): SavedItemAndSavedItemLabelCrossRefDao
|
||||
abstract fun savedItemAndHighlightCrossRefDao(): SavedItemAndHighlightCrossRefDao
|
||||
abstract class OmnivoreDatabase : RoomDatabase() {
|
||||
abstract fun viewerDao(): ViewerDao
|
||||
abstract fun savedItemDao(): SavedItemDao
|
||||
abstract fun highlightDao(): HighlightDao
|
||||
abstract fun highlightChangesDao(): HighlightChangesDao
|
||||
abstract fun savedItemLabelDao(): SavedItemLabelDao
|
||||
abstract fun savedItemWithLabelsAndHighlightsDao(): SavedItemWithLabelsAndHighlightsDao
|
||||
abstract fun savedItemAndSavedItemLabelCrossRefDao(): SavedItemAndSavedItemLabelCrossRefDao
|
||||
abstract fun savedItemAndHighlightCrossRefDao(): SavedItemAndHighlightCrossRefDao
|
||||
}
|
||||
@ -13,7 +13,6 @@ import kotlinx.coroutines.flow.Flow
|
||||
@Dao
|
||||
interface SavedItemDao {
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM savedItem")
|
||||
fun getAll(): Flow<List<SavedItem>>
|
||||
|
||||
|
||||
@ -73,7 +73,20 @@ data class SavedItemWithLabelsAndHighlights(
|
||||
associateBy = Junction(SavedItemAndHighlightCrossRef::class)
|
||||
)
|
||||
val highlights: List<Highlight>
|
||||
)
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as SavedItemWithLabelsAndHighlights
|
||||
|
||||
return savedItem.savedItemId == other.savedItem.savedItemId
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return savedItem.savedItemId.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
@Dao
|
||||
interface HighlightDao {
|
||||
|
||||
@ -3,7 +3,7 @@ package app.omnivore.omnivore.di
|
||||
import android.content.Context
|
||||
import app.omnivore.omnivore.core.analytics.EventTracker
|
||||
import app.omnivore.omnivore.core.data.DataService
|
||||
import app.omnivore.omnivore.core.database.AppDatabase
|
||||
import app.omnivore.omnivore.core.database.OmnivoreDatabase
|
||||
import app.omnivore.omnivore.core.datastore.DatastoreRepository
|
||||
import app.omnivore.omnivore.core.datastore.OmnivoreDatastore
|
||||
import app.omnivore.omnivore.core.network.Networker
|
||||
@ -35,8 +35,8 @@ object AppModule {
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideDataService(
|
||||
networker: Networker,
|
||||
appDatabase: AppDatabase
|
||||
) = DataService(networker, appDatabase)
|
||||
networker: Networker,
|
||||
omnivoreDatabase: OmnivoreDatabase
|
||||
) = DataService(networker, omnivoreDatabase)
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package app.omnivore.omnivore.di
|
||||
|
||||
import app.omnivore.omnivore.core.database.AppDatabase
|
||||
import app.omnivore.omnivore.core.database.OmnivoreDatabase
|
||||
import app.omnivore.omnivore.core.database.dao.SavedItemDao
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
@ -10,8 +10,9 @@ import dagger.hilt.components.SingletonComponent
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object DaosModule {
|
||||
|
||||
@Provides
|
||||
fun providesTopicsDao(
|
||||
database: AppDatabase,
|
||||
fun providesSavedItemDao(
|
||||
database: OmnivoreDatabase,
|
||||
): SavedItemDao = database.savedItemDao()
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ package app.omnivore.omnivore.di
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import app.omnivore.omnivore.core.database.AppDatabase
|
||||
import app.omnivore.omnivore.core.database.OmnivoreDatabase
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
@ -17,9 +17,9 @@ object DatabaseModule {
|
||||
@Singleton
|
||||
fun providesOmnivoreDatabase(
|
||||
@ApplicationContext context: Context,
|
||||
): AppDatabase = Room.databaseBuilder(
|
||||
): OmnivoreDatabase = Room.databaseBuilder(
|
||||
context,
|
||||
AppDatabase::class.java,
|
||||
OmnivoreDatabase::class.java,
|
||||
"omnivore-database",
|
||||
).build()
|
||||
}
|
||||
|
||||
@ -20,7 +20,6 @@ import androidx.compose.material.DismissValue
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.FractionalThreshold
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.ScaffoldState
|
||||
import androidx.compose.material.SwipeToDismiss
|
||||
import androidx.compose.material.icons.Icons
|
||||
@ -36,6 +35,7 @@ import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@ -45,6 +45,7 @@ import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@ -127,7 +128,6 @@ internal fun LibraryView(
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
scaffoldState = scaffoldState,
|
||||
topBar = {
|
||||
LibraryNavigationBar(
|
||||
savedItemViewModel = viewModel,
|
||||
@ -334,8 +334,7 @@ fun LibraryViewContent(
|
||||
val swipeThreshold = 0.45f
|
||||
|
||||
val currentThresholdFraction = remember { mutableStateOf(0f) }
|
||||
//val currentItem by rememberUpdatedState(cardDataWithLabels.savedItem)
|
||||
val currentItem = cardDataWithLabels.savedItem
|
||||
val currentItem by rememberUpdatedState(cardDataWithLabels.savedItem)
|
||||
val swipeState = rememberDismissState(
|
||||
confirmStateChange = {
|
||||
when(it) {
|
||||
@ -412,10 +411,15 @@ fun LibraryViewContent(
|
||||
dismissContent = {
|
||||
val selected =
|
||||
currentItem.savedItemId == selectedItem?.savedItem?.savedItemId
|
||||
val test = SavedItemWithLabelsAndHighlights(
|
||||
savedItem = cardDataWithLabels.savedItem,
|
||||
labels = listOf(),
|
||||
highlights = listOf()
|
||||
)
|
||||
SavedItemCard(
|
||||
selected = selected,
|
||||
savedItemViewModel = libraryViewModel,
|
||||
savedItem = cardDataWithLabels,
|
||||
savedItem = test,
|
||||
onClickHandler = {
|
||||
libraryViewModel.actionsMenuItemLiveData.postValue(null)
|
||||
val activityClass =
|
||||
|
||||
@ -33,22 +33,16 @@ import com.apollographql.apollo3.api.Optional
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.time.Instant
|
||||
import javax.inject.Inject
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@HiltViewModel
|
||||
class LibraryViewModel @Inject constructor(
|
||||
private val networker: Networker,
|
||||
@ -75,16 +69,33 @@ class LibraryViewModel @Inject constructor(
|
||||
)
|
||||
)
|
||||
|
||||
val uiState: StateFlow<LibraryUiState> = _libraryQuery.flatMapLatest { query ->
|
||||
// Correct way - but not working
|
||||
/* val uiState: StateFlow<LibraryUiState> = _libraryQuery.flatMapLatest { query ->
|
||||
libraryRepository.getSavedItems(query)
|
||||
}
|
||||
.map(LibraryUiState::Success)
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
started = SharingStarted.Lazily,
|
||||
initialValue = LibraryUiState.Loading
|
||||
)
|
||||
)*/
|
||||
|
||||
// This approach needs to be replaced with the StateFlow above after fixing Room Flow
|
||||
private val _uiState = MutableStateFlow<LibraryUiState>(LibraryUiState.Loading)
|
||||
val uiState: StateFlow<LibraryUiState> = _uiState
|
||||
|
||||
init {
|
||||
loadSavedItems()
|
||||
}
|
||||
|
||||
private fun loadSavedItems() {
|
||||
viewModelScope.launch {
|
||||
libraryRepository.getSavedItems(_libraryQuery.value)
|
||||
.collect { favoriteNews ->
|
||||
_uiState.value = LibraryUiState.Success(favoriteNews)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val itemsLiveData = MediatorLiveData<List<SavedItemWithLabelsAndHighlights>>()
|
||||
val appliedFilterLiveData = MutableLiveData(SavedItemFilter.INBOX)
|
||||
@ -259,6 +270,7 @@ class LibraryViewModel @Inject constructor(
|
||||
excludedLabels = excludeLabels,
|
||||
allowedContentReaders = allowedContentReaders
|
||||
)
|
||||
loadSavedItems()
|
||||
}
|
||||
}
|
||||
|
||||
@ -338,13 +350,17 @@ class LibraryViewModel @Inject constructor(
|
||||
|
||||
SavedItemAction.MarkRead -> {
|
||||
viewModelScope.launch {
|
||||
_uiState.value = LibraryUiState.Success(emptyList())
|
||||
libraryRepository.updateReadingProgress(itemID, 100.0, 0)
|
||||
loadSavedItems()
|
||||
}
|
||||
}
|
||||
|
||||
SavedItemAction.MarkUnread -> {
|
||||
viewModelScope.launch {
|
||||
_uiState.value = LibraryUiState.Success(emptyList())
|
||||
libraryRepository.updateReadingProgress(itemID, 0.0, 0)
|
||||
loadSavedItems()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user