diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/widgets/IconsView.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/widgets/IconsView.kt new file mode 100644 index 000000000..ad8f1fd5a --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/widgets/IconsView.kt @@ -0,0 +1,90 @@ +package org.koitharu.kotatsu.core.ui.widgets + +import android.content.Context +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.annotation.DrawableRes +import androidx.core.content.withStyledAttributes +import androidx.core.view.isVisible +import org.koitharu.kotatsu.R + +class IconsView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, +) : LinearLayout(context, attrs) { + + private var iconSize = LinearLayout.LayoutParams.WRAP_CONTENT + private var iconSpacing = 0 + + val iconsCount: Int + get() { + var count = 0 + repeat(childCount) { i -> + if (getChildAt(i).isVisible) { + count++ + } + } + return count + } + + init { + context.withStyledAttributes(attrs, R.styleable.IconsView) { + iconSize = getDimensionPixelSize(R.styleable.IconsView_iconSize, iconSize) + iconSpacing = getDimensionPixelOffset(R.styleable.IconsView_iconSpacing, iconSpacing) + } + } + + fun setIcons(icons: Iterable) { + var index = 0 + for (icon in icons) { + val imageView = (getChildAt(index) as ImageView?) ?: addImageView() + imageView.setImageDrawable(icon) + imageView.isVisible = true + index++ + } + for (i in index until childCount) { + val imageView = getChildAt(i) as? ImageView ?: continue + imageView.setImageDrawable(null) + imageView.isVisible = false + } + } + + fun clearIcons() { + repeat(childCount) { i -> + getChildAt(i).isVisible = false + } + } + + fun addIcon(drawable: Drawable) { + val imageView = getNextImageView() + imageView.setImageDrawable(drawable) + imageView.isVisible = true + } + + fun addIcon(@DrawableRes resId: Int) { + val imageView = getNextImageView() + imageView.setImageResource(resId) + imageView.isVisible = true + } + + private fun getNextImageView(): ImageView { + repeat(childCount) { i -> + val child = getChildAt(i) + if (child is ImageView && !child.isVisible) { + return child + } + } + return addImageView() + } + + private fun addImageView() = ImageView(context).also { + it.scaleType = ImageView.ScaleType.FIT_CENTER + val lp = LayoutParams(iconSize, iconSize) + if (childCount != 0) { + lp.marginStart = iconSpacing + } + addView(it, lp) + } +} 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 01acb1b19..25ba313ce 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 @@ -146,6 +146,7 @@ class DetailsViewModel @Inject constructor( mangaListMapper.toListModelList( manga = relatedMangaUseCase(it).orEmpty(), mode = ListMode.GRID, + flags = 0, ) } 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 3a9e30e9b..1c77dc858 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 @@ -52,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 -> mangaListMapper.toListModelList(list, mode) + else -> mangaListMapper.toListModelList(list, mode, 0) } }.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 161a75a1d..4fc9ae64a 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 @@ -206,6 +206,7 @@ class ExploreViewModel @Inject constructor( counter = 0, progress = null, isFavorite = false, + isSaved = 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 fd559caa3..5abe8a0b9 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 @@ -144,7 +144,7 @@ class FavouritesListViewModel @Inject constructor( } val result = ArrayList(size + 1) quickFilter.filterItem(filters)?.let(result::add) - mangaListMapper.toListModelList(result, this, mode) + mangaListMapper.toListModelList(result, this, mode, MangaListMapper.NO_FAVORITE) return result } 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 81de88924..b03725673 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 @@ -190,7 +190,7 @@ class HistoryListViewModel @Inject constructor( prevHeader = header } } - result += mangaListMapper.toListModel(manga, mode) + result += mangaListMapper.toListModel(manga, mode, 0) } if (filters.isNotEmpty() && isEmpty) { result += getEmptyState(hasFilters = true) 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 index 802833859..8d918206e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/MangaListMapper.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/domain/MangaListMapper.kt @@ -2,6 +2,7 @@ package org.koitharu.kotatsu.list.domain import android.content.Context import androidx.annotation.ColorRes +import androidx.annotation.IntDef import androidx.collection.MutableScatterSet import androidx.collection.ScatterSet import dagger.hilt.android.qualifiers.ApplicationContext @@ -15,6 +16,7 @@ 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.local.data.index.LocalMangaIndex import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.tracker.domain.TrackingRepository @@ -28,59 +30,74 @@ class MangaListMapper @Inject constructor( private val trackingRepository: TrackingRepository, private val historyRepository: HistoryRepository, private val favouritesRepository: FavouritesRepository, + private val localMangaIndex: LocalMangaIndex, ) { private val dict by lazy { readTagsDict(context) } - suspend fun toListModelList(manga: Collection, mode: ListMode): List = manga.map { - toListModel(it, mode) + suspend fun toListModelList( + manga: Collection, + mode: ListMode, + @Flags flags: Int + ): List = manga.map { + toListModel(it, mode, flags) } suspend fun toListModelList( destination: MutableCollection, manga: Collection, - mode: ListMode - ) = manga.mapTo(destination) { - toListModel(it, mode) + mode: ListMode, + @Flags flags: Int, + ) { + manga.mapTo(destination) { + toListModel(it, mode, flags) + } } - 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 toListModel( + manga: Manga, + mode: ListMode, + @Flags flags: Int + ): MangaListModel = when (mode) { + ListMode.LIST -> toCompactListModel(manga, flags) + ListMode.DETAILED_LIST -> toDetailedListModel(manga, flags) + ListMode.GRID -> toGridModel(manga, flags) } - suspend fun toCompactListModel(manga: Manga) = MangaCompactListModel( + suspend fun toCompactListModel(manga: Manga, @Flags flags: Int) = 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), - isFavorite = isFavorite(manga.id), + counter = getCounter(manga.id, flags), + progress = getProgress(manga.id, flags), + isFavorite = isFavorite(manga.id, flags), + isSaved = isSaved(manga.id, flags), ) - suspend fun toDetailedListModel(manga: Manga) = MangaDetailedListModel( + suspend fun toDetailedListModel(manga: Manga, @Flags flags: Int) = MangaDetailedListModel( id = manga.id, title = manga.title, subtitle = manga.altTitle, coverUrl = manga.coverUrl, manga = manga, - counter = getCounter(manga.id), - progress = getProgress(manga.id), - isFavorite = isFavorite(manga.id), + counter = getCounter(manga.id, flags), + progress = getProgress(manga.id, flags), + isFavorite = isFavorite(manga.id, flags), + isSaved = isSaved(manga.id, flags), tags = mapTags(manga.tags), ) - suspend fun toGridModel(manga: Manga) = MangaGridModel( + suspend fun toGridModel(manga: Manga, @Flags flags: Int) = MangaGridModel( id = manga.id, title = manga.title, coverUrl = manga.coverUrl, manga = manga, - counter = getCounter(manga.id), - progress = getProgress(manga.id), - isFavorite = isFavorite(manga.id), + counter = getCounter(manga.id, flags), + progress = getProgress(manga.id, flags), + isFavorite = isFavorite(manga.id, flags), + isSaved = isSaved(manga.id, flags), ) fun mapTags(tags: Collection) = tags.map { @@ -91,7 +108,7 @@ class MangaListMapper @Inject constructor( ) } - private suspend fun getCounter(mangaId: Long): Int { + private suspend fun getCounter(mangaId: Long, @Flags flags: Int): Int { return if (settings.isTrackerEnabled) { trackingRepository.getNewChaptersCount(mangaId) } else { @@ -99,12 +116,20 @@ class MangaListMapper @Inject constructor( } } - private suspend fun getProgress(mangaId: Long): ReadingProgress? { - return historyRepository.getProgress(mangaId, settings.progressIndicatorMode) + private suspend fun getProgress(mangaId: Long, @Flags flags: Int): ReadingProgress? { + return if (flags.hasNoFlag(NO_PROGRESS)) { + historyRepository.getProgress(mangaId, settings.progressIndicatorMode) + } else { + null + } } - private fun isFavorite(mangaId: Long): Boolean { - return false // TODO favouritesRepository.isFavorite(mangaId) + private suspend fun isFavorite(mangaId: Long, @Flags flags: Int): Boolean { + return flags.hasNoFlag(NO_FAVORITE) && favouritesRepository.isFavorite(mangaId) + } + + private suspend fun isSaved(mangaId: Long, @Flags flags: Int): Boolean { + return flags.hasNoFlag(NO_SAVED) && mangaId in localMangaIndex } @ColorRes @@ -128,4 +153,18 @@ class MangaListMapper @Inject constructor( set.trim() set } + + private fun Int.hasNoFlag(flag: Int) = this and flag == 0 + + + @IntDef(0, NO_SAVED, NO_PROGRESS, NO_FAVORITE) + @Retention(AnnotationRetention.SOURCE) + annotation class Flags + + companion object { + + const val NO_SAVED = 1 + const val NO_PROGRESS = 2 + const val NO_FAVORITE = 4 + } } 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 bc7b76292..79a37cb1f 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 @@ -6,6 +6,7 @@ import coil3.ImageLoader import coil3.request.allowRgb565 import coil3.request.transformations import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding +import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver import org.koitharu.kotatsu.core.ui.image.TrimTransformation import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter @@ -36,7 +37,12 @@ fun mangaGridItemAD( bind { payloads -> binding.textViewTitle.text = item.title binding.progressView.setProgress(item.progress, PAYLOAD_PROGRESS_CHANGED in payloads) - binding.imageViewFavorite.isVisible = item.isFavorite + with(binding.iconsView) { + clearIcons() + if (item.isSaved) addIcon(R.drawable.ic_storage) + if (item.isFavorite) addIcon(R.drawable.ic_heart_outline) + isVisible = iconsCount > 0 + } binding.imageViewCover.newImageRequest(lifecycleOwner, item.coverUrl)?.run { size(CoverSizeResolver(binding.imageViewCover)) defaultPlaceholders(context) 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 index d7c122492..c4145c330 100644 --- 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 @@ -12,4 +12,5 @@ data class MangaCompactListModel( override val counter: Int, override val progress: ReadingProgress?, override val isFavorite: Boolean, + override val isSaved: Boolean, ) : MangaListModel() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaDetailedListModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaDetailedListModel.kt index ee83aa9b8..53bfaf7fc 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaDetailedListModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/model/MangaDetailedListModel.kt @@ -13,5 +13,6 @@ data class MangaDetailedListModel( override val counter: Int, override val progress: ReadingProgress?, override val isFavorite: Boolean, + override val isSaved: Boolean, val tags: List, ) : 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 52007c3b5..26f6e99a8 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 @@ -11,4 +11,5 @@ data class MangaGridModel( override val counter: Int, override val progress: ReadingProgress?, override val isFavorite: Boolean, + override val isSaved: Boolean, ) : MangaListModel() 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 4afb11370..06c804898 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 @@ -14,6 +14,7 @@ sealed class MangaListModel : ListModel { abstract val coverUrl: String? abstract val counter: Int abstract val isFavorite: Boolean + abstract val isSaved: Boolean abstract val progress: ReadingProgress? val source: MangaSource @@ -27,7 +28,9 @@ sealed class MangaListModel : ListModel { previousState !is MangaListModel || previousState.manga != manga -> null previousState.progress != progress -> PAYLOAD_PROGRESS_CHANGED - previousState.isFavorite != isFavorite || previousState.counter != counter -> PAYLOAD_ANYTHING_CHANGED + previousState.isFavorite != isFavorite || + previousState.isSaved != isSaved || + previousState.counter != counter -> PAYLOAD_ANYTHING_CHANGED else -> null } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/index/LocalMangaIndex.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/index/LocalMangaIndex.kt index d2425be9e..a81ca5aab 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/index/LocalMangaIndex.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/index/LocalMangaIndex.kt @@ -73,6 +73,10 @@ class LocalMangaIndex @Inject constructor( }.getOrNull() } + suspend operator fun contains(mangaId: Long): Boolean { + return db.getLocalMangaIndexDao().findPath(mangaId) != null + } + suspend fun put(manga: LocalManga) = mutex.withLock { db.withTransaction { upsert(manga) 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 5c60c1bf9..421a723e3 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 @@ -8,6 +8,7 @@ import kotlinx.coroutines.flow.SharedFlow import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.toFileOrNull @@ -25,6 +26,7 @@ import org.koitharu.kotatsu.local.data.LocalStorageChanges import org.koitharu.kotatsu.local.data.LocalStorageManager import org.koitharu.kotatsu.local.domain.DeleteLocalMangaUseCase import org.koitharu.kotatsu.local.domain.model.LocalManga +import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.remotelist.ui.RemoteListViewModel import javax.inject.Inject @@ -107,6 +109,12 @@ class LocalListViewModel @Inject constructor( } } + override suspend fun mapMangaList( + destination: MutableCollection, + manga: Collection, + mode: ListMode + ) = mangaListMapper.toListModelList(destination, manga, mode, MangaListMapper.NO_SAVED) + override fun createEmptyState(canResetFilter: Boolean): EmptyState = if (canResetFilter) { super.createEmptyState(true) } else { 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 55f08c9b4..48b6c1062 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 @@ -22,6 +22,7 @@ import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.distinctById import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.getCauseUrl @@ -36,6 +37,7 @@ 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.MangaListModel import org.koitharu.kotatsu.list.ui.model.toErrorFooter import org.koitharu.kotatsu.list.ui.model.toErrorState import org.koitharu.kotatsu.parsers.model.Manga @@ -50,7 +52,7 @@ open class RemoteListViewModel @Inject constructor( mangaRepositoryFactory: MangaRepository.Factory, final override val filterCoordinator: FilterCoordinator, settings: AppSettings, - mangaListMapper: MangaListMapper, + protected val mangaListMapper: MangaListMapper, downloadScheduler: DownloadWorker.Scheduler, private val exploreRepository: ExploreRepository, sourcesRepository: MangaSourcesRepository, @@ -85,7 +87,7 @@ open class RemoteListViewModel @Inject constructor( list == null -> add(LoadingState) list.isEmpty() -> add(createEmptyState(canResetFilter = filterCoordinator.isFilterApplied)) else -> { - mangaListMapper.toListModelList(this, list, mode) + mapMangaList(this, list, mode) when { error != null -> add(error.toErrorFooter()) hasNext -> add(LoadingFooter()) @@ -171,6 +173,12 @@ open class RemoteListViewModel @Inject constructor( protected open suspend fun onBuildList(list: MutableList) = Unit + protected open suspend fun mapMangaList( + destination: MutableCollection, + manga: Collection, + mode: ListMode + ) = mangaListMapper.toListModelList(destination, manga, mode, 0) + fun openRandom() { if (randomJob?.isActive == true) { return diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/SearchViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/SearchViewModel.kt index ac5cbef66..2a207c2ce 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/SearchViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/SearchViewModel.kt @@ -126,6 +126,7 @@ class SearchViewModel @Inject constructor( mangaListMapper.toListModelList( manga = repository.getList(offset = 0, null, MangaListFilter(query = q)), mode = ListMode.GRID, + flags = 0, ) } }.fold( @@ -161,7 +162,7 @@ class SearchViewModel @Inject constructor( titleResId = R.string.history, source = UnknownMangaSource, hasMore = false, - list = mangaListMapper.toListModelList(manga = result, mode = ListMode.GRID), + list = mangaListMapper.toListModelList(manga = result, mode = ListMode.GRID, flags = 0), error = null, ) } else { @@ -190,7 +191,7 @@ class SearchViewModel @Inject constructor( titleResId = R.string.favourites, source = UnknownMangaSource, hasMore = false, - list = mangaListMapper.toListModelList(manga = result, mode = ListMode.GRID), + list = mangaListMapper.toListModelList(manga = result, mode = ListMode.GRID, flags = 0), error = null, ) } else { @@ -219,7 +220,7 @@ class SearchViewModel @Inject constructor( titleResId = 0, source = LocalMangaSource, hasMore = result.size > MIN_HAS_MORE_ITEMS, - list = mangaListMapper.toListModelList(manga = result, mode = ListMode.GRID), + list = mangaListMapper.toListModelList(manga = result, mode = ListMode.GRID,flags = 0), error = null, ) } else { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/storage/PickDirectoryContract.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/storage/PickDirectoryContract.kt index bad93c72b..af04bb8e8 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/storage/PickDirectoryContract.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/storage/PickDirectoryContract.kt @@ -5,6 +5,7 @@ import android.content.Intent import android.net.Uri import androidx.activity.result.contract.ActivityResultContracts +//FIXME: https://stackoverflow.com/questions/77555641/saf-no-activity-found-to-handle-intent-android-intent-action-open-document-tr class PickDirectoryContract : ActivityResultContracts.OpenDocumentTree() { override fun createIntent(context: Context, input: Uri?): Intent { 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 e1080f5c1..fe933b5e1 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 @@ -67,7 +67,7 @@ class SuggestionsViewModel @Inject constructor( else -> buildList(list.size + 1) { quickFilter.filterItem(filters)?.let(::add) - mangaListMapper.toListModelList(this, list, mode) + mangaListMapper.toListModelList(this, list, mode, 0) } } }.onStart { 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 598d57455..27869f4ad 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 @@ -151,7 +151,7 @@ class FeedViewModel @Inject constructor( null } else { UpdatedMangaHeader( - mangaList.map { mangaListMapper.toGridModel(it.manga) }, + mangaList.map { mangaListMapper.toGridModel(it.manga, 0) }, ) } } 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 b332edf0a..9cd35d993 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 @@ -107,7 +107,7 @@ class UpdatesViewModel @Inject constructor( prevHeader = header } } - result += mangaListMapper.toListModel(item.manga, mode) + result += mangaListMapper.toListModel(item.manga, mode, 0) } return result } diff --git a/app/src/main/res/drawable/bg_list_icons.xml b/app/src/main/res/drawable/bg_list_icons.xml new file mode 100644 index 000000000..3ed4e9fe4 --- /dev/null +++ b/app/src/main/res/drawable/bg_list_icons.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/app/src/main/res/layout/item_manga_grid.xml b/app/src/main/res/layout/item_manga_grid.xml index 546660514..de4a9bc3f 100644 --- a/app/src/main/res/layout/item_manga_grid.xml +++ b/app/src/main/res/layout/item_manga_grid.xml @@ -34,16 +34,17 @@ android:layout_gravity="bottom|end" android:layout_margin="@dimen/card_indicator_offset" /> - + android:layout_marginBottom="@dimen/card_indicator_offset" + android:background="@drawable/bg_list_icons" + android:orientation="horizontal" + android:padding="4dp" + app:iconSize="12dp" + app:iconSpacing="2dp" /> + + + + + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 97d367af7..69cb9b4bf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ material = "1.13.0-alpha10" moshi = "1.15.2" okhttp = "4.12.0" okio = "3.10.2" -parsers = "794a737b6d" +parsers = "198e859850" preference = "1.2.1" recyclerview = "1.4.0" room = "2.6.1"