From 607785dcd460d6a6f7b6d9b427d6c16dcb97d9f1 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 22 Jul 2024 14:58:55 +0300 Subject: [PATCH] Refactor manga list model mapping --- .gitignore | 1 + .../alternatives/ui/AlternativesViewModel.kt | 21 +-- .../kotatsu/details/ui/DetailsActivity.kt | 18 +-- .../kotatsu/details/ui/DetailsViewModel.kt | 14 +- .../ui/related/RelatedListViewModel.kt | 7 +- .../kotatsu/explore/ui/ExploreViewModel.kt | 4 +- .../ui/adapter/ExploreAdapterDelegates.kt | 6 +- .../explore/ui/model/RecommendationsItem.kt | 4 +- .../ui/list/FavouritesListViewModel.kt | 7 +- .../history/ui/HistoryListViewModel.kt | 13 +- .../kotatsu/list/domain/ListExtraProvider.kt | 60 -------- .../kotatsu/list/domain/MangaListMapper.kt | 129 ++++++++++++++++++ .../kotatsu/list/ui/MangaListFragment.kt | 7 +- .../list/ui/MangaSelectionDecoration.kt | 4 +- .../ui/adapter/MangaListDetailedItemAD.kt | 4 +- .../list/ui/adapter/MangaListItemAD.kt | 4 +- .../list/ui/model/ListModelConversionExt.kt | 66 --------- .../list/ui/model/MangaCompactListModel.kt | 13 ++ ...iledModel.kt => MangaDetailedListModel.kt} | 4 +- .../kotatsu/list/ui/model/MangaGridModel.kt | 2 +- .../kotatsu/list/ui/model/MangaItemModel.kt | 31 ----- .../kotatsu/list/ui/model/MangaListModel.kt | 36 +++-- .../list/ui/preview/PreviewViewModel.kt | 13 +- .../kotatsu/local/ui/LocalListViewModel.kt | 10 +- .../remotelist/ui/RemoteListViewModel.kt | 7 +- .../kotatsu/search/ui/SearchViewModel.kt | 7 +- .../search/ui/multi/MultiSearchListModel.kt | 4 +- .../search/ui/multi/MultiSearchViewModel.kt | 11 +- .../suggestions/ui/SuggestionsViewModel.kt | 7 +- .../kotatsu/tracker/ui/feed/FeedViewModel.kt | 7 +- .../ui/feed/model/UpdatedMangaHeader.kt | 4 +- .../tracker/ui/updates/UpdatesViewModel.kt | 13 +- 32 files changed, 255 insertions(+), 283 deletions(-) delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProvider.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/list/domain/MangaListMapper.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaCompactListModel.kt rename app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/{MangaListDetailedModel.kt => MangaDetailedListModel.kt} (87%) delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaItemModel.kt diff --git a/.gitignore b/.gitignore index dcbfd2e89..6155175a9 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ .externalNativeBuild .cxx /.idea/deviceManager.xml +/.kotlin/ diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/alternatives/ui/AlternativesViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/alternatives/ui/AlternativesViewModel.kt index 64eab5e0b..40cb46ad6 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/alternatives/ui/AlternativesViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/alternatives/ui/AlternativesViewModel.kt @@ -15,11 +15,13 @@ import org.koitharu.kotatsu.core.model.chaptersCount import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.parser.MangaIntent import org.koitharu.kotatsu.core.parser.MangaRepository +import org.koitharu.kotatsu.core.prefs.AppSettings 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.core.util.ext.require -import org.koitharu.kotatsu.list.domain.ListExtraProvider +import org.koitharu.kotatsu.history.data.HistoryRepository +import org.koitharu.kotatsu.history.data.PROGRESS_NONE import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.LoadingFooter @@ -34,7 +36,8 @@ class AlternativesViewModel @Inject constructor( private val mangaRepositoryFactory: MangaRepository.Factory, private val alternativesUseCase: AlternativesUseCase, private val migrateUseCase: MigrateUseCase, - private val extraProvider: ListExtraProvider, + private val historyRepository: HistoryRepository, + private val settings: AppSettings, ) : BaseViewModel() { val manga = savedStateHandle.require(MangaIntent.KEY_MANGA).manga @@ -53,7 +56,7 @@ class AlternativesViewModel @Inject constructor( .map { MangaAlternativeModel( manga = it, - progress = extraProvider.getProgress(it.id), + progress = getProgress(it.id), referenceChapters = refCount, ) }.runningFold>(listOf(LoadingState)) { acc, item -> @@ -86,13 +89,11 @@ class AlternativesViewModel @Inject constructor( } } - private suspend fun mapList(list: List, refCount: Int): List { - return list.map { - MangaAlternativeModel( - manga = it, - progress = extraProvider.getProgress(it.id), - referenceChapters = refCount, - ) + private 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/details/ui/DetailsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt index 2d9987de9..77b087326 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt @@ -89,11 +89,11 @@ import org.koitharu.kotatsu.details.ui.scrobbling.ScrollingInfoAdapter import org.koitharu.kotatsu.download.ui.worker.DownloadStartedObserver import org.koitharu.kotatsu.favourites.ui.categories.select.FavoriteSheet import org.koitharu.kotatsu.image.ui.ImageActivity -import org.koitharu.kotatsu.list.domain.ListExtraProvider +import org.koitharu.kotatsu.list.domain.MangaListMapper import org.koitharu.kotatsu.list.ui.adapter.ListItemType import org.koitharu.kotatsu.list.ui.adapter.mangaGridItemAD import org.koitharu.kotatsu.list.ui.model.ListModel -import org.koitharu.kotatsu.list.ui.model.MangaItemModel +import org.koitharu.kotatsu.list.ui.model.MangaListModel import org.koitharu.kotatsu.list.ui.size.StaticItemSizeResolver import org.koitharu.kotatsu.local.ui.info.LocalInfoDialog import org.koitharu.kotatsu.parsers.model.Manga @@ -122,7 +122,7 @@ class DetailsActivity : lateinit var coil: ImageLoader @Inject - lateinit var tagHighlighter: ListExtraProvider + lateinit var listMapper: MangaListMapper private val viewModel: DetailsViewModel by viewModels() private lateinit var menuProvider: DetailsMenuProvider @@ -391,7 +391,7 @@ class DetailsActivity : } } - private fun onRelatedMangaChanged(related: List) { + private fun onRelatedMangaChanged(related: List) { if (related.isEmpty()) { viewBinding.groupRelated.isVisible = false return @@ -613,15 +613,7 @@ class DetailsActivity : private fun bindTags(manga: Manga) { viewBinding.chipsTags.isVisible = manga.tags.isNotEmpty() - viewBinding.chipsTags.setChips( - manga.tags.map { tag -> - ChipsView.ChipModel( - title = tag.title, - tint = tagHighlighter.getTagTint(tag), - data = tag, - ) - }, - ) + viewBinding.chipsTags.setChips(listMapper.mapTags(manga.tags)) } private fun loadCover(manga: Manga) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt index 5d1d6c798..bb1336682 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt @@ -50,9 +50,8 @@ import org.koitharu.kotatsu.details.ui.model.HistoryInfo import org.koitharu.kotatsu.details.ui.model.MangaBranch import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.history.data.HistoryRepository -import org.koitharu.kotatsu.list.domain.ListExtraProvider -import org.koitharu.kotatsu.list.ui.model.MangaItemModel -import org.koitharu.kotatsu.list.ui.model.toUi +import org.koitharu.kotatsu.list.domain.MangaListMapper +import org.koitharu.kotatsu.list.ui.model.MangaListModel import org.koitharu.kotatsu.local.data.LocalStorageChanges import org.koitharu.kotatsu.local.domain.DeleteLocalMangaUseCase import org.koitharu.kotatsu.local.domain.model.LocalManga @@ -76,7 +75,7 @@ class DetailsViewModel @Inject constructor( savedStateHandle: SavedStateHandle, private val deleteLocalMangaUseCase: DeleteLocalMangaUseCase, private val relatedMangaUseCase: RelatedMangaUseCase, - private val extraProvider: ListExtraProvider, + private val mangaListMapper: MangaListMapper, private val detailsLoadUseCase: DetailsLoadUseCase, private val progressUpdateUseCase: ProgressUpdateUseCase, private val readingTimeUseCase: ReadingTimeUseCase, @@ -171,9 +170,12 @@ class DetailsViewModel @Inject constructor( val scrobblingInfo: StateFlow> = interactor.observeScrobblingInfo(mangaId) .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList()) - val relatedManga: StateFlow> = manga.mapLatest { + val relatedManga: StateFlow> = manga.mapLatest { if (it != null && settings.isRelatedMangaEnabled) { - relatedMangaUseCase.invoke(it)?.toUi(ListMode.GRID, extraProvider).orEmpty() + mangaListMapper.toListModelList( + manga = relatedMangaUseCase(it).orEmpty(), + mode = ListMode.GRID, + ) } else { emptyList() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/related/RelatedListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/related/RelatedListViewModel.kt index 8cc83be4b..d820bb4f6 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/related/RelatedListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/related/RelatedListViewModel.kt @@ -20,12 +20,11 @@ import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug 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.domain.MangaListMapper import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState 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.Manga import javax.inject.Inject @@ -34,7 +33,7 @@ class RelatedListViewModel @Inject constructor( savedStateHandle: SavedStateHandle, mangaRepositoryFactory: MangaRepository.Factory, settings: AppSettings, - private val extraProvider: ListExtraProvider, + private val mangaListMapper: MangaListMapper, downloadScheduler: DownloadWorker.Scheduler, ) : MangaListViewModel(settings, downloadScheduler) { @@ -53,7 +52,7 @@ class RelatedListViewModel @Inject constructor( list.isNullOrEmpty() && error != null -> listOf(error.toErrorState(canRetry = true)) list == null -> listOf(LoadingState) list.isEmpty() -> listOf(createEmptyState()) - else -> list.toUi(mode, extraProvider) + else -> mangaListMapper.toListModelList(list, mode) } }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt index f92d13103..0b2224e19 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt @@ -33,7 +33,7 @@ import org.koitharu.kotatsu.list.ui.model.EmptyHint import org.koitharu.kotatsu.list.ui.model.ListHeader import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.LoadingState -import org.koitharu.kotatsu.list.ui.model.MangaListModel +import org.koitharu.kotatsu.list.ui.model.MangaCompactListModel import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.util.runCatchingCancellable @@ -190,7 +190,7 @@ class ExploreViewModel @Inject constructor( } private fun List.toRecommendationList() = map { manga -> - MangaListModel( + MangaCompactListModel( id = manga.id, title = manga.title, subtitle = manga.tags.joinToString { it.title }, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapterDelegates.kt b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapterDelegates.kt index 7dc91d9b9..28b93d6e5 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapterDelegates.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapterDelegates.kt @@ -34,7 +34,7 @@ import org.koitharu.kotatsu.explore.ui.model.MangaSourceItem import org.koitharu.kotatsu.explore.ui.model.RecommendationsItem import org.koitharu.kotatsu.list.ui.adapter.ListItemType import org.koitharu.kotatsu.list.ui.model.ListModel -import org.koitharu.kotatsu.list.ui.model.MangaListModel +import org.koitharu.kotatsu.list.ui.model.MangaCompactListModel import org.koitharu.kotatsu.parsers.model.Manga fun exploreButtonsAD( @@ -66,7 +66,7 @@ fun exploreRecommendationItemAD( { layoutInflater, parent -> ItemRecommendationBinding.inflate(layoutInflater, parent, false) }, ) { - val adapter = BaseListAdapter() + val adapter = BaseListAdapter() .addDelegate(ListItemType.MANGA_LIST, recommendationMangaItemAD(coil, itemClickListener, lifecycleOwner)) binding.pager.adapter = adapter binding.pager.recyclerView?.isNestedScrollingEnabled = false @@ -81,7 +81,7 @@ fun recommendationMangaItemAD( coil: ImageLoader, itemClickListener: OnListItemClickListener, lifecycleOwner: LifecycleOwner, -) = adapterDelegateViewBinding( +) = adapterDelegateViewBinding( { layoutInflater, parent -> ItemRecommendationMangaBinding.inflate(layoutInflater, parent, false) }, ) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/model/RecommendationsItem.kt b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/model/RecommendationsItem.kt index 347ea9bba..078a00b61 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/model/RecommendationsItem.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/model/RecommendationsItem.kt @@ -1,10 +1,10 @@ package org.koitharu.kotatsu.explore.ui.model import org.koitharu.kotatsu.list.ui.model.ListModel -import org.koitharu.kotatsu.list.ui.model.MangaListModel +import org.koitharu.kotatsu.list.ui.model.MangaCompactListModel data class RecommendationsItem( - val manga: List + val manga: List ) : ListModel { override fun areItemsTheSame(other: ListModel): Boolean { 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 4bd578710..17124863e 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 @@ -24,13 +24,12 @@ 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.domain.MarkAsReadUseCase -import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.domain.ListSortOrder +import org.koitharu.kotatsu.list.domain.MangaListMapper import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState 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.Manga import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject @@ -41,7 +40,7 @@ private const val PAGE_SIZE = 20 class FavouritesListViewModel @Inject constructor( savedStateHandle: SavedStateHandle, private val repository: FavouritesRepository, - private val listExtraProvider: ListExtraProvider, + private val mangaListMapper: MangaListMapper, private val markAsReadUseCase: MarkAsReadUseCase, settings: AppSettings, downloadScheduler: DownloadWorker.Scheduler, @@ -86,7 +85,7 @@ class FavouritesListViewModel @Inject constructor( else -> { isReady.set(true) - list.toUi(mode, listExtraProvider) + mangaListMapper.toListModelList(list, mode) } } }.catch { 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 e10d0c626..7b9f9e678 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 @@ -28,8 +28,8 @@ import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.history.data.HistoryRepository import org.koitharu.kotatsu.history.domain.MarkAsReadUseCase import org.koitharu.kotatsu.history.domain.model.MangaWithHistory -import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.domain.ListSortOrder +import org.koitharu.kotatsu.list.domain.MangaListMapper import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyHint import org.koitharu.kotatsu.list.ui.model.EmptyState @@ -38,9 +38,6 @@ import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.LoadingState import org.koitharu.kotatsu.list.ui.model.TipModel 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.local.data.LocalMangaRepository import org.koitharu.kotatsu.parsers.model.Manga import java.time.Instant @@ -53,7 +50,7 @@ private const val PAGE_SIZE = 20 class HistoryListViewModel @Inject constructor( private val repository: HistoryRepository, settings: AppSettings, - private val extraProvider: ListExtraProvider, + private val mangaListMapper: MangaListMapper, private val localMangaRepository: LocalMangaRepository, private val markAsReadUseCase: MarkAsReadUseCase, networkState: NetworkState, @@ -203,11 +200,7 @@ class HistoryListViewModel @Inject constructor( prevHeader = header } } - result += when (mode) { - ListMode.LIST -> manga.toListModel(extraProvider) - ListMode.DETAILED_LIST -> manga.toListDetailedModel(extraProvider) - ListMode.GRID -> manga.toGridModel(extraProvider) - } + result += mangaListMapper.toListModel(manga, mode) } 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 deleted file mode 100644 index 60cc18885..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/ListExtraProvider.kt +++ /dev/null @@ -1,60 +0,0 @@ -package org.koitharu.kotatsu.list.domain - -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 - -@Reusable -class ListExtraProvider @Inject constructor( - @ApplicationContext context: Context, - private val settings: AppSettings, - private val trackingRepository: TrackingRepository, - private val historyRepository: HistoryRepository, -) { - - 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/MangaListMapper.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/MangaListMapper.kt new file mode 100644 index 000000000..cc903ef66 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/MangaListMapper.kt @@ -0,0 +1,129 @@ +package org.koitharu.kotatsu.list.domain + +import android.content.Context +import androidx.annotation.ColorRes +import androidx.collection.MutableScatterSet +import androidx.collection.ScatterSet +import dagger.hilt.android.qualifiers.ApplicationContext +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.core.prefs.ListMode +import org.koitharu.kotatsu.core.ui.widgets.ChipsView +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.list.ui.model.MangaCompactListModel +import org.koitharu.kotatsu.list.ui.model.MangaDetailedListModel +import org.koitharu.kotatsu.list.ui.model.MangaGridModel +import org.koitharu.kotatsu.list.ui.model.MangaListModel +import org.koitharu.kotatsu.parsers.model.Manga +import org.koitharu.kotatsu.parsers.model.MangaTag +import org.koitharu.kotatsu.tracker.domain.TrackingRepository +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class MangaListMapper @Inject constructor( + @ApplicationContext context: Context, + private val settings: AppSettings, + private val trackingRepository: TrackingRepository, + private val historyRepository: HistoryRepository, + private val favouritesRepository: FavouritesRepository, +) { + + private val dict by lazy { readTagsDict(context) } + + suspend fun toListModelList(manga: Collection, mode: ListMode): List = manga.map { + toListModel(it, mode) + } + + suspend fun toListModelList( + destination: MutableCollection, + manga: Collection, + mode: ListMode + ) = manga.mapTo(destination) { + toListModel(it, mode) + } + + suspend fun toListModel(manga: Manga, mode: ListMode): MangaListModel = when (mode) { + ListMode.LIST -> toCompactListModel(manga) + ListMode.DETAILED_LIST -> toDetailedListModel(manga) + ListMode.GRID -> toGridModel(manga) + } + + suspend fun toCompactListModel(manga: Manga) = MangaCompactListModel( + id = manga.id, + title = manga.title, + subtitle = manga.tags.joinToString(", ") { it.title }, + coverUrl = manga.coverUrl, + manga = manga, + counter = getCounter(manga.id), + progress = getProgress(manga.id), + ) + + suspend fun toDetailedListModel(manga: Manga) = MangaDetailedListModel( + id = manga.id, + title = manga.title, + subtitle = manga.altTitle, + coverUrl = manga.coverUrl, + manga = manga, + counter = getCounter(manga.id), + progress = getProgress(manga.id), + tags = mapTags(manga.tags), + ) + + suspend fun toGridModel(manga: Manga) = MangaGridModel( + id = manga.id, + title = manga.title, + coverUrl = manga.coverUrl, + manga = manga, + counter = getCounter(manga.id), + progress = getProgress(manga.id), + ) + + fun mapTags(tags: Collection) = tags.map { + ChipsView.ChipModel( + tint = getTagTint(it), + title = it.title, + data = it, + ) + } + + private suspend fun getCounter(mangaId: Long): Int { + return if (settings.isTrackerEnabled) { + trackingRepository.getNewChaptersCount(mangaId) + } else { + 0 + } + } + + private suspend fun getProgress(mangaId: Long): Float { + return if (settings.isReadingIndicatorsEnabled) { + historyRepository.getProgress(mangaId) + } else { + PROGRESS_NONE + } + } + + @ColorRes + private fun getTagTint(tag: MangaTag): Int { + return if (tag.title.lowercase() in dict) { + R.color.warning + } else { + 0 + } + } + + private fun readTagsDict(context: Context): ScatterSet = + context.resources.openRawResource(R.raw.tags_redlist).use { + val set = MutableScatterSet() + it.bufferedReader().forEachLine { x -> + val line = x.trim() + if (line.isNotEmpty()) { + set.add(line) + } + } + set.trim() + set + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt index 61f3e49a3..03d46fe2c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt @@ -20,7 +20,6 @@ import coil.ImageLoader import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.browser.cloudflare.CaptchaNotifier import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver import org.koitharu.kotatsu.core.prefs.AppSettings @@ -51,7 +50,7 @@ import org.koitharu.kotatsu.list.ui.adapter.MangaListListener import org.koitharu.kotatsu.list.ui.adapter.TypedListSpacingDecoration import org.koitharu.kotatsu.list.ui.model.ListHeader import org.koitharu.kotatsu.list.ui.model.ListModel -import org.koitharu.kotatsu.list.ui.model.MangaItemModel +import org.koitharu.kotatsu.list.ui.model.MangaListModel import org.koitharu.kotatsu.list.ui.size.DynamicItemSizeResolver import org.koitharu.kotatsu.main.ui.MainActivity import org.koitharu.kotatsu.main.ui.owners.AppBarOwner @@ -281,7 +280,7 @@ abstract class MangaListFragment : return when (item.itemId) { R.id.action_select_all -> { val ids = listAdapter?.items?.mapNotNull { - (it as? MangaItemModel)?.id + (it as? MangaListModel)?.id } ?: return false selectionController?.addAll(ids) true @@ -327,7 +326,7 @@ abstract class MangaListFragment : val items = listAdapter?.items ?: return emptySet() val result = ArraySet(checkedIds.size) for (item in items) { - if (item is MangaItemModel && item.id in checkedIds) { + if (item is MangaListModel && item.id in checkedIds) { result.add(item.manga) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaSelectionDecoration.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaSelectionDecoration.kt index a2824ed63..81aec7a3a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaSelectionDecoration.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaSelectionDecoration.kt @@ -14,7 +14,7 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.list.decor.AbstractSelectionItemDecoration import org.koitharu.kotatsu.core.util.ext.getItem import org.koitharu.kotatsu.core.util.ext.getThemeColor -import org.koitharu.kotatsu.list.ui.model.MangaItemModel +import org.koitharu.kotatsu.list.ui.model.MangaListModel import com.google.android.material.R as materialR open class MangaSelectionDecoration(context: Context) : AbstractSelectionItemDecoration() { @@ -37,7 +37,7 @@ open class MangaSelectionDecoration(context: Context) : AbstractSelectionItemDec override fun getItemId(parent: RecyclerView, child: View): Long { val holder = parent.getChildViewHolder(child) ?: return NO_ID - val item = holder.getItem(MangaItemModel::class.java) ?: return NO_ID + val item = holder.getItem(MangaListModel::class.java) ?: return NO_ID return item.id } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt index 5e575d225..241e69f21 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt @@ -16,13 +16,13 @@ import org.koitharu.kotatsu.core.util.ext.textAndVisible import org.koitharu.kotatsu.databinding.ItemMangaListDetailsBinding import org.koitharu.kotatsu.list.ui.ListModelDiffCallback import org.koitharu.kotatsu.list.ui.model.ListModel -import org.koitharu.kotatsu.list.ui.model.MangaListDetailedModel +import org.koitharu.kotatsu.list.ui.model.MangaDetailedListModel fun mangaListDetailedItemAD( coil: ImageLoader, lifecycleOwner: LifecycleOwner, clickListener: MangaDetailsClickListener, -) = adapterDelegateViewBinding( +) = adapterDelegateViewBinding( { inflater, parent -> ItemMangaListDetailsBinding.inflate(inflater, parent, false) }, ) { var badge: BadgeDrawable? = null diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListItemAD.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListItemAD.kt index 6a92013f5..8115b990b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListItemAD.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListItemAD.kt @@ -15,14 +15,14 @@ import org.koitharu.kotatsu.core.util.ext.source import org.koitharu.kotatsu.core.util.ext.textAndVisible import org.koitharu.kotatsu.databinding.ItemMangaListBinding import org.koitharu.kotatsu.list.ui.model.ListModel -import org.koitharu.kotatsu.list.ui.model.MangaListModel +import org.koitharu.kotatsu.list.ui.model.MangaCompactListModel import org.koitharu.kotatsu.parsers.model.Manga fun mangaListItemAD( coil: ImageLoader, lifecycleOwner: LifecycleOwner, clickListener: OnListItemClickListener, -) = adapterDelegateViewBinding( +) = adapterDelegateViewBinding( { inflater, parent -> ItemMangaListBinding.inflate(inflater, parent, false) }, ) { var badge: BadgeDrawable? = null 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 42a847b46..d489538b2 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,74 +3,8 @@ package org.koitharu.kotatsu.list.ui.model import androidx.annotation.StringRes import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver -import org.koitharu.kotatsu.core.prefs.ListMode -import org.koitharu.kotatsu.core.ui.widgets.ChipsView import org.koitharu.kotatsu.core.util.ext.getDisplayIcon import org.koitharu.kotatsu.core.util.ext.ifZero -import org.koitharu.kotatsu.history.data.PROGRESS_NONE -import org.koitharu.kotatsu.list.domain.ListExtraProvider -import org.koitharu.kotatsu.parsers.model.Manga - -suspend fun Manga.toListModel( - extraProvider: ListExtraProvider? -) = MangaListModel( - id = id, - title = title, - subtitle = tags.joinToString(", ") { it.title }, - coverUrl = coverUrl, - manga = this, - counter = extraProvider?.getCounter(id) ?: 0, - progress = extraProvider?.getProgress(id) ?: PROGRESS_NONE, -) - -suspend fun Manga.toListDetailedModel( - extraProvider: ListExtraProvider?, -) = MangaListDetailedModel( - id = id, - title = title, - subtitle = altTitle, - coverUrl = coverUrl, - manga = this, - counter = extraProvider?.getCounter(id) ?: 0, - progress = extraProvider?.getProgress(id) ?: PROGRESS_NONE, - tags = tags.map { - ChipsView.ChipModel( - tint = extraProvider?.getTagTint(it) ?: 0, - title = it.title, - data = it, - ) - }, -) - -suspend fun Manga.toGridModel( - extraProvider: ListExtraProvider?, -) = MangaGridModel( - id = id, - title = title, - coverUrl = coverUrl, - manga = this, - counter = extraProvider?.getCounter(id) ?: 0, - progress = extraProvider?.getProgress(id) ?: PROGRESS_NONE, -) - -suspend fun List.toUi( - mode: ListMode, - extraProvider: ListExtraProvider, -): List = if (isEmpty()) { - emptyList() -} else { - toUi(ArrayList(size), mode, extraProvider) -} - -suspend fun > List.toUi( - destination: C, - mode: ListMode, - extraProvider: ListExtraProvider, -): C = when (mode) { - 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, @StringRes secondaryAction: Int = 0) = ErrorState( exception = this, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaCompactListModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaCompactListModel.kt new file mode 100644 index 000000000..11ba59dd9 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaCompactListModel.kt @@ -0,0 +1,13 @@ +package org.koitharu.kotatsu.list.ui.model + +import org.koitharu.kotatsu.parsers.model.Manga + +data class MangaCompactListModel( + override val id: Long, + override val title: String, + val subtitle: String, + override val coverUrl: String, + override val manga: Manga, + override val counter: Int, + override val progress: Float, +) : MangaListModel() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaListDetailedModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaDetailedListModel.kt similarity index 87% rename from app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaListDetailedModel.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaDetailedListModel.kt index e64c47ada..48be34fbf 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaListDetailedModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaDetailedListModel.kt @@ -3,7 +3,7 @@ package org.koitharu.kotatsu.list.ui.model import org.koitharu.kotatsu.core.ui.widgets.ChipsView import org.koitharu.kotatsu.parsers.model.Manga -data class MangaListDetailedModel( +data class MangaDetailedListModel( override val id: Long, override val title: String, val subtitle: String?, @@ -12,4 +12,4 @@ data class MangaListDetailedModel( override val counter: Int, override val progress: Float, val tags: List, -) : MangaItemModel() +) : MangaListModel() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaGridModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaGridModel.kt index 2b94795c6..1105451e1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaGridModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaGridModel.kt @@ -9,4 +9,4 @@ data class MangaGridModel( override val manga: Manga, override val counter: Int, override val progress: Float, -) : MangaItemModel() +) : MangaListModel() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaItemModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaItemModel.kt deleted file mode 100644 index 95ea83b60..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaItemModel.kt +++ /dev/null @@ -1,31 +0,0 @@ -package org.koitharu.kotatsu.list.ui.model - -import org.koitharu.kotatsu.list.ui.ListModelDiffCallback -import org.koitharu.kotatsu.parsers.model.Manga -import org.koitharu.kotatsu.parsers.model.MangaSource - -sealed class MangaItemModel : ListModel { - - abstract val id: Long - abstract val manga: Manga - abstract val title: String - abstract val coverUrl: String - abstract val counter: Int - abstract val progress: Float - - val source: MangaSource - get() = manga.source - - override fun areItemsTheSame(other: ListModel): Boolean { - return other is MangaItemModel && other.javaClass == javaClass && id == other.id - } - - override fun getChangePayload(previousState: ListModel): Any? { - return when { - previousState !is MangaItemModel -> super.getChangePayload(previousState) - progress != previousState.progress -> ListModelDiffCallback.PAYLOAD_PROGRESS_CHANGED - counter != previousState.counter -> ListModelDiffCallback.PAYLOAD_ANYTHING_CHANGED - else -> null - } - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaListModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaListModel.kt index 54b0a800a..264d58f08 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaListModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaListModel.kt @@ -1,13 +1,31 @@ package org.koitharu.kotatsu.list.ui.model +import org.koitharu.kotatsu.list.ui.ListModelDiffCallback import org.koitharu.kotatsu.parsers.model.Manga +import org.koitharu.kotatsu.parsers.model.MangaSource -data class MangaListModel( - override val id: Long, - override val title: String, - val subtitle: String, - override val coverUrl: String, - override val manga: Manga, - override val counter: Int, - override val progress: Float, -) : MangaItemModel() +sealed class MangaListModel : ListModel { + + abstract val id: Long + abstract val manga: Manga + abstract val title: String + abstract val coverUrl: String + abstract val counter: Int + abstract val progress: Float + + val source: MangaSource + get() = manga.source + + override fun areItemsTheSame(other: ListModel): Boolean { + return other is MangaListModel && other.javaClass == javaClass && id == other.id + } + + override fun getChangePayload(previousState: ListModel): Any? { + return when { + previousState !is MangaListModel -> super.getChangePayload(previousState) + progress != previousState.progress -> ListModelDiffCallback.PAYLOAD_PROGRESS_CHANGED + counter != previousState.counter -> ListModelDiffCallback.PAYLOAD_ANYTHING_CHANGED + else -> null + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/preview/PreviewViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/preview/PreviewViewModel.kt index 360190b46..45398c9da 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/preview/PreviewViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/preview/PreviewViewModel.kt @@ -25,18 +25,17 @@ import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.parser.MangaIntent import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.ui.BaseViewModel -import org.koitharu.kotatsu.core.ui.widgets.ChipsView import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.core.util.ext.sanitize 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.MangaListMapper import javax.inject.Inject @HiltViewModel class PreviewViewModel @Inject constructor( savedStateHandle: SavedStateHandle, - private val extraProvider: ListExtraProvider, + private val mangaListMapper: MangaListMapper, private val repositoryFactory: MangaRepository.Factory, private val historyRepository: HistoryRepository, private val imageGetter: Html.ImageGetter, @@ -81,13 +80,7 @@ class PreviewViewModel @Inject constructor( }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.WhileSubscribed(5000), null) val tagsChips = manga.map { - it.tags.map { tag -> - ChipsView.ChipModel( - title = tag.title, - tint = extraProvider.getTagTint(tag), - data = tag, - ) - } + mangaListMapper.mapTags(it.tags) }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList()) init { 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 4eed4c626..7e566c679 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 @@ -16,10 +16,10 @@ import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.explore.data.MangaSourcesRepository import org.koitharu.kotatsu.explore.domain.ExploreRepository import org.koitharu.kotatsu.filter.ui.FilterCoordinator -import org.koitharu.kotatsu.list.domain.ListExtraProvider +import org.koitharu.kotatsu.list.domain.MangaListMapper import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel -import org.koitharu.kotatsu.list.ui.model.MangaItemModel +import org.koitharu.kotatsu.list.ui.model.MangaListModel import org.koitharu.kotatsu.list.ui.model.TipModel import org.koitharu.kotatsu.local.data.LocalStorageChanges import org.koitharu.kotatsu.local.data.LocalStorageManager @@ -35,7 +35,7 @@ class LocalListViewModel @Inject constructor( filter: FilterCoordinator, private val settings: AppSettings, downloadScheduler: DownloadWorker.Scheduler, - listExtraProvider: ListExtraProvider, + mangaListMapper: MangaListMapper, private val deleteLocalMangaUseCase: DeleteLocalMangaUseCase, exploreRepository: ExploreRepository, @LocalStorageChanges private val localStorageChanges: SharedFlow, @@ -46,7 +46,7 @@ class LocalListViewModel @Inject constructor( mangaRepositoryFactory, filter, settings, - listExtraProvider, + mangaListMapper, downloadScheduler, exploreRepository, sourcesRepository, @@ -70,7 +70,7 @@ class LocalListViewModel @Inject constructor( return } for (item in list) { - if (item !is MangaItemModel) { + if (item !is MangaListModel) { continue } val file = item.manga.url.toUriOrNull()?.toFileOrNull() ?: continue 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 cef84a201..a16d989c1 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 @@ -32,7 +32,7 @@ import org.koitharu.kotatsu.explore.data.MangaSourcesRepository import org.koitharu.kotatsu.explore.domain.ExploreRepository import org.koitharu.kotatsu.filter.ui.FilterCoordinator import org.koitharu.kotatsu.filter.ui.MangaFilter -import org.koitharu.kotatsu.list.domain.ListExtraProvider +import org.koitharu.kotatsu.list.domain.MangaListMapper import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel @@ -40,7 +40,6 @@ import org.koitharu.kotatsu.list.ui.model.LoadingFooter import org.koitharu.kotatsu.list.ui.model.LoadingState import org.koitharu.kotatsu.list.ui.model.toErrorFooter import org.koitharu.kotatsu.list.ui.model.toErrorState -import org.koitharu.kotatsu.list.ui.model.toUi import org.koitharu.kotatsu.parsers.exception.NotFoundException import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaListFilter @@ -55,7 +54,7 @@ open class RemoteListViewModel @Inject constructor( mangaRepositoryFactory: MangaRepository.Factory, private val filter: FilterCoordinator, settings: AppSettings, - listExtraProvider: ListExtraProvider, + mangaListMapper: MangaListMapper, downloadScheduler: DownloadWorker.Scheduler, private val exploreRepository: ExploreRepository, sourcesRepository: MangaSourcesRepository, @@ -96,7 +95,7 @@ open class RemoteListViewModel @Inject constructor( list == null -> add(LoadingState) list.isEmpty() -> add(createEmptyState(canResetFilter = header.value.isFilterApplied)) else -> { - list.toUi(this, mode, listExtraProvider) + mangaListMapper.toListModelList(this, list, mode) 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 a1a6a0f1d..8409551a5 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 @@ -20,7 +20,7 @@ import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.core.util.ext.sizeOrZero import org.koitharu.kotatsu.download.ui.worker.DownloadWorker -import org.koitharu.kotatsu.list.domain.ListExtraProvider +import org.koitharu.kotatsu.list.domain.MangaListMapper import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel @@ -28,7 +28,6 @@ import org.koitharu.kotatsu.list.ui.model.LoadingFooter import org.koitharu.kotatsu.list.ui.model.LoadingState import org.koitharu.kotatsu.list.ui.model.toErrorFooter import org.koitharu.kotatsu.list.ui.model.toErrorState -import org.koitharu.kotatsu.list.ui.model.toUi import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaListFilter import javax.inject.Inject @@ -38,7 +37,7 @@ class SearchViewModel @Inject constructor( savedStateHandle: SavedStateHandle, repositoryFactory: MangaRepository.Factory, settings: AppSettings, - private val extraProvider: ListExtraProvider, + private val mangaListMapper: MangaListMapper, downloadScheduler: DownloadWorker.Scheduler, ) : MangaListViewModel(settings, downloadScheduler) { @@ -69,7 +68,7 @@ class SearchViewModel @Inject constructor( else -> { val result = ArrayList(list.size + 1) - list.toUi(result, mode, extraProvider) + mangaListMapper.toListModelList(result, list, mode) when { error != null -> result += error.toErrorFooter() hasNext -> result += LoadingFooter() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchListModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchListModel.kt index 7d6f802fc..317652294 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchListModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchListModel.kt @@ -2,13 +2,13 @@ package org.koitharu.kotatsu.search.ui.multi import org.koitharu.kotatsu.list.ui.ListModelDiffCallback import org.koitharu.kotatsu.list.ui.model.ListModel -import org.koitharu.kotatsu.list.ui.model.MangaItemModel +import org.koitharu.kotatsu.list.ui.model.MangaListModel import org.koitharu.kotatsu.parsers.model.MangaSource data class MultiSearchListModel( val source: MangaSource, val hasMore: Boolean, - val list: List, + val list: List, val error: Throwable?, ) : ListModel { 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 f26a46092..e772af0be 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 @@ -29,12 +29,11 @@ import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.explore.data.MangaSourcesRepository -import org.koitharu.kotatsu.list.domain.ListExtraProvider +import org.koitharu.kotatsu.list.domain.MangaListMapper import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.LoadingFooter import org.koitharu.kotatsu.list.ui.model.LoadingState -import org.koitharu.kotatsu.list.ui.model.toUi import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaListFilter import org.koitharu.kotatsu.parsers.util.runCatchingCancellable @@ -46,7 +45,7 @@ private const val MIN_HAS_MORE_ITEMS = 8 @HiltViewModel class MultiSearchViewModel @Inject constructor( savedStateHandle: SavedStateHandle, - private val extraProvider: ListExtraProvider, + private val mangaListMapper: MangaListMapper, private val mangaRepositoryFactory: MangaRepository.Factory, private val downloadScheduler: DownloadWorker.Scheduler, private val sourcesRepository: MangaSourcesRepository, @@ -121,8 +120,10 @@ class MultiSearchViewModel @Inject constructor( launch { val item = runCatchingCancellable { semaphore.withPermit { - repository.getList(offset = 0, filter = MangaListFilter.Search(q)) - .toUi(ListMode.GRID, extraProvider) + mangaListMapper.toListModelList( + manga = repository.getList(offset = 0, filter = MangaListFilter.Search(q)), + mode = ListMode.GRID, + ) } }.fold( onSuccess = { list -> 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 a87d532f7..927015c9d 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 @@ -14,12 +14,11 @@ import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.observeAsFlow 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.domain.MangaListMapper import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState 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.suggestions.domain.SuggestionRepository import javax.inject.Inject @@ -27,7 +26,7 @@ import javax.inject.Inject class SuggestionsViewModel @Inject constructor( repository: SuggestionRepository, settings: AppSettings, - private val extraProvider: ListExtraProvider, + private val mangaListMapper: MangaListMapper, downloadScheduler: DownloadWorker.Scheduler, private val suggestionsScheduler: SuggestionsWorker.Scheduler, ) : MangaListViewModel(settings, downloadScheduler) { @@ -49,7 +48,7 @@ class SuggestionsViewModel @Inject constructor( ), ) - else -> list.toUi(mode, extraProvider) + else -> mangaListMapper.toListModelList(list, mode) } }.onStart { loadingCounter.increment() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedViewModel.kt index 511ef1aae..70871c4a1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedViewModel.kt @@ -20,12 +20,11 @@ import org.koitharu.kotatsu.core.ui.model.DateTimeAgo import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.calculateTimeAgo import org.koitharu.kotatsu.core.util.ext.call -import org.koitharu.kotatsu.list.domain.ListExtraProvider +import org.koitharu.kotatsu.list.domain.MangaListMapper import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListHeader import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.LoadingState -import org.koitharu.kotatsu.list.ui.model.toGridModel import org.koitharu.kotatsu.tracker.domain.TrackingRepository import org.koitharu.kotatsu.tracker.domain.model.TrackingLogItem import org.koitharu.kotatsu.tracker.ui.feed.model.FeedItem @@ -42,7 +41,7 @@ class FeedViewModel @Inject constructor( private val settings: AppSettings, private val repository: TrackingRepository, private val scheduler: TrackWorker.Scheduler, - private val listExtraProvider: ListExtraProvider, + private val mangaListMapper: MangaListMapper, ) : BaseViewModel() { private val limit = MutableStateFlow(PAGE_SIZE) @@ -135,7 +134,7 @@ class FeedViewModel @Inject constructor( null } else { UpdatedMangaHeader( - mangaList.map { it.manga.toGridModel(listExtraProvider) }, + mangaList.map { mangaListMapper.toGridModel(it.manga) }, ) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/model/UpdatedMangaHeader.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/model/UpdatedMangaHeader.kt index 71e2ce8de..d4687fd6e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/model/UpdatedMangaHeader.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/model/UpdatedMangaHeader.kt @@ -2,10 +2,10 @@ package org.koitharu.kotatsu.tracker.ui.feed.model import org.koitharu.kotatsu.list.ui.ListModelDiffCallback import org.koitharu.kotatsu.list.ui.model.ListModel -import org.koitharu.kotatsu.list.ui.model.MangaItemModel +import org.koitharu.kotatsu.list.ui.model.MangaListModel data class UpdatedMangaHeader( - val list: List, + val list: List, ) : ListModel { override fun areItemsTheSame(other: ListModel): Boolean { 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 8bd8290be..78a7a7fc1 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 @@ -17,16 +17,13 @@ import org.koitharu.kotatsu.core.ui.model.DateTimeAgo import org.koitharu.kotatsu.core.util.ext.calculateTimeAgo 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.domain.MangaListMapper import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListHeader 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.tracker.domain.TrackingRepository import org.koitharu.kotatsu.tracker.domain.model.MangaTracking import javax.inject.Inject @@ -35,7 +32,7 @@ import javax.inject.Inject class UpdatesViewModel @Inject constructor( private val repository: TrackingRepository, settings: AppSettings, - private val extraProvider: ListExtraProvider, + private val mangaListMapper: MangaListMapper, downloadScheduler: DownloadWorker.Scheduler, ) : MangaListViewModel(settings, downloadScheduler) { @@ -93,11 +90,7 @@ class UpdatesViewModel @Inject constructor( prevHeader = header } } - result += when (mode) { - ListMode.LIST -> item.manga.toListModel(extraProvider) - ListMode.DETAILED_LIST -> item.manga.toListDetailedModel(extraProvider) - ListMode.GRID -> item.manga.toGridModel(extraProvider) - } + result += mangaListMapper.toListModel(item.manga, mode) } return result }