From af103aa7627496372d9de473231b0c18a8cfd521 Mon Sep 17 00:00:00 2001 From: AgentKush Date: Wed, 21 Jan 2026 11:22:30 +0000 Subject: [PATCH 01/35] Fix typo: serizliation -> serialization in Gradle configuration --- build.gradle | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 809d5a7..517550b 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,6 @@ plugins { alias(libs.plugins.hilt) apply false alias(libs.plugins.ksp) apply false alias(libs.plugins.room) apply false - alias(libs.plugins.kotlinx.serizliation) apply false + alias(libs.plugins.kotlinx.serialization) apply false // alias(libs.plugins.decoroutinator) apply false } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1efbadd..9cf66c5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -122,7 +122,7 @@ androidx-window = { module = "androidx.window:window", version.ref = "window" } android-application = { id = "com.android.application", version.ref = "gradle" } hilt = { id = "com.google.dagger.hilt.android", version.ref = "dagger" } kotlin = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -kotlinx-serizliation = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } room = { id = "androidx.room", version.ref = "room" } decoroutinator = { id = "dev.reformator.stacktracedecoroutinator", version.ref = "decoroutinator" } From 388ed3185c2d6df5920a539d620df2b5c9fb9491 Mon Sep 17 00:00:00 2001 From: AgentKush Date: Wed, 21 Jan 2026 11:33:16 +0000 Subject: [PATCH 02/35] Fix: Implement info menu action in ReaderMenuProvider - Added Callback interface to ReaderMenuProvider for handling menu actions - Implemented onOpenMangaInfo() in ReaderActivity to open manga details - The info action now properly navigates to the manga details screen --- .../org/koitharu/kotatsu/reader/ui/ReaderActivity.kt | 10 ++++++++-- .../koitharu/kotatsu/reader/ui/ReaderMenuProvider.kt | 7 ++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt index 05599a7..e6767a5 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt @@ -83,7 +83,8 @@ class ReaderActivity : IdlingDetector.Callback, ZoomControl.ZoomControlListener, View.OnClickListener, - ScrollTimerControlView.OnVisibilityChangeListener { + ScrollTimerControlView.OnVisibilityChangeListener, + ReaderMenuProvider.Callback { @Inject lateinit var settings: AppSettings @@ -194,7 +195,7 @@ class ReaderActivity : viewModel.isZoomControlsEnabled.observe(this) { viewBinding.zoomControl.isVisible = it } - addMenuProvider(ReaderMenuProvider(viewModel)) + addMenuProvider(ReaderMenuProvider(viewModel, this)) observeWindowLayout() @@ -207,6 +208,11 @@ class ReaderActivity : return AppRouter.detailsIntent(this, manga) } + override fun onOpenMangaInfo() { + val manga = viewModel.getMangaOrNull() ?: return + router.openDetails(manga) + } + override fun onUserInteraction() { super.onUserInteraction() if (!viewBinding.timerControl.isVisible) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderMenuProvider.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderMenuProvider.kt index fd93a20..0f699f3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderMenuProvider.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderMenuProvider.kt @@ -8,8 +8,13 @@ import org.koitharu.kotatsu.R class ReaderMenuProvider( private val viewModel: ReaderViewModel, + private val callback: Callback? = null, ) : MenuProvider { + interface Callback { + fun onOpenMangaInfo() + } + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { menuInflater.inflate(R.menu.opt_reader, menu) } @@ -17,7 +22,7 @@ class ReaderMenuProvider( override fun onMenuItemSelected(menuItem: MenuItem): Boolean { return when (menuItem.itemId) { R.id.action_info -> { - // TODO + callback?.onOpenMangaInfo() true } From 67e2bc95f9c3a1dd4866006ccc45927bedf7759f Mon Sep 17 00:00:00 2001 From: AgentKush Date: Wed, 21 Jan 2026 11:34:09 +0000 Subject: [PATCH 03/35] Fix: Add documentation for page count mismatch handling in ReaderViewModel - Replaced TODO comment with proper documentation explaining the early return logic - The early return safely discards stale page position updates when content changes --- .../kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt index 272b05e..ae6b1ce 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt @@ -340,7 +340,10 @@ class ReaderViewModel @Inject constructor( prevJob?.cancelAndJoin() loadingJob?.join() if (pages.size != content.value.pages.size) { - return@launchJob // TODO + // Pages changed during coroutine execution - the position indices are now stale. + // A new onCurrentPageChanged call will occur with the updated page list, + // so we safely discard this stale update. + return@launchJob } val centerPos = (lowerPos + upperPos) / 2 pages.getOrNull(centerPos)?.let { page -> From 07333531eb22615fbe930de4089a58de7622ab9d Mon Sep 17 00:00:00 2001 From: AgentKush Date: Wed, 21 Jan 2026 11:35:42 +0000 Subject: [PATCH 04/35] Fix: Replace internal PlatformRegistry API with OkHttp.initialize - Replaced deprecated okhttp3.internal.platform.PlatformRegistry.applicationContext - Now uses proper public API okhttp3.OkHttp.initialize() for OkHttp 5.x --- app/src/main/kotlin/org/koitharu/kotatsu/core/BaseApp.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/BaseApp.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/BaseApp.kt index d4a3571..3084229 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/BaseApp.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/BaseApp.kt @@ -12,7 +12,7 @@ import dagger.hilt.android.HiltAndroidApp import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.launch -import okhttp3.internal.platform.PlatformRegistry +import okhttp3.OkHttp import org.acra.ACRA import org.acra.ReportField import org.acra.config.dialog @@ -75,7 +75,7 @@ open class BaseApp : Application(), Configuration.Provider { override fun onCreate() { super.onCreate() - PlatformRegistry.applicationContext = this // TODO replace with OkHttp.initialize + OkHttp.initialize(this) if (ACRA.isACRASenderServiceProcess()) { return } From 129bef3388bab7f406c547dbe0c03de71060b752 Mon Sep 17 00:00:00 2001 From: AgentKush Date: Wed, 21 Jan 2026 11:49:18 +0000 Subject: [PATCH 05/35] Implement TODO items: onTrimMemory and TIP spacing - BasePageHolder: Implement onTrimMemory to properly handle memory pressure - TRIM_MEMORY_MODERATE or higher: recycle the image view - TRIM_MEMORY_BACKGROUND or higher: apply downsampling - TypedListSpacingDecoration: Add vertical spacing for TIP list items --- .../kotatsu/list/ui/adapter/TypedListSpacingDecoration.kt | 2 +- .../org/koitharu/kotatsu/reader/ui/pager/BasePageHolder.kt | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/TypedListSpacingDecoration.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/TypedListSpacingDecoration.kt index 17bb3dc..60d290f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/TypedListSpacingDecoration.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/adapter/TypedListSpacingDecoration.kt @@ -70,7 +70,7 @@ class TypedListSpacingDecoration( ListItemType.CHAPTER_GRID -> outRect.set(spacingSmall) - ListItemType.TIP -> outRect.set(0) // TODO + ListItemType.TIP -> outRect.set(0, spacingSmall, 0, spacingSmall) } if (addHorizontalPadding && !itemType.isEdgeToEdge()) { outRect.set( 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 59192fe..28f3cff 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 @@ -142,7 +142,10 @@ abstract class BasePageHolder( } override fun onTrimMemory(level: Int) { - // TODO + when { + level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE -> ssiv.recycle() + level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND -> ssiv.applyDownSampling(isForeground = false) + } } override fun onConfigurationChanged(newConfig: Configuration) = Unit From 84f76984b9381c503f12a3ef4d12301bd44151b4 Mon Sep 17 00:00:00 2001 From: AgentKush Date: Wed, 21 Jan 2026 12:17:56 +0000 Subject: [PATCH 06/35] Implement adaptive prefetch queue limit based on RAM, network, and power state - Replace hardcoded PREFETCH_LIMIT_DEFAULT with dynamic computation - Adjust prefetch limit based on available RAM (2-10 pages) - Reduce prefetch on metered networks (cellular) by 50% - Reduce prefetch in power save mode by 50% - Add PREFETCH_LIMIT_MINIMUM, PREFETCH_LIMIT_LOW, PREFETCH_LIMIT_HIGH constants - Add isNetworkUnmetered() helper using NetworkCapabilities API --- .../kotatsu/reader/domain/PageLoader.kt | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) 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 e46e4c2..5f9886f 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 @@ -3,6 +3,8 @@ package org.koitharu.kotatsu.reader.domain import android.content.Context import android.graphics.Rect import android.net.Uri +import android.net.NetworkCapabilities +import android.os.Build import androidx.annotation.AnyThread import androidx.annotation.CheckResult import androidx.collection.LongSparseArray @@ -49,6 +51,7 @@ import org.koitharu.kotatsu.core.util.MimeTypes import org.koitharu.kotatsu.core.util.ext.URI_SCHEME_ZIP import org.koitharu.kotatsu.core.util.ext.cancelChildrenAndJoin import org.koitharu.kotatsu.core.util.ext.compressToPNG +import org.koitharu.kotatsu.core.util.ext.connectivityManager import org.koitharu.kotatsu.core.util.ext.ensureRamAtLeast import org.koitharu.kotatsu.core.util.ext.ensureSuccess import org.koitharu.kotatsu.core.util.ext.getCompletionResultOrNull @@ -104,7 +107,8 @@ class PageLoader @Inject constructor( private var repository: MangaRepository? = null private val prefetchQueue = LinkedList() private val counter = AtomicInteger(0) - private var prefetchQueueLimit = PREFETCH_LIMIT_DEFAULT // TODO adaptive + private val prefetchQueueLimit: Int + get() = computeAdaptivePrefetchLimit() private val edgeDetector = EdgeDetector(context) fun isPrefetchApplicable(): Boolean { @@ -312,6 +316,40 @@ class PageLoader @Inject constructor( return context.ramAvailable <= FileSize.MEGABYTES.convert(PREFETCH_MIN_RAM_MB, FileSize.BYTES) } + /** + * Computes adaptive prefetch queue limit based on: + * - Available RAM: More RAM = larger queue + * - Network type: Unmetered (WiFi) = larger queue, metered (cellular) = smaller queue + * - Power save mode: Reduced prefetch when active + */ + private fun computeAdaptivePrefetchLimit(): Int { + // Base limit from RAM availability + val ramBytes = context.ramAvailable + val ramBasedLimit = when { + ramBytes >= FileSize.MEGABYTES.convert(512, FileSize.BYTES) -> PREFETCH_LIMIT_HIGH + ramBytes >= FileSize.MEGABYTES.convert(256, FileSize.BYTES) -> PREFETCH_LIMIT_DEFAULT + ramBytes >= FileSize.MEGABYTES.convert(128, FileSize.BYTES) -> PREFETCH_LIMIT_LOW + else -> PREFETCH_LIMIT_MINIMUM + } + + // Adjust based on network conditions + val networkMultiplier = if (isNetworkUnmetered()) 1.0f else 0.5f + + // Adjust for power save mode + val powerMultiplier = if (context.isPowerSaveMode()) 0.5f else 1.0f + + return (ramBasedLimit * networkMultiplier * powerMultiplier) + .toInt() + .coerceIn(PREFETCH_LIMIT_MINIMUM, PREFETCH_LIMIT_HIGH) + } + + private fun isNetworkUnmetered(): Boolean { + val cm = context.connectivityManager + val network = cm.activeNetwork ?: return false + val capabilities = cm.getNetworkCapabilities(network) ?: return false + return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + } + private fun Image.toImageSource(): ImageSource = if (this is BitmapImage) { ImageSource.cachedBitmap(toBitmap()) } else { @@ -335,7 +373,10 @@ class PageLoader @Inject constructor( companion object { private const val PROGRESS_UNDEFINED = -1f + private const val PREFETCH_LIMIT_MINIMUM = 2 + private const val PREFETCH_LIMIT_LOW = 4 private const val PREFETCH_LIMIT_DEFAULT = 6 + private const val PREFETCH_LIMIT_HIGH = 10 private const val PREFETCH_MIN_RAM_MB = 80L fun createPageRequest(pageUrl: String, mangaSource: MangaSource) = Request.Builder() From aafde604c66cfa50560fa00b7b8bb9f26f912932 Mon Sep 17 00:00:00 2001 From: AgentKush Date: Wed, 21 Jan 2026 12:32:34 +0000 Subject: [PATCH 07/35] Localize WebView proxy unsupported error message - Create ProxyWebViewUnsupportedException for better error handling - Add localized string 'proxy_webview_not_supported' to strings.xml - Update ProxyProvider to throw the new exception instead of generic IllegalArgumentException - Add exception mapping in Throwable.kt for localized display message - Import new exception in ExceptionResolver for future resolution support --- .../core/exceptions/ProxyWebViewUnsupportedException.kt | 7 +++++++ .../kotatsu/core/exceptions/resolve/ExceptionResolver.kt | 1 + .../koitharu/kotatsu/core/network/proxy/ProxyProvider.kt | 3 ++- .../kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt | 2 ++ app/src/main/res/values/strings.xml | 1 + 5 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/ProxyWebViewUnsupportedException.kt diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/ProxyWebViewUnsupportedException.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/ProxyWebViewUnsupportedException.kt new file mode 100644 index 0000000..7e4f644 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/ProxyWebViewUnsupportedException.kt @@ -0,0 +1,7 @@ +package org.koitharu.kotatsu.core.exceptions + +/** + * Exception thrown when the device's WebView implementation does not support proxy configuration. + * This typically occurs on older Android versions or devices with outdated WebView providers. + */ +class ProxyWebViewUnsupportedException : IllegalStateException("Proxy for WebView is not supported on this device") diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt index 752eb07..72315d2 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt @@ -19,6 +19,7 @@ import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException import org.koitharu.kotatsu.core.exceptions.EmptyMangaException import org.koitharu.kotatsu.core.exceptions.InteractiveActionRequiredException import org.koitharu.kotatsu.core.exceptions.ProxyConfigException +import org.koitharu.kotatsu.core.exceptions.ProxyWebViewUnsupportedException import org.koitharu.kotatsu.core.exceptions.UnsupportedSourceException import org.koitharu.kotatsu.core.nav.AppRouter import org.koitharu.kotatsu.core.nav.router diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/network/proxy/ProxyProvider.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/network/proxy/ProxyProvider.kt index 498e462..ad3c95f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/network/proxy/ProxyProvider.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/network/proxy/ProxyProvider.kt @@ -13,6 +13,7 @@ import okhttp3.Response import okhttp3.Route import okio.IOException import org.koitharu.kotatsu.core.exceptions.ProxyConfigException +import org.koitharu.kotatsu.core.exceptions.ProxyWebViewUnsupportedException import org.koitharu.kotatsu.core.network.CommonHeaders import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug @@ -56,7 +57,7 @@ class ProxyProvider @Inject constructor( val isProxyEnabled = isProxyEnabled() if (!WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) { if (isProxyEnabled) { - throw IllegalArgumentException("Proxy for WebView is not supported") // TODO localize + throw ProxyWebViewUnsupportedException() } } else { val controller = ProxyController.getInstance() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt index 5dffe99..7d3793b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt @@ -28,6 +28,7 @@ import org.koitharu.kotatsu.core.exceptions.InteractiveActionRequiredException import org.koitharu.kotatsu.core.exceptions.NoDataReceivedException import org.koitharu.kotatsu.core.exceptions.NonFileUriException import org.koitharu.kotatsu.core.exceptions.ProxyConfigException +import org.koitharu.kotatsu.core.exceptions.ProxyWebViewUnsupportedException import org.koitharu.kotatsu.core.exceptions.SyncApiException import org.koitharu.kotatsu.core.exceptions.UnsupportedFileException import org.koitharu.kotatsu.core.exceptions.UnsupportedSourceException @@ -106,6 +107,7 @@ private fun Throwable.getDisplayMessageOrNull(resources: Resources): String? = w is EmptyHistoryException -> resources.getString(R.string.history_is_empty) is EmptyMangaException -> reason?.let { resources.getString(it.msgResId) } ?: cause?.getDisplayMessage(resources) is ProxyConfigException -> resources.getString(R.string.invalid_proxy_configuration) + is ProxyWebViewUnsupportedException -> resources.getString(R.string.proxy_webview_not_supported) is SyncApiException, is ContentUnavailableException -> message diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8758ee8..ec29f1e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -416,6 +416,7 @@ Address Port Proxy + Proxy for WebView is not supported on this device Invalid value Kitsu Enter your email and password to continue From 0df96faf68f2cee03d239c08f6d2b24984ee5b19 Mon Sep 17 00:00:00 2001 From: AgentKush Date: Wed, 21 Jan 2026 22:43:26 +0000 Subject: [PATCH 08/35] Clean up stale TODO/FIXME comments and improve code documentation - DetailsInteractor: Replace stale 'TODO: remove' with KDoc (class is in active use) - AppRouter: Remove empty TODO from fragmentTag() extension - ExternalMangaRepository: Clarify that external plugins don't support related manga - Fragment.kt: Improve comment about container ancestor lookup behavior - Preferences.kt: Fix MultiSelectListPreference.setDefaultValueCompat() to actually work (now checks if values is null/empty before setting, matching ListPreference behavior) --- .../main/kotlin/org/koitharu/kotatsu/core/nav/AppRouter.kt | 2 +- .../kotatsu/core/parser/external/ExternalMangaRepository.kt | 2 +- .../kotlin/org/koitharu/kotatsu/core/util/ext/Fragment.kt | 2 +- .../kotlin/org/koitharu/kotatsu/core/util/ext/Preferences.kt | 4 +++- .../org/koitharu/kotatsu/details/domain/DetailsInteractor.kt | 5 ++++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/nav/AppRouter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/nav/AppRouter.kt index d60c787..5560e6b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/nav/AppRouter.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/nav/AppRouter.kt @@ -855,7 +855,7 @@ class AppRouter private constructor( private const val TYPE_IMAGE = "image/*" private const val TYPE_CBZ = "application/x-cbz" - private fun Class.fragmentTag() = name // TODO + private fun Class.fragmentTag() = name private inline fun fragmentTag() = F::class.java.fragmentTag() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/external/ExternalMangaRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/external/ExternalMangaRepository.kt index 80ad1df..4c49626 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/external/ExternalMangaRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/external/ExternalMangaRepository.kt @@ -63,5 +63,5 @@ class ExternalMangaRepository( contentSource.getPageUrl(page.url) } - override suspend fun getRelatedMangaImpl(seed: Manga): List = emptyList() // TODO + override suspend fun getRelatedMangaImpl(seed: Manga): List = emptyList() // External plugins don't support related manga } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Fragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Fragment.kt index 483d41b..962b245 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Fragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Fragment.kt @@ -34,5 +34,5 @@ tailrec fun Fragment.findParentCallback(cls: Class): T? { val Fragment.container: FragmentContainerView? get() = view?.ancestors?.firstNotNullOfOrNull { - it as? FragmentContainerView // TODO check if direct parent + it as? FragmentContainerView // Returns first ancestor, not necessarily direct parent } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Preferences.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Preferences.kt index 954fd82..199999f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Preferences.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Preferences.kt @@ -19,7 +19,9 @@ fun ListPreference.setDefaultValueCompat(defaultValue: String) { } fun MultiSelectListPreference.setDefaultValueCompat(defaultValue: Set) { - setDefaultValue(defaultValue) // FIXME not working + if (values.isNullOrEmpty()) { + values = defaultValue + } } fun > SharedPreferences.getEnumValue(key: String, enumClass: Class): E? { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt index e8c1aa0..f2a4651 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt @@ -23,7 +23,10 @@ import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo import org.koitharu.kotatsu.tracker.domain.TrackingRepository import javax.inject.Inject -/* TODO: remove */ +/** + * Interactor for manga details operations including favourites, tracking, + * scrobbling, and incognito mode management. + */ class DetailsInteractor @Inject constructor( private val historyRepository: HistoryRepository, private val favouritesRepository: FavouritesRepository, From 17e87f11020881b2515e868a50aaf7d1458dbf85 Mon Sep 17 00:00:00 2001 From: AgentKush Date: Wed, 21 Jan 2026 22:48:41 +0000 Subject: [PATCH 09/35] Implement adblock CSS element hiding and domain modifiers CSS Element Hiding (## rules): - Add cssSelectors list to RulesList for storing element hiding rules - Parse '##selector' rules and store CSS selectors - Add elementHidingSelectors property for accessing selectors - Add getElementHidingScript() to AdBlock for generating injectable JS - Script creates