From 1847759ec3ebb8fbf94d6eb7fe91414348ff1690 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 4 Jun 2023 17:37:54 +0300 Subject: [PATCH] Refactor list extra provider --- .../org/koitharu/kotatsu/core/AppModule.kt | 5 -- .../core/parser/MangaTagHighlighter.kt | 37 ----------- .../kotatsu/details/ui/DetailsFragment.kt | 6 +- .../ui/list/FavouritesListViewModel.kt | 30 ++------- .../kotatsu/history/data/HistoryDao.kt | 10 ++- .../kotatsu/history/data/HistoryRepository.kt | 6 ++ .../history/ui/HistoryListViewModel.kt | 20 ++---- .../kotatsu/list/domain/ListExtraProvider.kt | 60 ++++++++++++++++-- .../list/domain/ListExtraProviderImpl.kt | 32 ---------- .../list/ui/model/ListModelConversionExt.kt | 63 ++++++------------- .../kotatsu/local/ui/LocalListViewModel.kt | 3 - .../remotelist/ui/RemoteListViewModel.kt | 4 +- .../kotatsu/search/ui/SearchViewModel.kt | 6 +- .../search/ui/multi/MultiSearchViewModel.kt | 4 +- .../domain/ShelfContentObserveUseCase.kt | 11 ++-- .../shelf/domain/model/ShelfContent.kt | 5 +- .../kotatsu/shelf/ui/ShelfViewModel.kt | 49 ++++----------- .../suggestions/ui/SuggestionsViewModel.kt | 6 +- .../kotatsu/tracker/data/TracksDao.kt | 5 +- .../tracker/domain/TrackingRepository.kt | 5 +- .../tracker/ui/updates/UpdatesViewModel.kt | 33 ++-------- 21 files changed, 143 insertions(+), 257 deletions(-) delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaTagHighlighter.kt delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProviderImpl.kt diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/AppModule.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/AppModule.kt index 1aad04a76..25332e92e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/AppModule.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/AppModule.kt @@ -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.connectivityManager 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.CbzFetcher import org.koitharu.kotatsu.local.data.LocalStorageChanges @@ -65,9 +63,6 @@ interface AppModule { @Binds fun bindImageGetter(coilImageGetter: CoilImageGetter): Html.ImageGetter - @Binds - fun bindListExtraProvider(impl: ListExtraProviderImpl): ListExtraProvider - companion object { @Provides diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaTagHighlighter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaTagHighlighter.kt deleted file mode 100644 index 7168445bd..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaTagHighlighter.kt +++ /dev/null @@ -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() - 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 - } - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt index 7c581df2b..5cf4dc756 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt @@ -23,7 +23,6 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter 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.image.CoverSizeResolver 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.history.data.PROGRESS_NONE 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.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaSource @@ -67,7 +67,7 @@ class DetailsFragment : lateinit var coil: ImageLoader @Inject - lateinit var tagHighlighter: MangaTagHighlighter + lateinit var tagHighlighter: ListExtraProvider private val viewModel by activityViewModels() @@ -283,7 +283,7 @@ class DetailsFragment : manga.tags.map { tag -> ChipsView.ChipModel( title = tag.title, - tint = tagHighlighter.getTint(tag), + tint = tagHighlighter.getTagTint(tag), icon = 0, data = tag, isCheckable = false, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt index 3c7ceb019..dea73f94f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt @@ -13,7 +13,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.util.ReversibleAction 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.ui.list.FavouritesListFragment.Companion.ARG_CATEGORY_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.ui.MangaListViewModel 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.toUi import org.koitharu.kotatsu.parsers.model.SortOrder -import org.koitharu.kotatsu.tracker.domain.TrackingRepository import javax.inject.Inject @HiltViewModel class FavouritesListViewModel @Inject constructor( savedStateHandle: SavedStateHandle, private val repository: FavouritesRepository, - private val trackingRepository: TrackingRepository, - private val historyRepository: HistoryRepository, - private val settings: AppSettings, - private val tagHighlighter: MangaTagHighlighter, + private val listExtraProvider: ListExtraProvider, + settings: AppSettings, downloadScheduler: DownloadWorker.Scheduler, -) : MangaListViewModel(settings, downloadScheduler), ListExtraProvider { +) : MangaListViewModel(settings, downloadScheduler) { 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 { emit(listOf(it.toErrorState(canRetry = false))) @@ -108,20 +102,4 @@ class FavouritesListViewModel @Inject constructor( 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 - } - } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryDao.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryDao.kt index be2c5f7e9..0e033ddd5 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryDao.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryDao.kt @@ -1,6 +1,10 @@ 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 org.koitharu.kotatsu.core.db.entity.MangaEntity 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") abstract fun observeAll(): Flow> + @Transaction + @Query("SELECT * FROM history WHERE deleted_at = 0 ORDER BY updated_at DESC LIMIT :limit") + abstract fun observeAll(limit: Int): Flow> + @Query("SELECT * FROM manga WHERE manga_id IN (SELECT manga_id FROM history WHERE deleted_at = 0)") abstract suspend fun findAllManga(): List diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt index f8977fabf..3cd576e87 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt @@ -51,6 +51,12 @@ class HistoryRepository @Inject constructor( } } + fun observeAll(limit: Int): Flow> { + return db.historyDao.observeAll(limit).mapItems { + it.manga.toManga(it.tags.toMangaTags()) + } + } + fun observeAllWithHistory(): Flow> { return db.historyDao.observeAll().mapItems { MangaWithHistory( diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt index c46f349db..673fbc87d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt @@ -10,7 +10,6 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus 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.ListMode 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.download.ui.worker.DownloadWorker 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.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState 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.toListDetailedModel import org.koitharu.kotatsu.list.ui.model.toListModel -import org.koitharu.kotatsu.tracker.domain.TrackingRepository import java.util.Date import java.util.concurrent.TimeUnit import javax.inject.Inject @@ -40,8 +38,7 @@ import javax.inject.Inject class HistoryListViewModel @Inject constructor( private val repository: HistoryRepository, private val settings: AppSettings, - private val trackingRepository: TrackingRepository, - private val tagHighlighter: MangaTagHighlighter, + private val extraProvider: ListExtraProvider, downloadScheduler: DownloadWorker.Scheduler, ) : MangaListViewModel(settings, downloadScheduler) { @@ -106,7 +103,6 @@ class HistoryListViewModel @Inject constructor( mode: ListMode, ): List { val result = ArrayList(if (grouped) (list.size * 1.4).toInt() else list.size + 1) - val showPercent = settings.isReadingIndicatorsEnabled var prevDate: DateTimeAgo? = null for ((manga, history) in list) { if (grouped) { @@ -116,16 +112,10 @@ class HistoryListViewModel @Inject constructor( } 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) { - ListMode.LIST -> manga.toListModel(counter, percent) - ListMode.DETAILED_LIST -> manga.toListDetailedModel(counter, percent, tagHighlighter) - ListMode.GRID -> manga.toGridModel(counter, percent) + ListMode.LIST -> manga.toListModel(extraProvider) + ListMode.DETAILED_LIST -> manga.toListDetailedModel(extraProvider) + ListMode.GRID -> manga.toGridModel(extraProvider) } } return result diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProvider.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProvider.kt index 7c547e0ae..60cc18885 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProvider.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProvider.kt @@ -1,8 +1,60 @@ 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 -} \ No newline at end of file + private val dict by lazy { + context.resources.openRawResource(R.raw.tags_redlist).use { + val set = HashSet() + 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 + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProviderImpl.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProviderImpl.kt deleted file mode 100644 index c972feb7e..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProviderImpl.kt +++ /dev/null @@ -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 - } - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt index 172fe3aeb..aa6014626 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt @@ -3,7 +3,6 @@ package org.koitharu.kotatsu.list.ui.model import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException 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.ui.widgets.ChipsView 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.UnknownHostException -fun Manga.toListModel( - counter: Int, - progress: Float, +suspend fun Manga.toListModel( + extraProvider: ListExtraProvider? ) = MangaListModel( id = id, title = title, subtitle = tags.joinToString(", ") { it.title }, coverUrl = coverUrl, manga = this, - counter = counter, - progress = progress, + counter = extraProvider?.getCounter(id) ?: 0, + progress = extraProvider?.getProgress(id) ?: PROGRESS_NONE, ) -fun Manga.toListDetailedModel( - counter: Int, - progress: Float, - tagHighlighter: MangaTagHighlighter?, +suspend fun Manga.toListDetailedModel( + extraProvider: ListExtraProvider?, ) = MangaListDetailedModel( id = id, title = title, subtitle = altTitle, coverUrl = coverUrl, manga = this, - counter = counter, - progress = progress, + counter = extraProvider?.getCounter(id) ?: 0, + progress = extraProvider?.getProgress(id) ?: PROGRESS_NONE, tags = tags.map { ChipsView.ChipModel( - tint = tagHighlighter?.getTint(it) ?: 0, + tint = extraProvider?.getTagTint(it) ?: 0, title = it.title, icon = 0, 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, title = title, coverUrl = coverUrl, manga = this, - counter = counter, - progress = progress, + counter = extraProvider?.getCounter(id) ?: 0, + progress = extraProvider?.getProgress(id) ?: PROGRESS_NONE, ) suspend fun List.toUi( mode: ListMode, extraProvider: ListExtraProvider, - tagHighlighter: MangaTagHighlighter?, -): List = toUi(ArrayList(size), mode, extraProvider, tagHighlighter) - -fun List.toUi( - mode: ListMode, - tagHighlighter: MangaTagHighlighter?, -): List = toUi(ArrayList(size), mode, tagHighlighter) - -fun > List.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) } -} +): List = toUi(ArrayList(size), mode, extraProvider) suspend fun > List.toUi( destination: C, mode: ListMode, extraProvider: ListExtraProvider, - tagHighlighter: MangaTagHighlighter?, ): C = when (mode) { - ListMode.LIST -> mapTo(destination) { - it.toListModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id)) - } - - 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)) - } + ListMode.LIST -> mapTo(destination) { it.toListModel(extraProvider) } + ListMode.DETAILED_LIST -> mapTo(destination) { it.toListDetailedModel(extraProvider) } + ListMode.GRID -> mapTo(destination) { it.toGridModel(extraProvider) } } fun Throwable.toErrorState(canRetry: Boolean = true) = ErrorState( diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt index 65f7a393e..99723036a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt @@ -6,7 +6,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharedFlow import org.koitharu.kotatsu.R 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.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.call @@ -25,7 +24,6 @@ class LocalListViewModel @Inject constructor( savedStateHandle: SavedStateHandle, mangaRepositoryFactory: MangaRepository.Factory, filter: FilterCoordinator, - tagHighlighter: MangaTagHighlighter, settings: AppSettings, downloadScheduler: DownloadWorker.Scheduler, listExtraProvider: ListExtraProvider, @@ -35,7 +33,6 @@ class LocalListViewModel @Inject constructor( savedStateHandle, mangaRepositoryFactory, filter, - tagHighlighter, settings, listExtraProvider, downloadScheduler, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt index 130a34233..816c464f7 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt @@ -18,7 +18,6 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus import org.koitharu.kotatsu.R 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.util.ext.call import org.koitharu.kotatsu.core.util.ext.require @@ -47,7 +46,6 @@ open class RemoteListViewModel @Inject constructor( savedStateHandle: SavedStateHandle, mangaRepositoryFactory: MangaRepository.Factory, private val filter: FilterCoordinator, - private val tagHighlighter: MangaTagHighlighter, settings: AppSettings, listExtraProvider: ListExtraProvider, downloadScheduler: DownloadWorker.Scheduler, @@ -72,7 +70,7 @@ open class RemoteListViewModel @Inject constructor( list == null -> add(LoadingState) list.isEmpty() -> add(createEmptyState(header.value.hasSelectedTags)) else -> { - list.toUi(this, mode, listExtraProvider, tagHighlighter) + list.toUi(this, mode, listExtraProvider) when { error != null -> add(error.toErrorFooter()) hasNext -> add(LoadingFooter()) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchViewModel.kt index ff7abf11c..a1ad1f52a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/SearchViewModel.kt @@ -13,10 +13,10 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus import org.koitharu.kotatsu.R 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.util.ext.require 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.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel @@ -33,7 +33,7 @@ class SearchViewModel @Inject constructor( savedStateHandle: SavedStateHandle, repositoryFactory: MangaRepository.Factory, settings: AppSettings, - private val tagHighlighter: MangaTagHighlighter, + private val extraProvider: ListExtraProvider, downloadScheduler: DownloadWorker.Scheduler, ) : MangaListViewModel(settings, downloadScheduler) { @@ -64,7 +64,7 @@ class SearchViewModel @Inject constructor( else -> { val result = ArrayList(list.size + 1) - list.toUi(result, mode, tagHighlighter) + list.toUi(result, mode, extraProvider) when { error != null -> result += error.toErrorFooter() hasNext -> result += LoadingFooter() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt index 51a273537..f117f6d09 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchViewModel.kt @@ -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.call 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.ListModel import org.koitharu.kotatsu.list.ui.model.LoadingFooter @@ -42,6 +43,7 @@ private const val MIN_HAS_MORE_ITEMS = 8 @HiltViewModel class MultiSearchViewModel @Inject constructor( savedStateHandle: SavedStateHandle, + private val extraProvider: ListExtraProvider, private val settings: AppSettings, private val mangaRepositoryFactory: MangaRepository.Factory, private val downloadScheduler: DownloadWorker.Scheduler, @@ -128,7 +130,7 @@ class MultiSearchViewModel @Inject constructor( async(dispatcher) { runCatchingCancellable { val list = mangaRepositoryFactory.create(source).getList(offset = 0, query = q) - .toUi(ListMode.GRID, null) + .toUi(ListMode.GRID, extraProvider) if (list.isNotEmpty()) { MultiSearchListModel(source, list.size > MIN_HAS_MORE_ITEMS, list) } else { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfContentObserveUseCase.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfContentObserveUseCase.kt index 5fa916e1c..b2104c199 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfContentObserveUseCase.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/ShelfContentObserveUseCase.kt @@ -25,6 +25,7 @@ import org.koitharu.kotatsu.suggestions.domain.SuggestionRepository import org.koitharu.kotatsu.tracker.domain.TrackingRepository import javax.inject.Inject +@Suppress("SameParameterValue") class ShelfContentObserveUseCase @Inject constructor( private val localMangaRepository: LocalMangaRepository, private val historyRepository: HistoryRepository, @@ -35,20 +36,20 @@ class ShelfContentObserveUseCase @Inject constructor( ) { operator fun invoke(): Flow = combine( - historyRepository.observeAllWithHistory(), - observeLocalManga(SortOrder.UPDATED), + historyRepository.observeAll(20), + observeLocalManga(SortOrder.UPDATED, 20), observeFavourites(), trackingRepository.observeUpdatedManga(), - suggestionRepository.observeAll(16), + suggestionRepository.observeAll(20), ) { history, local, favorites, updated, suggestions -> ShelfContent(history, favorites, updated, local, suggestions) } - private fun observeLocalManga(sortOrder: SortOrder): Flow> { + private fun observeLocalManga(sortOrder: SortOrder, limit: Int): Flow> { return localStorageChanges .onStart { emit(null) } .mapLatest { - localMangaRepository.getList(0, null, sortOrder) + localMangaRepository.getList(0, null, sortOrder).take(limit) }.distinctUntilChanged() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/model/ShelfContent.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/model/ShelfContent.kt index 3e98c8cd3..39c88010f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/model/ShelfContent.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/domain/model/ShelfContent.kt @@ -1,13 +1,12 @@ package org.koitharu.kotatsu.shelf.domain.model import org.koitharu.kotatsu.core.model.FavouriteCategory -import org.koitharu.kotatsu.history.domain.model.MangaWithHistory import org.koitharu.kotatsu.parsers.model.Manga class ShelfContent( - val history: List, + val history: List, val favourites: Map>, - val updated: Map, + val updated: List, val local: List, val suggestions: List, ) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt index 557801d47..16ea86002 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfViewModel.kt @@ -23,8 +23,6 @@ import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.favourites.domain.FavouritesRepository 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.ui.model.EmptyHint 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.ui.model.ShelfSectionModel import org.koitharu.kotatsu.sync.domain.SyncController -import org.koitharu.kotatsu.tracker.domain.TrackingRepository import javax.inject.Inject @HiltViewModel class ShelfViewModel @Inject constructor( private val historyRepository: HistoryRepository, private val favouritesRepository: FavouritesRepository, - private val trackingRepository: TrackingRepository, private val settings: AppSettings, private val downloadScheduler: DownloadWorker.Scheduler, private val deleteLocalMangaUseCase: DeleteLocalMangaUseCase, + private val listExtraProvider: ListExtraProvider, shelfContentObserveUseCase: ShelfContentObserveUseCase, syncController: SyncController, networkState: NetworkState, -) : BaseViewModel(), ListExtraProvider { +) : BaseViewModel() { val onActionDone = MutableEventFlow() val onDownloadStarted = MutableEventFlow() @@ -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) { if (ids.isEmpty()) { return @@ -194,7 +175,7 @@ class ShelfViewModel @Inject constructor( when (section) { ShelfSection.HISTORY -> mapHistory( result, - content.history.filter { it.manga.source == MangaSource.LOCAL }, + content.history.filter { it.source == MangaSource.LOCAL }, ) ShelfSection.LOCAL -> mapLocal(result, content.local) @@ -222,17 +203,14 @@ class ShelfViewModel @Inject constructor( private suspend fun mapHistory( destination: MutableList, - list: List, + list: List, ) { if (list.isEmpty()) { return } - val showPercent = settings.isReadingIndicatorsEnabled destination += ShelfSectionModel.History( - items = list.map { (manga, history) -> - val counter = getCounter(manga.id) - val percent = if (showPercent) history.percent else PROGRESS_NONE - manga.toGridModel(counter, percent) + items = list.map { manga -> + manga.toGridModel(listExtraProvider) }, showAllButtonText = R.string.show_all, ) @@ -240,16 +218,15 @@ class ShelfViewModel @Inject constructor( private suspend fun mapUpdated( destination: MutableList, - updated: Map, + updated: List, ) { if (updated.isEmpty()) { return } - val showPercent = settings.isReadingIndicatorsEnabled + settings.isReadingIndicatorsEnabled destination += ShelfSectionModel.Updated( - items = updated.map { (manga, counter) -> - val percent = if (showPercent) getProgress(manga.id) else PROGRESS_NONE - manga.toGridModel(counter, percent) + items = updated.map { manga -> + manga.toGridModel(listExtraProvider) }, showAllButtonText = R.string.show_all, ) @@ -263,7 +240,7 @@ class ShelfViewModel @Inject constructor( return } destination += ShelfSectionModel.Local( - items = local.toUi(ListMode.GRID, this, null), + items = local.toUi(ListMode.GRID, listExtraProvider), showAllButtonText = R.string.show_all, ) } @@ -276,7 +253,7 @@ class ShelfViewModel @Inject constructor( return } destination += ShelfSectionModel.Suggestions( - items = suggestions.toUi(ListMode.GRID, this, null), + items = suggestions.toUi(ListMode.GRID, listExtraProvider), showAllButtonText = R.string.show_all, ) } @@ -291,7 +268,7 @@ class ShelfViewModel @Inject constructor( for ((category, list) in favourites) { if (list.isNotEmpty()) { destination += ShelfSectionModel.Favourites( - items = list.toUi(ListMode.GRID, this, null), + items = list.toUi(ListMode.GRID, listExtraProvider), category = category, showAllButtonText = R.string.show_all, ) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt index 5eff7818f..40338a217 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt @@ -10,10 +10,10 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.core.parser.MangaTagHighlighter import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.util.ext.onFirst 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.model.EmptyState import org.koitharu.kotatsu.list.ui.model.LoadingState @@ -26,7 +26,7 @@ import javax.inject.Inject class SuggestionsViewModel @Inject constructor( repository: SuggestionRepository, settings: AppSettings, - private val tagHighlighter: MangaTagHighlighter, + private val extraProvider: ListExtraProvider, downloadScheduler: DownloadWorker.Scheduler, ) : MangaListViewModel(settings, downloadScheduler) { @@ -44,7 +44,7 @@ class SuggestionsViewModel @Inject constructor( ), ) - else -> list.toUi(mode, tagHighlighter) + else -> list.toUi(mode, extraProvider) } }.onStart { loadingCounter.increment() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/data/TracksDao.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/data/TracksDao.kt index 0915582a1..bd9b03a83 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/data/TracksDao.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/data/TracksDao.kt @@ -34,9 +34,8 @@ abstract class TracksDao { abstract fun observeNewChapters(mangaId: Long): Flow @Transaction - @MapInfo(valueColumn = "chapters_new") - @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> + @Query("SELECT manga.* 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> @Query("DELETE FROM tracks") abstract suspend fun clear() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt index a6b3b8518..482b25fa1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt @@ -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.toManga 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.parsers.model.Manga 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 } } } - fun observeUpdatedManga(): Flow> { + fun observeUpdatedManga(): Flow> { return db.tracksDao.observeUpdatedManga() - .map { x -> x.mapKeys { it.key.toManga() } } + .mapItems { it.toManga() } .distinctUntilChanged() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/updates/UpdatesViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/updates/UpdatesViewModel.kt index a3dffc059..a8c437c6b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/updates/UpdatesViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/updates/UpdatesViewModel.kt @@ -10,22 +10,16 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.plus 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.ListMode import org.koitharu.kotatsu.core.util.ext.onFirst import org.koitharu.kotatsu.download.ui.worker.DownloadWorker 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.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.toErrorState -import org.koitharu.kotatsu.list.ui.model.toGridModel -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.list.ui.model.toUi import org.koitharu.kotatsu.tracker.domain.TrackingRepository import javax.inject.Inject @@ -34,16 +28,16 @@ class UpdatesViewModel @Inject constructor( private val repository: TrackingRepository, private val settings: AppSettings, private val historyRepository: HistoryRepository, - private val tagHighlighter: MangaTagHighlighter, + private val extraProvider: ListExtraProvider, downloadScheduler: DownloadWorker.Scheduler, ) : MangaListViewModel(settings, downloadScheduler) { override val content = combine( repository.observeUpdatedManga(), listMode, - ) { mangaMap, mode -> + ) { mangaList, mode -> when { - mangaMap.isEmpty() -> listOf( + mangaList.isEmpty() -> listOf( EmptyState( icon = R.drawable.ic_empty_history, 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 { loadingCounter.increment() @@ -65,19 +59,4 @@ class UpdatesViewModel @Inject constructor( override fun onRefresh() = Unit override fun onRetry() = Unit - - private suspend fun mapList( - mangaMap: Map, - mode: ListMode, - ): List { - 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) - } - } - } }