diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/lifecycle/LifecycleAwareViewHolder.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/lifecycle/LifecycleAwareViewHolder.kt index 33f75ed37..b0543f462 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/lifecycle/LifecycleAwareViewHolder.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/lifecycle/LifecycleAwareViewHolder.kt @@ -19,9 +19,6 @@ abstract class LifecycleAwareViewHolder( init { parentLifecycleOwner.lifecycle.addObserver(ParentLifecycleObserver()) - if (parentLifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)) { - lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) - } } fun setIsCurrent(value: Boolean) { @@ -29,6 +26,9 @@ abstract class LifecycleAwareViewHolder( dispatchResumed() } + @CallSuper + open fun onCreate() = lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) + @CallSuper open fun onStart() = lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) @@ -41,6 +41,9 @@ abstract class LifecycleAwareViewHolder( @CallSuper open fun onStop() = lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP) + @CallSuper + open fun onDestroy() = lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) + private fun dispatchResumed() { val isParentResumed = parentLifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED) if (isCurrent && isParentResumed) { @@ -60,28 +63,18 @@ abstract class LifecycleAwareViewHolder( private inner class ParentLifecycleObserver : DefaultLifecycleObserver { - override fun onCreate(owner: LifecycleOwner) { - lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) - } + override fun onCreate(owner: LifecycleOwner) = this@LifecycleAwareViewHolder.onCreate() - override fun onStart(owner: LifecycleOwner) { - onStart() - } + override fun onStart(owner: LifecycleOwner) = this@LifecycleAwareViewHolder.onStart() - override fun onResume(owner: LifecycleOwner) { - dispatchResumed() - } + override fun onResume(owner: LifecycleOwner) = this@LifecycleAwareViewHolder.dispatchResumed() - override fun onPause(owner: LifecycleOwner) { - dispatchResumed() - } + override fun onPause(owner: LifecycleOwner) = this@LifecycleAwareViewHolder.dispatchResumed() - override fun onStop(owner: LifecycleOwner) { - onStop() - } + override fun onStop(owner: LifecycleOwner) = this@LifecycleAwareViewHolder.onStop() override fun onDestroy(owner: LifecycleOwner) { - lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) + this@LifecycleAwareViewHolder.onDestroy() owner.lifecycle.removeObserver(this) } } 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 7b9cb3e8c..720d33f28 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 @@ -25,7 +25,7 @@ import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding -import androidx.swiperefreshlayout.widget.CircularProgressDrawable +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import coil3.ImageLoader import coil3.request.ImageRequest import coil3.request.SuccessResult @@ -127,7 +127,7 @@ class DetailsActivity : View.OnClickListener, View.OnLongClickListener, PopupMenu.OnMenuItemClickListener, View.OnLayoutChangeListener, ViewTreeObserver.OnDrawListener, ChipsView.OnChipClickListener, OnListItemClickListener, - OnContextClickListenerCompat { + OnContextClickListenerCompat, SwipeRefreshLayout.OnRefreshListener { @Inject lateinit var shortcutManager: AppShortcutManager @@ -165,6 +165,7 @@ class DetailsActivity : viewBinding.infoLayout.chipSource.setOnClickListener(this) viewBinding.infoLayout.chipSize.setOnClickListener(this) viewBinding.textViewDescription.addOnLayoutChangeListener(this) + viewBinding.swipeRefreshLayout.setOnRefreshListener(this) viewBinding.textViewDescription.viewTreeObserver.addOnDrawListener(this) viewBinding.textViewDescription.movementMethod = LinkMovementMethodCompat.getInstance() viewBinding.chipsTags.onChipClickListener = this @@ -349,6 +350,10 @@ class DetailsActivity : Toast.makeText(view.context, R.string.incognito_mode, Toast.LENGTH_SHORT).show() } + override fun onRefresh() { + viewModel.reload() + } + override fun onDraw() { viewBinding.run { buttonDescriptionMore.isVisible = textViewDescription.maxLines == Int.MAX_VALUE || @@ -420,18 +425,7 @@ class DetailsActivity : } private fun onLoadingStateChanged(isLoading: Boolean) { - val button = viewBinding.buttonDownload ?: return - if (isLoading) { - button.setImageDrawable( - CircularProgressDrawable(this).also { - it.setStyle(CircularProgressDrawable.LARGE) - it.setColorSchemeColors(getThemeColor(materialR.attr.colorControlNormal)) - it.start() - }, - ) - } else { - button.setImageResource(R.drawable.ic_download) - } + viewBinding.swipeRefreshLayout.isRefreshing = isLoading } private fun onScrobblingInfoChanged(scrobblings: List) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/dialog/ChaptersSelectMacro.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/dialog/ChaptersSelectMacro.kt index 5302df6d3..ac04335e9 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/dialog/ChaptersSelectMacro.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/dialog/ChaptersSelectMacro.kt @@ -44,7 +44,7 @@ interface ChaptersSelectMacro { ) : ChaptersSelectMacro { override fun getChaptersIds(mangaId: Long, chapters: List): Set { - val result = ArraySet(chaptersCount) + val result = ArraySet(minOf(chaptersCount, chapters.size)) for (c in chapters) { if (c.branch == branch) { result.add(c.id) @@ -72,7 +72,7 @@ interface ChaptersSelectMacro { val currentChapterId = currentChaptersIds.getOrDefault(mangaId, chapters.first().id) var branch: String? = null var isAdding = false - val result = ArraySet(chaptersCount) + val result = ArraySet(minOf(chaptersCount, chapters.size)) for (c in chapters) { if (!isAdding) { if (c.id == currentChapterId) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryDao.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryDao.kt index 1065ee922..dbe45dc9f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryDao.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryDao.kt @@ -122,6 +122,8 @@ abstract class HistoryDao : MangaQueryBuilder.ConditionCallback { suspend fun deleteAfter(minDate: Long) = setDeletedAtAfter(minDate, System.currentTimeMillis()) + suspend fun deleteNotFavorite() = setDeletedAtNotFavorite(System.currentTimeMillis()) + suspend fun clear() = setDeletedAtAfter(0L, System.currentTimeMillis()) suspend fun update(entity: HistoryEntity) = update( @@ -157,6 +159,9 @@ abstract class HistoryDao : MangaQueryBuilder.ConditionCallback { @Query("UPDATE history SET deleted_at = :deletedAt WHERE created_at >= :minDate AND deleted_at = 0") protected abstract suspend fun setDeletedAtAfter(minDate: Long, deletedAt: Long) + @Query("UPDATE history SET deleted_at = :deletedAt WHERE deleted_at = 0 AND NOT EXISTS(SELECT * FROM favourites WHERE history.manga_id = favourites.manga_id)") + protected abstract suspend fun setDeletedAtNotFavorite(deletedAt: Long) + @Transaction @RawQuery(observedEntities = [HistoryEntity::class]) protected abstract fun observeAllImpl(query: SupportSQLiteQuery): Flow> diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt index 9176e66c5..d93f2df01 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt @@ -164,6 +164,10 @@ class HistoryRepository @Inject constructor( db.getHistoryDao().deleteAfter(minDate) } + suspend fun deleteNotFavorite() { + db.getHistoryDao().deleteNotFavorite() + } + suspend fun delete(ids: Collection): ReversibleHandle { db.withTransaction { for (id in ids) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListMenuProvider.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListMenuProvider.kt index a30adb5f2..1c412c3ae 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListMenuProvider.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListMenuProvider.kt @@ -53,6 +53,7 @@ class HistoryListMenuProvider( arrayOf( context.getString(R.string.last_2_hours), context.getString(R.string.today), + context.getString(R.string.not_in_favorites), context.getString(R.string.clear_all_history), ), selectionListener.selection, @@ -61,13 +62,12 @@ class HistoryListMenuProvider( setIcon(R.drawable.ic_delete_all) setNegativeButton(android.R.string.cancel, null) setPositiveButton(R.string.clear) { _, _ -> - val minDate = when (selectionListener.selection) { - 0 -> Instant.now().minus(2, ChronoUnit.HOURS) - 1 -> LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant() - 2 -> Instant.EPOCH - else -> return@setPositiveButton + when (selectionListener.selection) { + 0 -> viewModel.clearHistory(Instant.now().minus(2, ChronoUnit.HOURS)) + 1 -> viewModel.clearHistory(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant()) + 2 -> viewModel.removeNotFavorite() + 3 -> viewModel.clearHistory(null) } - viewModel.clearHistory(minDate) } }.show() } 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 b12c906f4..81de88924 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 @@ -101,9 +101,9 @@ class HistoryListViewModel @Inject constructor( override fun onRetry() = Unit - fun clearHistory(minDate: Instant) { + fun clearHistory(minDate: Instant?) { launchJob(Dispatchers.Default) { - val stringRes = if (minDate <= Instant.EPOCH) { + val stringRes = if (minDate == null) { repository.clear() R.string.history_cleared } else { @@ -114,6 +114,13 @@ class HistoryListViewModel @Inject constructor( } } + fun removeNotFavorite() { + launchJob(Dispatchers.Default) { + repository.deleteNotFavorite() + onActionDone.call(ReversibleAction(R.string.removed_from_history, null)) + } + } + fun removeFromHistory(ids: Set) { if (ids.isEmpty()) { return diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/image/ui/ImageActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/image/ui/ImageActivity.kt index 20f09ba8d..c030f6222 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/image/ui/ImageActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/image/ui/ImageActivity.kt @@ -169,7 +169,7 @@ class ImageActivity : BaseActivity(), ImageRequest.Listene private fun setDrawable(drawable: Drawable?) { if (drawable != null) { - view.setImage(ImageSource.Bitmap(drawable.toBitmap())) + view.setImage(ImageSource.bitmap(drawable.toBitmap())) } else { view.recycle() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/EdgeDetector.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/EdgeDetector.kt index c21e83300..5b4f9cb5b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/EdgeDetector.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/EdgeDetector.kt @@ -6,6 +6,7 @@ import android.graphics.Color import android.graphics.Point import android.graphics.Rect import androidx.annotation.ColorInt +import androidx.collection.LruCache import androidx.core.graphics.alpha import androidx.core.graphics.blue import androidx.core.graphics.get @@ -28,38 +29,46 @@ import kotlin.math.abs class EdgeDetector(private val context: Context) { private val mutex = Mutex() + private val cache = LruCache(CACHE_SIZE) - suspend fun getBounds(imageSource: ImageSource): Rect? = mutex.withLock { - withContext(Dispatchers.IO) { - val decoder = SkiaPooledImageRegionDecoder(Bitmap.Config.RGB_565) - try { - val size = runInterruptible { - decoder.init(context, imageSource) - } - val edges = coroutineScope { - listOf( - async { detectLeftRightEdge(decoder, size, isLeft = true) }, - async { detectTopBottomEdge(decoder, size, isTop = true) }, - async { detectLeftRightEdge(decoder, size, isLeft = false) }, - async { detectTopBottomEdge(decoder, size, isTop = false) }, - ).awaitAll() - } - var hasEdges = false - for (edge in edges) { - if (edge > 0) { - hasEdges = true - } else if (edge < 0) { - return@withContext null + suspend fun getBounds(imageSource: ImageSource): Rect? { + cache[imageSource]?.let { rect -> + return if (rect.isEmpty) null else rect + } + return mutex.withLock { + withContext(Dispatchers.IO) { + val decoder = SkiaPooledImageRegionDecoder(Bitmap.Config.RGB_565) + try { + val size = runInterruptible { + decoder.init(context, imageSource) } + val edges = coroutineScope { + listOf( + async { detectLeftRightEdge(decoder, size, isLeft = true) }, + async { detectTopBottomEdge(decoder, size, isTop = true) }, + async { detectLeftRightEdge(decoder, size, isLeft = false) }, + async { detectTopBottomEdge(decoder, size, isTop = false) }, + ).awaitAll() + } + var hasEdges = false + for (edge in edges) { + if (edge > 0) { + hasEdges = true + } else if (edge < 0) { + return@withContext null + } + } + if (hasEdges) { + Rect(edges[0], edges[1], size.x - edges[2], size.y - edges[3]) + } else { + null + } + } finally { + decoder.recycle() } - if (hasEdges) { - Rect(edges[0], edges[1], size.x - edges[2], size.y - edges[3]) - } else { - null - } - } finally { - decoder.recycle() } + }.also { + cache.put(imageSource, it ?: EMPTY_RECT) } } @@ -135,6 +144,8 @@ class EdgeDetector(private val context: Context) { private const val BLOCK_SIZE = 100 private const val COLOR_TOLERANCE = 16 + private const val CACHE_SIZE = 24 + private val EMPTY_RECT = Rect(0, 0, 0, 0) fun isColorTheSame(@ColorInt a: Int, @ColorInt b: Int, tolerance: Int): Boolean { return abs(a.red - b.red) <= tolerance && diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt index 6ad489c49..04b5759b4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt @@ -164,7 +164,7 @@ class PageLoader @Inject constructor( } suspend fun getTrimmedBounds(uri: Uri): Rect? = runCatchingCancellable { - edgeDetector.getBounds(ImageSource.Uri(uri)) + edgeDetector.getBounds(ImageSource.uri(uri)) }.onFailure { error -> error.printStackTraceDebug() }.getOrNull() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/BasePageHolder.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/BasePageHolder.kt index bfc3205e6..71c0f78cf 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/BasePageHolder.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/BasePageHolder.kt @@ -57,6 +57,11 @@ abstract class BasePageHolder( protected abstract fun onBind(data: ReaderPage) + override fun onCreate() { + super.onCreate() + context.registerComponentCallbacks(delegate) + } + override fun onResume() { super.onResume() if (delegate.state == State.ERROR && !delegate.isLoading()) { @@ -64,6 +69,11 @@ abstract class BasePageHolder( } } + override fun onDestroy() { + context.unregisterComponentCallbacks(delegate) + super.onDestroy() + } + @CallSuper open fun onAttachedToWindow() { delegate.onAttachedToWindow() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt index 7c7ec895f..d37907fc8 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt @@ -1,9 +1,12 @@ package org.koitharu.kotatsu.reader.ui.pager +import android.content.ComponentCallbacks2 +import android.content.res.Configuration import android.graphics.Rect import android.net.Uri import androidx.lifecycle.Observer import com.davemorrissey.labs.subscaleview.DefaultOnImageEventListener +import com.davemorrissey.labs.subscaleview.ImageSource import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -34,7 +37,7 @@ class PageHolderDelegate( private val networkState: NetworkState, private val exceptionResolver: ExceptionResolver, private val isWebtoon: Boolean, -) : DefaultOnImageEventListener, Observer { +) : DefaultOnImageEventListener, Observer, ComponentCallbacks2 { private val scope = loader.loaderScope + Dispatchers.Main.immediate var state = State.EMPTY @@ -99,7 +102,7 @@ class PageHolderDelegate( fun reload() { if (state == State.SHOWN) { uri?.let { - callback.onImageReady(it, cachedBounds) + callback.onImageReady(it.toImageSource(cachedBounds)) } } } @@ -135,6 +138,15 @@ class PageHolderDelegate( callback.onConfigChanged() } + override fun onConfigurationChanged(newConfig: Configuration) = Unit + + @Suppress("OVERRIDE_DEPRECATION") + override fun onLowMemory() = Unit + + override fun onTrimMemory(level: Int) { + callback.onTrimMemory() + } + private fun tryConvert(uri: Uri, e: Exception) { val prevJob = job job = scope.launch { @@ -148,7 +160,7 @@ class PageHolderDelegate( null } state = State.CONVERTED - callback.onImageReady(newUri, cachedBounds) + callback.onImageReady(newUri.toImageSource(cachedBounds)) } catch (ce: CancellationException) { throw ce } catch (e2: Throwable) { @@ -181,7 +193,7 @@ class PageHolderDelegate( } else { null } - callback.onImageReady(checkNotNull(uri), cachedBounds) + callback.onImageReady(checkNotNull(uri).toImageSource(cachedBounds)) } catch (e: CancellationException) { throw e } catch (e: Throwable) { @@ -201,6 +213,15 @@ class PageHolderDelegate( .onEach { callback.onProgressChanged((100 * it).toInt()) } .launchIn(scope) + private fun Uri.toImageSource(bounds: Rect?): ImageSource { + val source = ImageSource.uri(this) + return if (bounds != null) { + source.region(bounds) + } else { + source + } + } + enum class State { EMPTY, LOADING, LOADED, CONVERTING, CONVERTED, SHOWING, SHOWN, ERROR } @@ -211,7 +232,7 @@ class PageHolderDelegate( fun onError(e: Throwable) - fun onImageReady(uri: Uri, bounds: Rect?) + fun onImageReady(source: ImageSource) fun onImageShowing(settings: ReaderSettings) @@ -220,5 +241,7 @@ class PageHolderDelegate( fun onProgressChanged(progress: Int) fun onConfigChanged() + + fun onTrimMemory() } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt index e901d9079..b5eefe56e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt @@ -2,8 +2,6 @@ package org.koitharu.kotatsu.reader.ui.pager.standard import android.annotation.SuppressLint import android.graphics.PointF -import android.graphics.Rect -import android.net.Uri import android.view.View import android.view.animation.DecelerateInterpolator import androidx.core.view.isVisible @@ -91,11 +89,7 @@ open class PageHolder( } } - override fun onImageReady(uri: Uri, bounds: Rect?) { - val source = ImageSource.Uri(uri) - if (bounds != null) { - source.region(bounds) - } + override fun onImageReady(source: ImageSource) { binding.ssiv.setImage(source) } @@ -143,6 +137,10 @@ open class PageHolder( bindingInfo.progressBar.hide() } + override fun onTrimMemory() { + // TODO https://developer.android.com/topic/performance/memory + } + final override fun onClick(v: View) { when (v.id) { R.id.button_retry -> delegate.retry(boundData?.toMangaPage() ?: return, isFromUser = true) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt index 31501e97d..81d65e676 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt @@ -1,7 +1,5 @@ package org.koitharu.kotatsu.reader.ui.pager.webtoon -import android.graphics.Rect -import android.net.Uri import android.view.View import androidx.core.view.isVisible import androidx.lifecycle.LifecycleOwner @@ -91,11 +89,7 @@ class WebtoonHolder( } } - override fun onImageReady(uri: Uri, bounds: Rect?) { - val source = ImageSource.Uri(uri) - if (bounds != null) { - source.region(bounds) - } + override fun onImageReady(source: ImageSource) { binding.ssiv.setImage(source) } @@ -117,6 +111,10 @@ class WebtoonHolder( bindingInfo.progressBar.hide() } + override fun onTrimMemory() { + // TODO + } + override fun onClick(v: View) { when (v.id) { R.id.button_retry -> delegate.retry(boundData?.toMangaPage() ?: return, isFromUser = true) diff --git a/app/src/main/res/layout-w600dp-land/activity_details.xml b/app/src/main/res/layout-w600dp-land/activity_details.xml index f9fb29423..d90ca8c41 100644 --- a/app/src/main/res/layout-w600dp-land/activity_details.xml +++ b/app/src/main/res/layout-w600dp-land/activity_details.xml @@ -31,361 +31,368 @@ - - - - - - - - - - - - - - - - - - - - - - - - - -