diff --git a/app/detekt-baseline.xml b/app/detekt-baseline.xml index 5a91d2a..d2900b2 100644 --- a/app/detekt-baseline.xml +++ b/app/detekt-baseline.xml @@ -2,18 +2,24 @@ + ComplexCondition:HtmlParser.kt$HtmlParser$images.isNotEmpty() && (images.size > 5 || isChapterPage(url) || filteredParagraphs.size < 10) + ComplexCondition:ImageIntegrity.kt$ImageIntegrity$header.size >= 12 && header[0] == 'R'.code.toByte() && header[1] == 'I'.code.toByte() && header[2] == 'F'.code.toByte() && header[3] == 'F'.code.toByte() && header[8] == 'W'.code.toByte() && header[9] == 'E'.code.toByte() && header[10] == 'B'.code.toByte() && header[11] == 'P'.code.toByte() + ComplexCondition:ImageIntegrity.kt$ImageIntegrity$header.size >= 12 && header[4] == 'f'.code.toByte() && header[5] == 't'.code.toByte() && header[6] == 'y'.code.toByte() && header[7] == 'p'.code.toByte() + ComplexCondition:ImageIntegrity.kt$ImageIntegrity$header.size >= 6 && header[0] == 'G'.code.toByte() && header[1] == 'I'.code.toByte() && header[2] == 'F'.code.toByte() && header[3] == '8'.code.toByte() && (header[4] == '7'.code.toByte() || header[4] == '9'.code.toByte()) && header[5] == 'a'.code.toByte() + ComplexCondition:ImageIntegrity.kt$ImageIntegrity$header.size >= 8 && header[0] == 0x89.toByte() && header[1] == 0x50.toByte() && header[2] == 0x4E.toByte() && header[3] == 0x47.toByte() && header[4] == 0x0D.toByte() && header[5] == 0x0A.toByte() && header[6] == 0x1A.toByte() && header[7] == 0x0A.toByte() ComplexCondition:SummaryService.kt$SummaryService$text.contains("\"") || text.contains("'") || lowerText.contains("said") || lowerText.contains("asked") ComplexCondition:UrlSanitizer.kt$UrlSanitizer$scheme.all { it.isLetterOrDigit() || it == '-' || it == '+' || it == '.' } ComplexCondition:UrlSecurity.kt$UrlSecurity$address.isLoopbackAddress || address.isAnyLocalAddress || address.isLinkLocalAddress || address.isSiteLocalAddress || address.isMulticastAddress - ComplexCondition:WebContentLoader.kt$WebContentLoader$attempt == attempts - 1 || (e is Exception && e.message?.startsWith("HTTP") == true && !shouldRetryException(e)) CyclomaticComplexMethod:ChapterListSheet.kt$@OptIn(ExperimentalMaterial3Api::class, androidx.compose.foundation.ExperimentalFoundationApi::class) @Composable fun ChapterListSheet( uiState: ReaderViewModel.ReaderUiState, libraryViewModel: LibraryViewModel, onDismiss: () -> Unit, onNavigateToChapter: (String, String) -> Unit, sheetState: SheetState ) - CyclomaticComplexMethod:EpubContentLoader.kt$EpubContentLoader$private fun loadEpubChapter(filePath: String, book: EpubBook, href: String): EpubChapter + CyclomaticComplexMethod:ChapterListSheet.kt$internal fun chapterCacheStatusKind( isCurrent: Boolean, cacheState: PrefetchResult?, isInLibrary: Boolean, isDownloaded: Boolean = false ): ChapterStatus? + CyclomaticComplexMethod:EpubContentLoader.kt$EpubContentLoader$private suspend fun enrichEpubImageDimensionsFromCache( els: List<ContentElement> ): List<ContentElement> CyclomaticComplexMethod:ErrorMessages.kt$ErrorMessages$fun fromRaw(raw: String?): Friendly CyclomaticComplexMethod:ExploreDetailSheet.kt$@OptIn(ExperimentalLayoutApi::class) @Composable fun ExploreItemDetailSheet( item: ExploreItem, isLoading: Boolean = false, isInLibrary: Boolean = false, onAddToLibrary: () -> Unit, onRead: () -> Unit ): Unit CyclomaticComplexMethod:ExploreGridSection.kt$@Composable internal fun ExploreGrid( gridState: LazyGridState, modifier: Modifier = Modifier, uiState: ExploreViewModel.ExploreUiState, hasActiveFilters: Boolean, onItemSelect: (ExploreItem) -> Unit, onLoadMore: () -> Unit, onClearFilters: () -> Unit, onRetryFailedSource: (String) -> Unit ): Unit CyclomaticComplexMethod:HtmlParser.kt$HtmlParser$private fun parseImages(document: Document, url: String): List<ContentElement.Image> CyclomaticComplexMethod:ImageBoundsParser.kt$ImageBoundsParser$private fun parseJpeg(bytes: ByteArray): Pair<Int, Int>? CyclomaticComplexMethod:ImageDownloader.kt$ImageDownloader$private fun parseImageResponse( response: Response, destinationFile: File? = null ): ImageFetchResult + CyclomaticComplexMethod:ImageIntegrity.kt$ImageIntegrity$private fun classifyFormat(header: ByteArray): ImageFormat? CyclomaticComplexMethod:LibraryItemCard.kt$@OptIn(ExperimentalFoundationApi::class) @Composable fun LibraryItemCard( item: LibraryItem, isSelected: Boolean, isCurrent: Boolean, onClick: () -> Unit, onLongClick: () -> Unit, onNewTagClick: (() -> Unit)? = null, onDelete: (() -> Unit)? = null, onResetProgress: (() -> Unit)? = null, onMarkFinished: (() -> Unit)? = null ) CyclomaticComplexMethod:LibraryRepository.kt$LibraryRepository$suspend fun refreshLibraryUpdates(exploreRepository: ExploreRepository): Unit CyclomaticComplexMethod:LibraryScreen.kt$@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable fun LibraryScreen( libraryViewModel: LibraryViewModel, readerViewModel: ReaderViewModel, navController: NavController, onOpenFilePicker: () -> Unit, onNavigateBack: () -> Unit ): Unit @@ -26,19 +32,25 @@ CyclomaticComplexMethod:ReaderContentRenderers.kt$@Composable internal fun ScrollingReaderView( content: ChapterContent, listState: LazyListState, uiState: ReaderViewModel.ReaderUiState, isManhwa: Boolean, fontFamily: FontFamily, bgColor: Color, textColor: Color, readerViewModel: ReaderViewModel ): Unit CyclomaticComplexMethod:ReaderContentRenderers.kt$@OptIn(ExperimentalFoundationApi::class) @Composable internal fun PagedReaderView( content: ChapterContent, pagerState: PagerState, uiState: ReaderViewModel.ReaderUiState, fontFamily: FontFamily, bgColor: Color, textColor: Color, readerViewModel: ReaderViewModel, isZoomable: Boolean ): Unit CyclomaticComplexMethod:ReaderImageView.kt$@Composable fun ReaderImageView( imageUrl: String, altText: String?, readerViewModel: ReaderViewModel, pageUrl: String, contentScale: ContentScale = ContentScale.Fit, backgroundColor: Color = Color.Black, width: Int = 0, height: Int = 0, resolvedWidth: Int = 0, resolvedHeight: Int = 0, side: ContentElement.Image.Side = ContentElement.Image.Side.FULL, enableZoom: Boolean = false, dynamicHeight: Boolean = false, zoomStateKey: Any? = null, onZoomChanged: ((Boolean) -> Unit)? = null, onDimensionsResolved: ((String, Int, Int) -> Unit)? = null, lockTapWhileZoomed: Boolean = false, onTap: (() -> Unit)? = null ) - CyclomaticComplexMethod:ReaderProgressController.kt$ReaderProgressController$fun calculateInitialScroll( content: ChapterContent, libraryItem: LibraryItem?, fromBottom: Boolean, isExplicitNavigation: Boolean ): ScrollState - CyclomaticComplexMethod:ReaderProgressController.kt$ReaderProgressController$suspend fun updateReadingProgress( progress: Int, scrollPosition: Float? = null, index: Int? = null, offset: Int? = null, offsetFraction: Float? = null, currentChapterUrl: String? = null, content: ChapterContent? = null ) - CyclomaticComplexMethod:ReaderScreen.kt$@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable fun ReaderScreen( readerViewModel: ReaderViewModel, libraryViewModel: LibraryViewModel, navController: NavController, onOpenFilePicker: () -> Unit, modifier: Modifier = Modifier ): Unit + CyclomaticComplexMethod:ReaderProgressController.kt$ReaderProgressController$fun calculateInitialPosition( content: ChapterContent, libraryItem: LibraryItem?, fromBottom: Boolean, isExplicitNavigation: Boolean ): ReaderProgressState + CyclomaticComplexMethod:ReaderProgressController.kt$ReaderProgressController$fun updateScrollPosition( scrollOffset: Float, maxScrollOffset: Float, viewportHeight: Float, index: Int, offsetFraction: Float, elementKey: String, content: ChapterContent?, canScrollForward: Boolean = true, firstVisibleItemSize: Int = 0 ) + CyclomaticComplexMethod:ReaderScreen.kt$@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable fun ReaderScreen( readerViewModel: ReaderViewModel, libraryViewModelProvider: () -> LibraryViewModel, navController: NavController, onOpenFilePicker: () -> Unit, modifier: Modifier = Modifier ): Unit CyclomaticComplexMethod:ReaderViewModel.kt$ReaderViewModel$fun loadEpubChapter( epubPath: String, href: String, libraryItemId: String? = null, fromBottom: Boolean = false, isSilent: Boolean = false ): Unit CyclomaticComplexMethod:ReaderViewModel.kt$ReaderViewModel$private suspend fun handleLoadSuccess( result: ContentResult.Success, libraryItemId: String?, fromBottom: Boolean ): Unit + CyclomaticComplexMethod:ReaderViewModel.kt$ReaderViewModel$suspend fun persistLifecycleProgress(): Unit + CyclomaticComplexMethod:SettingsScreen.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun SettingsScreen( readerViewModel: ReaderViewModel, libraryViewModel: LibraryViewModel, onNavigateBack: () -> Unit, backupViewModel: BackupViewModel = hiltViewModel() ) CyclomaticComplexMethod:TextFormattingPipeline.kt$TextFormattingPipeline$private fun replaceSpacesPlusNewline(text: String, replacementChar: Char): String CyclomaticComplexMethod:UrlSecurity.kt$UrlSecurity$fun isSafeInetAddress(address: InetAddress): Boolean CyclomaticComplexMethod:WebContentLoader.kt$WebContentLoader$private suspend fun downloadAndCacheImageInternal( imageUrl: String, pageUrl: String, priority: ImageRequestPriority, writeTier: StorageTier = tierForPriority(priority) ): ImageDownloadResult + CyclomaticComplexMethod:WebContentLoader.kt$WebContentLoader$private suspend fun enrichParsedCacheDimensions(elements: List<ContentElement>): List<ContentElement> CyclomaticComplexMethod:WebContentLoader.kt$WebContentLoader$private suspend fun executePrefetch( url: String, mode: PrefetchMode, onProgress: (suspend (PrefetchResult) -> Unit)? = null ): PrefetchResult + CyclomaticComplexMethod:WebContentLoader.kt$WebContentLoader$private suspend fun inspectCacheInternal( url: String, cachedDocument: Document? = null, persistentOnly: Boolean = false ): PrefetchResult + CyclomaticComplexMethod:WebContentLoader.kt$WebContentLoader$private suspend fun migrateLegacySidecarIfPresent(url: String, now: Long) + CyclomaticComplexMethod:WebContentLoader.kt$WebContentLoader$suspend fun prefetch( url: String, mode: PrefetchMode, onProgress: (suspend (PrefetchResult) -> Unit)? ): PrefetchResult CyclomaticComplexMethod:ZoomableBox.kt$@Composable fun ZoomableBox( modifier: Modifier = Modifier, minScale: Float = 1f, maxScale: Float = 3f, enableZoom: Boolean = false, dynamicHeight: Boolean = false, zoomStateKey: Any? = null, onZoomChanged: ((Boolean) -> Unit)? = null, lockTapWhileZoomed: Boolean = false, onTap: (() -> Unit)? = null, content: @Composable BoxScope.() -> Unit ) EmptyFunctionBlock:HtmlParser.kt$HtmlParser.<no name provided>${} FunctionNaming:ChapterListSheet.kt$@OptIn(ExperimentalMaterial3Api::class, androidx.compose.foundation.ExperimentalFoundationApi::class) @Composable fun ChapterListSheet( uiState: ReaderViewModel.ReaderUiState, libraryViewModel: LibraryViewModel, onDismiss: () -> Unit, onNavigateToChapter: (String, String) -> Unit, sheetState: SheetState ) - FunctionNaming:ChapterSummaryDropdown.kt$@Composable fun ChapterSummaryDropdown( summary: String?, isGenerating: Boolean, onGenerateSummary: () -> Unit, onCancel: (() -> Unit)? = null, isAvailable: Boolean = true, modifier: Modifier = Modifier ) + FunctionNaming:ChapterSummaryDropdown.kt$@Composable fun ChapterSummaryDropdown( summary: String?, isGenerating: Boolean, onGenerateSummary: () -> Unit, onCancel: (() -> Unit)? = null, aiSupportedInBuild: Boolean = true, aiOptedIn: Boolean = true, onEnableAi: (() -> Unit)? = null, isInitializing: Boolean = false, isReady: Boolean = aiSupportedInBuild && aiOptedIn, modifier: Modifier = Modifier ) FunctionNaming:ContentRenderer.kt$@Composable fun AsyncImageElement( url: String, altText: String?, side: ContentElement.Image.Side = ContentElement.Image.Side.FULL, width: Int = 0, height: Int = 0, pageUrl: String = "" ) FunctionNaming:ContentRenderer.kt$@Composable fun ContentRenderer( elements: List<ContentElement>, modifier: Modifier = Modifier, backgroundColor: Color = Color.Black, textColor: Color = Color.White, pageUrl: String = "" ) FunctionNaming:ExploreDetailSheet.kt$@OptIn(ExperimentalLayoutApi::class) @Composable fun ExploreItemDetailSheet( item: ExploreItem, isLoading: Boolean = false, isInLibrary: Boolean = false, onAddToLibrary: () -> Unit, onRead: () -> Unit ): Unit @@ -83,7 +95,7 @@ FunctionNaming:LibraryScreenListSections.kt$@OptIn(ExperimentalFoundationApi::class) @Composable private fun NovelGroupCard( title: String, items: List<LibraryItem>, uiState: LibraryViewModel.LibraryUiState, readerUiState: ReaderViewModel.ReaderUiState, summaryUiState: SummaryViewModel.SummaryUiState, isExpanded: Boolean, showFullChapters: Boolean, onToggleExpand: () -> Unit, onToggleShowFull: () -> Unit, libraryViewModel: LibraryViewModel, readerViewModel: ReaderViewModel, summaryViewModel: SummaryViewModel, onCloseLibrary: () -> Unit ): Unit FunctionNaming:LibraryScreenListSections.kt$@OptIn(ExperimentalFoundationApi::class) @Composable private fun NovelGroupHeader( title: String, items: List<LibraryItem>, isExpanded: Boolean, isSelectionMode: Boolean, isGroupSelected: Boolean, hasGroupSelection: Boolean, readerUiState: ReaderViewModel.ReaderUiState, onToggleExpand: () -> Unit, onToggleSelection: () -> Unit, onOpenItem: (LibraryItem) -> Unit, onOpenNewChapter: (LibraryItem) -> Unit, onResetProgress: () -> Unit, onRemoveGroup: () -> Unit ): Unit FunctionNaming:LibraryScreenListSections.kt$@OptIn(ExperimentalFoundationApi::class) @Composable private fun SelectableClickBox( modifier: Modifier = Modifier, onClick: (() -> Unit)? = null, onLongClick: (() -> Unit)? = null, content: @Composable BoxScope.() -> Unit ) - FunctionNaming:ReaderContentArea.kt$@Composable private fun EdgeHintChip( text: String, icon: androidx.compose.ui.graphics.vector.ImageVector ) + FunctionNaming:ReaderContentArea.kt$@Composable private fun EdgeHintChip( text: String, icon: ImageVector ) FunctionNaming:ReaderContentArea.kt$@Composable private fun EdgeNavigationHint(atTop: Boolean, atBottom: Boolean) FunctionNaming:ReaderContentArea.kt$@Composable private fun ReaderBottomNavigationBar( readerViewModel: ReaderViewModel, canNavigatePrevious: Boolean, canNavigateNext: Boolean, onPreviousClick: () -> Unit, onNextClick: () -> Unit, onProgressChange: (Float) -> Unit ) FunctionNaming:ReaderContentArea.kt$@OptIn(androidx.compose.foundation.ExperimentalFoundationApi::class) @Composable internal fun ContentArea( uiState: ReaderViewModel.ReaderUiState, content: ChapterContent, readerViewModel: ReaderViewModel, onLibraryClick: () -> Unit, onShowChapterList: () -> Unit, onShowSettings: () -> Unit ): Unit @@ -98,7 +110,7 @@ FunctionNaming:ReaderScreen.kt$@Composable private fun CloudflareDialog( url: String, onDismiss: () -> Unit, onRetry: () -> Unit ): Unit FunctionNaming:ReaderScreen.kt$@Composable private fun NavigationOverlay(): Unit FunctionNaming:ReaderScreen.kt$@Composable private fun ReaderContent( uiState: ReaderViewModel.ReaderUiState, readerViewModel: ReaderViewModel, onOpenLibrary: () -> Unit, onOpenLibraryScreen: () -> Unit, onShowChapterList: () -> Unit, onShowSettings: () -> Unit ): Unit - FunctionNaming:ReaderScreen.kt$@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable fun ReaderScreen( readerViewModel: ReaderViewModel, libraryViewModel: LibraryViewModel, navController: NavController, onOpenFilePicker: () -> Unit, modifier: Modifier = Modifier ): Unit + FunctionNaming:ReaderScreen.kt$@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable fun ReaderScreen( readerViewModel: ReaderViewModel, libraryViewModelProvider: () -> LibraryViewModel, navController: NavController, onOpenFilePicker: () -> Unit, modifier: Modifier = Modifier ): Unit FunctionNaming:ReaderSettingsSheet.kt$@Composable fun SettingSlider( label: String, value: Float, onValueChange: (Float) -> Unit, valueRange: ClosedFloatingPointRange<Float>, steps: Int, displayValue: String ) FunctionNaming:ReaderSettingsSheet.kt$@Composable private fun AccentThemeChip( accentTheme: AccentTheme, isSelected: Boolean, onClick: () -> Unit ) FunctionNaming:ReaderSettingsSheet.kt$@Composable private fun FontFamilyChip( font: String, isSelected: Boolean, onClick: () -> Unit ) @@ -117,7 +129,6 @@ ImplicitDefaultLocale:ReaderSettingsSheet.kt$String.format("%.1f", uiState.lineHeight) ImplicitDefaultLocale:ReaderSettingsSheet.kt$String.format("%.1f", uiState.paragraphSpacing) ImplicitDefaultLocale:SettingsScreen.kt$String.format("%.1f %s", value, units[unit]) - InstanceOfCheckForException:WebContentLoader.kt$WebContentLoader$e is Exception InvalidPackageDeclaration:LibraryDrawerContent.kt$package io.aatricks.easyreader.ui.screens InvalidPackageDeclaration:LibraryNovelHelpers.kt$package io.aatricks.easyreader.ui.screens InvalidPackageDeclaration:LibraryScreen.kt$package io.aatricks.easyreader.ui.screens @@ -130,7 +141,7 @@ LargeClass:ReaderViewModel.kt$ReaderViewModel : BaseViewModel LargeClass:WebContentLoader.kt$WebContentLoader LongMethod:ChapterListSheet.kt$@OptIn(ExperimentalMaterial3Api::class, androidx.compose.foundation.ExperimentalFoundationApi::class) @Composable fun ChapterListSheet( uiState: ReaderViewModel.ReaderUiState, libraryViewModel: LibraryViewModel, onDismiss: () -> Unit, onNavigateToChapter: (String, String) -> Unit, sheetState: SheetState ) - LongMethod:ChapterSummaryDropdown.kt$@Composable fun ChapterSummaryDropdown( summary: String?, isGenerating: Boolean, onGenerateSummary: () -> Unit, onCancel: (() -> Unit)? = null, isAvailable: Boolean = true, modifier: Modifier = Modifier ) + LongMethod:ChapterSummaryDropdown.kt$@Composable fun ChapterSummaryDropdown( summary: String?, isGenerating: Boolean, onGenerateSummary: () -> Unit, onCancel: (() -> Unit)? = null, aiSupportedInBuild: Boolean = true, aiOptedIn: Boolean = true, onEnableAi: (() -> Unit)? = null, isInitializing: Boolean = false, isReady: Boolean = aiSupportedInBuild && aiOptedIn, modifier: Modifier = Modifier ) LongMethod:ContentRenderer.kt$@Composable fun ContentRenderer( elements: List<ContentElement>, modifier: Modifier = Modifier, backgroundColor: Color = Color.Black, textColor: Color = Color.White, pageUrl: String = "" ) LongMethod:ExploreDetailSheet.kt$@OptIn(ExperimentalLayoutApi::class) @Composable fun ExploreItemDetailSheet( item: ExploreItem, isLoading: Boolean = false, isInLibrary: Boolean = false, onAddToLibrary: () -> Unit, onRead: () -> Unit ): Unit LongMethod:ExploreGridSection.kt$@Composable fun ExploreItemCard( item: ExploreItem, onClick: () -> Unit ): Unit @@ -161,8 +172,9 @@ LongMethod:ReaderControls.kt$@Composable fun TopInfoBar( novelName: String, chapterTitle: String, onLibraryClick: () -> Unit, onShowChapterList: () -> Unit, onShowSettings: () -> Unit ) LongMethod:ReaderControls.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun BottomNavigationBar( progress: Float, canNavigatePrevious: Boolean, canNavigateNext: Boolean, onPreviousClick: () -> Unit, onNextClick: () -> Unit, onProgressChange: (Float) -> Unit ) LongMethod:ReaderImageView.kt$@Composable fun ReaderImageView( imageUrl: String, altText: String?, readerViewModel: ReaderViewModel, pageUrl: String, contentScale: ContentScale = ContentScale.Fit, backgroundColor: Color = Color.Black, width: Int = 0, height: Int = 0, resolvedWidth: Int = 0, resolvedHeight: Int = 0, side: ContentElement.Image.Side = ContentElement.Image.Side.FULL, enableZoom: Boolean = false, dynamicHeight: Boolean = false, zoomStateKey: Any? = null, onZoomChanged: ((Boolean) -> Unit)? = null, onDimensionsResolved: ((String, Int, Int) -> Unit)? = null, lockTapWhileZoomed: Boolean = false, onTap: (() -> Unit)? = null ) + LongMethod:ReaderProgressController.kt$ReaderProgressController$fun updateScrollPosition( scrollOffset: Float, maxScrollOffset: Float, viewportHeight: Float, index: Int, offsetFraction: Float, elementKey: String, content: ChapterContent?, canScrollForward: Boolean = true, firstVisibleItemSize: Int = 0 ) LongMethod:ReaderScreen.kt$@Composable private fun CloudflareDialog( url: String, onDismiss: () -> Unit, onRetry: () -> Unit ): Unit - LongMethod:ReaderScreen.kt$@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable fun ReaderScreen( readerViewModel: ReaderViewModel, libraryViewModel: LibraryViewModel, navController: NavController, onOpenFilePicker: () -> Unit, modifier: Modifier = Modifier ): Unit + LongMethod:ReaderScreen.kt$@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable fun ReaderScreen( readerViewModel: ReaderViewModel, libraryViewModelProvider: () -> LibraryViewModel, navController: NavController, onOpenFilePicker: () -> Unit, modifier: Modifier = Modifier ): Unit LongMethod:ReaderSettingsSheet.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun ReaderSettingsSheet( uiState: ReaderViewModel.ReaderUiState, onDismiss: () -> Unit, onUpdatePagedMode: (Boolean) -> Unit, onUpdateRtl: (Boolean) -> Unit, onUpdateFontSize: (Float) -> Unit, onUpdateLineHeight: (Float) -> Unit, onUpdateFontFamily: (String) -> Unit, onUpdateMargins: (Int) -> Unit, onUpdateParagraphSpacing: (Float) -> Unit, onUpdateReaderTheme: (ReaderTheme) -> Unit, onUpdateAccentTheme: (AccentTheme) -> Unit, sheetState: SheetState ) LongMethod:ReaderViewModel.kt$ReaderViewModel$fun loadEpubChapter( epubPath: String, href: String, libraryItemId: String? = null, fromBottom: Boolean = false, isSilent: Boolean = false ): Unit LongMethod:ReaderViewModel.kt$ReaderViewModel$private suspend fun handleLoadSuccess( result: ContentResult.Success, libraryItemId: String?, fromBottom: Boolean ): Unit @@ -170,15 +182,15 @@ LongMethod:WebContentLoader.kt$WebContentLoader$private suspend fun downloadAndCacheImageInternal( imageUrl: String, pageUrl: String, priority: ImageRequestPriority, writeTier: StorageTier = tierForPriority(priority) ): ImageDownloadResult LongMethod:WebContentLoader.kt$WebContentLoader$private suspend fun executePrefetch( url: String, mode: PrefetchMode, onProgress: (suspend (PrefetchResult) -> Unit)? = null ): PrefetchResult LongMethod:ZoomableBox.kt$@Composable fun ZoomableBox( modifier: Modifier = Modifier, minScale: Float = 1f, maxScale: Float = 3f, enableZoom: Boolean = false, dynamicHeight: Boolean = false, zoomStateKey: Any? = null, onZoomChanged: ((Boolean) -> Unit)? = null, lockTapWhileZoomed: Boolean = false, onTap: (() -> Unit)? = null, content: @Composable BoxScope.() -> Unit ) - LongParameterList:ChapterSummaryDropdown.kt$( summary: String?, isGenerating: Boolean, onGenerateSummary: () -> Unit, onCancel: (() -> Unit)? = null, isAvailable: Boolean = true, modifier: Modifier = Modifier ) + LongParameterList:ChapterSummaryDropdown.kt$( summary: String?, isGenerating: Boolean, onGenerateSummary: () -> Unit, onCancel: (() -> Unit)? = null, aiSupportedInBuild: Boolean = true, aiOptedIn: Boolean = true, onEnableAi: (() -> Unit)? = null, isInitializing: Boolean = false, isReady: Boolean = aiSupportedInBuild && aiOptedIn, modifier: Modifier = Modifier ) LongParameterList:ContentRenderer.kt$( url: String, altText: String?, side: ContentElement.Image.Side = ContentElement.Image.Side.FULL, width: Int = 0, height: Int = 0, pageUrl: String = "" ) LongParameterList:ContentRepository.kt$ContentRepository$( private val webLoader: WebContentLoader, private val pdfLoader: PdfContentLoader, private val epubLoader: EpubContentLoader, private val localLoader: LocalContentLoader, private val contentUriTypeResolver: ContentUriTypeResolver, @ApplicationContext private val context: Context, private val okHttpClient: OkHttpClient ) LongParameterList:ExploreGridSection.kt$( gridState: LazyGridState, modifier: Modifier = Modifier, uiState: ExploreViewModel.ExploreUiState, hasActiveFilters: Boolean, onItemSelect: (ExploreItem) -> Unit, onLoadMore: () -> Unit, onClearFilters: () -> Unit, onRetryFailedSource: (String) -> Unit ) LongParameterList:ExploreScreen.kt$( uiState: ExploreViewModel.ExploreUiState, hasActiveFilters: Boolean, onOpenFilters: () -> Unit, onSourceSelect: (String?) -> Unit, onTagToggle: (String) -> Unit, onClearFilters: () -> Unit ) LongParameterList:ExploreScreen.kt$( uiState: ExploreViewModel.ExploreUiState, modifier: Modifier = Modifier, hasActiveFilters: Boolean, onSearchQueryChange: (String) -> Unit, onPerformSearch: () -> Unit, onOpenFilters: () -> Unit, onClearFilters: () -> Unit, onSetBrowseMode: (BrowseMode) -> Unit, onSourceSelect: (String?) -> Unit, onTagToggle: (String) -> Unit, onItemSelect: (ExploreItem) -> Unit, onLoadMore: () -> Unit, onRetryFailedSource: (String) -> Unit ) LongParameterList:LibraryItemCard.kt$( item: LibraryItem, isSelected: Boolean, isCurrent: Boolean, onClick: () -> Unit, onLongClick: () -> Unit, onNewTagClick: (() -> Unit)? = null, onDelete: (() -> Unit)? = null, onResetProgress: (() -> Unit)? = null, onMarkFinished: (() -> Unit)? = null ) - LongParameterList:LibraryRepository.kt$LibraryRepository$( itemId: String, currentChapter: String = "", progress: FieldUpdate<Int> = FieldUpdate.Unchanged, currentChapterUrl: FieldUpdate<String> = FieldUpdate.Unchanged, lastScrollProgress: FieldUpdate<Float> = FieldUpdate.Unchanged, lastReadIndex: FieldUpdate<Int> = FieldUpdate.Unchanged, lastReadOffset: FieldUpdate<Int> = FieldUpdate.Unchanged, lastReadOffsetFraction: FieldUpdate<Float?> = FieldUpdate.Unchanged ) - LongParameterList:LibraryRepository.kt$LibraryRepository$( itemId: String, currentChapter: String, progress: Int, currentChapterUrl: String? = null, lastScrollProgress: Float? = null, lastReadIndex: Int? = null, lastReadOffset: Int? = null, lastReadOffsetFraction: Float? = null ) + LongParameterList:LibraryRepository.kt$LibraryRepository$( itemId: String, currentChapter: String = "", progress: FieldUpdate<Int> = FieldUpdate.Unchanged, currentChapterUrl: FieldUpdate<String> = FieldUpdate.Unchanged, lastScrollProgress: FieldUpdate<Float> = FieldUpdate.Unchanged, lastReadIndex: FieldUpdate<Int> = FieldUpdate.Unchanged, lastReadElementKey: FieldUpdate<String> = FieldUpdate.Unchanged, lastReadOffsetFraction: FieldUpdate<Float> = FieldUpdate.Unchanged ) + LongParameterList:LibraryRepository.kt$LibraryRepository$( itemId: String, currentChapter: String, progress: Int, currentChapterUrl: String? = null, lastScrollProgress: Float? = null, lastReadIndex: Int? = null, lastReadElementKey: String? = null, lastReadOffsetFraction: Float? = null ) LongParameterList:LibraryRepository.kt$LibraryRepository$( title: String, url: String, contentType: ContentType, currentChapter: String = "Chapter 1", baseTitle: String = title, baseNovelUrl: String = "", sourceName: String = "", totalChapters: Int = 0 ) LongParameterList:LibraryScreen.kt$( query: String, totalCount: Int, visibleCount: Int, isSelectionMode: Boolean, selectedCount: Int, onSelectionClick: () -> Unit ) LongParameterList:LibraryScreenEpubSections.kt$( item: LibraryItem, uiState: LibraryViewModel.LibraryUiState, contentRepository: ContentRepository, readerViewModel: ReaderViewModel, libraryViewModel: LibraryViewModel, onCloseLibrary: () -> Unit ) @@ -188,7 +200,6 @@ LongParameterList:LibraryScreenListSections.kt$( title: String, items: List<LibraryItem>, uiState: LibraryViewModel.LibraryUiState, readerUiState: ReaderViewModel.ReaderUiState, summaryUiState: SummaryViewModel.SummaryUiState, isExpanded: Boolean, showFullChapters: Boolean, onToggleExpand: () -> Unit, onToggleShowFull: () -> Unit, libraryViewModel: LibraryViewModel, readerViewModel: ReaderViewModel, summaryViewModel: SummaryViewModel, onCloseLibrary: () -> Unit ) LongParameterList:LibraryScreenListSections.kt$( uiState: LibraryViewModel.LibraryUiState, readerUiState: ReaderViewModel.ReaderUiState, summaryUiState: SummaryViewModel.SummaryUiState, libraryViewModel: LibraryViewModel, readerViewModel: ReaderViewModel, summaryViewModel: SummaryViewModel, onCloseLibrary: () -> Unit ) LongParameterList:PreferencesManager.kt$PreferencesManager$( fontSize: Float? = null, lineHeight: Float? = null, fontFamily: String? = null, margins: Int? = null, paragraphSpacing: Float? = null, readerTheme: String? = null, accentTheme: String? = null ) - LongParameterList:ReaderContentArea.kt$( firstVisibleItemIndex: Int, firstVisibleItemMeasuredIndex: Int, firstVisibleItemScrollOffset: Int, canScrollForward: Boolean, totalItemsCount: Int, viewportHeightPx: Int, firstVisibleItemSize: Int ) LongParameterList:ReaderContentArea.kt$( readerViewModel: ReaderViewModel, canNavigatePrevious: Boolean, canNavigateNext: Boolean, onPreviousClick: () -> Unit, onNextClick: () -> Unit, onProgressChange: (Float) -> Unit ) LongParameterList:ReaderContentArea.kt$( uiState: ReaderViewModel.ReaderUiState, content: ChapterContent, readerViewModel: ReaderViewModel, onLibraryClick: () -> Unit, onShowChapterList: () -> Unit, onShowSettings: () -> Unit ) LongParameterList:ReaderContentGestures.kt$( uiState: ReaderViewModel.ReaderUiState, pagerState: PagerState, listState: LazyListState, content: ChapterContent, threshold: Float, onHideControls: () -> Unit, onUserInteraction: () -> Unit, onPullAmountChange: (Float) -> Unit, onNavigatePrevious: () -> Unit, onNavigateNext: () -> Unit ) @@ -197,16 +208,14 @@ LongParameterList:ReaderContentRenderers.kt$( images: List<ContentElement.Image>, pageUrl: String, pageIndex: Int, backgroundColor: Color, readerViewModel: ReaderViewModel, enableZoom: Boolean, onPageZoomChanged: (Boolean) -> Unit ) LongParameterList:ReaderControls.kt$( progress: Float, canNavigatePrevious: Boolean, canNavigateNext: Boolean, onPreviousClick: () -> Unit, onNextClick: () -> Unit, onProgressChange: (Float) -> Unit ) LongParameterList:ReaderImageView.kt$( imageUrl: String, altText: String?, readerViewModel: ReaderViewModel, pageUrl: String, contentScale: ContentScale = ContentScale.Fit, backgroundColor: Color = Color.Black, width: Int = 0, height: Int = 0, resolvedWidth: Int = 0, resolvedHeight: Int = 0, side: ContentElement.Image.Side = ContentElement.Image.Side.FULL, enableZoom: Boolean = false, dynamicHeight: Boolean = false, zoomStateKey: Any? = null, onZoomChanged: ((Boolean) -> Unit)? = null, onDimensionsResolved: ((String, Int, Int) -> Unit)? = null, lockTapWhileZoomed: Boolean = false, onTap: (() -> Unit)? = null ) - LongParameterList:ReaderProgressController.kt$ReaderProgressController$( progress: Int, scrollPosition: Float? = null, index: Int? = null, offset: Int? = null, offsetFraction: Float? = null, currentChapterUrl: String? = null, content: ChapterContent? = null ) - LongParameterList:ReaderProgressController.kt$ReaderProgressController$( scrollOffset: Float, maxScrollOffset: Float, viewportHeight: Float, index: Int, offset: Int, content: ChapterContent?, canScrollForward: Boolean = true, firstVisibleItemSize: Int = 0 ) - LongParameterList:ReaderProgressController.kt$ReaderProgressController$( scrollPosition: Float, scrollProgress: Int, scrollIndex: Int, scrollOffset: Int, scrollOffsetFraction: Float? = _progressState.value.scrollOffsetFraction, firstVisibleItemSize: Int = _progressState.value.firstVisibleItemSize, seekTrigger: Long = _progressState.value.seekTrigger, targetScrollPosition: Float? = _progressState.value.targetScrollPosition ) + LongParameterList:ReaderProgressController.kt$ReaderProgressController$( progress: Int, scrollPosition: Float? = null, index: Int? = null, elementKey: String? = null, offsetFraction: Float? = null, currentChapterUrl: String? = null, content: ChapterContent? = null, forcePersist: Boolean = false ) + LongParameterList:ReaderProgressController.kt$ReaderProgressController$( scrollOffset: Float, maxScrollOffset: Float, viewportHeight: Float, index: Int, offsetFraction: Float, elementKey: String, content: ChapterContent?, canScrollForward: Boolean = true, firstVisibleItemSize: Int = 0 ) LongParameterList:ReaderScreen.kt$( uiState: ReaderViewModel.ReaderUiState, readerViewModel: ReaderViewModel, onOpenLibrary: () -> Unit, onOpenLibraryScreen: () -> Unit, onShowChapterList: () -> Unit, onShowSettings: () -> Unit ) LongParameterList:ReaderSettingsSheet.kt$( label: String, value: Float, onValueChange: (Float) -> Unit, valueRange: ClosedFloatingPointRange<Float>, steps: Int, displayValue: String ) LongParameterList:ReaderSettingsSheet.kt$( uiState: ReaderViewModel.ReaderUiState, onDismiss: () -> Unit, onUpdatePagedMode: (Boolean) -> Unit, onUpdateRtl: (Boolean) -> Unit, onUpdateFontSize: (Float) -> Unit, onUpdateLineHeight: (Float) -> Unit, onUpdateFontFamily: (String) -> Unit, onUpdateMargins: (Int) -> Unit, onUpdateParagraphSpacing: (Float) -> Unit, onUpdateReaderTheme: (ReaderTheme) -> Unit, onUpdateAccentTheme: (AccentTheme) -> Unit, sheetState: SheetState ) LongParameterList:ReaderStates.kt$( icon: ImageVector, iconTint: androidx.compose.ui.graphics.Color, iconDescription: String, title: String, body: String, action: @Composable (() -> Unit)? = null ) - LongParameterList:ReaderViewModel.kt$ReaderViewModel$( progress: Int, scrollPosition: Float? = null, index: Int? = null, offset: Int? = null, offsetFraction: Float? = null, currentChapterUrl: String? = null ) - LongParameterList:ReaderViewModel.kt$ReaderViewModel$( scrollOffset: Float, maxScrollOffset: Float, viewportHeight: Float, index: Int, offset: Int, canScrollForward: Boolean = true, firstVisibleItemSize: Int = 0 ) - LongParameterList:ReaderViewModel.kt$ReaderViewModel$( scrollPosition: Float, scrollProgress: Int, scrollIndex: Int, scrollOffset: Int, scrollOffsetFraction: Float? = progressController.progressState.value.scrollOffsetFraction, firstVisibleItemSize: Int = progressController.progressState.value.firstVisibleItemSize, seekTrigger: Long = progressController.progressState.value.seekTrigger, targetScrollPosition: Float? = progressController.progressState.value.targetScrollPosition ) + LongParameterList:ReaderViewModel.kt$ReaderViewModel$( progress: Int, scrollPosition: Float? = null, index: Int? = null, elementKey: String? = null, offsetFraction: Float? = null, currentChapterUrl: String? = null, forcePersist: Boolean = false ) + LongParameterList:ReaderViewModel.kt$ReaderViewModel$( scrollOffset: Float, maxScrollOffset: Float, viewportHeight: Float, index: Int, offsetFraction: Float, elementKey: String, canScrollForward: Boolean = true, firstVisibleItemSize: Int = 0 ) LongParameterList:ReaderViewModel.kt$ReaderViewModel$( url: String, libraryItemId: String? = null, fromBottom: Boolean = false, isSilent: Boolean = false, isExplicitNavigation: Boolean = false, resetWebStateBeforeLoad: Boolean = false ) LongParameterList:ReaderViewModel.kt$ReaderViewModel$( url: String, libraryItemId: String?, fromBottom: Boolean, isSilent: Boolean, isExplicitNavigation: Boolean, preloadedResult: ContentResult.Success? = null, resetWebStateBeforeLoad: Boolean = false ) LongParameterList:WebContentLoader.kt$WebContentLoader$( imageUrls: List<String>, pageUrl: String, priority: ImageRequestPriority, writeTier: StorageTier, maxConcurrency: Int, onImageCached: (suspend () -> Unit)? = null ) @@ -215,6 +224,7 @@ LoopWithTooManyJumpStatements:ContentRepository.kt$ContentRepository$for LoopWithTooManyJumpStatements:HtmlParser.kt$HtmlParser$while LoopWithTooManyJumpStatements:MangaBatSource.kt$MangaBatSource$for + LoopWithTooManyJumpStatements:ReaderContentGestures.kt$for LoopWithTooManyJumpStatements:SafeRedirectInterceptor.kt$SafeRedirectInterceptor$while LoopWithTooManyJumpStatements:SmartSource.kt$SmartSource$for LoopWithTooManyJumpStatements:TextFormattingPipeline.kt$TextFormattingPipeline$while @@ -290,10 +300,17 @@ MagicNumber:AppDatabase.kt$AppDatabase.Companion.<no name provided>$4 MagicNumber:AppDatabase.kt$AppDatabase.Companion.<no name provided>$5 MagicNumber:AppDatabase.kt$AppDatabase.Companion.<no name provided>$6 + MagicNumber:AppDatabase.kt$AppDatabase.Companion.<no name provided>$7 + MagicNumber:AppDatabase.kt$AppDatabase.Companion.<no name provided>$8 + MagicNumber:AppDatabase.kt$AppDatabase.Companion.<no name provided>$9 MagicNumber:AutoDeletionPolicy.kt$100 MagicNumber:BaseJsoupSource.kt$BaseJsoupSource$15000L MagicNumber:CacheKeyUtils.kt$CacheKeyUtils$0xff MagicNumber:CacheKeyUtils.kt$CacheKeyUtils$4 + MagicNumber:ChapterDownloadQueue.kt$WorkManagerChapterDownloadQueue$3 + MagicNumber:ChapterDownloadQueue.kt$WorkManagerChapterDownloadQueue$30 + MagicNumber:ChapterDownloadQueue.kt$WorkManagerChapterDownloadQueue$4 + MagicNumber:ChapterDownloadQueue.kt$WorkManagerChapterDownloadQueue$5 MagicNumber:ChapterListSheet.kt$100 MagicNumber:EasyReaderApplication.kt$EasyReaderApplication$0.25 MagicNumber:EpubContentLoader.kt$EpubContentLoader$1024 @@ -310,6 +327,8 @@ MagicNumber:ExploreGridSection.kt$950 MagicNumber:ExploreViewModel.kt$ExploreViewModel$500L MagicNumber:FileUtils.kt$FileUtils$1024 + MagicNumber:HostThrottle.kt$HostThrottle.<no name provided>$0.75f + MagicNumber:HostThrottle.kt$HostThrottle.<no name provided>$16 MagicNumber:HtmlParser.kt$HtmlParser$10 MagicNumber:HtmlParser.kt$HtmlParser$5 MagicNumber:HtmlParser.kt$HtmlParser$80 @@ -364,8 +383,6 @@ MagicNumber:ImageBoundsParser.kt$ImageBoundsParser$9 MagicNumber:ImageDownloader.kt$ImageDownloader$429 MagicNumber:ImageDownloader.kt$ImageDownloader$8192 - MagicNumber:ImageDownloader.kt$ImageDownloader.<no name provided>$0.75f - MagicNumber:ImageDownloader.kt$ImageDownloader.<no name provided>$16 MagicNumber:LibraryItem.kt$LibraryItem$100 MagicNumber:LibraryItemCard.kt$0.992f MagicNumber:LibraryItemCard.kt$100 @@ -397,18 +414,20 @@ MagicNumber:PreferencesManager.kt$PreferencesManager$1.5f MagicNumber:PreferencesManager.kt$PreferencesManager$16 MagicNumber:PreferencesManager.kt$PreferencesManager$18f + MagicNumber:ReaderContentArea.kt$0.0001f MagicNumber:ReaderContentArea.kt$100f MagicNumber:ReaderContentGestures.kt$0.4f MagicNumber:ReaderContentGestures.kt$0xFF4CAF50 - MagicNumber:ReaderContentGestures.kt$10 MagicNumber:ReaderContentGestures.kt$180f - MagicNumber:ReaderContentGestures.kt$3 + MagicNumber:ReaderContentGestures.kt$6 MagicNumber:ReaderContentGestures.kt$<no name provided>$0.5f MagicNumber:ReaderContentRenderers.kt$10000000 MagicNumber:ReaderContentRenderers.kt$100f - MagicNumber:ReaderContentRenderers.kt$64 MagicNumber:ReaderImageView.kt$200 + MagicNumber:ReaderImageView.kt$750L + MagicNumber:ReaderProgressController.kt$64 MagicNumber:ReaderProgressController.kt$ReaderProgressController$100 + MagicNumber:ReaderProgressController.kt$ReaderProgressController$1000f MagicNumber:ReaderProgressController.kt$ReaderProgressController$100f MagicNumber:ReaderScreen.kt$0.85f MagicNumber:ReaderScreen.kt$0.95f @@ -424,7 +443,6 @@ MagicNumber:ReaderTheme.kt$ReaderTheme.SEPIA$0xFF5B4636 MagicNumber:ReaderTheme.kt$ReaderTheme.SEPIA$0xFFF4ECD8 MagicNumber:ReaderViewModel.kt$ReaderViewModel$1000 - MagicNumber:ReaderViewModel.kt$ReaderViewModel$10000000 MagicNumber:ReaderViewModel.kt$ReaderViewModel$100f MagicNumber:ReaderViewModel.kt$ReaderViewModel$12f MagicNumber:ReaderViewModel.kt$ReaderViewModel$2.5f @@ -497,6 +515,7 @@ MagicNumber:WebContentLoader.kt$WebContentLoader$1.6 MagicNumber:WebContentLoader.kt$WebContentLoader$1600 MagicNumber:WebContentLoader.kt$WebContentLoader$250L + MagicNumber:WebContentLoader.kt$WebContentLoader$429 MagicNumber:WebContentLoader.kt$WebContentLoader.<no name provided>$0.75f MagicNumber:ZipUtils.kt$ZipUtils$10 MagicNumber:ZipUtils.kt$ZipUtils$1024 @@ -508,21 +527,17 @@ MagicNumber:ZoomableBox.kt$300L MagicNumber:ZoomableBox.kt$4f MatchingDeclarationName:ReaderImageSizing.kt$ImageDimensions + MaxLineLength:AppDatabase.kt$AppDatabase.Companion.<no name provided>$db.execSQL("CREATE INDEX IF NOT EXISTS index_chapter_image_state_chapterUrl ON chapter_image_state (chapterUrl)") + MaxLineLength:AppDatabase.kt$AppDatabase.Companion.<no name provided>$db.execSQL("CREATE INDEX IF NOT EXISTS index_chapter_image_state_status ON chapter_image_state (status)") MaxLineLength:AppDatabase.kt$AppDatabase.Companion.<no name provided>$db.execSQL("CREATE INDEX index_library_items_isCurrentlyReading ON library_items_new (isCurrentlyReading)") MaxLineLength:BaseJsoupSource.kt$BaseJsoupSource$protected open val userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" MaxLineLength:ChapterListSheet.kt$colors = CheckboxDefaults.colors(checkedColor = MaterialTheme.colorScheme.primary) MaxLineLength:ChapterListSheet.kt$contentDescription = stringResource(R.string.chapter_action_remove_download) MaxLineLength:ChapterListSheet.kt$text = if (isDeleteMode) stringResource(R.string.common_delete) else stringResource(R.string.download_button) - MaxLineLength:ContentRepository.kt$ContentRepository$ContentKind.UNKNOWN -> PrefetchResult(url, htmlCached = false, totalImages = 0, cachedImages = 0, isComplete = false, isRetryable = false) MaxLineLength:ContentRepository.kt$ContentRepository$PrefetchResult(url, htmlCached = cached, totalImages = 0, cachedImages = 0, isComplete = cached, isRetryable = !cached) MaxLineLength:ContentRepository.kt$ContentRepository$PrefetchResult(url, htmlCached = false, totalImages = 0, cachedImages = 0, isComplete = false, isRetryable = true) - MaxLineLength:ContentRepository.kt$ContentRepository$PrefetchResult(url, htmlCached = true, totalImages = 0, cachedImages = 0, isComplete = true, isRetryable = false) - MaxLineLength:ContentRepository.kt$ContentRepository$return PrefetchResult(url, htmlCached = exists, totalImages = 0, cachedImages = 0, isComplete = exists, isRetryable = !exists) - MaxLineLength:EpubContentLoader.kt$EpubContentLoader$els.add(ContentElement.Image("$filePath#img:${resolveEpubPath(href, src)}", element.attr("alt"))) - MaxLineLength:EpubContentLoader.kt$EpubContentLoader$els.add(ContentElement.Image("$filePath#img:${resolveEpubPath(href, src)}", img.attr("alt"))) - MaxLineLength:EpubContentLoader.kt$EpubContentLoader$if + MaxLineLength:ContentRepository.kt$ContentRepository$suspend MaxLineLength:EpubContentLoader.kt$EpubContentLoader$suspend - MaxLineLength:EpubContentLoader.kt$EpubContentLoader$val opfPath = Jsoup.parse(String(cont), "", org.jsoup.parser.Parser.xmlParser()).select("rootfile").attr("full-path") MaxLineLength:ErrorMessages.kt$ErrorMessages$body = "The source is blocking automated access. Solve the challenge in the browser pop-up to continue." MaxLineLength:ExploreGridSection.kt$modifier = Modifier.padding(horizontal = EasyReaderSpacing.xs, vertical = EasyReaderSpacing.xxs) MaxLineLength:ExploreGridSection.kt$val shouldLoadMore = uiState.canLoadMore && !uiState.isLoading && uiState.items.isNotEmpty() && lastVisible >= totalItems - 4 @@ -531,14 +546,18 @@ MaxLineLength:ExploreViewModel.kt$ExploreViewModel$val novels = exploreRepository.getNovels(_uiState.value.browseMode, 1, _uiState.value.selectedSource, _uiState.value.selectedTags.toList()) MaxLineLength:ExploreViewModel.kt$ExploreViewModel$val novels = exploreRepository.getNovels(_uiState.value.browseMode, 1, _uiState.value.selectedSource, emptyList()) MaxLineLength:ExploreViewModel.kt$ExploreViewModel$val novels = exploreRepository.getNovels(_uiState.value.browseMode, 1, _uiState.value.selectedSource, newTags.toList()) + MaxLineLength:HtmlParser.kt$HtmlParser$Regex(""""url"\s*(?::|,)\s*\[?\s*\d*\s*,?\s*"(https?://[^"]+\.(?:webp|jpg|jpeg|png|gif))""""", RegexOption.IGNORE_CASE) MaxLineLength:HtmlParser.kt$HtmlParser$document.select("img[alt*='credit'], img[alt*='recommend'], img[src*='credit'], img[src*='recommend'], img[alt*='ei0qg'], img[title*='ei0qg']").remove() MaxLineLength:HtmlParser.kt$HtmlParser$if (p.isEmpty() || p.matches(DIGIT_ONLY_REGEX) || CHAPTER_CLEANUP_PATTERN.containsMatchIn(p)) return@filter false MaxLineLength:HtmlParser.kt$HtmlParser$private MaxLineLength:HtmlParser.kt$HtmlParser$val height = if (isMangaSite) 0 else element.attr("height").toIntOrNull() ?: element.attr("data-height").toIntOrNull() ?: 0 MaxLineLength:HtmlParser.kt$HtmlParser$val width = if (isMangaSite) 0 else element.attr("width").toIntOrNull() ?: element.attr("data-width").toIntOrNull() ?: 0 + MaxLineLength:HttpMediaCacheFetcher.kt$HttpMediaCacheFetcher$Log.w("HttpMediaCacheFetcher", "final file missing img=$safeUrl path=${file.absolutePath} exists=${file.exists()} len=${file.length()}") + MaxLineLength:ImageIntegrity.kt$ImageIntegrity$if (header[0] == 0xFF.toByte() && header[1] == 0xD8.toByte() && header[2] == 0xFF.toByte()) return ImageFormat.JPEG + MaxLineLength:LibraryBackupManager.kt$lastReadOffsetFraction = lastReadOffsetFraction.takeUnless { it == io.aatricks.easyreader.data.model.FRACTION_UNKNOWN } MaxLineLength:LibraryDao.kt$LibraryDao$@Query("UPDATE library_items SET baseNovelUrl = :baseNovelUrl, sourceName = :sourceName WHERE baseTitle = (SELECT baseTitle FROM library_items WHERE id = :itemId)") - MaxLineLength:LibraryDao.kt$LibraryDao$@Query("UPDATE library_items SET progress = 0, lastScrollPosition = 0, lastReadIndex = 0, lastReadOffset = 0, lastReadOffsetFraction = NULL WHERE baseTitle = :baseTitle") - MaxLineLength:LibraryDao.kt$LibraryDao$@Query("UPDATE library_items SET progress = 0, lastScrollPosition = 0, lastReadIndex = 0, lastReadOffset = 0, lastReadOffsetFraction = NULL, lastRead = :timestamp WHERE id = :id") + MaxLineLength:LibraryDao.kt$LibraryDao$@Query("UPDATE library_items SET progress = 0, lastScrollPosition = 0, lastReadIndex = 0, lastReadElementKey = '', lastReadOffsetFraction = -1 WHERE baseTitle = :baseTitle") + MaxLineLength:LibraryDao.kt$LibraryDao$@Query("UPDATE library_items SET progress = 0, lastScrollPosition = 0, lastReadIndex = 0, lastReadElementKey = '', lastReadOffsetFraction = -1, lastRead = :timestamp WHERE id = :id") MaxLineLength:LibraryItemCard.kt$color = if (item.progress == 100) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant MaxLineLength:LibraryItemCard.kt$val isLastChapter = chapterNumber != null && item.totalChapters > 0 && chapterNumber.toInt() >= item.totalChapters MaxLineLength:LibraryRepository.kt$LibraryRepository$?: @@ -553,8 +572,6 @@ MaxLineLength:LibraryScreenListSections.kt$val loadUrl = if (chapter.currentChapterUrl.isNotBlank()) chapter.currentChapterUrl else chapter.url MaxLineLength:LibraryScreenListSections.kt$val streamingSummary = if (summaryUiState.activeChapterUrl == chapterUrl) summaryUiState.currentSummary else cachedSummary MaxLineLength:LibraryViewModel.kt$LibraryViewModel$val readingUrl = item.readingUrl ?: exploreRepository.getNovelDetails(item.url, item.source)?.readingUrl ?: item.url - MaxLineLength:LibraryViewModel.kt$LibraryViewModel$val result = contentRepository.prefetchWithProgress(item.url, PrefetchMode.USER_REQUESTED) { setCacheState(it) } - MaxLineLength:LibraryViewModel.kt$LibraryViewModel$val result = contentRepository.prefetchWithProgress(url, PrefetchMode.USER_REQUESTED) { setCacheState(it) } MaxLineLength:LocalContentLoader.kt$LocalContentLoader$mime.contains("epub", ignoreCase = true) || mime.contains("application/epub+zip", ignoreCase = true) -> epubLoader.loadEpubContent(url) MaxLineLength:MangaBatSource.kt$MangaBatSource$. MaxLineLength:NovelFireSource.kt$NovelFireSource$"Sci-fi" @@ -570,43 +587,35 @@ MaxLineLength:ReaderContentRenderers.kt$zoomStateKey = "${content.url}_${page}_${subElement.url}_${subElement.side}" MaxLineLength:ReaderImageView.kt$// When dynamicHeight is true (scrolling mode zoom - though now disabled), we don't apply aspect ratio to the outer container. MaxLineLength:ReaderImageView.kt$// When enableZoom is true and dynamicHeight is false (Paged Manga mode), we fillMaxSize so zoom can cover black bars. - MaxLineLength:ReaderProgressController.kt$ReaderProgressController$"saveProgress url=${io.aatricks.easyreader.util.UrlSanitizer.sanitize(resolvedChapterUrl)} index=$lastIndex offset=$lastOffset offsetFraction=$lastOffsetFraction firstVisibleItemSize=${latest.firstVisibleItemSize} anchor=${if (elementAnchor != null) "<elt>" else "null"}" - MaxLineLength:ReaderProgressController.kt$ReaderProgressController$lastReadOffsetFraction = progressSnapshot.scrollOffsetFraction?.let { FieldUpdate.Set(it) } ?: FieldUpdate.Clear + MaxLineLength:ReaderProgressController.kt$ReaderProgressController$"saveProgress url=${io.aatricks.easyreader.util.UrlSanitizer.sanitize(resolvedChapterUrl)} index=$lastIndex elementKey=${if (lastElementKey.isNotEmpty()) "<set>" else "<empty>"} fraction=$lastFraction firstVisibleItemSize=${latest.firstVisibleItemSize}" + MaxLineLength:ReaderProgressController.kt$ReaderProgressController$maxScrollOffset > viewportHeight -> ((scrollOffset / (maxScrollOffset - viewportHeight)) * 100f).coerceIn(0f, 100f) + MaxLineLength:ReaderProgressController.kt$ReaderProgressController$val nextUiPendingRestoreOffsetFraction = if (uiPendingRestoreOffsetFraction != null) null else uiPendingRestoreOffsetFraction MaxLineLength:ReaderViewModel.kt$ReaderViewModel$"persistLifecycleProgress skip snap-to-top url=${io.aatricks.easyreader.util.UrlSanitizer.sanitize(currentChapterUrl)} dbProgress=${existing.progress}" - MaxLineLength:ReaderViewModel.kt$ReaderViewModel$"persistLifecycleProgress url=${io.aatricks.easyreader.util.UrlSanitizer.sanitize(currentChapterUrl)} index=${latest.scrollIndex} offset=${latest.scrollOffset} offsetFraction=${latest.scrollOffsetFraction} firstVisibleItemSize=${latest.firstVisibleItemSize}" + MaxLineLength:ReaderViewModel.kt$ReaderViewModel$"persistLifecycleProgress skip unstable url=${io.aatricks.easyreader.util.UrlSanitizer.sanitize(currentChapterUrl)} firstVisibleItemSize=${latest.firstVisibleItemSize} fraction=${latest.scrollOffsetFraction}" + MaxLineLength:ReaderViewModel.kt$ReaderViewModel$"persistLifecycleProgress url=${io.aatricks.easyreader.util.UrlSanitizer.sanitize(currentChapterUrl)} index=${latest.scrollIndex} fraction=${latest.scrollOffsetFraction} firstVisibleItemSize=${latest.firstVisibleItemSize}" MaxLineLength:ReaderViewModel.kt$ReaderViewModel$effectiveId = existing?.id ?: addChapterToLibrary(result.url, result.title, isNext = !fromBottom) ?: effectiveId - MaxLineLength:ReaderViewModel.kt$ReaderViewModel$lastReadOffsetFraction = progressToPersist.scrollOffsetFraction?.let { FieldUpdate.Set(it) } ?: FieldUpdate.Clear MaxLineLength:ReaderViewModel.kt$ReaderViewModel$libraryItem?.readingMode == ReadingMode.PAGED - MaxLineLength:ReaderViewModel.kt$ReaderViewModel$updateState { it.copy(targetScrollPosition = targetScrollPosition, pendingRestoreOffsetFraction = pendingRestoreOffsetFraction) } - MaxLineLength:ReaderViewModel.kt$ReaderViewModel$val initialScroll = progressController.calculateInitialScroll(content, libraryItem, fromBottom, isExplicitNavigation) + MaxLineLength:ReaderViewModel.kt$ReaderViewModel$val initialPosition = progressController.calculateInitialPosition(content, libraryItem, fromBottom, isExplicitNavigation) MaxLineLength:SummaryService.kt$SummaryService$Log.d(TAG, "Generating summary (${selectedContent.split(WHITESPACE_REGEX).size} words, ~${(selectedContent.length + prompt.length) / 4 + 200} tokens)") MaxLineLength:SummaryService.kt$SummaryService$val keywords = listOf("suddenly", "realized", "discovered", "decided", "arrived", "died", "killed", "attacked", "revealed", "secret", "important", "finally", "however", "shocked", "surprised") MaxLineLength:SummaryService.kt$SummaryService$val verbs = listOf("ran", "fought", "grabbed", "rushed", "jumped", "fell", "screamed", "whispered", "turned", "opened") MaxLineLength:TextFormattingPipeline.kt$TextFormattingPipeline$if - MaxLineLength:WebContentLoader.kt$WebContentLoader$"USER_REQUESTED prefetch pass=$pass fastPath=${fastPath.size} bgRest=${backgroundRest.size} url=$safeUrl" - MaxLineLength:WebContentLoader.kt$WebContentLoader$"cache/html fetch complete url=$safeUrl fromCache=${cachedDocument.fromCache} elapsedMs=${System.currentTimeMillis() - startedAtMs}" - MaxLineLength:WebContentLoader.kt$WebContentLoader$"dimension enrichment start url=$safeUrl diskOnly=$useDiskOnlyDimensions elapsedMs=${System.currentTimeMillis() - startedAtMs}" - MaxLineLength:WebContentLoader.kt$WebContentLoader$"image extraction count url=$safeUrl imageCount=$imageCount elapsedMs=${System.currentTimeMillis() - startedAtMs}" - MaxLineLength:WebContentLoader.kt$WebContentLoader$Log.d(TAG, "prefetch final result url=$safeUrl complete=${finalResult.isComplete} cached=${finalResult.cachedImages}/${finalResult.totalImages}") + MaxLineLength:WebContentLoader.kt$WebContentLoader$Log.d(TAG, "Invalid image payload, deleting and retrying: ${UrlSanitizer.sanitize(imageUrl)}") MaxLineLength:WebContentLoader.kt$WebContentLoader$finalElements.add(ContentElement.ImageGroup(element.images.map { it.copy(side = ContentElement.Image.Side.LEFT) })) MaxLineLength:WebContentLoader.kt$WebContentLoader$finalElements.add(ContentElement.ImageGroup(element.images.map { it.copy(side = ContentElement.Image.Side.RIGHT) })) MaxLineLength:WebContentLoader.kt$WebContentLoader$if MaxLineLength:WebContentLoader.kt$WebContentLoader$private suspend MaxLineLength:WebContentLoader.kt$WebContentLoader$processed[processed.size - 1] = ContentElement.ImageGroup(listOf(last as ContentElement.Image, element)) - MaxLineLength:WebContentLoader.kt$WebContentLoader$val backgroundRest = if (isFirstPass) missingImages.drop(FAST_PATH_USER_IMAGE_COUNT) else emptyList() MaxLineLength:WebContentLoader.kt$WebContentLoader$val isManga = url.contains("manga", ignoreCase = true) && !url.contains("manhwa", ignoreCase = true) MaxLineLength:WebContentLoader.kt$WebContentLoader$val lastImages = if (last is ContentElement.ImageGroup) last.images else listOf(last as ContentElement.Image) - MaxLineLength:WebContentLoader.kt$WebContentLoader$val maxAttempts = if (mode == PrefetchMode.USER_REQUESTED) MAX_USER_PREFETCH_ATTEMPTS else MAX_SPECULATIVE_PREFETCH_ATTEMPTS MaxLineLength:WebContentLoader.kt$WebContentLoader$val priority = if (mode == PrefetchMode.SPECULATIVE) ImageRequestPriority.SPECULATIVE else ImageRequestPriority.USER_REQUESTED MaxLineLength:WebContentLoader.kt$WebContentLoader$val result = downloadAndCacheImageInternal(imageUrl, pageUrl, ImageRequestPriority.SPECULATIVE, StorageTier.CACHE) - MaxLineLength:WebContentLoader.kt$WebContentLoader$val result = downloadAndCacheImageInternal(imageUrl, pageUrl, ImageRequestPriority.USER_REQUESTED, StorageTier.CACHE) MaxLineLength:WebViewUtils.kt$WebViewUtils$userAgentString = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" MaxLineLength:ZoomableBox.kt$// In dynamic mode, the container grows with the content, but the viewable area is still constrained by the screen/parent MaxLineLength:ZoomableBox.kt$if MaxLineLength:ZoomableBox.kt$offsetY = clampOffset(-deltaY * (targetScale - 1f), height, targetScale, isDynamic = dynamicHeight) - NestedBlockDepth:EpubContentLoader.kt$EpubContentLoader$private fun loadEpubChapter(filePath: String, book: EpubBook, href: String): EpubChapter - NestedBlockDepth:EpubContentLoader.kt$EpubContentLoader$private fun parseEpubFile(filePath: String): EpubBook NestedBlockDepth:EpubContentLoader.kt$EpubContentLoader$private fun resolveEpubFile(path: String, writeTier: StorageTier = StorageTier.CACHE): File + NestedBlockDepth:EpubContentLoader.kt$EpubContentLoader$private suspend fun enrichEpubImageDimensionsFromCache( els: List<ContentElement> ): List<ContentElement> NestedBlockDepth:HtmlParser.kt$HtmlParser$private fun mergeAndFormatParagraphs(paragraphs: List<String>): List<ContentElement.Text> NestedBlockDepth:ImageDownloader.kt$ImageDownloader$private fun parseImageResponse( response: Response, destinationFile: File? = null ): ImageFetchResult NestedBlockDepth:MainActivity.kt$MainActivity$private fun handleIntent(intent: Intent?): Unit @@ -618,14 +627,15 @@ NestedBlockDepth:TextFormattingPipeline.kt$TextFormattingPipeline$private fun replaceFourPlusNewlines(text: String): String NestedBlockDepth:TextFormattingPipeline.kt$TextFormattingPipeline$private fun replaceSpacesPlusNewline(text: String, replacementChar: Char): String NestedBlockDepth:WebContentLoader.kt$WebContentLoader$private fun expandWideElements( groupedElements: List<ContentElement>, url: String ): List<ContentElement> + NestedBlockDepth:WebContentLoader.kt$WebContentLoader$private fun fetchHtmlOnce(client: OkHttpClient, url: String): HtmlFetchOutcome NestedBlockDepth:WebContentLoader.kt$WebContentLoader$private fun groupSimilarElements(elements: List<ContentElement>): List<ContentElement> - NewLineAtEndOfFile:SummaryViewModel.kt$io.aatricks.easyreader.ui.viewmodel.SummaryViewModel.kt NewLineAtEndOfFile:TextHeuristics.kt$io.aatricks.easyreader.util.TextHeuristics.kt RethrowCaughtException:EpubContentLoader.kt$EpubContentLoader$throw e ReturnCount:ChapterListCache.kt$ChapterListCache$fun load(baseNovelUrl: String, sourceName: String): Entry? ReturnCount:ChapterListSheet.kt$internal fun chapterCacheStatusKind( isCurrent: Boolean, cacheState: PrefetchResult?, isInLibrary: Boolean, isDownloaded: Boolean = false ): ChapterStatus? ReturnCount:ContentRepository.kt$ContentRepository$private fun adjustChapterUrl(url: String, delta: Int): String? ReturnCount:EpubContentLoader.kt$EpubContentLoader$private fun promoteEpubToDownloads(path: String): File? + ReturnCount:EpubContentLoader.kt$EpubContentLoader$private suspend fun enrichEpubImageDimensionsFromCache( els: List<ContentElement> ): List<ContentElement> ReturnCount:EpubModels.kt$EpubTocItem$fun findByHref(href: String): EpubTocItem? ReturnCount:HtmlParser.kt$HtmlParser$fun parse(document: Document, url: String): List<ContentElement> ReturnCount:HttpMediaCacheFetcher.kt$HttpMediaCacheFetcher$override suspend fun fetch(): FetchResult? @@ -633,8 +643,15 @@ ReturnCount:ImageBoundsParser.kt$ImageBoundsParser$private fun parsePng(bytes: ByteArray): Pair<Int, Int>? ReturnCount:ImageBoundsParser.kt$ImageBoundsParser$private fun parseWebP(bytes: ByteArray): Pair<Int, Int>? ReturnCount:ImageCache.kt$ImageCache$fun promoteToDownloads(url: String): File? + ReturnCount:ImageCache.kt$ImageCache$private fun File.isCachedImageValid(): Boolean ReturnCount:ImageDownloader.kt$ImageDownloader$private fun parseImageResponse( response: Response, destinationFile: File? = null ): ImageFetchResult ReturnCount:ImageDownloader.kt$ImageDownloader$suspend fun executeImageRequest( imageUrl: String, pageUrl: String, priority: ImageRequestPriority, rangeHeader: String? = null, destinationFile: File? = null ): ImageFetchResult + ReturnCount:ImageIntegrity.kt$ImageIntegrity$fun isValidImageFile(file: File): Boolean + ReturnCount:ImageIntegrity.kt$ImageIntegrity$private fun ByteArray.containsSequence(needle: ByteArray): Boolean + ReturnCount:ImageIntegrity.kt$ImageIntegrity$private fun classifyFormat(header: ByteArray): ImageFormat? + ReturnCount:ImageIntegrity.kt$ImageIntegrity$private fun looksLikeHtml(header: ByteArray): Boolean + ReturnCount:LibraryBackupManager.kt$LibraryBackupManager$private fun convertBackupItem( backupItem: LibraryItemBackup, tempDir: File, epubsDir: File, existingUrls: Set<String> ): LibraryItem? + ReturnCount:LibraryBackupManager.kt$LibraryBackupManager$private fun resolveItemUrl(item: LibraryItemBackup, tempDir: File, epubsDir: File): ResolvedItem? ReturnCount:LibraryNovelHelpers.kt$internal fun isNovelFinished(item: LibraryItem, latestKnownChapterCount: Int): Boolean ReturnCount:LibraryRepository.kt$LibraryRepository$private fun parseChapterNumberOrNull(item: LibraryItem): Double? ReturnCount:LibraryStatus.kt$fun seriesReadingStatus(items: List<LibraryItem>): SeriesReadingStatus @@ -644,13 +661,17 @@ ReturnCount:PdfContentLoader.kt$PdfContentLoader$private suspend fun preloadPageContent( filePath: String, pageCount: Int, preloadPageIndex: Int? ): Map<Int, ContentElement> ReturnCount:PdfContentLoader.kt$PdfContentLoader.CombinedExtractionStrategy$override fun eventOccurred(data: IEventData?, type: EventType) ReturnCount:PdfContentLoader.kt$PdfContentLoader.PdfLazyList$private suspend fun acquireHandle(): PdfDocumentHandle? + ReturnCount:ReaderContentArea.kt$private fun buildScrollSnapshot(listState: LazyListState, content: ChapterContent): ReaderScrollSnapshot? + ReturnCount:ReaderContentArea.kt$private fun computeVisiblePercent(listState: LazyListState, totalItems: Int): Float? ReturnCount:ReaderContentGestures.kt$<no name provided>$override fun onPostScroll( consumed: Offset, available: Offset, source: NestedScrollSource ): Offset ReturnCount:ReaderContentGestures.kt$<no name provided>$override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset - ReturnCount:ReaderProgressController.kt$ReaderProgressController$fun updateScrollPosition( scrollOffset: Float, maxScrollOffset: Float, viewportHeight: Float, index: Int, offset: Int, content: ChapterContent?, canScrollForward: Boolean = true, firstVisibleItemSize: Int = 0 ) - ReturnCount:ReaderProgressController.kt$ReaderProgressController$private fun shouldSkipPersistForUnstableManhwaSample( content: ChapterContent?, index: Int, firstVisibleItemSize: Int ): Boolean + ReturnCount:ReaderProgressController.kt$ReaderProgressController$fun isSnapshotPersistable(content: ChapterContent?, snapshot: ReaderProgressState): Boolean + ReturnCount:ReaderProgressController.kt$ReaderProgressController$fun updateScrollPosition( scrollOffset: Float, maxScrollOffset: Float, viewportHeight: Float, index: Int, offsetFraction: Float, elementKey: String, content: ChapterContent?, canScrollForward: Boolean = true, firstVisibleItemSize: Int = 0 ) + ReturnCount:ReaderProgressController.kt$ReaderProgressController$private fun resolveRestoredIndex(content: ChapterContent, libraryItem: LibraryItem): ResolvedPosition ReturnCount:ReaderProgressController.kt$ReaderProgressController$suspend fun saveCurrentProgress(content: ChapterContent?) ReturnCount:ReaderViewModel.kt$ReaderViewModel$private fun updateNavigationUrls(): Unit ReturnCount:ReaderViewModel.kt$ReaderViewModel$private suspend fun resolvePdfResumeIndex( url: String, libraryItemId: String?, isExplicitNavigation: Boolean ): Int? + ReturnCount:ReaderViewModel.kt$ReaderViewModel$suspend fun persistLifecycleProgress(): Unit ReturnCount:SmartSource.kt$SmartSource$private fun absolutize(value: String, pageUrl: String): String ReturnCount:SmartSource.kt$SmartSource$private fun extractAuthor(document: Document): String? ReturnCount:SmartSource.kt$SmartSource$private fun extractCover(document: Document, pageUrl: String): String? @@ -665,13 +686,20 @@ ReturnCount:UrlSecurity.kt$UrlSecurity$fun isSafeUrlSynchronous(httpUrl: okhttp3.HttpUrl): Boolean ReturnCount:UrlSecurity.kt$UrlSecurity$fun isUnsafeHostLiteral(host: String): Boolean ReturnCount:UrlSecurity.kt$UrlSecurity$private fun isIpv4MappedIpv6(bytes: ByteArray): Boolean - ReturnCount:WebContentLoader.kt$WebContentLoader$private fun promoteHtmlToDownloads(url: String): File? + ReturnCount:WebContentLoader.kt$WebContentLoader$private fun detectMangaReaderHints(document: Document): Boolean + ReturnCount:WebContentLoader.kt$WebContentLoader$private fun ensureResultForTier( result: ImageDownloadResult, imageUrl: String, writeTier: StorageTier ): ImageDownloadResult ReturnCount:WebContentLoader.kt$WebContentLoader$private fun shouldGroupWithLastGroup(last: ContentElement, current: ContentElement.Image): Boolean ReturnCount:WebContentLoader.kt$WebContentLoader$private fun shouldGroupWithLastImage(last: ContentElement, current: ContentElement.Image): Boolean ReturnCount:WebContentLoader.kt$WebContentLoader$private fun shouldRetryException(e: Exception): Boolean + ReturnCount:WebContentLoader.kt$WebContentLoader$private suspend fun enrichParsedCacheDimensions(elements: List<ContentElement>): List<ContentElement> + ReturnCount:WebContentLoader.kt$WebContentLoader$private suspend fun executePrefetch( url: String, mode: PrefetchMode, onProgress: (suspend (PrefetchResult) -> Unit)? = null ): PrefetchResult ReturnCount:WebContentLoader.kt$WebContentLoader$private suspend fun getDocumentFromCacheOrNetwork( url: String, priority: ImageRequestPriority = ImageRequestPriority.USER_REQUESTED, writeTier: StorageTier? = null ): CachedDocument ReturnCount:WebContentLoader.kt$WebContentLoader$private suspend fun processChapterElements( elements: List<ContentElement>, url: String, diskOnly: Boolean ): List<ContentElement> + ReturnCount:WebContentLoader.kt$WebContentLoader$private suspend fun tryLoadFromParsedCache( url: String, safeUrl: String, startedAtMs: Long ): ContentResult.Success? ReturnCount:WebContentLoader.kt$WebContentLoader$suspend fun prefetch( url: String, mode: PrefetchMode, onProgress: (suspend (PrefetchResult) -> Unit)? ): PrefetchResult + ReturnCount:WebOfflineChapterStore.kt$WebOfflineChapterStore$fun hasImage(url: String, imageUrl: String): Boolean + ReturnCount:WebOfflineChapterStore.kt$WebOfflineChapterStore$fun loadContent(url: String): ContentResult.Success? + ReturnCount:WebOfflineChapterStore.kt$WebOfflineChapterStore$private suspend fun downloadImage(pageUrl: String, record: ImageRecord): ImageRecord? ReturnCount:WebViewUtils.kt$WebViewUtils$fun shouldAllowCloudflareNavigation(url: String?, expectedHost: String? = null): Boolean SwallowedException:ContentRenderer.kt$ex: Exception SwallowedException:ContentRepository.kt$ContentRepository$e: TimeoutCancellationException @@ -680,6 +708,7 @@ SwallowedException:PreferencesManager.kt$PreferencesManager$e: Exception ThrowsCount:EpubContentLoader.kt$EpubContentLoader$private fun resolveEpubFile(path: String, writeTier: StorageTier = StorageTier.CACHE): File ThrowsCount:WebContentLoader.kt$WebContentLoader$private suspend fun downloadHtml(url: String, priority: ImageRequestPriority = ImageRequestPriority.USER_REQUESTED): String + TooGenericExceptionCaught:ChapterDownloadWorker.kt$ChapterDownloadWorker$t: Throwable TooGenericExceptionCaught:ContentRenderer.kt$ex: Exception TooGenericExceptionCaught:ContentRepository.kt$ContentRepository$e: Exception TooGenericExceptionCaught:Converters.kt$Converters$e: Exception @@ -710,8 +739,6 @@ TooGenericExceptionThrown:LocalContentLoader.kt$LocalContentLoader$throw Exception("Unable to read $filePath") TooGenericExceptionThrown:PdfContentLoader.kt$PdfContentLoader$throw Exception("No text in PDF") TooGenericExceptionThrown:PdfContentLoader.kt$PdfContentLoader$throw Exception("PDF not found") - TooGenericExceptionThrown:WebContentLoader.kt$WebContentLoader$throw Exception("Empty body") - TooGenericExceptionThrown:WebContentLoader.kt$WebContentLoader$throw Exception("HTTP ${response.code}") TooGenericExceptionThrown:ZipUtils.kt$ZipUtils$throw Exception("File too large") TooManyFunctions:AsuraScansSource.kt$AsuraScansSource : BaseJsoupSource TooManyFunctions:ContentRepository.kt$ContentRepository @@ -721,21 +748,24 @@ TooManyFunctions:FileUtils.kt$FileUtils TooManyFunctions:HtmlParser.kt$HtmlParser TooManyFunctions:ImageCache.kt$ImageCache + TooManyFunctions:ImageIntegrity.kt$ImageIntegrity TooManyFunctions:LibraryDao.kt$LibraryDao TooManyFunctions:LibraryRepository.kt$LibraryRepository TooManyFunctions:LibraryViewModel.kt$LibraryViewModel : BaseViewModel + TooManyFunctions:MainActivity.kt$MainActivity : ComponentActivity TooManyFunctions:MangaBatSource.kt$MangaBatSource : BaseJsoupSource TooManyFunctions:NovelFireSource.kt$NovelFireSource : BaseJsoupSource TooManyFunctions:PdfContentLoader.kt$PdfContentLoader TooManyFunctions:ReaderProgressController.kt$ReaderProgressController TooManyFunctions:ReaderViewModel.kt$ReaderViewModel : BaseViewModel TooManyFunctions:SmartSource.kt$SmartSource : BaseJsoupSource + TooManyFunctions:SummaryService.kt$SummaryService TooManyFunctions:TextFormattingPipeline.kt$TextFormattingPipeline TooManyFunctions:TextUtils.kt$TextUtils TooManyFunctions:WebContentLoader.kt$WebContentLoader + TooManyFunctions:WebOfflineChapterStore.kt$WebOfflineChapterStore UnusedParameter:AsuraScansSource.kt$AsuraScansSource$seriesUrl: String UnusedParameter:ComposeUtils.kt$height: Int - UnusedParameter:EpubContentLoader.kt$EpubContentLoader$manifest: Map<String, String> UnusedParameter:LibraryScreen.kt$isSearchEmpty: Boolean = false UnusedParameter:NovelFireSource.kt$NovelFireSource$chaptersUrl: String UnusedParameter:SummaryService.kt$SummaryService$selectedContent: String @@ -744,12 +774,10 @@ UnusedParameter:ZoomableBox.kt$isDynamic: Boolean = false UnusedPrivateMember:MangaBatSource.kt$MangaBatSource$private suspend fun fetchChaptersFromApi(slug: String): List<ChapterInfo> UnusedPrivateMember:ReaderViewModel.kt$ReaderViewModel$private fun isPlaceholderAtCurrentPosition(index: Int? = null): Boolean - UnusedPrivateMember:WebContentLoader.kt$WebContentLoader$private fun tierForMode(mode: PrefetchMode): StorageTier UnusedPrivateProperty:ExploreRepository.kt$ExploreRepository$@ApplicationContext private val context: android.content.Context UnusedPrivateProperty:HtmlParser.kt$HtmlParser.Companion$private val WHITESPACE_REGEX = Regex("\\s+") UnusedPrivateProperty:LibraryRepository.kt$LibraryRepository$val semaphore = Semaphore(5) UnusedPrivateProperty:LlmEdgeSummaryEngine.kt$LlmEdgeSummaryEngine.Companion$private const val MODEL_FILENAME = "Qwen3-0.6B-Q4_K_M.gguf" - UnusedPrivateProperty:ReaderProgressController.kt$ReaderProgressController$val deltaRaw = if (lastRawScrollOffset < 0f) 0f else scrollOffset - lastRawScrollOffset UnusedPrivateProperty:ReaderViewModel.kt$ReaderViewModel.Companion$private const val MIN_SCROLL_OFFSET_DELTA_PX = 8 UnusedPrivateProperty:TextFormattingPipeline.kt$TextFormattingPipeline$k UnusedPrivateProperty:TextUtils.kt$TextUtils$private val FOUR_PLUS_NEWLINES_REGEX = Regex("\\n{4,}") diff --git a/app/src/main/java/io/aatricks/easyreader/data/repository/DownloadStatusReconciler.kt b/app/src/main/java/io/aatricks/easyreader/data/repository/DownloadStatusReconciler.kt index 7316dec..df1d568 100644 --- a/app/src/main/java/io/aatricks/easyreader/data/repository/DownloadStatusReconciler.kt +++ b/app/src/main/java/io/aatricks/easyreader/data/repository/DownloadStatusReconciler.kt @@ -33,6 +33,7 @@ class DownloadStatusReconciler @Inject constructor( fun isFullyDownloaded(result: PrefetchResult): Boolean = result.isStrictOfflineReady() + @Suppress("ReturnCount") suspend fun reconcile( item: LibraryItem, result: PrefetchResult, diff --git a/app/src/main/java/io/aatricks/easyreader/data/repository/content/WebContentLoader.kt b/app/src/main/java/io/aatricks/easyreader/data/repository/content/WebContentLoader.kt index e657126..5dd8ff6 100644 --- a/app/src/main/java/io/aatricks/easyreader/data/repository/content/WebContentLoader.kt +++ b/app/src/main/java/io/aatricks/easyreader/data/repository/content/WebContentLoader.kt @@ -622,22 +622,6 @@ class WebContentLoader @Suppress("LongParameterList") @Inject constructor( ) } - private fun promoteHtmlToDownloads(url: String): File? { - val target = primaryCachedFile(url, StorageTier.DOWNLOADS) - if (target.exists()) return target - val src = legacyCachedFile(url).takeIf(File::exists) - ?: primaryCachedFile(url, StorageTier.CACHE).takeIf(File::exists) - ?: return null - target.parentFile?.mkdirs() - val moved = if (src.renameTo(target)) target else runCatching { - src.copyTo(target, overwrite = true) - src.delete() - target - }.getOrNull() - moved?.let { parsedContentCache.moveAlongside(src, it) } - return moved - } - private fun extractImageUrls(elements: List): List { return elements.flatMap { element -> when (element) { diff --git a/app/src/main/java/io/aatricks/easyreader/ui/viewmodel/ReaderProgressController.kt b/app/src/main/java/io/aatricks/easyreader/ui/viewmodel/ReaderProgressController.kt index e938df7..3a18914 100644 --- a/app/src/main/java/io/aatricks/easyreader/ui/viewmodel/ReaderProgressController.kt +++ b/app/src/main/java/io/aatricks/easyreader/ui/viewmodel/ReaderProgressController.kt @@ -348,20 +348,34 @@ class ReaderProgressController( } val isStable = firstVisibleItemSize >= MIN_STABLE_ITEM_SIZE_PX - val effectiveFraction = if (isStable) offsetFraction.coerceIn(0f, 1f) else FRACTION_UNKNOWN + val isTerminal = !canScrollForward + val effectiveFraction = when { + isTerminal -> offsetFraction.coerceIn(0f, 1f) + isStable -> offsetFraction.coerceIn(0f, 1f) + else -> FRACTION_UNKNOWN + } val nextState = _progressState.value.copy( scrollPosition = progress, scrollProgress = progressInt, scrollIndex = index, - scrollElementKey = if (isStable) elementKey else _progressState.value.scrollElementKey, + scrollElementKey = if (isStable || isTerminal) elementKey else _progressState.value.scrollElementKey, scrollOffsetFraction = effectiveFraction, firstVisibleItemSize = firstVisibleItemSize ) _progressState.value = nextState - // Only schedule a DB write when the sample is stable enough to be meaningful. - if (!isStable || !isSnapshotPersistable(content, nextState)) { + // Terminal end-of-chapter samples are explicit intent: persist them via the + // PAGED_POSITION_ITEM_SIZE_PX sentinel so isSnapshotPersistable bypasses the + // upstream-layout-stability gate (which near the end almost always fails because + // earlier images haven't been measured yet). + val persistSnapshot = if (isTerminal) { + nextState.copy(firstVisibleItemSize = PAGED_POSITION_ITEM_SIZE_PX) + } else { + nextState + } + + if ((!isStable && !isTerminal) || !isSnapshotPersistable(content, persistSnapshot)) { lastRawScrollOffset = scrollOffset return } @@ -376,7 +390,8 @@ class ReaderProgressController( index = index, elementKey = elementKey, offsetFraction = effectiveFraction, - content = content + content = content, + forcePersist = isTerminal ) } lastRawScrollOffset = scrollOffset @@ -390,7 +405,8 @@ class ReaderProgressController( elementKey: String? = null, offsetFraction: Float? = null, currentChapterUrl: String? = null, - content: ChapterContent? = null + content: ChapterContent? = null, + forcePersist: Boolean = false ) { val itemId = currentLibraryItemId ?: return runCatching { @@ -405,7 +421,8 @@ class ReaderProgressController( scrollProgress = progress, scrollIndex = lastIndex, scrollElementKey = lastElementKey, - scrollOffsetFraction = lastFraction + scrollOffsetFraction = lastFraction, + firstVisibleItemSize = if (forcePersist) PAGED_POSITION_ITEM_SIZE_PX else latest.firstVisibleItemSize ) if (isPlaceholderAtCurrentPosition(content, lastIndex)) return@runCatching diff --git a/app/src/main/java/io/aatricks/easyreader/ui/viewmodel/ReaderViewModel.kt b/app/src/main/java/io/aatricks/easyreader/ui/viewmodel/ReaderViewModel.kt index efb5691..36d6878 100644 --- a/app/src/main/java/io/aatricks/easyreader/ui/viewmodel/ReaderViewModel.kt +++ b/app/src/main/java/io/aatricks/easyreader/ui/viewmodel/ReaderViewModel.kt @@ -15,6 +15,7 @@ import io.aatricks.easyreader.ui.theme.AccentTheme import io.aatricks.easyreader.util.normalizeChapterList import io.aatricks.easyreader.util.TextUtils import io.aatricks.easyreader.util.UrlSecurity +import io.aatricks.easyreader.ui.viewmodel.ReaderProgressController.Companion.PAGED_POSITION_ITEM_SIZE_PX import io.aatricks.easyreader.util.FieldUpdate import io.aatricks.easyreader.util.computeAutoDeleteCandidates import kotlinx.coroutines.CancellationException @@ -1082,7 +1083,8 @@ class ReaderViewModel @Inject constructor( index: Int? = null, elementKey: String? = null, offsetFraction: Float? = null, - currentChapterUrl: String? = null + currentChapterUrl: String? = null, + forcePersist: Boolean = false ): Unit { progressController.updateReadingProgress( progress = progress, @@ -1091,7 +1093,8 @@ class ReaderViewModel @Inject constructor( elementKey = elementKey, offsetFraction = offsetFraction, currentChapterUrl = currentChapterUrl, - content = _uiState.value.content + content = _uiState.value.content, + forcePersist = forcePersist ) } @@ -1228,19 +1231,26 @@ class ReaderViewModel @Inject constructor( scrollElementKey = targetElementKey, scrollOffsetFraction = targetFraction, isPreciseRestore = false, - firstVisibleItemSize = progressController.progressState.value.firstVisibleItemSize, + firstVisibleItemSize = PAGED_POSITION_ITEM_SIZE_PX, seekTrigger = System.currentTimeMillis(), targetScrollPosition = if (targetPercent == 100f) 100f else null ) ) + // Seek-bar drag is explicit user intent. Mark it before scheduling the write so + // the restore loop triggered by seekTrigger does not later suppress saves, and + // pass forcePersist=true to bypass the upstream-layout-stability gate (which + // would otherwise reject seeks into chapters with unmeasured images). + progressController.markUserDragged() + viewModelScope.launch { updateReadingProgress( progress = targetPercent.toInt(), scrollPosition = targetPercent, index = roughIndex, elementKey = targetElementKey, - offsetFraction = targetFraction + offsetFraction = targetFraction, + forcePersist = true ) } } diff --git a/app/src/main/java/io/aatricks/easyreader/util/ImageIntegrity.kt b/app/src/main/java/io/aatricks/easyreader/util/ImageIntegrity.kt index 82d9840..fd6ec34 100644 --- a/app/src/main/java/io/aatricks/easyreader/util/ImageIntegrity.kt +++ b/app/src/main/java/io/aatricks/easyreader/util/ImageIntegrity.kt @@ -1,3 +1,5 @@ +@file:Suppress("MagicNumber") + package io.aatricks.easyreader.util import java.io.File diff --git a/app/src/main/java/io/aatricks/easyreader/work/ChapterDownloadWorker.kt b/app/src/main/java/io/aatricks/easyreader/work/ChapterDownloadWorker.kt index 35aa813..5d052c2 100644 --- a/app/src/main/java/io/aatricks/easyreader/work/ChapterDownloadWorker.kt +++ b/app/src/main/java/io/aatricks/easyreader/work/ChapterDownloadWorker.kt @@ -32,6 +32,7 @@ class ChapterDownloadWorker @AssistedInject constructor( private val downloadStatusReconciler: DownloadStatusReconciler ) : CoroutineWorker(appContext, params) { + @Suppress("ReturnCount") override suspend fun doWork(): Result { val url = inputData.getString(KEY_CHAPTER_URL) if (url.isNullOrBlank()) {