diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaRepository.kt index 8fab1b77c..d3df9f404 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaRepository.kt @@ -36,6 +36,8 @@ interface MangaRepository { suspend fun getTags(): Set + suspend fun getRelated(seed: Manga): List + @Singleton class Factory @Inject constructor( private val localMangaRepository: LocalMangaRepository, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt index 3df9988bd..9e7f59daf 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/RemoteMangaRepository.kt @@ -51,7 +51,7 @@ class RemoteMangaRepository( getConfig()[parser.configKeyDomain] = value } - val headers: Headers? + val headers: Headers get() = parser.headers override fun intercept(chain: Interceptor.Chain): Response { @@ -94,6 +94,10 @@ class RemoteMangaRepository( suspend fun getFavicons(): Favicons = parser.getFavicons() + override suspend fun getRelated(seed: Manga): List { + return parser.getRelatedManga(seed).filterNot { it.id == seed.id } + } + fun getAuthProvider(): MangaParserAuthProvider? = parser as? MangaParserAuthProvider fun getConfigKeys(): List> = ArrayList>().also { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseListAdapter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseListAdapter.kt index 8e6949df1..ef3bbced1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseListAdapter.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseListAdapter.kt @@ -1,6 +1,7 @@ package org.koitharu.kotatsu.core.ui import androidx.recyclerview.widget.AsyncListDiffer.ListListener +import com.hannesdorfmann.adapterdelegates4.AdapterDelegate import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter import kotlinx.coroutines.flow.FlowCollector import org.koitharu.kotatsu.core.util.ContinuationResumeRunnable @@ -8,7 +9,9 @@ import org.koitharu.kotatsu.list.ui.ListModelDiffCallback import org.koitharu.kotatsu.list.ui.model.ListModel import kotlin.coroutines.suspendCoroutine -abstract class BaseListAdapter : AsyncListDifferDelegationAdapter(ListModelDiffCallback), +open class BaseListAdapter( + vararg delegates: AdapterDelegate>, +) : AsyncListDifferDelegationAdapter(ListModelDiffCallback, *delegates), FlowCollector> { override suspend fun emit(value: List) = suspendCoroutine { cont -> diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/RelatedMangaUseCase.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/RelatedMangaUseCase.kt new file mode 100644 index 000000000..15670f6ab --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/RelatedMangaUseCase.kt @@ -0,0 +1,18 @@ +package org.koitharu.kotatsu.details.domain + +import org.koitharu.kotatsu.core.parser.MangaRepository +import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug +import org.koitharu.kotatsu.parsers.model.Manga +import org.koitharu.kotatsu.parsers.util.runCatchingCancellable +import javax.inject.Inject + +class RelatedMangaUseCase @Inject constructor( + private val mangaRepositoryFactory: MangaRepository.Factory, +) { + + suspend operator fun invoke(seed: Manga) = runCatchingCancellable { + mangaRepositoryFactory.create(seed.source).getRelated(seed) + }.onFailure { + it.printStackTraceDebug() + }.getOrNull() +} 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 b98d8180b..eb71185e0 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 @@ -24,6 +24,7 @@ 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.ui.BaseFragment +import org.koitharu.kotatsu.core.ui.BaseListAdapter import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.ui.list.decor.SpacingItemDecoration @@ -45,6 +46,9 @@ 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.list.ui.adapter.mangaGridItemAD +import org.koitharu.kotatsu.list.ui.model.MangaItemModel +import org.koitharu.kotatsu.list.ui.size.StaticItemSizeResolver import org.koitharu.kotatsu.main.ui.owners.NoModalBottomSheetOwner import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaSource @@ -87,6 +91,9 @@ class DetailsFragment : binding.infoLayout.textViewSource.setOnClickListener(this) binding.textViewDescription.movementMethod = LinkMovementMethod.getInstance() binding.chipsTags.onChipClickListener = this + binding.recyclerViewRelated.addItemDecoration( + SpacingItemDecoration(resources.getDimensionPixelOffset(R.dimen.grid_spacing)), + ) TitleScrollCoordinator(binding.textViewTitle).attach(binding.scrollView) viewModel.manga.filterNotNull().observe(viewLifecycleOwner, ::onMangaUpdated) viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged) @@ -96,6 +103,7 @@ class DetailsFragment : viewModel.description.observe(viewLifecycleOwner, ::onDescriptionChanged) viewModel.chapters.observe(viewLifecycleOwner, ::onChaptersChanged) viewModel.localSize.observe(viewLifecycleOwner, ::onLocalSizeChanged) + viewModel.relatedManga.observe(viewLifecycleOwner, ::onRelatedMangaChanged) } override fun onItemClick(item: Bookmark, view: View) { @@ -193,6 +201,24 @@ class DetailsFragment : } } + private fun onRelatedMangaChanged(related: List) { + if (related.isEmpty()) { + requireViewBinding().groupRelated.isVisible = false + return + } + val rv = viewBinding?.recyclerViewRelated ?: return + val adapter = (rv.adapter as? BaseListAdapter) ?: BaseListAdapter( + mangaGridItemAD( + coil, viewLifecycleOwner, + StaticItemSizeResolver(resources.getDimensionPixelSize(R.dimen.smaller_grid_width)), + ) { item, view -> + startActivity(DetailsActivity.newIntent(view.context, item), scaleUpActivityOptionsOf(view)) + }, + ).also { rv.adapter = it } + adapter.items = related + requireViewBinding().groupRelated.isVisible = true + } + private fun onHistoryChanged(history: HistoryInfo) { requireViewBinding().progressView.setPercent(history.history?.percent ?: PROGRESS_NONE, animate = true) } 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 38b041a6e..c0e82cb6f 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 @@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.flow.update @@ -34,6 +35,7 @@ import org.koitharu.kotatsu.core.model.getPreferredBranch import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.parser.MangaIntent import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.util.ext.MutableEventFlow @@ -46,12 +48,16 @@ import org.koitharu.kotatsu.core.util.ext.toFileOrNull import org.koitharu.kotatsu.details.domain.BranchComparator import org.koitharu.kotatsu.details.domain.DetailsInteractor import org.koitharu.kotatsu.details.domain.DoubleMangaLoadUseCase +import org.koitharu.kotatsu.details.domain.RelatedMangaUseCase import org.koitharu.kotatsu.details.domain.model.DoubleManga import org.koitharu.kotatsu.details.ui.model.ChapterListItem 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.local.data.LocalStorageChanges import org.koitharu.kotatsu.local.domain.DeleteLocalMangaUseCase import org.koitharu.kotatsu.local.domain.model.LocalManga @@ -74,6 +80,8 @@ class DetailsViewModel @Inject constructor( savedStateHandle: SavedStateHandle, private val deleteLocalMangaUseCase: DeleteLocalMangaUseCase, private val doubleMangaLoadUseCase: DoubleMangaLoadUseCase, + private val relatedMangaUseCase: RelatedMangaUseCase, + private val extraProvider: ListExtraProvider, networkState: NetworkState, ) : BaseViewModel() { @@ -155,6 +163,18 @@ class DetailsViewModel @Inject constructor( val scrobblingInfo: StateFlow> = interactor.observeScrobblingInfo(mangaId) .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList()) + val relatedManga: StateFlow> = doubleManga.map { + it?.remote + }.distinctUntilChangedBy { it?.id } + .mapLatest { + if (it != null) { + relatedMangaUseCase.invoke(it)?.toUi(ListMode.GRID, extraProvider).orEmpty() + } else { + emptyList() + } + } + .stateIn(viewModelScope, SharingStarted.Lazily, emptyList()) + val branches: StateFlow> = combine( doubleManga, selectedBranch, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt index 0b75d440e..97f09e1e2 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt @@ -14,16 +14,16 @@ import org.koitharu.kotatsu.core.util.ext.newImageRequest import org.koitharu.kotatsu.core.util.ext.source import org.koitharu.kotatsu.databinding.ItemMangaGridBinding import org.koitharu.kotatsu.history.data.PROGRESS_NONE -import org.koitharu.kotatsu.list.ui.ItemSizeResolver import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.MangaGridModel +import org.koitharu.kotatsu.list.ui.size.ItemSizeResolver import org.koitharu.kotatsu.parsers.model.Manga fun mangaGridItemAD( coil: ImageLoader, lifecycleOwner: LifecycleOwner, - clickListener: OnListItemClickListener, sizeResolver: ItemSizeResolver?, + clickListener: OnListItemClickListener, ) = adapterDelegateViewBinding( { inflater, parent -> ItemMangaGridBinding.inflate(inflater, parent, false) }, ) { @@ -35,7 +35,7 @@ fun mangaGridItemAD( itemView.setOnLongClickListener { clickListener.onItemLongClick(item.manga, it) } - sizeResolver?.attachToView(lifecycleOwner, itemView, binding.textViewTitle) + sizeResolver?.attachToView(lifecycleOwner, itemView, binding.textViewTitle, binding.progressView) bind { payloads -> binding.textViewTitle.text = item.title diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListAdapter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListAdapter.kt index bf4c3c07d..ceffdca06 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListAdapter.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/MangaListAdapter.kt @@ -14,7 +14,7 @@ open class MangaListAdapter( delegatesManager .addDelegate(ITEM_TYPE_MANGA_LIST, mangaListItemAD(coil, lifecycleOwner, listener)) .addDelegate(ITEM_TYPE_MANGA_LIST_DETAILED, mangaListDetailedItemAD(coil, lifecycleOwner, listener)) - .addDelegate(ITEM_TYPE_MANGA_GRID, mangaGridItemAD(coil, lifecycleOwner, listener, null)) + .addDelegate(ITEM_TYPE_MANGA_GRID, mangaGridItemAD(coil, lifecycleOwner, null, listener)) .addDelegate(ITEM_TYPE_LOADING_FOOTER, loadingFooterAD()) .addDelegate(ITEM_TYPE_LOADING_STATE, loadingStateAD()) .addDelegate(ITEM_TYPE_ERROR_STATE, errorStateListAD(listener)) 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 aa6014626..066d1a6f2 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 @@ -61,7 +61,11 @@ suspend fun Manga.toGridModel( suspend fun List.toUi( mode: ListMode, extraProvider: ListExtraProvider, -): List = toUi(ArrayList(size), mode, extraProvider) +): List = if (isEmpty()) { + emptyList() +} else { + toUi(ArrayList(size), mode, extraProvider) +} suspend fun > List.toUi( destination: C, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/ItemSizeResolver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/size/DynamicItemSizeResolver.kt similarity index 71% rename from app/src/main/kotlin/org/koitharu/kotatsu/list/ui/ItemSizeResolver.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/list/ui/size/DynamicItemSizeResolver.kt index 64747aedd..cf9fbd7cf 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/ItemSizeResolver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/size/DynamicItemSizeResolver.kt @@ -1,4 +1,4 @@ -package org.koitharu.kotatsu.list.ui +package org.koitharu.kotatsu.list.ui.size import android.content.SharedPreferences import android.content.res.Resources @@ -9,21 +9,27 @@ import androidx.core.view.updateLayoutParams import androidx.core.widget.TextViewCompat import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner -import kotlin.math.roundToInt import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.history.ui.util.ReadingProgressView +import kotlin.math.roundToInt -class ItemSizeResolver(resources: Resources, private val settings: AppSettings) { +class DynamicItemSizeResolver(resources: Resources, private val settings: AppSettings) : ItemSizeResolver { private val gridWidth = resources.getDimension(R.dimen.preferred_grid_width) private val scaleFactor: Float get() = settings.gridSize / 100f - val cellWidth: Int + override val cellWidth: Int get() = (gridWidth * scaleFactor).roundToInt() - fun attachToView(lifecycleOwner: LifecycleOwner, view: View, textView: TextView?) { - val observer = SizeObserver(view, textView) + override fun attachToView( + lifecycleOwner: LifecycleOwner, + view: View, + textView: TextView?, + progressView: ReadingProgressView? + ) { + val observer = SizeObserver(view, textView, progressView) view.addOnAttachStateChangeListener(observer) lifecycleOwner.lifecycle.addObserver(observer) if (view.isAttachedToWindow) { @@ -34,6 +40,7 @@ class ItemSizeResolver(resources: Resources, private val settings: AppSettings) private inner class SizeObserver( private val view: View, private val textView: TextView?, + private val progressView: ReadingProgressView?, ) : DefaultLifecycleObserver, SharedPreferences.OnSharedPreferenceChangeListener, View.OnAttachStateChangeListener { private val widthThreshold = view.resources.getDimensionPixelSize(R.dimen.small_grid_width) @@ -68,6 +75,23 @@ class ItemSizeResolver(resources: Resources, private val settings: AppSettings) view.updateLayoutParams { width = newWidth } + progressView?.adjustSize(newWidth) + } + + private fun ReadingProgressView.adjustSize(width: Int) { + val lp = layoutParams + val size = resources.getDimensionPixelSize( + if (width < widthThreshold) { + R.dimen.card_indicator_size_small + } else { + R.dimen.card_indicator_size + }, + ) + if (lp.width != size || lp.height != size) { + lp.width = size + lp.height = size + layoutParams = lp + } } private fun TextView.adjustTextAppearance(width: Int) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/size/ItemSizeResolver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/size/ItemSizeResolver.kt new file mode 100644 index 000000000..de44dff58 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/size/ItemSizeResolver.kt @@ -0,0 +1,18 @@ +package org.koitharu.kotatsu.list.ui.size + +import android.view.View +import android.widget.TextView +import androidx.lifecycle.LifecycleOwner +import org.koitharu.kotatsu.history.ui.util.ReadingProgressView + +interface ItemSizeResolver { + + val cellWidth: Int + + fun attachToView( + lifecycleOwner: LifecycleOwner, + view: View, + textView: TextView?, + progressView: ReadingProgressView?, + ) +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/size/StaticItemSizeResolver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/size/StaticItemSizeResolver.kt new file mode 100644 index 000000000..e4f1bc919 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/size/StaticItemSizeResolver.kt @@ -0,0 +1,56 @@ +package org.koitharu.kotatsu.list.ui.size + +import android.view.View +import android.widget.TextView +import androidx.core.view.updateLayoutParams +import androidx.core.widget.TextViewCompat +import androidx.lifecycle.LifecycleOwner +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.history.ui.util.ReadingProgressView + +class StaticItemSizeResolver( + override val cellWidth: Int, +) : ItemSizeResolver { + + private var widthThreshold: Int = -1 + private var textAppearanceResId = R.style.TextAppearance_Kotatsu_GridTitle + + override fun attachToView( + lifecycleOwner: LifecycleOwner, + view: View, + textView: TextView?, + progressView: ReadingProgressView? + ) { + if (widthThreshold == -1) { + widthThreshold = view.resources.getDimensionPixelSize(R.dimen.small_grid_width) + textAppearanceResId = if (cellWidth < widthThreshold) { + R.style.TextAppearance_Kotatsu_GridTitle_Small + } else { + R.style.TextAppearance_Kotatsu_GridTitle + } + } + if (textView != null) { + TextViewCompat.setTextAppearance(textView, textAppearanceResId) + } + view.updateLayoutParams { + width = cellWidth + } + progressView?.adjustSize() + } + + private fun ReadingProgressView.adjustSize() { + val lp = layoutParams + val size = resources.getDimensionPixelSize( + if (cellWidth < widthThreshold) { + R.dimen.card_indicator_size_small + } else { + R.dimen.card_indicator_size + }, + ) + if (lp.width != size || lp.height != size) { + lp.width = size + lp.height = size + layoutParams = lp + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/LocalMangaRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/LocalMangaRepository.kt index 439cdc847..7950f4575 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/LocalMangaRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/LocalMangaRepository.kt @@ -16,6 +16,7 @@ import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.util.CompositeMutex import org.koitharu.kotatsu.core.util.ext.deleteAwait +import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.local.data.input.LocalMangaInput import org.koitharu.kotatsu.local.data.output.LocalMangaOutput import org.koitharu.kotatsu.local.data.output.LocalMangaUtil @@ -27,9 +28,7 @@ import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.util.runCatchingCancellable -import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import java.io.File -import java.io.FilenameFilter import java.util.EnumSet import javax.inject.Inject import javax.inject.Singleton @@ -153,6 +152,8 @@ class LocalMangaRepository @Inject constructor( override suspend fun getTags() = emptySet() + override suspend fun getRelated(seed: Manga): List = emptyList() + suspend fun getOutputDir(manga: Manga): File? { val defaultDir = storageManager.getDefaultWriteableDir() if (defaultDir != null && LocalMangaOutput.get(defaultDir, manga) != null) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchActivity.kt index 3871a0cfc..3e1ca30ab 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/MultiSearchActivity.kt @@ -28,10 +28,10 @@ import org.koitharu.kotatsu.databinding.ActivitySearchMultiBinding import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.download.ui.worker.DownloadStartedObserver import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesSheet -import org.koitharu.kotatsu.list.ui.ItemSizeResolver import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration import org.koitharu.kotatsu.list.ui.adapter.MangaListListener import org.koitharu.kotatsu.list.ui.model.ListHeader +import org.koitharu.kotatsu.list.ui.size.DynamicItemSizeResolver import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.reader.ui.ReaderActivity.IntentBuilder @@ -64,7 +64,7 @@ class MultiSearchActivity : val itemCLickListener = OnListItemClickListener { item, view -> startActivity(SearchActivity.newIntent(view.context, item.source, viewModel.query.value)) } - val sizeResolver = ItemSizeResolver(resources, settings) + val sizeResolver = DynamicItemSizeResolver(resources, settings) val selectionDecoration = MangaSelectionDecoration(this) selectionController = ListSelectionController( activity = this, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/adapter/MultiSearchAdapter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/adapter/MultiSearchAdapter.kt index 5abb41e8c..099bda6ac 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/adapter/MultiSearchAdapter.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/adapter/MultiSearchAdapter.kt @@ -6,7 +6,6 @@ import androidx.recyclerview.widget.RecyclerView.RecycledViewPool import coil.ImageLoader import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener -import org.koitharu.kotatsu.list.ui.ItemSizeResolver import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration import org.koitharu.kotatsu.list.ui.adapter.MangaListListener import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD @@ -15,6 +14,7 @@ import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.LoadingFooter +import org.koitharu.kotatsu.list.ui.size.ItemSizeResolver import org.koitharu.kotatsu.search.ui.multi.MultiSearchListModel import kotlin.jvm.internal.Intrinsics diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/adapter/SearchResultsAD.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/adapter/SearchResultsAD.kt index 9bd049052..d2cc89e47 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/adapter/SearchResultsAD.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/adapter/SearchResultsAD.kt @@ -14,10 +14,10 @@ import org.koitharu.kotatsu.core.ui.list.decor.SpacingItemDecoration import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.textAndVisible import org.koitharu.kotatsu.databinding.ItemListGroupBinding -import org.koitharu.kotatsu.list.ui.ItemSizeResolver import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration import org.koitharu.kotatsu.list.ui.adapter.mangaGridItemAD import org.koitharu.kotatsu.list.ui.model.ListModel +import org.koitharu.kotatsu.list.ui.size.ItemSizeResolver import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.search.ui.multi.MultiSearchListModel @@ -35,7 +35,7 @@ fun searchResultsAD( binding.recyclerView.setRecycledViewPool(sharedPool) val adapter = ListDelegationAdapter( - mangaGridItemAD(coil, lifecycleOwner, listener, sizeResolver), + mangaGridItemAD(coil, lifecycleOwner, sizeResolver, listener), ) binding.recyclerView.addItemDecoration(selectionDecoration) binding.recyclerView.adapter = adapter diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfFragment.kt index 50e2073af..6a53b6a49 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/ShelfFragment.kt @@ -28,8 +28,8 @@ import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.download.ui.worker.DownloadStartedObserver import org.koitharu.kotatsu.favourites.ui.FavouritesActivity import org.koitharu.kotatsu.history.ui.HistoryActivity -import org.koitharu.kotatsu.list.ui.ItemSizeResolver import org.koitharu.kotatsu.list.ui.model.ListModel +import org.koitharu.kotatsu.list.ui.size.DynamicItemSizeResolver import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.search.ui.MangaListActivity @@ -67,7 +67,7 @@ class ShelfFragment : override fun onViewBindingCreated(binding: FragmentShelfBinding, savedInstanceState: Bundle?) { super.onViewBindingCreated(binding, savedInstanceState) nestedScrollStateHandle = NestedScrollStateHandle(savedInstanceState, KEY_NESTED_SCROLL) - val sizeResolver = ItemSizeResolver(resources, settings) + val sizeResolver = DynamicItemSizeResolver(resources, settings) selectionController = SectionedSelectionController( activity = requireActivity(), owner = this, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/adapter/ShelfAdapter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/adapter/ShelfAdapter.kt index 0b1680d7e..7380f4164 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/adapter/ShelfAdapter.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/adapter/ShelfAdapter.kt @@ -2,14 +2,12 @@ package org.koitharu.kotatsu.shelf.ui.adapter import android.content.Context import androidx.lifecycle.LifecycleOwner -import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import coil.ImageLoader import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter import org.koitharu.kotatsu.core.ui.list.NestedScrollStateHandle import org.koitharu.kotatsu.core.ui.list.SectionedSelectionController import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller -import org.koitharu.kotatsu.list.ui.ItemSizeResolver import org.koitharu.kotatsu.list.ui.ListModelDiffCallback import org.koitharu.kotatsu.list.ui.adapter.emptyHintAD import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD @@ -17,9 +15,8 @@ import org.koitharu.kotatsu.list.ui.adapter.errorStateListAD import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD import org.koitharu.kotatsu.list.ui.model.ListModel -import org.koitharu.kotatsu.list.ui.model.LoadingFooter +import org.koitharu.kotatsu.list.ui.size.ItemSizeResolver import org.koitharu.kotatsu.shelf.ui.model.ShelfSectionModel -import kotlin.jvm.internal.Intrinsics class ShelfAdapter( lifecycleOwner: LifecycleOwner, @@ -33,16 +30,16 @@ class ShelfAdapter( init { val pool = RecyclerView.RecycledViewPool() delegatesManager.addDelegate( - shelfGroupAD( - sharedPool = pool, - lifecycleOwner = lifecycleOwner, - coil = coil, - sizeResolver = sizeResolver, - selectionController = selectionController, - listener = listener, - nestedScrollStateHandle = nestedScrollStateHandle, - ), - ).addDelegate(loadingStateAD()).addDelegate(loadingFooterAD()) + shelfGroupAD( + sharedPool = pool, + lifecycleOwner = lifecycleOwner, + coil = coil, + sizeResolver = sizeResolver, + selectionController = selectionController, + listener = listener, + nestedScrollStateHandle = nestedScrollStateHandle, + ), + ).addDelegate(loadingStateAD()).addDelegate(loadingFooterAD()) .addDelegate(emptyHintAD(coil, lifecycleOwner, listener)) .addDelegate(emptyStateListAD(coil, lifecycleOwner, listener)).addDelegate(errorStateListAD(listener)) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/adapter/ShelfGroupAD.kt b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/adapter/ShelfGroupAD.kt index 9e633798a..544920a8d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/adapter/ShelfGroupAD.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/shelf/ui/adapter/ShelfGroupAD.kt @@ -15,10 +15,10 @@ import org.koitharu.kotatsu.core.ui.list.decor.SpacingItemDecoration import org.koitharu.kotatsu.core.util.ext.removeItemDecoration import org.koitharu.kotatsu.core.util.ext.setTextAndVisible import org.koitharu.kotatsu.databinding.ItemListGroupBinding -import org.koitharu.kotatsu.list.ui.ItemSizeResolver import org.koitharu.kotatsu.list.ui.ListModelDiffCallback import org.koitharu.kotatsu.list.ui.adapter.mangaGridItemAD import org.koitharu.kotatsu.list.ui.model.ListModel +import org.koitharu.kotatsu.list.ui.size.ItemSizeResolver import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.shelf.ui.model.ShelfSectionModel @@ -49,7 +49,7 @@ fun shelfGroupAD( val adapter = AsyncListDifferDelegationAdapter( ListModelDiffCallback, - mangaGridItemAD(coil, lifecycleOwner, listenerAdapter, sizeResolver), + mangaGridItemAD(coil, lifecycleOwner, sizeResolver, listenerAdapter), ) adapter.stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY adapter.registerAdapterDataObserver(ScrollKeepObserver(binding.recyclerView)) diff --git a/app/src/main/res/layout/fragment_details.xml b/app/src/main/res/layout/fragment_details.xml index 66e41f044..67953909d 100644 --- a/app/src/main/res/layout/fragment_details.xml +++ b/app/src/main/res/layout/fragment_details.xml @@ -301,6 +301,56 @@ app:constraint_referenced_ids="recyclerView_scrobbling,textView_scrobbling_title,button_scrobbling_more" tools:visibility="visible" /> + + +