Refactor list extra provider
This commit is contained in:
@@ -40,8 +40,6 @@ import org.koitharu.kotatsu.core.util.IncognitoModeIndicator
|
|||||||
import org.koitharu.kotatsu.core.util.ext.activityManager
|
import org.koitharu.kotatsu.core.util.ext.activityManager
|
||||||
import org.koitharu.kotatsu.core.util.ext.connectivityManager
|
import org.koitharu.kotatsu.core.util.ext.connectivityManager
|
||||||
import org.koitharu.kotatsu.core.util.ext.isLowRamDevice
|
import org.koitharu.kotatsu.core.util.ext.isLowRamDevice
|
||||||
import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
|
||||||
import org.koitharu.kotatsu.list.domain.ListExtraProviderImpl
|
|
||||||
import org.koitharu.kotatsu.local.data.CacheDir
|
import org.koitharu.kotatsu.local.data.CacheDir
|
||||||
import org.koitharu.kotatsu.local.data.CbzFetcher
|
import org.koitharu.kotatsu.local.data.CbzFetcher
|
||||||
import org.koitharu.kotatsu.local.data.LocalStorageChanges
|
import org.koitharu.kotatsu.local.data.LocalStorageChanges
|
||||||
@@ -65,9 +63,6 @@ interface AppModule {
|
|||||||
@Binds
|
@Binds
|
||||||
fun bindImageGetter(coilImageGetter: CoilImageGetter): Html.ImageGetter
|
fun bindImageGetter(coilImageGetter: CoilImageGetter): Html.ImageGetter
|
||||||
|
|
||||||
@Binds
|
|
||||||
fun bindListExtraProvider(impl: ListExtraProviderImpl): ListExtraProvider
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.core.parser
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.annotation.ColorRes
|
|
||||||
import dagger.Reusable
|
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@Reusable
|
|
||||||
class MangaTagHighlighter @Inject constructor(
|
|
||||||
@ApplicationContext context: Context,
|
|
||||||
) {
|
|
||||||
|
|
||||||
private val dict by lazy {
|
|
||||||
context.resources.openRawResource(R.raw.tags_redlist).use {
|
|
||||||
val set = HashSet<String>()
|
|
||||||
it.bufferedReader().forEachLine { x ->
|
|
||||||
val line = x.trim()
|
|
||||||
if (line.isNotEmpty()) {
|
|
||||||
set.add(line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ColorRes
|
|
||||||
fun getTint(tag: MangaTag): Int {
|
|
||||||
return if (tag.title.lowercase() in dict) {
|
|
||||||
R.color.warning
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -23,7 +23,6 @@ import org.koitharu.kotatsu.R
|
|||||||
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
|
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
|
||||||
import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter
|
import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter
|
||||||
import org.koitharu.kotatsu.core.model.countChaptersByBranch
|
import org.koitharu.kotatsu.core.model.countChaptersByBranch
|
||||||
import org.koitharu.kotatsu.core.parser.MangaTagHighlighter
|
|
||||||
import org.koitharu.kotatsu.core.ui.BaseFragment
|
import org.koitharu.kotatsu.core.ui.BaseFragment
|
||||||
import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver
|
import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver
|
||||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||||
@@ -45,6 +44,7 @@ import org.koitharu.kotatsu.details.ui.scrobbling.ScrobblingItemDecoration
|
|||||||
import org.koitharu.kotatsu.details.ui.scrobbling.ScrollingInfoAdapter
|
import org.koitharu.kotatsu.details.ui.scrobbling.ScrollingInfoAdapter
|
||||||
import org.koitharu.kotatsu.history.data.PROGRESS_NONE
|
import org.koitharu.kotatsu.history.data.PROGRESS_NONE
|
||||||
import org.koitharu.kotatsu.image.ui.ImageActivity
|
import org.koitharu.kotatsu.image.ui.ImageActivity
|
||||||
|
import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
||||||
import org.koitharu.kotatsu.main.ui.owners.NoModalBottomSheetOwner
|
import org.koitharu.kotatsu.main.ui.owners.NoModalBottomSheetOwner
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
@@ -67,7 +67,7 @@ class DetailsFragment :
|
|||||||
lateinit var coil: ImageLoader
|
lateinit var coil: ImageLoader
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var tagHighlighter: MangaTagHighlighter
|
lateinit var tagHighlighter: ListExtraProvider
|
||||||
|
|
||||||
private val viewModel by activityViewModels<DetailsViewModel>()
|
private val viewModel by activityViewModels<DetailsViewModel>()
|
||||||
|
|
||||||
@@ -283,7 +283,7 @@ class DetailsFragment :
|
|||||||
manga.tags.map { tag ->
|
manga.tags.map { tag ->
|
||||||
ChipsView.ChipModel(
|
ChipsView.ChipModel(
|
||||||
title = tag.title,
|
title = tag.title,
|
||||||
tint = tagHighlighter.getTint(tag),
|
tint = tagHighlighter.getTagTint(tag),
|
||||||
icon = 0,
|
icon = 0,
|
||||||
data = tag,
|
data = tag,
|
||||||
isCheckable = false,
|
isCheckable = false,
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.plus
|
import kotlinx.coroutines.plus
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.parser.MangaTagHighlighter
|
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
|
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
|
||||||
import org.koitharu.kotatsu.core.util.ext.call
|
import org.koitharu.kotatsu.core.util.ext.call
|
||||||
@@ -21,8 +20,6 @@ import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
|||||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||||
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment.Companion.ARG_CATEGORY_ID
|
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment.Companion.ARG_CATEGORY_ID
|
||||||
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment.Companion.NO_ID
|
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment.Companion.NO_ID
|
||||||
import org.koitharu.kotatsu.history.data.HistoryRepository
|
|
||||||
import org.koitharu.kotatsu.history.data.PROGRESS_NONE
|
|
||||||
import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
||||||
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
||||||
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
||||||
@@ -30,19 +27,16 @@ import org.koitharu.kotatsu.list.ui.model.LoadingState
|
|||||||
import org.koitharu.kotatsu.list.ui.model.toErrorState
|
import org.koitharu.kotatsu.list.ui.model.toErrorState
|
||||||
import org.koitharu.kotatsu.list.ui.model.toUi
|
import org.koitharu.kotatsu.list.ui.model.toUi
|
||||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||||
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class FavouritesListViewModel @Inject constructor(
|
class FavouritesListViewModel @Inject constructor(
|
||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
private val repository: FavouritesRepository,
|
private val repository: FavouritesRepository,
|
||||||
private val trackingRepository: TrackingRepository,
|
private val listExtraProvider: ListExtraProvider,
|
||||||
private val historyRepository: HistoryRepository,
|
settings: AppSettings,
|
||||||
private val settings: AppSettings,
|
|
||||||
private val tagHighlighter: MangaTagHighlighter,
|
|
||||||
downloadScheduler: DownloadWorker.Scheduler,
|
downloadScheduler: DownloadWorker.Scheduler,
|
||||||
) : MangaListViewModel(settings, downloadScheduler), ListExtraProvider {
|
) : MangaListViewModel(settings, downloadScheduler) {
|
||||||
|
|
||||||
val categoryId: Long = savedStateHandle[ARG_CATEGORY_ID] ?: NO_ID
|
val categoryId: Long = savedStateHandle[ARG_CATEGORY_ID] ?: NO_ID
|
||||||
|
|
||||||
@@ -76,7 +70,7 @@ class FavouritesListViewModel @Inject constructor(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> list.toUi(mode, this, tagHighlighter)
|
else -> list.toUi(mode, listExtraProvider)
|
||||||
}
|
}
|
||||||
}.catch {
|
}.catch {
|
||||||
emit(listOf(it.toErrorState(canRetry = false)))
|
emit(listOf(it.toErrorState(canRetry = false)))
|
||||||
@@ -108,20 +102,4 @@ class FavouritesListViewModel @Inject constructor(
|
|||||||
repository.setCategoryOrder(categoryId, order)
|
repository.setCategoryOrder(categoryId, order)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getCounter(mangaId: Long): Int {
|
|
||||||
return if (settings.isTrackerEnabled) {
|
|
||||||
trackingRepository.getNewChaptersCount(mangaId)
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getProgress(mangaId: Long): Float {
|
|
||||||
return if (settings.isReadingIndicatorsEnabled) {
|
|
||||||
historyRepository.getProgress(mangaId)
|
|
||||||
} else {
|
|
||||||
PROGRESS_NONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package org.koitharu.kotatsu.history.data
|
package org.koitharu.kotatsu.history.data
|
||||||
|
|
||||||
import androidx.room.*
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import androidx.room.Transaction
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||||
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||||
@@ -20,6 +24,10 @@ abstract class HistoryDao {
|
|||||||
@Query("SELECT * FROM history WHERE deleted_at = 0 ORDER BY updated_at DESC")
|
@Query("SELECT * FROM history WHERE deleted_at = 0 ORDER BY updated_at DESC")
|
||||||
abstract fun observeAll(): Flow<List<HistoryWithManga>>
|
abstract fun observeAll(): Flow<List<HistoryWithManga>>
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM history WHERE deleted_at = 0 ORDER BY updated_at DESC LIMIT :limit")
|
||||||
|
abstract fun observeAll(limit: Int): Flow<List<HistoryWithManga>>
|
||||||
|
|
||||||
@Query("SELECT * FROM manga WHERE manga_id IN (SELECT manga_id FROM history WHERE deleted_at = 0)")
|
@Query("SELECT * FROM manga WHERE manga_id IN (SELECT manga_id FROM history WHERE deleted_at = 0)")
|
||||||
abstract suspend fun findAllManga(): List<MangaEntity>
|
abstract suspend fun findAllManga(): List<MangaEntity>
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,12 @@ class HistoryRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun observeAll(limit: Int): Flow<List<Manga>> {
|
||||||
|
return db.historyDao.observeAll(limit).mapItems {
|
||||||
|
it.manga.toManga(it.tags.toMangaTags())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun observeAllWithHistory(): Flow<List<MangaWithHistory>> {
|
fun observeAllWithHistory(): Flow<List<MangaWithHistory>> {
|
||||||
return db.historyDao.observeAll().mapItems {
|
return db.historyDao.observeAll().mapItems {
|
||||||
MangaWithHistory(
|
MangaWithHistory(
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import kotlinx.coroutines.flow.onStart
|
|||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.plus
|
import kotlinx.coroutines.plus
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.parser.MangaTagHighlighter
|
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.core.prefs.ListMode
|
import org.koitharu.kotatsu.core.prefs.ListMode
|
||||||
import org.koitharu.kotatsu.core.prefs.observeAsStateFlow
|
import org.koitharu.kotatsu.core.prefs.observeAsStateFlow
|
||||||
@@ -21,8 +20,8 @@ import org.koitharu.kotatsu.core.util.ext.daysDiff
|
|||||||
import org.koitharu.kotatsu.core.util.ext.onFirst
|
import org.koitharu.kotatsu.core.util.ext.onFirst
|
||||||
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
||||||
import org.koitharu.kotatsu.history.data.HistoryRepository
|
import org.koitharu.kotatsu.history.data.HistoryRepository
|
||||||
import org.koitharu.kotatsu.history.data.PROGRESS_NONE
|
|
||||||
import org.koitharu.kotatsu.history.domain.model.MangaWithHistory
|
import org.koitharu.kotatsu.history.domain.model.MangaWithHistory
|
||||||
|
import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
||||||
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
||||||
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
||||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||||
@@ -31,7 +30,6 @@ import org.koitharu.kotatsu.list.ui.model.toErrorState
|
|||||||
import org.koitharu.kotatsu.list.ui.model.toGridModel
|
import org.koitharu.kotatsu.list.ui.model.toGridModel
|
||||||
import org.koitharu.kotatsu.list.ui.model.toListDetailedModel
|
import org.koitharu.kotatsu.list.ui.model.toListDetailedModel
|
||||||
import org.koitharu.kotatsu.list.ui.model.toListModel
|
import org.koitharu.kotatsu.list.ui.model.toListModel
|
||||||
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -40,8 +38,7 @@ import javax.inject.Inject
|
|||||||
class HistoryListViewModel @Inject constructor(
|
class HistoryListViewModel @Inject constructor(
|
||||||
private val repository: HistoryRepository,
|
private val repository: HistoryRepository,
|
||||||
private val settings: AppSettings,
|
private val settings: AppSettings,
|
||||||
private val trackingRepository: TrackingRepository,
|
private val extraProvider: ListExtraProvider,
|
||||||
private val tagHighlighter: MangaTagHighlighter,
|
|
||||||
downloadScheduler: DownloadWorker.Scheduler,
|
downloadScheduler: DownloadWorker.Scheduler,
|
||||||
) : MangaListViewModel(settings, downloadScheduler) {
|
) : MangaListViewModel(settings, downloadScheduler) {
|
||||||
|
|
||||||
@@ -106,7 +103,6 @@ class HistoryListViewModel @Inject constructor(
|
|||||||
mode: ListMode,
|
mode: ListMode,
|
||||||
): List<ListModel> {
|
): List<ListModel> {
|
||||||
val result = ArrayList<ListModel>(if (grouped) (list.size * 1.4).toInt() else list.size + 1)
|
val result = ArrayList<ListModel>(if (grouped) (list.size * 1.4).toInt() else list.size + 1)
|
||||||
val showPercent = settings.isReadingIndicatorsEnabled
|
|
||||||
var prevDate: DateTimeAgo? = null
|
var prevDate: DateTimeAgo? = null
|
||||||
for ((manga, history) in list) {
|
for ((manga, history) in list) {
|
||||||
if (grouped) {
|
if (grouped) {
|
||||||
@@ -116,16 +112,10 @@ class HistoryListViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
prevDate = date
|
prevDate = date
|
||||||
}
|
}
|
||||||
val counter = if (settings.isTrackerEnabled) {
|
|
||||||
trackingRepository.getNewChaptersCount(manga.id)
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
val percent = if (showPercent) history.percent else PROGRESS_NONE
|
|
||||||
result += when (mode) {
|
result += when (mode) {
|
||||||
ListMode.LIST -> manga.toListModel(counter, percent)
|
ListMode.LIST -> manga.toListModel(extraProvider)
|
||||||
ListMode.DETAILED_LIST -> manga.toListDetailedModel(counter, percent, tagHighlighter)
|
ListMode.DETAILED_LIST -> manga.toListDetailedModel(extraProvider)
|
||||||
ListMode.GRID -> manga.toGridModel(counter, percent)
|
ListMode.GRID -> manga.toGridModel(extraProvider)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -1,8 +1,60 @@
|
|||||||
package org.koitharu.kotatsu.list.domain
|
package org.koitharu.kotatsu.list.domain
|
||||||
|
|
||||||
interface ListExtraProvider {
|
import android.content.Context
|
||||||
|
import androidx.annotation.ColorRes
|
||||||
|
import dagger.Reusable
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.history.data.HistoryRepository
|
||||||
|
import org.koitharu.kotatsu.history.data.PROGRESS_NONE
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||||
|
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
suspend fun getCounter(mangaId: Long): Int
|
@Reusable
|
||||||
|
class ListExtraProvider @Inject constructor(
|
||||||
|
@ApplicationContext context: Context,
|
||||||
|
private val settings: AppSettings,
|
||||||
|
private val trackingRepository: TrackingRepository,
|
||||||
|
private val historyRepository: HistoryRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
suspend fun getProgress(mangaId: Long): Float
|
private val dict by lazy {
|
||||||
}
|
context.resources.openRawResource(R.raw.tags_redlist).use {
|
||||||
|
val set = HashSet<String>()
|
||||||
|
it.bufferedReader().forEachLine { x ->
|
||||||
|
val line = x.trim()
|
||||||
|
if (line.isNotEmpty()) {
|
||||||
|
set.add(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getCounter(mangaId: Long): Int {
|
||||||
|
return if (settings.isTrackerEnabled) {
|
||||||
|
trackingRepository.getNewChaptersCount(mangaId)
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getProgress(mangaId: Long): Float {
|
||||||
|
return if (settings.isReadingIndicatorsEnabled) {
|
||||||
|
historyRepository.getProgress(mangaId)
|
||||||
|
} else {
|
||||||
|
PROGRESS_NONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorRes
|
||||||
|
fun getTagTint(tag: MangaTag): Int {
|
||||||
|
return if (tag.title.lowercase() in dict) {
|
||||||
|
R.color.warning
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.list.domain
|
|
||||||
|
|
||||||
import dagger.Reusable
|
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
|
||||||
import org.koitharu.kotatsu.history.data.HistoryRepository
|
|
||||||
import org.koitharu.kotatsu.history.data.PROGRESS_NONE
|
|
||||||
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@Reusable
|
|
||||||
class ListExtraProviderImpl @Inject constructor(
|
|
||||||
private val settings: AppSettings,
|
|
||||||
private val trackingRepository: TrackingRepository,
|
|
||||||
private val historyRepository: HistoryRepository,
|
|
||||||
) : ListExtraProvider {
|
|
||||||
|
|
||||||
override suspend fun getCounter(mangaId: Long): Int {
|
|
||||||
return if (settings.isTrackerEnabled) {
|
|
||||||
trackingRepository.getNewChaptersCount(mangaId)
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getProgress(mangaId: Long): Float {
|
|
||||||
return if (settings.isReadingIndicatorsEnabled) {
|
|
||||||
historyRepository.getProgress(mangaId)
|
|
||||||
} else {
|
|
||||||
PROGRESS_NONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ package org.koitharu.kotatsu.list.ui.model
|
|||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
||||||
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
||||||
import org.koitharu.kotatsu.core.parser.MangaTagHighlighter
|
|
||||||
import org.koitharu.kotatsu.core.prefs.ListMode
|
import org.koitharu.kotatsu.core.prefs.ListMode
|
||||||
import org.koitharu.kotatsu.core.ui.widgets.ChipsView
|
import org.koitharu.kotatsu.core.ui.widgets.ChipsView
|
||||||
import org.koitharu.kotatsu.core.util.ext.ifZero
|
import org.koitharu.kotatsu.core.util.ext.ifZero
|
||||||
@@ -14,34 +13,31 @@ import org.koitharu.kotatsu.parsers.model.Manga
|
|||||||
import java.net.SocketTimeoutException
|
import java.net.SocketTimeoutException
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
|
|
||||||
fun Manga.toListModel(
|
suspend fun Manga.toListModel(
|
||||||
counter: Int,
|
extraProvider: ListExtraProvider?
|
||||||
progress: Float,
|
|
||||||
) = MangaListModel(
|
) = MangaListModel(
|
||||||
id = id,
|
id = id,
|
||||||
title = title,
|
title = title,
|
||||||
subtitle = tags.joinToString(", ") { it.title },
|
subtitle = tags.joinToString(", ") { it.title },
|
||||||
coverUrl = coverUrl,
|
coverUrl = coverUrl,
|
||||||
manga = this,
|
manga = this,
|
||||||
counter = counter,
|
counter = extraProvider?.getCounter(id) ?: 0,
|
||||||
progress = progress,
|
progress = extraProvider?.getProgress(id) ?: PROGRESS_NONE,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun Manga.toListDetailedModel(
|
suspend fun Manga.toListDetailedModel(
|
||||||
counter: Int,
|
extraProvider: ListExtraProvider?,
|
||||||
progress: Float,
|
|
||||||
tagHighlighter: MangaTagHighlighter?,
|
|
||||||
) = MangaListDetailedModel(
|
) = MangaListDetailedModel(
|
||||||
id = id,
|
id = id,
|
||||||
title = title,
|
title = title,
|
||||||
subtitle = altTitle,
|
subtitle = altTitle,
|
||||||
coverUrl = coverUrl,
|
coverUrl = coverUrl,
|
||||||
manga = this,
|
manga = this,
|
||||||
counter = counter,
|
counter = extraProvider?.getCounter(id) ?: 0,
|
||||||
progress = progress,
|
progress = extraProvider?.getProgress(id) ?: PROGRESS_NONE,
|
||||||
tags = tags.map {
|
tags = tags.map {
|
||||||
ChipsView.ChipModel(
|
ChipsView.ChipModel(
|
||||||
tint = tagHighlighter?.getTint(it) ?: 0,
|
tint = extraProvider?.getTagTint(it) ?: 0,
|
||||||
title = it.title,
|
title = it.title,
|
||||||
icon = 0,
|
icon = 0,
|
||||||
isCheckable = false,
|
isCheckable = false,
|
||||||
@@ -51,53 +47,30 @@ fun Manga.toListDetailedModel(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
fun Manga.toGridModel(counter: Int, progress: Float) = MangaGridModel(
|
suspend fun Manga.toGridModel(
|
||||||
|
extraProvider: ListExtraProvider?,
|
||||||
|
) = MangaGridModel(
|
||||||
id = id,
|
id = id,
|
||||||
title = title,
|
title = title,
|
||||||
coverUrl = coverUrl,
|
coverUrl = coverUrl,
|
||||||
manga = this,
|
manga = this,
|
||||||
counter = counter,
|
counter = extraProvider?.getCounter(id) ?: 0,
|
||||||
progress = progress,
|
progress = extraProvider?.getProgress(id) ?: PROGRESS_NONE,
|
||||||
)
|
)
|
||||||
|
|
||||||
suspend fun List<Manga>.toUi(
|
suspend fun List<Manga>.toUi(
|
||||||
mode: ListMode,
|
mode: ListMode,
|
||||||
extraProvider: ListExtraProvider,
|
extraProvider: ListExtraProvider,
|
||||||
tagHighlighter: MangaTagHighlighter?,
|
): List<MangaItemModel> = toUi(ArrayList(size), mode, extraProvider)
|
||||||
): List<MangaItemModel> = toUi(ArrayList(size), mode, extraProvider, tagHighlighter)
|
|
||||||
|
|
||||||
fun List<Manga>.toUi(
|
|
||||||
mode: ListMode,
|
|
||||||
tagHighlighter: MangaTagHighlighter?,
|
|
||||||
): List<MangaItemModel> = toUi(ArrayList(size), mode, tagHighlighter)
|
|
||||||
|
|
||||||
fun <C : MutableCollection<in MangaItemModel>> List<Manga>.toUi(
|
|
||||||
destination: C,
|
|
||||||
mode: ListMode,
|
|
||||||
tagHighlighter: MangaTagHighlighter?,
|
|
||||||
): C = when (mode) {
|
|
||||||
ListMode.LIST -> mapTo(destination) { it.toListModel(0, PROGRESS_NONE) }
|
|
||||||
ListMode.DETAILED_LIST -> mapTo(destination) { it.toListDetailedModel(0, PROGRESS_NONE, tagHighlighter) }
|
|
||||||
ListMode.GRID -> mapTo(destination) { it.toGridModel(0, PROGRESS_NONE) }
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun <C : MutableCollection<in MangaItemModel>> List<Manga>.toUi(
|
suspend fun <C : MutableCollection<in MangaItemModel>> List<Manga>.toUi(
|
||||||
destination: C,
|
destination: C,
|
||||||
mode: ListMode,
|
mode: ListMode,
|
||||||
extraProvider: ListExtraProvider,
|
extraProvider: ListExtraProvider,
|
||||||
tagHighlighter: MangaTagHighlighter?,
|
|
||||||
): C = when (mode) {
|
): C = when (mode) {
|
||||||
ListMode.LIST -> mapTo(destination) {
|
ListMode.LIST -> mapTo(destination) { it.toListModel(extraProvider) }
|
||||||
it.toListModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id))
|
ListMode.DETAILED_LIST -> mapTo(destination) { it.toListDetailedModel(extraProvider) }
|
||||||
}
|
ListMode.GRID -> mapTo(destination) { it.toGridModel(extraProvider) }
|
||||||
|
|
||||||
ListMode.DETAILED_LIST -> mapTo(destination) {
|
|
||||||
it.toListDetailedModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id), tagHighlighter)
|
|
||||||
}
|
|
||||||
|
|
||||||
ListMode.GRID -> mapTo(destination) {
|
|
||||||
it.toGridModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Throwable.toErrorState(canRetry: Boolean = true) = ErrorState(
|
fun Throwable.toErrorState(canRetry: Boolean = true) = ErrorState(
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||||
import org.koitharu.kotatsu.core.parser.MangaTagHighlighter
|
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
|
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
|
||||||
import org.koitharu.kotatsu.core.util.ext.call
|
import org.koitharu.kotatsu.core.util.ext.call
|
||||||
@@ -25,7 +24,6 @@ class LocalListViewModel @Inject constructor(
|
|||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
mangaRepositoryFactory: MangaRepository.Factory,
|
mangaRepositoryFactory: MangaRepository.Factory,
|
||||||
filter: FilterCoordinator,
|
filter: FilterCoordinator,
|
||||||
tagHighlighter: MangaTagHighlighter,
|
|
||||||
settings: AppSettings,
|
settings: AppSettings,
|
||||||
downloadScheduler: DownloadWorker.Scheduler,
|
downloadScheduler: DownloadWorker.Scheduler,
|
||||||
listExtraProvider: ListExtraProvider,
|
listExtraProvider: ListExtraProvider,
|
||||||
@@ -35,7 +33,6 @@ class LocalListViewModel @Inject constructor(
|
|||||||
savedStateHandle,
|
savedStateHandle,
|
||||||
mangaRepositoryFactory,
|
mangaRepositoryFactory,
|
||||||
filter,
|
filter,
|
||||||
tagHighlighter,
|
|
||||||
settings,
|
settings,
|
||||||
listExtraProvider,
|
listExtraProvider,
|
||||||
downloadScheduler,
|
downloadScheduler,
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import kotlinx.coroutines.flow.stateIn
|
|||||||
import kotlinx.coroutines.plus
|
import kotlinx.coroutines.plus
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||||
import org.koitharu.kotatsu.core.parser.MangaTagHighlighter
|
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.core.util.ext.call
|
import org.koitharu.kotatsu.core.util.ext.call
|
||||||
import org.koitharu.kotatsu.core.util.ext.require
|
import org.koitharu.kotatsu.core.util.ext.require
|
||||||
@@ -47,7 +46,6 @@ open class RemoteListViewModel @Inject constructor(
|
|||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
mangaRepositoryFactory: MangaRepository.Factory,
|
mangaRepositoryFactory: MangaRepository.Factory,
|
||||||
private val filter: FilterCoordinator,
|
private val filter: FilterCoordinator,
|
||||||
private val tagHighlighter: MangaTagHighlighter,
|
|
||||||
settings: AppSettings,
|
settings: AppSettings,
|
||||||
listExtraProvider: ListExtraProvider,
|
listExtraProvider: ListExtraProvider,
|
||||||
downloadScheduler: DownloadWorker.Scheduler,
|
downloadScheduler: DownloadWorker.Scheduler,
|
||||||
@@ -72,7 +70,7 @@ open class RemoteListViewModel @Inject constructor(
|
|||||||
list == null -> add(LoadingState)
|
list == null -> add(LoadingState)
|
||||||
list.isEmpty() -> add(createEmptyState(header.value.hasSelectedTags))
|
list.isEmpty() -> add(createEmptyState(header.value.hasSelectedTags))
|
||||||
else -> {
|
else -> {
|
||||||
list.toUi(this, mode, listExtraProvider, tagHighlighter)
|
list.toUi(this, mode, listExtraProvider)
|
||||||
when {
|
when {
|
||||||
error != null -> add(error.toErrorFooter())
|
error != null -> add(error.toErrorFooter())
|
||||||
hasNext -> add(LoadingFooter())
|
hasNext -> add(LoadingFooter())
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import kotlinx.coroutines.flow.stateIn
|
|||||||
import kotlinx.coroutines.plus
|
import kotlinx.coroutines.plus
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||||
import org.koitharu.kotatsu.core.parser.MangaTagHighlighter
|
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.core.util.ext.require
|
import org.koitharu.kotatsu.core.util.ext.require
|
||||||
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
||||||
|
import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
||||||
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
||||||
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
||||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||||
@@ -33,7 +33,7 @@ class SearchViewModel @Inject constructor(
|
|||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
repositoryFactory: MangaRepository.Factory,
|
repositoryFactory: MangaRepository.Factory,
|
||||||
settings: AppSettings,
|
settings: AppSettings,
|
||||||
private val tagHighlighter: MangaTagHighlighter,
|
private val extraProvider: ListExtraProvider,
|
||||||
downloadScheduler: DownloadWorker.Scheduler,
|
downloadScheduler: DownloadWorker.Scheduler,
|
||||||
) : MangaListViewModel(settings, downloadScheduler) {
|
) : MangaListViewModel(settings, downloadScheduler) {
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ class SearchViewModel @Inject constructor(
|
|||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
val result = ArrayList<ListModel>(list.size + 1)
|
val result = ArrayList<ListModel>(list.size + 1)
|
||||||
list.toUi(result, mode, tagHighlighter)
|
list.toUi(result, mode, extraProvider)
|
||||||
when {
|
when {
|
||||||
error != null -> result += error.toErrorFooter()
|
error != null -> result += error.toErrorFooter()
|
||||||
hasNext -> result += LoadingFooter()
|
hasNext -> result += LoadingFooter()
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.koitharu.kotatsu.core.ui.BaseViewModel
|
|||||||
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
|
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
|
||||||
import org.koitharu.kotatsu.core.util.ext.call
|
import org.koitharu.kotatsu.core.util.ext.call
|
||||||
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
||||||
|
import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
||||||
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
||||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||||
import org.koitharu.kotatsu.list.ui.model.LoadingFooter
|
import org.koitharu.kotatsu.list.ui.model.LoadingFooter
|
||||||
@@ -42,6 +43,7 @@ private const val MIN_HAS_MORE_ITEMS = 8
|
|||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class MultiSearchViewModel @Inject constructor(
|
class MultiSearchViewModel @Inject constructor(
|
||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
|
private val extraProvider: ListExtraProvider,
|
||||||
private val settings: AppSettings,
|
private val settings: AppSettings,
|
||||||
private val mangaRepositoryFactory: MangaRepository.Factory,
|
private val mangaRepositoryFactory: MangaRepository.Factory,
|
||||||
private val downloadScheduler: DownloadWorker.Scheduler,
|
private val downloadScheduler: DownloadWorker.Scheduler,
|
||||||
@@ -128,7 +130,7 @@ class MultiSearchViewModel @Inject constructor(
|
|||||||
async(dispatcher) {
|
async(dispatcher) {
|
||||||
runCatchingCancellable {
|
runCatchingCancellable {
|
||||||
val list = mangaRepositoryFactory.create(source).getList(offset = 0, query = q)
|
val list = mangaRepositoryFactory.create(source).getList(offset = 0, query = q)
|
||||||
.toUi(ListMode.GRID, null)
|
.toUi(ListMode.GRID, extraProvider)
|
||||||
if (list.isNotEmpty()) {
|
if (list.isNotEmpty()) {
|
||||||
MultiSearchListModel(source, list.size > MIN_HAS_MORE_ITEMS, list)
|
MultiSearchListModel(source, list.size > MIN_HAS_MORE_ITEMS, list)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.koitharu.kotatsu.suggestions.domain.SuggestionRepository
|
|||||||
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("SameParameterValue")
|
||||||
class ShelfContentObserveUseCase @Inject constructor(
|
class ShelfContentObserveUseCase @Inject constructor(
|
||||||
private val localMangaRepository: LocalMangaRepository,
|
private val localMangaRepository: LocalMangaRepository,
|
||||||
private val historyRepository: HistoryRepository,
|
private val historyRepository: HistoryRepository,
|
||||||
@@ -35,20 +36,20 @@ class ShelfContentObserveUseCase @Inject constructor(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
operator fun invoke(): Flow<ShelfContent> = combine(
|
operator fun invoke(): Flow<ShelfContent> = combine(
|
||||||
historyRepository.observeAllWithHistory(),
|
historyRepository.observeAll(20),
|
||||||
observeLocalManga(SortOrder.UPDATED),
|
observeLocalManga(SortOrder.UPDATED, 20),
|
||||||
observeFavourites(),
|
observeFavourites(),
|
||||||
trackingRepository.observeUpdatedManga(),
|
trackingRepository.observeUpdatedManga(),
|
||||||
suggestionRepository.observeAll(16),
|
suggestionRepository.observeAll(20),
|
||||||
) { history, local, favorites, updated, suggestions ->
|
) { history, local, favorites, updated, suggestions ->
|
||||||
ShelfContent(history, favorites, updated, local, suggestions)
|
ShelfContent(history, favorites, updated, local, suggestions)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeLocalManga(sortOrder: SortOrder): Flow<List<Manga>> {
|
private fun observeLocalManga(sortOrder: SortOrder, limit: Int): Flow<List<Manga>> {
|
||||||
return localStorageChanges
|
return localStorageChanges
|
||||||
.onStart { emit(null) }
|
.onStart { emit(null) }
|
||||||
.mapLatest {
|
.mapLatest {
|
||||||
localMangaRepository.getList(0, null, sortOrder)
|
localMangaRepository.getList(0, null, sortOrder).take(limit)
|
||||||
}.distinctUntilChanged()
|
}.distinctUntilChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
package org.koitharu.kotatsu.shelf.domain.model
|
package org.koitharu.kotatsu.shelf.domain.model
|
||||||
|
|
||||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||||
import org.koitharu.kotatsu.history.domain.model.MangaWithHistory
|
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
|
|
||||||
class ShelfContent(
|
class ShelfContent(
|
||||||
val history: List<MangaWithHistory>,
|
val history: List<Manga>,
|
||||||
val favourites: Map<FavouriteCategory, List<Manga>>,
|
val favourites: Map<FavouriteCategory, List<Manga>>,
|
||||||
val updated: Map<Manga, Int>,
|
val updated: List<Manga>,
|
||||||
val local: List<Manga>,
|
val local: List<Manga>,
|
||||||
val suggestions: List<Manga>,
|
val suggestions: List<Manga>,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ import org.koitharu.kotatsu.core.util.ext.call
|
|||||||
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
||||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||||
import org.koitharu.kotatsu.history.data.HistoryRepository
|
import org.koitharu.kotatsu.history.data.HistoryRepository
|
||||||
import org.koitharu.kotatsu.history.data.PROGRESS_NONE
|
|
||||||
import org.koitharu.kotatsu.history.domain.model.MangaWithHistory
|
|
||||||
import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
||||||
import org.koitharu.kotatsu.list.ui.model.EmptyHint
|
import org.koitharu.kotatsu.list.ui.model.EmptyHint
|
||||||
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
||||||
@@ -41,21 +39,20 @@ import org.koitharu.kotatsu.shelf.domain.model.ShelfContent
|
|||||||
import org.koitharu.kotatsu.shelf.domain.model.ShelfSection
|
import org.koitharu.kotatsu.shelf.domain.model.ShelfSection
|
||||||
import org.koitharu.kotatsu.shelf.ui.model.ShelfSectionModel
|
import org.koitharu.kotatsu.shelf.ui.model.ShelfSectionModel
|
||||||
import org.koitharu.kotatsu.sync.domain.SyncController
|
import org.koitharu.kotatsu.sync.domain.SyncController
|
||||||
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class ShelfViewModel @Inject constructor(
|
class ShelfViewModel @Inject constructor(
|
||||||
private val historyRepository: HistoryRepository,
|
private val historyRepository: HistoryRepository,
|
||||||
private val favouritesRepository: FavouritesRepository,
|
private val favouritesRepository: FavouritesRepository,
|
||||||
private val trackingRepository: TrackingRepository,
|
|
||||||
private val settings: AppSettings,
|
private val settings: AppSettings,
|
||||||
private val downloadScheduler: DownloadWorker.Scheduler,
|
private val downloadScheduler: DownloadWorker.Scheduler,
|
||||||
private val deleteLocalMangaUseCase: DeleteLocalMangaUseCase,
|
private val deleteLocalMangaUseCase: DeleteLocalMangaUseCase,
|
||||||
|
private val listExtraProvider: ListExtraProvider,
|
||||||
shelfContentObserveUseCase: ShelfContentObserveUseCase,
|
shelfContentObserveUseCase: ShelfContentObserveUseCase,
|
||||||
syncController: SyncController,
|
syncController: SyncController,
|
||||||
networkState: NetworkState,
|
networkState: NetworkState,
|
||||||
) : BaseViewModel(), ListExtraProvider {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
val onActionDone = MutableEventFlow<ReversibleAction>()
|
val onActionDone = MutableEventFlow<ReversibleAction>()
|
||||||
val onDownloadStarted = MutableEventFlow<Unit>()
|
val onDownloadStarted = MutableEventFlow<Unit>()
|
||||||
@@ -78,22 +75,6 @@ class ShelfViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getCounter(mangaId: Long): Int {
|
|
||||||
return if (settings.isTrackerEnabled) {
|
|
||||||
trackingRepository.getNewChaptersCount(mangaId)
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getProgress(mangaId: Long): Float {
|
|
||||||
return if (settings.isReadingIndicatorsEnabled) {
|
|
||||||
historyRepository.getProgress(mangaId)
|
|
||||||
} else {
|
|
||||||
PROGRESS_NONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun removeFromFavourites(category: FavouriteCategory, ids: Set<Long>) {
|
fun removeFromFavourites(category: FavouriteCategory, ids: Set<Long>) {
|
||||||
if (ids.isEmpty()) {
|
if (ids.isEmpty()) {
|
||||||
return
|
return
|
||||||
@@ -194,7 +175,7 @@ class ShelfViewModel @Inject constructor(
|
|||||||
when (section) {
|
when (section) {
|
||||||
ShelfSection.HISTORY -> mapHistory(
|
ShelfSection.HISTORY -> mapHistory(
|
||||||
result,
|
result,
|
||||||
content.history.filter { it.manga.source == MangaSource.LOCAL },
|
content.history.filter { it.source == MangaSource.LOCAL },
|
||||||
)
|
)
|
||||||
|
|
||||||
ShelfSection.LOCAL -> mapLocal(result, content.local)
|
ShelfSection.LOCAL -> mapLocal(result, content.local)
|
||||||
@@ -222,17 +203,14 @@ class ShelfViewModel @Inject constructor(
|
|||||||
|
|
||||||
private suspend fun mapHistory(
|
private suspend fun mapHistory(
|
||||||
destination: MutableList<in ShelfSectionModel.History>,
|
destination: MutableList<in ShelfSectionModel.History>,
|
||||||
list: List<MangaWithHistory>,
|
list: List<Manga>,
|
||||||
) {
|
) {
|
||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val showPercent = settings.isReadingIndicatorsEnabled
|
|
||||||
destination += ShelfSectionModel.History(
|
destination += ShelfSectionModel.History(
|
||||||
items = list.map { (manga, history) ->
|
items = list.map { manga ->
|
||||||
val counter = getCounter(manga.id)
|
manga.toGridModel(listExtraProvider)
|
||||||
val percent = if (showPercent) history.percent else PROGRESS_NONE
|
|
||||||
manga.toGridModel(counter, percent)
|
|
||||||
},
|
},
|
||||||
showAllButtonText = R.string.show_all,
|
showAllButtonText = R.string.show_all,
|
||||||
)
|
)
|
||||||
@@ -240,16 +218,15 @@ class ShelfViewModel @Inject constructor(
|
|||||||
|
|
||||||
private suspend fun mapUpdated(
|
private suspend fun mapUpdated(
|
||||||
destination: MutableList<in ShelfSectionModel.Updated>,
|
destination: MutableList<in ShelfSectionModel.Updated>,
|
||||||
updated: Map<Manga, Int>,
|
updated: List<Manga>,
|
||||||
) {
|
) {
|
||||||
if (updated.isEmpty()) {
|
if (updated.isEmpty()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val showPercent = settings.isReadingIndicatorsEnabled
|
settings.isReadingIndicatorsEnabled
|
||||||
destination += ShelfSectionModel.Updated(
|
destination += ShelfSectionModel.Updated(
|
||||||
items = updated.map { (manga, counter) ->
|
items = updated.map { manga ->
|
||||||
val percent = if (showPercent) getProgress(manga.id) else PROGRESS_NONE
|
manga.toGridModel(listExtraProvider)
|
||||||
manga.toGridModel(counter, percent)
|
|
||||||
},
|
},
|
||||||
showAllButtonText = R.string.show_all,
|
showAllButtonText = R.string.show_all,
|
||||||
)
|
)
|
||||||
@@ -263,7 +240,7 @@ class ShelfViewModel @Inject constructor(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
destination += ShelfSectionModel.Local(
|
destination += ShelfSectionModel.Local(
|
||||||
items = local.toUi(ListMode.GRID, this, null),
|
items = local.toUi(ListMode.GRID, listExtraProvider),
|
||||||
showAllButtonText = R.string.show_all,
|
showAllButtonText = R.string.show_all,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -276,7 +253,7 @@ class ShelfViewModel @Inject constructor(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
destination += ShelfSectionModel.Suggestions(
|
destination += ShelfSectionModel.Suggestions(
|
||||||
items = suggestions.toUi(ListMode.GRID, this, null),
|
items = suggestions.toUi(ListMode.GRID, listExtraProvider),
|
||||||
showAllButtonText = R.string.show_all,
|
showAllButtonText = R.string.show_all,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -291,7 +268,7 @@ class ShelfViewModel @Inject constructor(
|
|||||||
for ((category, list) in favourites) {
|
for ((category, list) in favourites) {
|
||||||
if (list.isNotEmpty()) {
|
if (list.isNotEmpty()) {
|
||||||
destination += ShelfSectionModel.Favourites(
|
destination += ShelfSectionModel.Favourites(
|
||||||
items = list.toUi(ListMode.GRID, this, null),
|
items = list.toUi(ListMode.GRID, listExtraProvider),
|
||||||
category = category,
|
category = category,
|
||||||
showAllButtonText = R.string.show_all,
|
showAllButtonText = R.string.show_all,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ import kotlinx.coroutines.flow.onStart
|
|||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.plus
|
import kotlinx.coroutines.plus
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.parser.MangaTagHighlighter
|
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.core.util.ext.onFirst
|
import org.koitharu.kotatsu.core.util.ext.onFirst
|
||||||
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
||||||
|
import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
||||||
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
||||||
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
||||||
import org.koitharu.kotatsu.list.ui.model.LoadingState
|
import org.koitharu.kotatsu.list.ui.model.LoadingState
|
||||||
@@ -26,7 +26,7 @@ import javax.inject.Inject
|
|||||||
class SuggestionsViewModel @Inject constructor(
|
class SuggestionsViewModel @Inject constructor(
|
||||||
repository: SuggestionRepository,
|
repository: SuggestionRepository,
|
||||||
settings: AppSettings,
|
settings: AppSettings,
|
||||||
private val tagHighlighter: MangaTagHighlighter,
|
private val extraProvider: ListExtraProvider,
|
||||||
downloadScheduler: DownloadWorker.Scheduler,
|
downloadScheduler: DownloadWorker.Scheduler,
|
||||||
) : MangaListViewModel(settings, downloadScheduler) {
|
) : MangaListViewModel(settings, downloadScheduler) {
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ class SuggestionsViewModel @Inject constructor(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> list.toUi(mode, tagHighlighter)
|
else -> list.toUi(mode, extraProvider)
|
||||||
}
|
}
|
||||||
}.onStart {
|
}.onStart {
|
||||||
loadingCounter.increment()
|
loadingCounter.increment()
|
||||||
|
|||||||
@@ -34,9 +34,8 @@ abstract class TracksDao {
|
|||||||
abstract fun observeNewChapters(mangaId: Long): Flow<Int?>
|
abstract fun observeNewChapters(mangaId: Long): Flow<Int?>
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
@MapInfo(valueColumn = "chapters_new")
|
@Query("SELECT manga.* FROM tracks LEFT JOIN manga ON manga.manga_id = tracks.manga_id WHERE chapters_new > 0 ORDER BY chapters_new DESC")
|
||||||
@Query("SELECT manga.*, chapters_new FROM tracks LEFT JOIN manga ON manga.manga_id = tracks.manga_id WHERE chapters_new > 0 ORDER BY chapters_new DESC")
|
abstract fun observeUpdatedManga(): Flow<List<MangaWithTags>>
|
||||||
abstract fun observeUpdatedManga(): Flow<Map<MangaWithTags, Int>>
|
|
||||||
|
|
||||||
@Query("DELETE FROM tracks")
|
@Query("DELETE FROM tracks")
|
||||||
abstract suspend fun clear()
|
abstract suspend fun clear()
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import org.koitharu.kotatsu.core.db.MangaDatabase
|
|||||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||||
import org.koitharu.kotatsu.core.db.entity.toManga
|
import org.koitharu.kotatsu.core.db.entity.toManga
|
||||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.mapItems
|
||||||
import org.koitharu.kotatsu.favourites.data.toFavouriteCategory
|
import org.koitharu.kotatsu.favourites.data.toFavouriteCategory
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
@@ -44,9 +45,9 @@ class TrackingRepository @Inject constructor(
|
|||||||
return db.tracksDao.observeNewChapters().map { list -> list.count { it > 0 } }
|
return db.tracksDao.observeNewChapters().map { list -> list.count { it > 0 } }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun observeUpdatedManga(): Flow<Map<Manga, Int>> {
|
fun observeUpdatedManga(): Flow<List<Manga>> {
|
||||||
return db.tracksDao.observeUpdatedManga()
|
return db.tracksDao.observeUpdatedManga()
|
||||||
.map { x -> x.mapKeys { it.key.toManga() } }
|
.mapItems { it.toManga() }
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,22 +10,16 @@ import kotlinx.coroutines.flow.onStart
|
|||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.plus
|
import kotlinx.coroutines.plus
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.parser.MangaTagHighlighter
|
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.core.prefs.ListMode
|
|
||||||
import org.koitharu.kotatsu.core.util.ext.onFirst
|
import org.koitharu.kotatsu.core.util.ext.onFirst
|
||||||
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
||||||
import org.koitharu.kotatsu.history.data.HistoryRepository
|
import org.koitharu.kotatsu.history.data.HistoryRepository
|
||||||
import org.koitharu.kotatsu.history.data.PROGRESS_NONE
|
import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
||||||
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
||||||
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
||||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
|
||||||
import org.koitharu.kotatsu.list.ui.model.LoadingState
|
import org.koitharu.kotatsu.list.ui.model.LoadingState
|
||||||
import org.koitharu.kotatsu.list.ui.model.toErrorState
|
import org.koitharu.kotatsu.list.ui.model.toErrorState
|
||||||
import org.koitharu.kotatsu.list.ui.model.toGridModel
|
import org.koitharu.kotatsu.list.ui.model.toUi
|
||||||
import org.koitharu.kotatsu.list.ui.model.toListDetailedModel
|
|
||||||
import org.koitharu.kotatsu.list.ui.model.toListModel
|
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
|
||||||
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -34,16 +28,16 @@ class UpdatesViewModel @Inject constructor(
|
|||||||
private val repository: TrackingRepository,
|
private val repository: TrackingRepository,
|
||||||
private val settings: AppSettings,
|
private val settings: AppSettings,
|
||||||
private val historyRepository: HistoryRepository,
|
private val historyRepository: HistoryRepository,
|
||||||
private val tagHighlighter: MangaTagHighlighter,
|
private val extraProvider: ListExtraProvider,
|
||||||
downloadScheduler: DownloadWorker.Scheduler,
|
downloadScheduler: DownloadWorker.Scheduler,
|
||||||
) : MangaListViewModel(settings, downloadScheduler) {
|
) : MangaListViewModel(settings, downloadScheduler) {
|
||||||
|
|
||||||
override val content = combine(
|
override val content = combine(
|
||||||
repository.observeUpdatedManga(),
|
repository.observeUpdatedManga(),
|
||||||
listMode,
|
listMode,
|
||||||
) { mangaMap, mode ->
|
) { mangaList, mode ->
|
||||||
when {
|
when {
|
||||||
mangaMap.isEmpty() -> listOf(
|
mangaList.isEmpty() -> listOf(
|
||||||
EmptyState(
|
EmptyState(
|
||||||
icon = R.drawable.ic_empty_history,
|
icon = R.drawable.ic_empty_history,
|
||||||
textPrimary = R.string.text_history_holder_primary,
|
textPrimary = R.string.text_history_holder_primary,
|
||||||
@@ -52,7 +46,7 @@ class UpdatesViewModel @Inject constructor(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> mapList(mangaMap, mode)
|
else -> mangaList.toUi(mode, extraProvider)
|
||||||
}
|
}
|
||||||
}.onStart {
|
}.onStart {
|
||||||
loadingCounter.increment()
|
loadingCounter.increment()
|
||||||
@@ -65,19 +59,4 @@ class UpdatesViewModel @Inject constructor(
|
|||||||
override fun onRefresh() = Unit
|
override fun onRefresh() = Unit
|
||||||
|
|
||||||
override fun onRetry() = Unit
|
override fun onRetry() = Unit
|
||||||
|
|
||||||
private suspend fun mapList(
|
|
||||||
mangaMap: Map<Manga, Int>,
|
|
||||||
mode: ListMode,
|
|
||||||
): List<ListModel> {
|
|
||||||
val showPercent = settings.isReadingIndicatorsEnabled
|
|
||||||
return mangaMap.map { (manga, counter) ->
|
|
||||||
val percent = if (showPercent) historyRepository.getProgress(manga.id) else PROGRESS_NONE
|
|
||||||
when (mode) {
|
|
||||||
ListMode.LIST -> manga.toListModel(counter, percent)
|
|
||||||
ListMode.DETAILED_LIST -> manga.toListDetailedModel(counter, percent, tagHighlighter)
|
|
||||||
ListMode.GRID -> manga.toGridModel(counter, percent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user