Use a single SQL query for loading library data

This commit is contained in:
Jackson Harper
2023-04-24 18:26:30 +08:00
parent aaf27b0631
commit 32f5bd2407
10 changed files with 200 additions and 84 deletions

View File

@ -17,8 +17,8 @@ android {
applicationId "app.omnivore.omnivore"
minSdk 26
targetSdk 33
versionCode 33
versionName "0.0.33"
versionCode 44
versionName "0.0.44"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {

View File

@ -2,6 +2,7 @@ package app.omnivore.omnivore.persistence.entities
import androidx.core.net.toUri
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.room.*
import app.omnivore.omnivore.BuildConfig
import app.omnivore.omnivore.graphql.generated.SearchQuery
@ -160,9 +161,73 @@ interface SavedItemDao {
"ORDER BY publishDate DESC"
)
fun getLibraryLiveDataSortedByRecentlyPublished(archiveFilter: Int): LiveData<List<SavedItemCardDataWithLabels>>
@Transaction
@Query(
"SELECT ${SavedItemQueryConstants.libraryColumns} " +
"FROM SavedItem " +
"LEFT OUTER JOIN SavedItemAndSavedItemLabelCrossRef on SavedItem.savedItemId = SavedItemAndSavedItemLabelCrossRef.savedItemId " +
"LEFT OUTER JOIN SavedItemAndHighlightCrossRef on SavedItem.savedItemId = SavedItemAndHighlightCrossRef.savedItemId " +
"LEFT OUTER JOIN SavedItemLabel on SavedItemLabel.savedItemLabelId = SavedItemAndSavedItemLabelCrossRef.savedItemLabelId " +
"LEFT OUTER JOIN Highlight on highlight.highlightId = SavedItemAndHighlightCrossRef.highlightId " +
"WHERE SavedItem.serverSyncStatus != 2 " +
"AND SavedItem.isArchived != :archiveFilter " +
"AND SavedItem.contentReader IN (:allowedContentReaders) " +
"AND CASE WHEN :hasRequiredLabels THEN SavedItemLabel.name in (:requiredLabels) ELSE 1 END " +
"AND CASE WHEN :hasExcludedLabels THEN SavedItemLabel.name is NULL OR SavedItemLabel.name not in (:excludedLabels) ELSE 1 END " +
"GROUP BY SavedItem.savedItemId " +
"ORDER BY \n" +
"CASE WHEN :sortKey = 'newest' THEN SavedItem.savedAt END DESC,\n" +
"CASE WHEN :sortKey = 'oldest' THEN SavedItem.savedAt END ASC,\n" +
"CASE WHEN :sortKey = 'recentlyRead' THEN SavedItem.readAt END DESC,\n" +
"CASE WHEN :sortKey = 'recentlyPublished' THEN SavedItem.publishDate END DESC"
)
fun _filteredLibraryData(archiveFilter: Int, sortKey: String, hasRequiredLabels: Int, hasExcludedLabels: Int, requiredLabels: List<String>, excludedLabels: List<String>, allowedContentReaders: List<String>): LiveData<List<SavedItemWithLabelsAndHighlights>>
fun filteredLibraryData(archiveFilter: Int, sortKey: String, requiredLabels: List<String>, excludedLabels: List<String>, allowedContentReaders: List<String>): LiveData<List<SavedItemWithLabelsAndHighlights>> {
return _filteredLibraryData(
archiveFilter = archiveFilter,
sortKey = sortKey,
hasRequiredLabels = requiredLabels.size,
hasExcludedLabels = excludedLabels.size,
requiredLabels = requiredLabels,
excludedLabels = excludedLabels,
allowedContentReaders = allowedContentReaders
)
}
}
object SavedItemQueryConstants {
const val columns = "savedItemId, slug, publisherURLString, title, author, imageURLString, isArchived, pageURLString, contentReader, savedAt, readingProgress, wordsCount"
const val libraryColumns = "SavedItem.savedItemId, " +
"SavedItem.slug, " +
"SavedItem.createdAt, " +
"SavedItem.publisherURLString, " +
"SavedItem.title, " +
"SavedItem.author, " +
"SavedItem.imageURLString, " +
"SavedItem.isArchived, " +
"SavedItem.pageURLString, " +
"SavedItem.contentReader, " +
"SavedItem.savedAt, " +
"SavedItem.readingProgress, " +
"SavedItem.readingProgressAnchor, " +
"SavedItem.serverSyncStatus, " +
"SavedItem.wordsCount, " +
"SavedItemLabel.savedItemLabelId, " +
"SavedItemLabel.name, " +
"SavedItemLabel.color, " +
"Highlight.highlightId, " +
"Highlight.shortId, " +
"Highlight.createdByMe "
}

View File

@ -76,7 +76,7 @@ fun LabelsSelectionSheet(viewModel: LibraryViewModel) {
isLibraryMode = false,
onSave = {
if (it != labels) {
viewModel.updateSavedItemLabels(savedItemID = currentSavedItemData.cardData.savedItemId, labels = it)
viewModel.updateSavedItemLabels(savedItemID = currentSavedItemData.savedItem.savedItemId, labels = it)
}
viewModel.labelsSelectionCurrentItemLiveData.value = null
viewModel.showLabelsSelectionSheetLiveData.value = false

View File

@ -27,6 +27,7 @@ import androidx.navigation.NavHostController
import app.omnivore.omnivore.R
import app.omnivore.omnivore.persistence.entities.SavedItemCardData
import app.omnivore.omnivore.persistence.entities.SavedItemCardDataWithLabels
import app.omnivore.omnivore.persistence.entities.SavedItemWithLabelsAndHighlights
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -35,7 +36,7 @@ fun LibraryNavigationBar(
onSearchClicked: () -> Unit,
onSettingsIconClick: () -> Unit
) {
val actionsMenuItem: SavedItemCardData? by savedItemViewModel.actionsMenuItemLiveData.observeAsState(null)
val actionsMenuItem: SavedItemWithLabelsAndHighlights? by savedItemViewModel.actionsMenuItemLiveData.observeAsState(null)
TopAppBar(
title = {
@ -62,10 +63,10 @@ fun LibraryNavigationBar(
actionsMenuItem?.let {
IconButton(onClick = {
savedItemViewModel.handleSavedItemAction(
it.savedItemId,
if (it.isArchived) SavedItemAction.Unarchive else SavedItemAction.Archive
it.savedItem.savedItemId,
if (it.savedItem.isArchived) SavedItemAction.Unarchive else SavedItemAction.Archive
) }) {
if (it.isArchived) {
if (it.savedItem.isArchived) {
Icon(
painter = painterResource(id = R.drawable.unarchive),
contentDescription = null
@ -77,13 +78,13 @@ fun LibraryNavigationBar(
)
}
}
IconButton(onClick = { savedItemViewModel.handleSavedItemAction(it.savedItemId, SavedItemAction.EditLabels) }) {
IconButton(onClick = { savedItemViewModel.handleSavedItemAction(it.savedItem.savedItemId, SavedItemAction.EditLabels) }) {
Icon(
painter = painterResource(id = R.drawable.tag),
contentDescription = null
)
}
IconButton(onClick = { savedItemViewModel.handleSavedItemAction(it.savedItemId, SavedItemAction.Delete) }) {
IconButton(onClick = { savedItemViewModel.handleSavedItemAction(it.savedItem.savedItemId, SavedItemAction.Delete) }) {
Icon(
imageVector = Icons.Outlined.Delete,
contentDescription = null

View File

@ -35,6 +35,7 @@ import app.omnivore.omnivore.R
import app.omnivore.omnivore.Routes
import app.omnivore.omnivore.persistence.entities.SavedItemCardData
import app.omnivore.omnivore.persistence.entities.SavedItemCardDataWithLabels
import app.omnivore.omnivore.persistence.entities.SavedItemWithLabelsAndHighlights
import app.omnivore.omnivore.ui.components.LabelsSelectionSheet
import app.omnivore.omnivore.ui.savedItemViews.SavedItemCard
import app.omnivore.omnivore.ui.reader.PDFReaderActivity
@ -49,9 +50,6 @@ fun LibraryView(
libraryViewModel: LibraryViewModel,
navController: NavHostController
) {
val actionsMenuItem: SavedItemCardData? by libraryViewModel.actionsMenuItemLiveData.observeAsState(null)
Scaffold(
topBar = {
LibraryNavigationBar(
@ -83,7 +81,7 @@ fun LibraryViewContent(libraryViewModel: LibraryViewModel, modifier: Modifier) {
onRefresh = { libraryViewModel.refresh() }
)
val cardsData: List<SavedItemCardDataWithLabels> by libraryViewModel.itemsLiveData.observeAsState(
val cardsData: List<SavedItemWithLabelsAndHighlights> by libraryViewModel.itemsLiveData.observeAsState(
listOf()
)
@ -107,18 +105,17 @@ fun LibraryViewContent(libraryViewModel: LibraryViewModel, modifier: Modifier) {
items(cardsData) { cardDataWithLabels ->
SavedItemCard(
savedItemViewModel = libraryViewModel,
cardData = cardDataWithLabels.cardData,
labels = cardDataWithLabels.labels,
savedItem = cardDataWithLabels,
onClickHandler = {
val activityClass =
if (cardDataWithLabels.cardData.isPDF()) PDFReaderActivity::class.java else WebReaderLoadingContainerActivity::class.java
if (cardDataWithLabels.savedItem.contentReader == "PDF") PDFReaderActivity::class.java else WebReaderLoadingContainerActivity::class.java
val intent = Intent(context, activityClass)
intent.putExtra("SAVED_ITEM_SLUG", cardDataWithLabels.cardData.slug)
intent.putExtra("SAVED_ITEM_SLUG", cardDataWithLabels.savedItem.slug)
context.startActivity(intent)
},
actionHandler = {
libraryViewModel.handleSavedItemAction(
cardDataWithLabels.cardData.savedItemId,
cardDataWithLabels.savedItem.savedItemId,
it
)
}

View File

@ -4,10 +4,7 @@ import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.*
import app.omnivore.omnivore.*
import app.omnivore.omnivore.dataService.*
import app.omnivore.omnivore.graphql.generated.type.CreateLabelInput
@ -38,8 +35,14 @@ class LibraryViewModel @Inject constructor(
private var receivedIdx = 0
// Live Data
private var itemsLiveDataInternal = dataService.libraryLiveData(SavedItemFilter.INBOX, SavedItemSortFilter.NEWEST, listOf())
val itemsLiveData = MediatorLiveData<List<SavedItemCardDataWithLabels>>()
private var itemsLiveDataInternal = dataService.db.savedItemDao().filteredLibraryData(
archiveFilter = 1,
sortKey = "newest",
requiredLabels = listOf(),
excludedLabels = listOf(),
allowedContentReaders = listOf("WEB", "PDF", "EPUB")
)
val itemsLiveData = MediatorLiveData<List<SavedItemWithLabelsAndHighlights>>()
val appliedFilterLiveData = MutableLiveData(SavedItemFilter.INBOX)
val appliedSortFilterLiveData = MutableLiveData(SavedItemSortFilter.NEWEST)
val showLabelsSelectionSheetLiveData = MutableLiveData(false)
@ -47,7 +50,7 @@ class LibraryViewModel @Inject constructor(
val savedItemLabelsLiveData = dataService.db.savedItemLabelDao().getSavedItemLabelsLiveData()
val activeLabelsLiveData = MutableLiveData<List<SavedItemLabel>>(listOf())
override val actionsMenuItemLiveData = MutableLiveData<SavedItemCardData?>(null)
override val actionsMenuItemLiveData = MutableLiveData<SavedItemWithLabelsAndHighlights?>(null)
var isRefreshing by mutableStateOf(false)
var hasLoadedInitialFilters = false
@ -62,25 +65,27 @@ class LibraryViewModel @Inject constructor(
}
}
runBlocking {
datastoreRepo.getString(DatastoreKeys.lastUsedSavedItemFilter)?.let { str ->
try {
val filter = SavedItemFilter.values().first { it.rawValue == str }
appliedFilterLiveData.postValue(filter)
} catch (e: Exception) {
Log.d("error", "invalid filter value stored in datastore repo: $e")
}
}
datastoreRepo.getString(DatastoreKeys.lastUsedSavedItemSortFilter)?.let { str ->
try {
val filter = SavedItemSortFilter.values().first { it.rawValue == str }
appliedSortFilterLiveData.postValue(filter)
} catch (e: Exception) {
Log.d("error", "invalid sort filter value stored in datastore repo: $e")
}
}
}
// runBlocking {
// datastoreRepo.getString(DatastoreKeys.lastUsedSavedItemFilter)?.let { str ->
// try {
// val filter = SavedItemFilter.values().first { it.rawValue == str }
// appliedFilterLiveData.postValue(filter)
// } catch (e: Exception) {
// Log.d("error", "invalid filter value stored in datastore repo: $e")
// }
//
// datastoreRepo.getString(DatastoreKeys.lastUsedSavedItemSortFilter)?.let { str ->
// try {
// val filter = SavedItemSortFilter.values().first { it.rawValue == str }
// appliedSortFilterLiveData.postValue(filter)
// } catch (e: Exception) {
// Log.d("error", "invalid sort filter value stored in datastore repo: $e")
// }
//
// handleFilterChanges()
// }
// }
// }
viewModelScope.launch {
handleFilterChanges()
@ -175,11 +180,56 @@ class LibraryViewModel @Inject constructor(
}
}
suspend fun handleFilterChanges() {
fun sortKey(appliedSortKey: String) {
when(appliedSortKey) {
}
}
fun handleFilterChanges() {
if (appliedSortFilterLiveData.value != null && appliedFilterLiveData.value != null) {
println("PERFORMING A FILTER CHANGE")
itemsLiveDataInternal = dataService.libraryLiveData(appliedFilterLiveData.value!!, appliedSortFilterLiveData.value!!, activeLabelsLiveData.value ?: listOf())
itemsLiveData.removeSource(itemsLiveDataInternal)
val applied = appliedFilterLiveData.value
val sortKey = when (appliedSortFilterLiveData.value) {
SavedItemSortFilter.NEWEST -> "newest"
SavedItemSortFilter.OLDEST -> "oldest"
SavedItemSortFilter.RECENTLY_READ -> "recentlyRead"
SavedItemSortFilter.RECENTLY_PUBLISHED -> "recentlyPublished"
else -> "newest"
}
val archiveFilter = when (appliedFilterLiveData.value) {
SavedItemFilter.ARCHIVED -> 0
else -> 1
}
val allowedContentReaders = when(appliedFilterLiveData.value) {
SavedItemFilter.FILES -> listOf("PDF", "EPUB")
else -> listOf("WEB", "PDF", "EPUB")
}
var requiredLabels = when(appliedFilterLiveData.value) {
SavedItemFilter.NEWSLETTERS -> listOf("Newsletter")
else -> (activeLabelsLiveData.value ?: listOf()).map { it.name }
}
activeLabelsLiveData.value?.let {
requiredLabels = requiredLabels + it.map { it.name }
}
val excludeLabels = when(appliedFilterLiveData.value) {
SavedItemFilter.READ_LATER -> listOf("Newsletter")
else -> listOf()
}
val newData = dataService.db.savedItemDao().filteredLibraryData(
archiveFilter = archiveFilter,
sortKey = sortKey,
requiredLabels = requiredLabels,
excludedLabels = excludeLabels,
allowedContentReaders = allowedContentReaders
)
itemsLiveData.removeSource(itemsLiveDataInternal)
itemsLiveDataInternal = newData
itemsLiveData.addSource(itemsLiveDataInternal, itemsLiveData::setValue)
}
}
@ -295,9 +345,9 @@ class LibraryViewModel @Inject constructor(
}
}
fun currentSavedItemUnderEdit(): SavedItemCardDataWithLabels? {
fun currentSavedItemUnderEdit(): SavedItemWithLabelsAndHighlights? {
labelsSelectionCurrentItemLiveData.value?.let { itemID ->
return itemsLiveData.value?.first { it.cardData.savedItemId == itemID }
return itemsLiveData.value?.first { it.savedItem.savedItemId == itemID }
}
return null

View File

@ -2,11 +2,12 @@ package app.omnivore.omnivore.ui.library
import androidx.lifecycle.MutableLiveData
import app.omnivore.omnivore.persistence.entities.SavedItemCardData
import app.omnivore.omnivore.persistence.entities.SavedItemWithLabelsAndHighlights
interface SavedItemViewModel {
val actionsMenuItemLiveData: MutableLiveData<SavedItemCardData?>
get() = MutableLiveData<SavedItemCardData?>(null)
val actionsMenuItemLiveData: MutableLiveData<SavedItemWithLabelsAndHighlights?>
get() = MutableLiveData<SavedItemWithLabelsAndHighlights?>(null)
fun handleSavedItemAction(itemID: String, action: SavedItemAction)
}

View File

@ -24,6 +24,7 @@ import androidx.navigation.NavHostController
import app.omnivore.omnivore.R
import app.omnivore.omnivore.persistence.entities.SavedItemCardData
import app.omnivore.omnivore.persistence.entities.SavedItemCardDataWithLabels
import app.omnivore.omnivore.persistence.entities.SavedItemWithLabelsAndHighlights
import app.omnivore.omnivore.ui.reader.WebReaderLoadingContainerActivity
import app.omnivore.omnivore.persistence.entities.TypeaheadCardData
import app.omnivore.omnivore.ui.reader.PDFReaderActivity
@ -39,7 +40,7 @@ fun SearchView(
val isRefreshing: Boolean by viewModel.isRefreshing.observeAsState(false)
val typeaheadMode: Boolean by viewModel.typeaheadMode.observeAsState(true)
val searchText: String by viewModel.searchTextLiveData.observeAsState("")
val actionsMenuItem: SavedItemCardData? by viewModel.actionsMenuItemLiveData.observeAsState(null)
val actionsMenuItem: SavedItemWithLabelsAndHighlights? by viewModel.actionsMenuItemLiveData.observeAsState(null)
Scaffold(
topBar = {
@ -174,7 +175,7 @@ fun SearchViewContent(viewModel: SearchViewModel, modifier: Modifier) {
val context = LocalContext.current
val listState = rememberLazyListState()
val cardsData: List<SavedItemCardDataWithLabels> by viewModel.itemsLiveData.observeAsState(listOf())
val cardsData: List<SavedItemWithLabelsAndHighlights> by viewModel.itemsLiveData.observeAsState(listOf())
LazyColumn(
state = listState,
@ -188,15 +189,14 @@ fun SearchViewContent(viewModel: SearchViewModel, modifier: Modifier) {
items(cardsData) { cardDataWithLabels ->
SavedItemCard(
savedItemViewModel = viewModel,
cardData = cardDataWithLabels.cardData,
labels = cardDataWithLabels.labels,
savedItem = cardDataWithLabels,
onClickHandler = {
val activityClass = if (cardDataWithLabels.cardData.isPDF()) PDFReaderActivity::class.java else WebReaderLoadingContainerActivity::class.java
val activityClass = if (cardDataWithLabels.savedItem.contentReader == "PDF") PDFReaderActivity::class.java else WebReaderLoadingContainerActivity::class.java
val intent = Intent(context, activityClass)
intent.putExtra("SAVED_ITEM_SLUG", cardDataWithLabels.cardData.slug)
intent.putExtra("SAVED_ITEM_SLUG", cardDataWithLabels.savedItem.slug)
context.startActivity(intent)
},
actionHandler = { viewModel.handleSavedItemAction(cardDataWithLabels.cardData.savedItemId, it) }
actionHandler = { viewModel.handleSavedItemAction(cardDataWithLabels.savedItem.savedItemId, it) }
)
}
}

View File

@ -42,9 +42,9 @@ class SearchViewModel @Inject constructor(
val typeaheadMode = MutableLiveData(true)
val searchTextLiveData = MutableLiveData("")
val searchItemsLiveData = MutableLiveData<List<TypeaheadCardData>>(listOf())
val itemsLiveData = MediatorLiveData<List<SavedItemCardDataWithLabels>>()
val itemsLiveData = MediatorLiveData<List<SavedItemWithLabelsAndHighlights>>()
override val actionsMenuItemLiveData = MutableLiveData<SavedItemCardData?>(null)
override val actionsMenuItemLiveData = MutableLiveData<SavedItemWithLabelsAndHighlights?>(null)
fun updateSearchText(text: String) {
typeaheadMode.postValue(true)
@ -88,7 +88,9 @@ class SearchViewModel @Inject constructor(
}
}
val newItems = result.savedItems.map {
val newItems = result.savedItems
/*
.map {
SavedItemCardDataWithLabels(
cardData = SavedItemCardData(
savedItemId = it.savedItem.savedItemId,
@ -107,6 +109,7 @@ class SearchViewModel @Inject constructor(
labels = listOf()
)
}
*/
itemsLiveData.value?.let{
itemsLiveData.postValue(newItems + it)

View File

@ -22,6 +22,7 @@ import androidx.compose.ui.unit.*
import app.omnivore.omnivore.R
import app.omnivore.omnivore.persistence.entities.SavedItemCardData
import app.omnivore.omnivore.persistence.entities.SavedItemLabel
import app.omnivore.omnivore.persistence.entities.SavedItemWithLabelsAndHighlights
import app.omnivore.omnivore.ui.components.LabelChipColors
import app.omnivore.omnivore.ui.library.LibraryViewModel
import app.omnivore.omnivore.ui.library.SavedItemAction
@ -31,18 +32,16 @@ import coil.compose.rememberAsyncImagePainter
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class,
)
@Composable
fun SavedItemCard(savedItemViewModel: SavedItemViewModel, cardData: SavedItemCardData, labels: List<SavedItemLabel>, onClickHandler: () -> Unit, actionHandler: (SavedItemAction) -> Unit) {
fun SavedItemCard(savedItemViewModel: SavedItemViewModel, savedItem: SavedItemWithLabelsAndHighlights, onClickHandler: () -> Unit, actionHandler: (SavedItemAction) -> Unit) {
val listState = rememberLazyListState()
val actionsMenuItem: SavedItemCardData? by savedItemViewModel.actionsMenuItemLiveData.observeAsState(null)
var isFocused = actionsMenuItem?.savedItemId == cardData.savedItemId
val actionsMenuItem: SavedItemWithLabelsAndHighlights? by savedItemViewModel.actionsMenuItemLiveData.observeAsState(null)
Column(
modifier = Modifier
.combinedClickable(
onClick = onClickHandler,
onLongClick = { savedItemViewModel.actionsMenuItemLiveData.postValue(cardData) }
onLongClick = { savedItemViewModel.actionsMenuItemLiveData.postValue(savedItem) }
)
.fillMaxWidth()
) {
@ -61,10 +60,10 @@ fun SavedItemCard(savedItemViewModel: SavedItemViewModel, cardData: SavedItemCar
.padding(end = 20.dp)
.defaultMinSize(minHeight = 55.dp)
) {
readInfo(item = cardData)
readInfo(item = savedItem)
Text(
text = cardData.title,
text = savedItem.savedItem.title,
style = TextStyle(
fontSize = 18.sp,
fontWeight = FontWeight.SemiBold
@ -73,9 +72,9 @@ fun SavedItemCard(savedItemViewModel: SavedItemViewModel, cardData: SavedItemCar
lineHeight = 20.sp
)
if (cardData.author != null && cardData.author != "") {
if (savedItem.savedItem.author != null && savedItem.savedItem.author != "") {
Text(
text = byline(cardData),
text = byline(savedItem),
style = TextStyle(
fontSize = 15.sp,
fontWeight = FontWeight.Normal,
@ -88,7 +87,7 @@ fun SavedItemCard(savedItemViewModel: SavedItemViewModel, cardData: SavedItemCar
}
Image(
painter = rememberAsyncImagePainter(cardData.imageURLString),
painter = rememberAsyncImagePainter(savedItem.savedItem.imageURLString),
contentDescription = "Image associated with saved item",
modifier = Modifier
.size(55.dp, 73.dp)
@ -105,7 +104,7 @@ fun SavedItemCard(savedItemViewModel: SavedItemViewModel, cardData: SavedItemCar
modifier = Modifier
.padding(start = 10.dp, bottom = 5.dp, end = 10.dp)
) {
items(labels.sortedBy { it.name }) { label ->
items(savedItem.labels.sortedBy { it.name }) { label ->
val chipColors = LabelChipColors.fromHex(label.color)
SuggestionChip(
@ -127,12 +126,12 @@ fun SavedItemCard(savedItemViewModel: SavedItemViewModel, cardData: SavedItemCar
}
}
fun byline(item: SavedItemCardData): String {
item.author?.let {
return item.author
fun byline(item: SavedItemWithLabelsAndHighlights): String {
item.savedItem.author?.let {
return item.savedItem.author
}
val publisherDisplayName = item.publisherDisplayName()
val publisherDisplayName = item.savedItem.publisherDisplayName()
publisherDisplayName?.let {
return publisherDisplayName
}
@ -149,8 +148,8 @@ fun byline(item: SavedItemCardData): String {
// return Int64(result)
//}
fun estimatedReadingTime(item: SavedItemCardData): String {
item.wordsCount?.let {
fun estimatedReadingTime(item: SavedItemWithLabelsAndHighlights): String {
item.savedItem.wordsCount?.let {
if (it > 0) {
val readLen = Math.max(1, it / 235)
return "$readLen MIN READ • "
@ -159,11 +158,11 @@ fun estimatedReadingTime(item: SavedItemCardData): String {
return ""
}
fun readingProgress(item: SavedItemCardData): String {
fun readingProgress(item: SavedItemWithLabelsAndHighlights): String {
// If there is no wordsCount don't show progress because it will make no sense
item.wordsCount?.let {
item.savedItem.wordsCount?.let {
if (it > 0) {
val intVal = item.readingProgress.toInt()
val intVal = item.savedItem.readingProgress.toInt()
return "$intVal%"
}
}
@ -201,7 +200,7 @@ fun readingProgress(item: SavedItemCardData): String {
//}
@Composable
fun readInfo(item: SavedItemCardData) {
fun readInfo(item: SavedItemWithLabelsAndHighlights) {
Row(
modifier = Modifier
.fillMaxWidth()
@ -223,7 +222,7 @@ fun readInfo(item: SavedItemCardData) {
style = TextStyle(
fontSize = 11.sp,
fontWeight = FontWeight.Medium,
color = if (item.readingProgress > 1) colorResource(R.color.green_55B938) else colorResource(R.color.gray_898989)
color = if (item.savedItem.readingProgress > 1) colorResource(R.color.green_55B938) else colorResource(R.color.gray_898989)
),
maxLines = 1,
overflow = TextOverflow.Ellipsis