diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/FavouritesModule.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/FavouritesModule.kt index 6d880abb9..f3bc159a8 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/FavouritesModule.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/FavouritesModule.kt @@ -11,10 +11,10 @@ import org.koitharu.kotatsu.favourites.ui.list.FavouritesListViewModel val favouritesModule get() = module { - factory { FavouritesRepository(get(), get()) } + single { FavouritesRepository(get(), get()) } viewModel { categoryId -> - FavouritesListViewModel(categoryId.get(), get(), get(), get()) + FavouritesListViewModel(categoryId.get(), get(), get(), get(), get()) } viewModel { FavouritesCategoriesViewModel(get(), get()) } viewModel { manga -> diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt index c2e8c00a1..6942925c0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt @@ -11,7 +11,8 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment.Companion.NO_ID -import org.koitharu.kotatsu.list.domain.CountersProvider +import org.koitharu.kotatsu.history.domain.HistoryRepository +import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.LoadingState @@ -25,8 +26,9 @@ class FavouritesListViewModel( private val categoryId: Long, private val repository: FavouritesRepository, private val trackingRepository: TrackingRepository, + private val historyRepository: HistoryRepository, settings: AppSettings, -) : MangaListViewModel(settings), CountersProvider { +) : MangaListViewModel(settings), ListExtraProvider { var sortOrder: LiveData = if (categoryId == NO_ID) { MutableLiveData(null) @@ -92,4 +94,8 @@ class FavouritesListViewModel( override suspend fun getCounter(mangaId: Long): Int { return trackingRepository.getNewChaptersCount(mangaId) } + + override suspend fun getProgress(mangaId: Long): Float { + return historyRepository.getProgress(mangaId) + } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/history/HistoryModule.kt b/app/src/main/java/org/koitharu/kotatsu/history/HistoryModule.kt index 246cb3a5f..74fb0ef40 100644 --- a/app/src/main/java/org/koitharu/kotatsu/history/HistoryModule.kt +++ b/app/src/main/java/org/koitharu/kotatsu/history/HistoryModule.kt @@ -8,6 +8,6 @@ import org.koitharu.kotatsu.history.ui.HistoryListViewModel val historyModule get() = module { - factory { HistoryRepository(get(), get(), get()) } + single { HistoryRepository(get(), get(), get()) } viewModel { HistoryListViewModel(get(), get(), get(), get()) } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/history/data/HistoryDao.kt b/app/src/main/java/org/koitharu/kotatsu/history/data/HistoryDao.kt index f52c5db6d..f27a0af0e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/history/data/HistoryDao.kt +++ b/app/src/main/java/org/koitharu/kotatsu/history/data/HistoryDao.kt @@ -45,26 +45,36 @@ abstract class HistoryDao { @Query("SELECT COUNT(*) FROM history") abstract fun observeCount(): Flow + @Query("SELECT percent FROM history WHERE manga_id = :id") + abstract fun findProgress(id: Long): Float? + @Query("DELETE FROM history") abstract suspend fun clear() @Insert(onConflict = OnConflictStrategy.IGNORE) abstract suspend fun insert(entity: HistoryEntity): Long - @Query("UPDATE history SET page = :page, chapter_id = :chapterId, scroll = :scroll, updated_at = :updatedAt WHERE manga_id = :mangaId") + @Query("UPDATE history SET page = :page, chapter_id = :chapterId, scroll = :scroll, percent = :percent, updated_at = :updatedAt WHERE manga_id = :mangaId") abstract suspend fun update( mangaId: Long, page: Int, chapterId: Long, scroll: Float, - updatedAt: Long + percent: Float, + updatedAt: Long, ): Int @Query("DELETE FROM history WHERE manga_id = :mangaId") abstract suspend fun delete(mangaId: Long) - suspend fun update(entity: HistoryEntity) = - update(entity.mangaId, entity.page, entity.chapterId, entity.scroll, entity.updatedAt) + suspend fun update(entity: HistoryEntity) = update( + mangaId = entity.mangaId, + page = entity.page, + chapterId = entity.chapterId, + scroll = entity.scroll, + percent = entity.percent, + updatedAt = entity.updatedAt + ) @Transaction open suspend fun upsert(entity: HistoryEntity): Boolean { diff --git a/app/src/main/java/org/koitharu/kotatsu/history/domain/HistoryRepository.kt b/app/src/main/java/org/koitharu/kotatsu/history/domain/HistoryRepository.kt index fa043ad14..61f49d6d9 100644 --- a/app/src/main/java/org/koitharu/kotatsu/history/domain/HistoryRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/history/domain/HistoryRepository.kt @@ -16,6 +16,8 @@ import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.tracker.domain.TrackingRepository import org.koitharu.kotatsu.utils.ext.mapItems +const val PROGRESS_NONE = -1f + class HistoryRepository( private val db: MangaDatabase, private val trackingRepository: TrackingRepository, @@ -86,6 +88,10 @@ class HistoryRepository( return db.historyDao.find(manga.id)?.toMangaHistory() } + suspend fun getProgress(mangaId: Long): Float { + return db.historyDao.findProgress(mangaId) ?: PROGRESS_NONE + } + suspend fun clear() { db.historyDao.clear() } diff --git a/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt index 1768c2a5f..231c89817 100644 --- a/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt @@ -2,8 +2,6 @@ package org.koitharu.kotatsu.history.ui import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import java.util.* -import java.util.concurrent.TimeUnit import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine @@ -26,6 +24,8 @@ import org.koitharu.kotatsu.utils.SingleLiveEvent import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct import org.koitharu.kotatsu.utils.ext.daysDiff import org.koitharu.kotatsu.utils.ext.onFirst +import java.util.* +import java.util.concurrent.TimeUnit class HistoryListViewModel( private val repository: HistoryRepository, @@ -112,9 +112,9 @@ class HistoryListViewModel( } val counter = trackingRepository.getNewChaptersCount(manga.id) result += when (mode) { - ListMode.LIST -> manga.toListModel(counter) - ListMode.DETAILED_LIST -> manga.toListDetailedModel(counter) - ListMode.GRID -> manga.toGridModel(counter) + ListMode.LIST -> manga.toListModel(counter, history.percent) + ListMode.DETAILED_LIST -> manga.toListDetailedModel(counter, history.percent) + ListMode.GRID -> manga.toGridModel(counter, history.percent) } } return result diff --git a/app/src/main/java/org/koitharu/kotatsu/history/ui/util/ReadingProgressDrawable.kt b/app/src/main/java/org/koitharu/kotatsu/history/ui/util/ReadingProgressDrawable.kt new file mode 100644 index 000000000..531615c03 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/history/ui/util/ReadingProgressDrawable.kt @@ -0,0 +1,129 @@ +package org.koitharu.kotatsu.history.ui.util + +import android.content.Context +import android.graphics.* +import android.graphics.drawable.Drawable +import androidx.annotation.StyleRes +import androidx.core.graphics.ColorUtils +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.history.domain.PROGRESS_NONE +import kotlin.math.roundToInt + +class ReadingProgressDrawable( + context: Context, + @StyleRes styleResId: Int, +) : Drawable() { + + private val paint = Paint(Paint.ANTI_ALIAS_FLAG) + private val lineColor: Int + private val outlineColor: Int + private val backgroundColor: Int + private val textColor: Int + private val textPattern = context.getString(R.string.percent_string_pattern) + private val textBounds = Rect() + private val hasBackground: Boolean + private val hasOutline: Boolean + private val hasText: Boolean + private val desiredHeight: Int + private val desiredWidth: Int + private val autoFitTextSize: Boolean + + var progress: Float = PROGRESS_NONE + set(value) { + field = value + text = textPattern.format((value * 100f).roundToInt().toString()) + paint.getTextBounds(text, 0, text.length, textBounds) + invalidateSelf() + } + private var text = "" + + init { + val ta = context.obtainStyledAttributes(styleResId, R.styleable.ProgressDrawable) + desiredHeight = ta.getDimensionPixelSize(R.styleable.ProgressDrawable_android_height, -1) + desiredWidth = ta.getDimensionPixelSize(R.styleable.ProgressDrawable_android_width, -1) + autoFitTextSize = ta.getBoolean(R.styleable.ProgressDrawable_autoFitTextSize, false) + lineColor = ta.getColor(R.styleable.ProgressDrawable_android_strokeColor, Color.BLACK) + outlineColor = ta.getColor(R.styleable.ProgressDrawable_outlineColor, Color.TRANSPARENT) + backgroundColor = ColorUtils.setAlphaComponent( + ta.getColor(R.styleable.ProgressDrawable_android_fillColor, Color.TRANSPARENT), + (255 * ta.getFloat(R.styleable.ProgressDrawable_android_fillAlpha, 0f)).toInt(), + ) + textColor = ta.getColor(R.styleable.ProgressDrawable_android_textColor, lineColor) + paint.strokeCap = Paint.Cap.ROUND + paint.textAlign = Paint.Align.CENTER + paint.textSize = ta.getDimension(R.styleable.ProgressDrawable_android_textSize, paint.textSize) + paint.strokeWidth = ta.getDimension(R.styleable.ProgressDrawable_strokeWidth, 1f) + hasBackground = Color.alpha(backgroundColor) != 0 + hasOutline = Color.alpha(outlineColor) != 0 + hasText = Color.alpha(textColor) != 0 && paint.textSize > 0 + ta.recycle() + } + + override fun onBoundsChange(bounds: Rect) { + super.onBoundsChange(bounds) + if (autoFitTextSize) { + val innerWidth = bounds.width() - (paint.strokeWidth * 2f) + paint.textSize = getTextSizeForWidth(innerWidth, "100%") + } + } + + override fun draw(canvas: Canvas) { + if (progress < 0f) { + return + } + val cx = bounds.exactCenterX() + val cy = bounds.exactCenterY() + val radius = minOf(bounds.width(), bounds.height()) / 2f + if (hasBackground) { + paint.style = Paint.Style.FILL + paint.color = backgroundColor + canvas.drawCircle(cx, cy, radius, paint) + } + val innerRadius = radius - paint.strokeWidth / 2f + paint.style = Paint.Style.STROKE + if (hasOutline) { + paint.color = outlineColor + canvas.drawCircle(cx, cy, innerRadius, paint) + } + paint.color = lineColor + canvas.drawArc( + cx - innerRadius, + cy - innerRadius, + cx + innerRadius, + cy + innerRadius, + -90f, + 360f * progress, + false, + paint, + ) + if (hasText) { + paint.style = Paint.Style.FILL + paint.color = textColor + val ty = bounds.height() / 2f + textBounds.height() / 2f - textBounds.bottom + canvas.drawText(text, cx, ty, paint) + } + } + + override fun setAlpha(alpha: Int) { + paint.alpha = alpha + } + + override fun setColorFilter(colorFilter: ColorFilter?) { + paint.colorFilter = colorFilter + } + + @Suppress("DeprecatedCallableAddReplaceWith") + @Deprecated("Deprecated in Java") + override fun getOpacity() = PixelFormat.TRANSLUCENT + + override fun getIntrinsicHeight() = desiredHeight + + override fun getIntrinsicWidth() = desiredWidth + + private fun getTextSizeForWidth(width: Float, text: String): Float { + val testTextSize = 48f + paint.textSize = testTextSize + paint.getTextBounds(text, 0, text.length, textBounds) + return testTextSize * width / textBounds.width() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/history/ui/util/ReadingProgressView.kt b/app/src/main/java/org/koitharu/kotatsu/history/ui/util/ReadingProgressView.kt new file mode 100644 index 000000000..2bb906c99 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/history/ui/util/ReadingProgressView.kt @@ -0,0 +1,114 @@ +package org.koitharu.kotatsu.history.ui.util + +import android.animation.Animator +import android.animation.ValueAnimator +import android.content.Context +import android.graphics.Outline +import android.util.AttributeSet +import android.view.View +import android.view.ViewOutlineProvider +import android.view.animation.AccelerateDecelerateInterpolator +import androidx.annotation.AttrRes +import androidx.annotation.StyleRes +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.history.domain.PROGRESS_NONE + +class ReadingProgressView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + @AttrRes defStyleAttr: Int = 0, +) : View(context, attrs, defStyleAttr), ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener { + + private var percentAnimator: ValueAnimator? = null + private val animationDuration = context.resources.getInteger(android.R.integer.config_shortAnimTime).toLong() + + @StyleRes + private val drawableStyle: Int + + var percent: Float + get() = peekProgressDrawable()?.progress ?: PROGRESS_NONE + set(value) { + cancelAnimation() + getProgressDrawable().progress = value + } + + init { + val ta = context.obtainStyledAttributes(attrs, R.styleable.ReadingProgressView, defStyleAttr, 0) + drawableStyle = ta.getResourceId(R.styleable.ReadingProgressView_progressStyle, R.style.ProgressDrawable) + ta.recycle() + outlineProvider = OutlineProvider() + if (isInEditMode) { + percent = 0.27f + } + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + percentAnimator?.run { + if (isRunning) end() + } + percentAnimator = null + } + + override fun onAnimationUpdate(animation: ValueAnimator) { + val p = animation.animatedValue as Float + getProgressDrawable().progress = p + } + + override fun onAnimationStart(animation: Animator?) = Unit + + override fun onAnimationEnd(animation: Animator?) { + if (percentAnimator === animation) { + percentAnimator = null + } + } + + override fun onAnimationCancel(animation: Animator?) = Unit + + override fun onAnimationRepeat(animation: Animator?) = Unit + + fun setPercent(value: Float, animate: Boolean) { + val currentDrawable = peekProgressDrawable() + if (!animate || currentDrawable == null || value == PROGRESS_NONE) { + percent = value + return + } + percentAnimator?.cancel() + percentAnimator = ValueAnimator.ofFloat( + currentDrawable.progress.coerceAtLeast(0f), + value + ).apply { + duration = animationDuration + interpolator = AccelerateDecelerateInterpolator() + addUpdateListener(this@ReadingProgressView) + addListener(this@ReadingProgressView) + start() + } + } + + private fun cancelAnimation() { + percentAnimator?.cancel() + percentAnimator = null + } + + private fun peekProgressDrawable(): ReadingProgressDrawable? { + return background as? ReadingProgressDrawable + } + + private fun getProgressDrawable(): ReadingProgressDrawable { + var d = peekProgressDrawable() + if (d != null) { + return d + } + d = ReadingProgressDrawable(context, drawableStyle) + background = d + return d + } + + private class OutlineProvider : ViewOutlineProvider() { + + override fun getOutline(view: View, outline: Outline) { + outline.setOval(0, 0, view.width, view.height) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/domain/CountersProvider.kt b/app/src/main/java/org/koitharu/kotatsu/list/domain/ListExtraProvider.kt similarity index 52% rename from app/src/main/java/org/koitharu/kotatsu/list/domain/CountersProvider.kt rename to app/src/main/java/org/koitharu/kotatsu/list/domain/ListExtraProvider.kt index e9594019c..7c547e0ae 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/domain/CountersProvider.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/domain/ListExtraProvider.kt @@ -1,6 +1,8 @@ package org.koitharu.kotatsu.list.domain -fun interface CountersProvider { +interface ListExtraProvider { suspend fun getCounter(mangaId: Long): Int + + suspend fun getProgress(mangaId: Long): Float } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt index e4ad38d3e..8145e240e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt @@ -11,6 +11,7 @@ import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.databinding.ItemMangaGridBinding +import org.koitharu.kotatsu.history.domain.PROGRESS_NONE import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.MangaGridModel import org.koitharu.kotatsu.parsers.model.Manga @@ -43,8 +44,9 @@ fun mangaGridItemAD( } } - bind { + bind { payloads -> binding.textViewTitle.text = item.title + binding.progressView.setPercent(item.progress, MangaListAdapter.PAYLOAD_PROGRESS in payloads) imageRequest?.dispose() imageRequest = binding.imageViewCover.newImageRequest(item.coverUrl) .referer(item.manga.publicUrl) @@ -60,6 +62,7 @@ fun mangaGridItemAD( onViewRecycled { itemView.clearBadge(badge) + binding.progressView.percent = PROGRESS_NONE badge = null imageRequest?.dispose() imageRequest = null diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListAdapter.kt index 93f271c0c..6b69445c5 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListAdapter.kt @@ -54,9 +54,14 @@ class MangaListAdapter( override fun getChangePayload(oldItem: ListModel, newItem: ListModel): Any? { return when (newItem) { - is MangaListModel, - is MangaGridModel, - is MangaListDetailedModel, + is MangaItemModel -> { + oldItem as MangaItemModel + if (oldItem.progress != newItem.progress) { + PAYLOAD_PROGRESS + } else { + Unit + } + } is CurrentFilterModel -> Unit else -> super.getChangePayload(oldItem, newItem) } @@ -77,5 +82,7 @@ class MangaListAdapter( const val ITEM_TYPE_HEADER = 9 const val ITEM_TYPE_FILTER = 10 const val ITEM_TYPE_HEADER_FILTER = 11 + + val PAYLOAD_PROGRESS = Any() } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt index 74a67378f..583be4079 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt @@ -10,6 +10,7 @@ import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.databinding.ItemMangaListDetailsBinding +import org.koitharu.kotatsu.history.domain.PROGRESS_NONE import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.MangaListDetailedModel import org.koitharu.kotatsu.parsers.model.Manga @@ -36,10 +37,11 @@ fun mangaListDetailedItemAD( clickListener.onItemLongClick(item.manga, it) } - bind { + bind { payloads -> imageRequest?.dispose() binding.textViewTitle.text = item.title binding.textViewSubtitle.textAndVisible = item.subtitle + binding.progressView.setPercent(item.progress, MangaListAdapter.PAYLOAD_PROGRESS in payloads) imageRequest = binding.imageViewCover.newImageRequest(item.coverUrl) .referer(item.manga.publicUrl) .placeholder(R.drawable.ic_placeholder) @@ -56,6 +58,7 @@ fun mangaListDetailedItemAD( onViewRecycled { itemView.clearBadge(badge) + binding.progressView.percent = PROGRESS_NONE badge = null imageRequest?.dispose() imageRequest = null diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt index cda127e73..b642a248b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/ListModelConversionExt.kt @@ -4,21 +4,23 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.prefs.ListMode -import org.koitharu.kotatsu.list.domain.CountersProvider +import org.koitharu.kotatsu.history.domain.PROGRESS_NONE +import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.parsers.exception.AuthRequiredException import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.utils.ext.ifZero -fun Manga.toListModel(counter: Int) = MangaListModel( +fun Manga.toListModel(counter: Int, progress: Float) = MangaListModel( id = id, title = title, subtitle = tags.joinToString(", ") { it.title }, coverUrl = coverUrl, manga = this, counter = counter, + progress = progress, ) -fun Manga.toListDetailedModel(counter: Int) = MangaListDetailedModel( +fun Manga.toListDetailedModel(counter: Int, progress: Float) = MangaListDetailedModel( id = id, title = title, subtitle = altTitle, @@ -27,50 +29,48 @@ fun Manga.toListDetailedModel(counter: Int) = MangaListDetailedModel( coverUrl = coverUrl, manga = this, counter = counter, + progress = progress, ) -fun Manga.toGridModel(counter: Int) = MangaGridModel( +fun Manga.toGridModel(counter: Int, progress: Float) = MangaGridModel( id = id, title = title, coverUrl = coverUrl, manga = this, counter = counter, + progress = progress, ) suspend fun List.toUi( mode: ListMode, - countersProvider: CountersProvider, + extraProvider: ListExtraProvider, ): List = when (mode) { - ListMode.LIST -> map { it.toListModel(countersProvider.getCounter(it.id)) } - ListMode.DETAILED_LIST -> map { it.toListDetailedModel(countersProvider.getCounter(it.id)) } - ListMode.GRID -> map { it.toGridModel(countersProvider.getCounter(it.id)) } -} - -suspend fun > List.toUi( - destination: C, - mode: ListMode, - countersProvider: CountersProvider, -): C = when (mode) { - ListMode.LIST -> mapTo(destination) { it.toListModel(countersProvider.getCounter(it.id)) } - ListMode.DETAILED_LIST -> mapTo(destination) { it.toListDetailedModel(countersProvider.getCounter(it.id)) } - ListMode.GRID -> mapTo(destination) { it.toGridModel(countersProvider.getCounter(it.id)) } + ListMode.LIST -> map { + it.toListModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id)) + } + ListMode.DETAILED_LIST -> map { + it.toListDetailedModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id)) + } + ListMode.GRID -> map { + it.toGridModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id)) + } } fun List.toUi( mode: ListMode, ): List = when (mode) { - ListMode.LIST -> map { it.toListModel(0) } - ListMode.DETAILED_LIST -> map { it.toListDetailedModel(0) } - ListMode.GRID -> map { it.toGridModel(0) } + ListMode.LIST -> map { it.toListModel(0, PROGRESS_NONE) } + ListMode.DETAILED_LIST -> map { it.toListDetailedModel(0, PROGRESS_NONE) } + ListMode.GRID -> map { it.toGridModel(0, PROGRESS_NONE) } } fun > List.toUi( destination: C, mode: ListMode, ): C = when (mode) { - ListMode.LIST -> mapTo(destination) { it.toListModel(0) } - ListMode.DETAILED_LIST -> mapTo(destination) { it.toListDetailedModel(0) } - ListMode.GRID -> mapTo(destination) { it.toGridModel(0) } + ListMode.LIST -> mapTo(destination) { it.toListModel(0, PROGRESS_NONE) } + ListMode.DETAILED_LIST -> mapTo(destination) { it.toListDetailedModel(0, PROGRESS_NONE) } + ListMode.GRID -> mapTo(destination) { it.toGridModel(0, PROGRESS_NONE) } } fun Throwable.toErrorState(canRetry: Boolean = true) = ErrorState( diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaGridModel.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaGridModel.kt index 9575d82fd..97a414879 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaGridModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaGridModel.kt @@ -4,8 +4,9 @@ import org.koitharu.kotatsu.parsers.model.Manga data class MangaGridModel( override val id: Long, - val title: String, - val coverUrl: String, + override val title: String, + override val coverUrl: String, override val manga: Manga, - val counter: Int, + override val counter: Int, + override val progress: Float, ) : MangaItemModel \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaItemModel.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaItemModel.kt index 64a4f66ae..ce5145d26 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaItemModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaItemModel.kt @@ -6,4 +6,8 @@ sealed interface MangaItemModel : ListModel { val id: Long val manga: Manga + val title: String + val coverUrl: String + val counter: Int + val progress: Float } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaListDetailedModel.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaListDetailedModel.kt index c1cedeb24..f9957f345 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaListDetailedModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaListDetailedModel.kt @@ -4,11 +4,12 @@ import org.koitharu.kotatsu.parsers.model.Manga data class MangaListDetailedModel( override val id: Long, - val title: String, + override val title: String, val subtitle: String?, val tags: String, - val coverUrl: String, + override val coverUrl: String, val rating: String?, override val manga: Manga, - val counter: Int, + override val counter: Int, + override val progress: Float, ) : MangaItemModel \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaListModel.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaListModel.kt index 7533858eb..71ac5743c 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaListModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/MangaListModel.kt @@ -4,9 +4,10 @@ import org.koitharu.kotatsu.parsers.model.Manga data class MangaListModel( override val id: Long, - val title: String, + override val title: String, val subtitle: String, - val coverUrl: String, + override val coverUrl: String, override val manga: Manga, - val counter: Int, + override val counter: Int, + override val progress: Float, ) : MangaItemModel \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt index 39ec6946a..1fe633456 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt @@ -376,6 +376,9 @@ class ReaderViewModel( val chapterIndex = chapters.indexOfFirst { x -> x.id == chapterId } val pages = content.value?.pages ?: return -1f val pagesCount = pages.count { x -> x.chapterId == chapterId } + if (chaptersCount == 0 || pagesCount == 0) { + return -1f + } val chapterPercent = (chapterIndex + 1) / chaptersCount.toFloat() val pagePercent = (pageIndex + 1) / pagesCount.toFloat() return pagePercent * chapterPercent // FIXME diff --git a/app/src/main/res/layout/item_manga_grid.xml b/app/src/main/res/layout/item_manga_grid.xml index 5174b647a..ef4ac491d 100644 --- a/app/src/main/res/layout/item_manga_grid.xml +++ b/app/src/main/res/layout/item_manga_grid.xml @@ -13,15 +13,28 @@ android:layout_height="wrap_content" android:orientation="vertical"> - + android:layout_height="wrap_content"> + + + + + + - + android:layout_height="match_parent"> + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index d563b55f8..622bdf251 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -26,6 +26,8 @@ 10dp 116dp 84dp + 4dp + 10dp 124dp 4dp diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index b4f3f77cf..b3f122cec 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -173,4 +173,15 @@ @layout/preference_widget_material_switch + + + +