├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── report_issue.yml │ └── request_feature.yml ├── assets │ ├── gemini.png │ ├── gt.png │ ├── logo.png │ ├── mlkit.png │ └── raw.png ├── pull_request_template.md ├── renovate.json5 └── workflows │ ├── build_pull_request.yml │ ├── build_push.yml │ └── lock.yml ├── .gitignore ├── .idea └── icon.svg ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── app ├── build.gradle.kts ├── proguard-android-optimize.txt ├── proguard-rules.pro ├── shortcuts.xml ├── src │ ├── debug │ │ └── res │ │ │ └── drawable │ │ │ ├── ic_launcher_background.xml │ │ │ └── ic_launcher_foreground.xml │ ├── dev │ │ └── java │ │ │ └── mihon │ │ │ └── core │ │ │ └── firebase │ │ │ └── FirebaseConfig.kt │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── baseline-prof.txt │ │ ├── java │ │ │ ├── eu │ │ │ │ └── kanade │ │ │ │ │ ├── core │ │ │ │ │ ├── preference │ │ │ │ │ │ ├── CheckboxState.kt │ │ │ │ │ │ └── PreferenceMutableState.kt │ │ │ │ │ └── util │ │ │ │ │ │ ├── CollectionUtils.kt │ │ │ │ │ │ └── SourceUtil.kt │ │ │ │ │ ├── domain │ │ │ │ │ ├── DomainModule.kt │ │ │ │ │ ├── base │ │ │ │ │ │ ├── BasePreferences.kt │ │ │ │ │ │ └── ExtensionInstallerPreference.kt │ │ │ │ │ ├── chapter │ │ │ │ │ │ ├── interactor │ │ │ │ │ │ │ ├── GetAvailableScanlators.kt │ │ │ │ │ │ │ ├── SetReadStatus.kt │ │ │ │ │ │ │ └── SyncChaptersWithSource.kt │ │ │ │ │ │ └── model │ │ │ │ │ │ │ ├── Chapter.kt │ │ │ │ │ │ │ └── ChapterFilter.kt │ │ │ │ │ ├── download │ │ │ │ │ │ └── interactor │ │ │ │ │ │ │ └── DeleteDownload.kt │ │ │ │ │ ├── extension │ │ │ │ │ │ ├── interactor │ │ │ │ │ │ │ ├── GetExtensionLanguages.kt │ │ │ │ │ │ │ ├── GetExtensionSources.kt │ │ │ │ │ │ │ ├── GetExtensionsByType.kt │ │ │ │ │ │ │ └── TrustExtension.kt │ │ │ │ │ │ └── model │ │ │ │ │ │ │ └── Extensions.kt │ │ │ │ │ ├── manga │ │ │ │ │ │ ├── interactor │ │ │ │ │ │ │ ├── GetExcludedScanlators.kt │ │ │ │ │ │ │ ├── SetExcludedScanlators.kt │ │ │ │ │ │ │ ├── SetMangaViewerFlags.kt │ │ │ │ │ │ │ └── UpdateManga.kt │ │ │ │ │ │ └── model │ │ │ │ │ │ │ └── Manga.kt │ │ │ │ │ ├── source │ │ │ │ │ │ ├── interactor │ │ │ │ │ │ │ ├── GetEnabledSources.kt │ │ │ │ │ │ │ ├── GetLanguagesWithSources.kt │ │ │ │ │ │ │ ├── GetSourcesWithFavoriteCount.kt │ │ │ │ │ │ │ ├── SetMigrateSorting.kt │ │ │ │ │ │ │ ├── ToggleLanguage.kt │ │ │ │ │ │ │ ├── ToggleSource.kt │ │ │ │ │ │ │ └── ToggleSourcePin.kt │ │ │ │ │ │ ├── model │ │ │ │ │ │ │ └── Source.kt │ │ │ │ │ │ └── service │ │ │ │ │ │ │ └── SourcePreferences.kt │ │ │ │ │ ├── track │ │ │ │ │ │ ├── interactor │ │ │ │ │ │ │ ├── AddTracks.kt │ │ │ │ │ │ │ ├── RefreshTracks.kt │ │ │ │ │ │ │ ├── SyncChapterProgressWithTrack.kt │ │ │ │ │ │ │ └── TrackChapter.kt │ │ │ │ │ │ ├── model │ │ │ │ │ │ │ ├── AutoTrackState.kt │ │ │ │ │ │ │ └── Track.kt │ │ │ │ │ │ ├── service │ │ │ │ │ │ │ ├── DelayedTrackingUpdateJob.kt │ │ │ │ │ │ │ └── TrackPreferences.kt │ │ │ │ │ │ └── store │ │ │ │ │ │ │ └── DelayedTrackingStore.kt │ │ │ │ │ └── ui │ │ │ │ │ │ ├── UiPreferences.kt │ │ │ │ │ │ └── model │ │ │ │ │ │ ├── AppTheme.kt │ │ │ │ │ │ ├── TabletUiMode.kt │ │ │ │ │ │ └── ThemeMode.kt │ │ │ │ │ ├── presentation │ │ │ │ │ ├── browse │ │ │ │ │ │ ├── BrowseSourceScreen.kt │ │ │ │ │ │ ├── ExtensionDetailsScreen.kt │ │ │ │ │ │ ├── ExtensionFilterScreen.kt │ │ │ │ │ │ ├── ExtensionsScreen.kt │ │ │ │ │ │ ├── GlobalSearchScreen.kt │ │ │ │ │ │ ├── MigrateMangaScreen.kt │ │ │ │ │ │ ├── MigrateSearchScreen.kt │ │ │ │ │ │ ├── MigrateSourceScreen.kt │ │ │ │ │ │ ├── SourcesFilterScreen.kt │ │ │ │ │ │ ├── SourcesScreen.kt │ │ │ │ │ │ └── components │ │ │ │ │ │ │ ├── BaseBrowseItem.kt │ │ │ │ │ │ │ ├── BaseSourceItem.kt │ │ │ │ │ │ │ ├── BrowseBadges.kt │ │ │ │ │ │ │ ├── BrowseIcons.kt │ │ │ │ │ │ │ ├── BrowseSourceComfortableGrid.kt │ │ │ │ │ │ │ ├── BrowseSourceCompactGrid.kt │ │ │ │ │ │ │ ├── BrowseSourceDialogs.kt │ │ │ │ │ │ │ ├── BrowseSourceList.kt │ │ │ │ │ │ │ ├── BrowseSourceLoadingItem.kt │ │ │ │ │ │ │ ├── BrowseSourceToolbar.kt │ │ │ │ │ │ │ ├── GlobalSearchCardRow.kt │ │ │ │ │ │ │ ├── GlobalSearchResultItems.kt │ │ │ │ │ │ │ └── GlobalSearchToolbar.kt │ │ │ │ │ ├── category │ │ │ │ │ │ ├── CategoryExtensions.kt │ │ │ │ │ │ ├── CategoryScreen.kt │ │ │ │ │ │ └── components │ │ │ │ │ │ │ ├── CategoryDialogs.kt │ │ │ │ │ │ │ ├── CategoryFloatingActionButton.kt │ │ │ │ │ │ │ └── CategoryListItem.kt │ │ │ │ │ ├── components │ │ │ │ │ │ ├── AdaptiveSheet.kt │ │ │ │ │ │ ├── AppBar.kt │ │ │ │ │ │ ├── Banners.kt │ │ │ │ │ │ ├── DateText.kt │ │ │ │ │ │ ├── DownloadDropdownMenu.kt │ │ │ │ │ │ ├── DropdownMenu.kt │ │ │ │ │ │ ├── EmptyScreen.kt │ │ │ │ │ │ ├── TabbedDialog.kt │ │ │ │ │ │ └── TabbedScreen.kt │ │ │ │ │ ├── crash │ │ │ │ │ │ └── CrashScreen.kt │ │ │ │ │ ├── history │ │ │ │ │ │ ├── HistoryScreen.kt │ │ │ │ │ │ ├── HistoryScreenModelStateProvider.kt │ │ │ │ │ │ └── components │ │ │ │ │ │ │ ├── HistoryDialogs.kt │ │ │ │ │ │ │ ├── HistoryItem.kt │ │ │ │ │ │ │ └── HistoryWithRelationsProvider.kt │ │ │ │ │ ├── library │ │ │ │ │ │ ├── DeleteLibraryMangaDialog.kt │ │ │ │ │ │ ├── LibrarySettingsDialog.kt │ │ │ │ │ │ └── components │ │ │ │ │ │ │ ├── CommonMangaItem.kt │ │ │ │ │ │ │ ├── GlobalSearchItem.kt │ │ │ │ │ │ │ ├── LazyLibraryGrid.kt │ │ │ │ │ │ │ ├── LibraryBadges.kt │ │ │ │ │ │ │ ├── LibraryComfortableGrid.kt │ │ │ │ │ │ │ ├── LibraryCompactGrid.kt │ │ │ │ │ │ │ ├── LibraryContent.kt │ │ │ │ │ │ │ ├── LibraryList.kt │ │ │ │ │ │ │ ├── LibraryPager.kt │ │ │ │ │ │ │ ├── LibraryTabs.kt │ │ │ │ │ │ │ └── LibraryToolbar.kt │ │ │ │ │ ├── manga │ │ │ │ │ │ ├── ChapterSettingsDialog.kt │ │ │ │ │ │ ├── DuplicateMangaDialog.kt │ │ │ │ │ │ ├── MangaScreen.kt │ │ │ │ │ │ ├── MangaScreenConstants.kt │ │ │ │ │ │ └── components │ │ │ │ │ │ │ ├── BaseMangaListItem.kt │ │ │ │ │ │ │ ├── ChapterDownloadIndicator.kt │ │ │ │ │ │ │ ├── ChapterHeader.kt │ │ │ │ │ │ │ ├── ChapterTranslationIndicator.kt │ │ │ │ │ │ │ ├── DotSeparatorText.kt │ │ │ │ │ │ │ ├── MangaBottomActionMenu.kt │ │ │ │ │ │ │ ├── MangaChapterListItem.kt │ │ │ │ │ │ │ ├── MangaCover.kt │ │ │ │ │ │ │ ├── MangaCoverDialog.kt │ │ │ │ │ │ │ ├── MangaDialogs.kt │ │ │ │ │ │ │ ├── MangaInfoHeader.kt │ │ │ │ │ │ │ ├── MangaToolbar.kt │ │ │ │ │ │ │ ├── MissingChapterCountListItem.kt │ │ │ │ │ │ │ └── ScanlatorFilterDialog.kt │ │ │ │ │ ├── more │ │ │ │ │ │ ├── LogoHeader.kt │ │ │ │ │ │ ├── MoreScreen.kt │ │ │ │ │ │ ├── NewUpdateScreen.kt │ │ │ │ │ │ ├── onboarding │ │ │ │ │ │ │ ├── GuidesStep.kt │ │ │ │ │ │ │ ├── OnboardingScreen.kt │ │ │ │ │ │ │ ├── OnboardingStep.kt │ │ │ │ │ │ │ ├── PermissionStep.kt │ │ │ │ │ │ │ ├── StorageStep.kt │ │ │ │ │ │ │ └── ThemeStep.kt │ │ │ │ │ │ ├── settings │ │ │ │ │ │ │ ├── Preference.kt │ │ │ │ │ │ │ ├── PreferenceItem.kt │ │ │ │ │ │ │ ├── PreferenceScaffold.kt │ │ │ │ │ │ │ ├── PreferenceScreen.kt │ │ │ │ │ │ │ ├── screen │ │ │ │ │ │ │ │ ├── Commons.kt │ │ │ │ │ │ │ │ ├── SearchableSettings.kt │ │ │ │ │ │ │ │ ├── SettingsAdvancedScreen.kt │ │ │ │ │ │ │ │ ├── SettingsAppearanceScreen.kt │ │ │ │ │ │ │ │ ├── SettingsBrowseScreen.kt │ │ │ │ │ │ │ │ ├── SettingsDataScreen.kt │ │ │ │ │ │ │ │ ├── SettingsDownloadScreen.kt │ │ │ │ │ │ │ │ ├── SettingsLibraryScreen.kt │ │ │ │ │ │ │ │ ├── SettingsMainScreen.kt │ │ │ │ │ │ │ │ ├── SettingsReaderScreen.kt │ │ │ │ │ │ │ │ ├── SettingsSearchScreen.kt │ │ │ │ │ │ │ │ ├── SettingsSecurityScreen.kt │ │ │ │ │ │ │ │ ├── SettingsTrackingScreen.kt │ │ │ │ │ │ │ │ ├── SettingsTranslationScreen.kt │ │ │ │ │ │ │ │ ├── about │ │ │ │ │ │ │ │ │ ├── AboutScreen.kt │ │ │ │ │ │ │ │ │ ├── OpenSourceLibraryLicenseScreen.kt │ │ │ │ │ │ │ │ │ └── OpenSourceLicensesScreen.kt │ │ │ │ │ │ │ │ ├── advanced │ │ │ │ │ │ │ │ │ └── ClearDatabaseScreen.kt │ │ │ │ │ │ │ │ ├── appearance │ │ │ │ │ │ │ │ │ └── AppLanguageScreen.kt │ │ │ │ │ │ │ │ ├── browse │ │ │ │ │ │ │ │ │ ├── ExtensionReposScreen.kt │ │ │ │ │ │ │ │ │ ├── ExtensionReposScreenModel.kt │ │ │ │ │ │ │ │ │ └── components │ │ │ │ │ │ │ │ │ │ ├── ExtensionReposContent.kt │ │ │ │ │ │ │ │ │ │ ├── ExtensionReposDialogs.kt │ │ │ │ │ │ │ │ │ │ └── ExtensionReposScreen.kt │ │ │ │ │ │ │ │ ├── data │ │ │ │ │ │ │ │ │ ├── CreateBackupScreen.kt │ │ │ │ │ │ │ │ │ ├── RestoreBackupScreen.kt │ │ │ │ │ │ │ │ │ └── StorageInfo.kt │ │ │ │ │ │ │ │ └── debug │ │ │ │ │ │ │ │ │ ├── BackupSchemaScreen.kt │ │ │ │ │ │ │ │ │ ├── DebugInfoScreen.kt │ │ │ │ │ │ │ │ │ └── WorkerInfoScreen.kt │ │ │ │ │ │ │ └── widget │ │ │ │ │ │ │ │ ├── AppThemeModePreferenceWidget.kt │ │ │ │ │ │ │ │ ├── AppThemePreferenceWidget.kt │ │ │ │ │ │ │ │ ├── BasePreferenceWidget.kt │ │ │ │ │ │ │ │ ├── EditTextPreferenceWidget.kt │ │ │ │ │ │ │ │ ├── InfoWidget.kt │ │ │ │ │ │ │ │ ├── ListPreferenceWidget.kt │ │ │ │ │ │ │ │ ├── MultiSelectListPreferenceWidget.kt │ │ │ │ │ │ │ │ ├── PreferenceGroupHeader.kt │ │ │ │ │ │ │ │ ├── SwitchPreferenceWidget.kt │ │ │ │ │ │ │ │ ├── TextPreferenceWidget.kt │ │ │ │ │ │ │ │ ├── TrackingPreferenceWidget.kt │ │ │ │ │ │ │ │ └── TriStateListDialog.kt │ │ │ │ │ │ └── stats │ │ │ │ │ │ │ ├── StatsScreenContent.kt │ │ │ │ │ │ │ ├── StatsScreenState.kt │ │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ └── StatsItem.kt │ │ │ │ │ │ │ └── data │ │ │ │ │ │ │ └── StatsData.kt │ │ │ │ │ ├── reader │ │ │ │ │ │ ├── ChapterTransition.kt │ │ │ │ │ │ ├── DisplayRefreshHost.kt │ │ │ │ │ │ ├── OrientationSelectDialog.kt │ │ │ │ │ │ ├── PageIndicatorText.kt │ │ │ │ │ │ ├── ReaderContentOverlay.kt │ │ │ │ │ │ ├── ReaderPageActionsDialog.kt │ │ │ │ │ │ ├── ReadingModeSelectDialog.kt │ │ │ │ │ │ ├── appbars │ │ │ │ │ │ │ ├── BottomReaderBar.kt │ │ │ │ │ │ │ └── ReaderAppBars.kt │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ ├── ChapterNavigator.kt │ │ │ │ │ │ │ └── ModeSelectionDialog.kt │ │ │ │ │ │ └── settings │ │ │ │ │ │ │ ├── ColorFilterPage.kt │ │ │ │ │ │ │ ├── GeneralSettingsPage.kt │ │ │ │ │ │ │ ├── ReaderSettingsDialog.kt │ │ │ │ │ │ │ └── ReadingModePage.kt │ │ │ │ │ ├── theme │ │ │ │ │ │ ├── TachiyomiTheme.kt │ │ │ │ │ │ └── colorscheme │ │ │ │ │ │ │ ├── BaseColorScheme.kt │ │ │ │ │ │ │ ├── GreenAppleColorScheme.kt │ │ │ │ │ │ │ ├── LavenderColorScheme.kt │ │ │ │ │ │ │ ├── MidnightDuskColorScheme.kt │ │ │ │ │ │ │ ├── MonetColorScheme.kt │ │ │ │ │ │ │ ├── NordColorScheme.kt │ │ │ │ │ │ │ ├── StrawberryColorScheme.kt │ │ │ │ │ │ │ ├── TachiyomiColorScheme.kt │ │ │ │ │ │ │ ├── TakoColorScheme.kt │ │ │ │ │ │ │ ├── TealTurqoiseColorScheme.kt │ │ │ │ │ │ │ ├── TidalWaveColorScheme.kt │ │ │ │ │ │ │ ├── YinYangColorScheme.kt │ │ │ │ │ │ │ └── YotsubaColorScheme.kt │ │ │ │ │ ├── track │ │ │ │ │ │ ├── TrackInfoDialogHome.kt │ │ │ │ │ │ ├── TrackInfoDialogHomePreviewProvider.kt │ │ │ │ │ │ ├── TrackInfoDialogSelector.kt │ │ │ │ │ │ ├── TrackerSearch.kt │ │ │ │ │ │ ├── TrackerSearchPreviewProvider.kt │ │ │ │ │ │ └── components │ │ │ │ │ │ │ ├── TrackLogoIcon.kt │ │ │ │ │ │ │ └── TrackLogoIconPreviewProvider.kt │ │ │ │ │ ├── updates │ │ │ │ │ │ ├── UpdatesDialog.kt │ │ │ │ │ │ ├── UpdatesScreen.kt │ │ │ │ │ │ └── UpdatesUiItem.kt │ │ │ │ │ ├── util │ │ │ │ │ │ ├── ChapterNumberFormatter.kt │ │ │ │ │ │ ├── ExceptionFormatter.kt │ │ │ │ │ │ ├── FastScrollAnimateItem.kt │ │ │ │ │ │ ├── Navigator.kt │ │ │ │ │ │ ├── Permissions.kt │ │ │ │ │ │ ├── Resources.kt │ │ │ │ │ │ ├── TimeUtils.kt │ │ │ │ │ │ └── WindowSize.kt │ │ │ │ │ └── webview │ │ │ │ │ │ └── WebViewScreenContent.kt │ │ │ │ │ ├── tachiyomi │ │ │ │ │ ├── App.kt │ │ │ │ │ ├── AppInfo.kt │ │ │ │ │ ├── crash │ │ │ │ │ │ ├── CrashActivity.kt │ │ │ │ │ │ └── GlobalExceptionHandler.kt │ │ │ │ │ ├── data │ │ │ │ │ │ ├── backup │ │ │ │ │ │ │ ├── BackupDecoder.kt │ │ │ │ │ │ │ ├── BackupFileValidator.kt │ │ │ │ │ │ │ ├── BackupNotifier.kt │ │ │ │ │ │ │ ├── create │ │ │ │ │ │ │ │ ├── BackupCreateJob.kt │ │ │ │ │ │ │ │ ├── BackupCreator.kt │ │ │ │ │ │ │ │ ├── BackupOptions.kt │ │ │ │ │ │ │ │ └── creators │ │ │ │ │ │ │ │ │ ├── CategoriesBackupCreator.kt │ │ │ │ │ │ │ │ │ ├── ExtensionRepoBackupCreator.kt │ │ │ │ │ │ │ │ │ ├── MangaBackupCreator.kt │ │ │ │ │ │ │ │ │ ├── PreferenceBackupCreator.kt │ │ │ │ │ │ │ │ │ └── SourcesBackupCreator.kt │ │ │ │ │ │ │ ├── models │ │ │ │ │ │ │ │ ├── Backup.kt │ │ │ │ │ │ │ │ ├── BackupCategory.kt │ │ │ │ │ │ │ │ ├── BackupChapter.kt │ │ │ │ │ │ │ │ ├── BackupExtensionRepos.kt │ │ │ │ │ │ │ │ ├── BackupHistory.kt │ │ │ │ │ │ │ │ ├── BackupManga.kt │ │ │ │ │ │ │ │ ├── BackupPreference.kt │ │ │ │ │ │ │ │ ├── BackupSource.kt │ │ │ │ │ │ │ │ └── BackupTracking.kt │ │ │ │ │ │ │ └── restore │ │ │ │ │ │ │ │ ├── BackupRestoreJob.kt │ │ │ │ │ │ │ │ ├── BackupRestorer.kt │ │ │ │ │ │ │ │ ├── RestoreOptions.kt │ │ │ │ │ │ │ │ └── restorers │ │ │ │ │ │ │ │ ├── CategoriesRestorer.kt │ │ │ │ │ │ │ │ ├── ExtensionRepoRestorer.kt │ │ │ │ │ │ │ │ ├── MangaRestorer.kt │ │ │ │ │ │ │ │ └── PreferenceRestorer.kt │ │ │ │ │ │ ├── cache │ │ │ │ │ │ │ ├── ChapterCache.kt │ │ │ │ │ │ │ └── CoverCache.kt │ │ │ │ │ │ ├── coil │ │ │ │ │ │ │ ├── BufferedSourceFetcher.kt │ │ │ │ │ │ │ ├── MangaCoverFetcher.kt │ │ │ │ │ │ │ ├── MangaCoverKeyer.kt │ │ │ │ │ │ │ ├── TachiyomiImageDecoder.kt │ │ │ │ │ │ │ └── Utils.kt │ │ │ │ │ │ ├── database │ │ │ │ │ │ │ └── models │ │ │ │ │ │ │ │ ├── Chapter.kt │ │ │ │ │ │ │ │ ├── ChapterImpl.kt │ │ │ │ │ │ │ │ ├── Track.kt │ │ │ │ │ │ │ │ └── TrackImpl.kt │ │ │ │ │ │ ├── download │ │ │ │ │ │ │ ├── DownloadCache.kt │ │ │ │ │ │ │ ├── DownloadJob.kt │ │ │ │ │ │ │ ├── DownloadManager.kt │ │ │ │ │ │ │ ├── DownloadNotifier.kt │ │ │ │ │ │ │ ├── DownloadPendingDeleter.kt │ │ │ │ │ │ │ ├── DownloadProvider.kt │ │ │ │ │ │ │ ├── DownloadStore.kt │ │ │ │ │ │ │ ├── Downloader.kt │ │ │ │ │ │ │ └── model │ │ │ │ │ │ │ │ └── Download.kt │ │ │ │ │ │ ├── library │ │ │ │ │ │ │ ├── LibraryUpdateJob.kt │ │ │ │ │ │ │ ├── LibraryUpdateNotifier.kt │ │ │ │ │ │ │ └── MetadataUpdateJob.kt │ │ │ │ │ │ ├── notification │ │ │ │ │ │ │ ├── NotificationHandler.kt │ │ │ │ │ │ │ ├── NotificationReceiver.kt │ │ │ │ │ │ │ └── Notifications.kt │ │ │ │ │ │ ├── preference │ │ │ │ │ │ │ └── SharedPreferencesDataStore.kt │ │ │ │ │ │ ├── saver │ │ │ │ │ │ │ └── ImageSaver.kt │ │ │ │ │ │ ├── track │ │ │ │ │ │ │ ├── BaseTracker.kt │ │ │ │ │ │ │ ├── DeletableTracker.kt │ │ │ │ │ │ │ ├── EnhancedTracker.kt │ │ │ │ │ │ │ ├── Tracker.kt │ │ │ │ │ │ │ ├── TrackerManager.kt │ │ │ │ │ │ │ ├── anilist │ │ │ │ │ │ │ │ ├── Anilist.kt │ │ │ │ │ │ │ │ ├── AnilistApi.kt │ │ │ │ │ │ │ │ ├── AnilistInterceptor.kt │ │ │ │ │ │ │ │ ├── AnilistUtils.kt │ │ │ │ │ │ │ │ └── dto │ │ │ │ │ │ │ │ │ ├── ALAddManga.kt │ │ │ │ │ │ │ │ │ ├── ALFuzzyDate.kt │ │ │ │ │ │ │ │ │ ├── ALManga.kt │ │ │ │ │ │ │ │ │ ├── ALOAuth.kt │ │ │ │ │ │ │ │ │ ├── ALSearch.kt │ │ │ │ │ │ │ │ │ ├── ALSearchItem.kt │ │ │ │ │ │ │ │ │ ├── ALUser.kt │ │ │ │ │ │ │ │ │ └── ALUserList.kt │ │ │ │ │ │ │ ├── bangumi │ │ │ │ │ │ │ │ ├── Bangumi.kt │ │ │ │ │ │ │ │ ├── BangumiApi.kt │ │ │ │ │ │ │ │ ├── BangumiInterceptor.kt │ │ │ │ │ │ │ │ ├── BangumiUtils.kt │ │ │ │ │ │ │ │ └── dto │ │ │ │ │ │ │ │ │ ├── BGMCollectionResponse.kt │ │ │ │ │ │ │ │ │ ├── BGMOAuth.kt │ │ │ │ │ │ │ │ │ ├── BGMSearch.kt │ │ │ │ │ │ │ │ │ └── BGMUser.kt │ │ │ │ │ │ │ ├── kavita │ │ │ │ │ │ │ │ ├── Kavita.kt │ │ │ │ │ │ │ │ ├── KavitaApi.kt │ │ │ │ │ │ │ │ ├── KavitaInterceptor.kt │ │ │ │ │ │ │ │ └── KavitaModels.kt │ │ │ │ │ │ │ ├── kitsu │ │ │ │ │ │ │ │ ├── Kitsu.kt │ │ │ │ │ │ │ │ ├── KitsuApi.kt │ │ │ │ │ │ │ │ ├── KitsuDateHelper.kt │ │ │ │ │ │ │ │ ├── KitsuInterceptor.kt │ │ │ │ │ │ │ │ ├── KitsuUtils.kt │ │ │ │ │ │ │ │ └── dto │ │ │ │ │ │ │ │ │ ├── KitsuAddManga.kt │ │ │ │ │ │ │ │ │ ├── KitsuListSearch.kt │ │ │ │ │ │ │ │ │ ├── KitsuOAuth.kt │ │ │ │ │ │ │ │ │ ├── KitsuSearch.kt │ │ │ │ │ │ │ │ │ ├── KitsuSearchItemCover.kt │ │ │ │ │ │ │ │ │ └── KitsuUser.kt │ │ │ │ │ │ │ ├── komga │ │ │ │ │ │ │ │ ├── Komga.kt │ │ │ │ │ │ │ │ ├── KomgaApi.kt │ │ │ │ │ │ │ │ └── KomgaModels.kt │ │ │ │ │ │ │ ├── mangaupdates │ │ │ │ │ │ │ │ ├── MangaUpdates.kt │ │ │ │ │ │ │ │ ├── MangaUpdatesApi.kt │ │ │ │ │ │ │ │ ├── MangaUpdatesInterceptor.kt │ │ │ │ │ │ │ │ └── dto │ │ │ │ │ │ │ │ │ ├── MUContext.kt │ │ │ │ │ │ │ │ │ ├── MUImage.kt │ │ │ │ │ │ │ │ │ ├── MUListItem.kt │ │ │ │ │ │ │ │ │ ├── MULoginResponse.kt │ │ │ │ │ │ │ │ │ ├── MURating.kt │ │ │ │ │ │ │ │ │ ├── MURecord.kt │ │ │ │ │ │ │ │ │ ├── MUSearch.kt │ │ │ │ │ │ │ │ │ ├── MUSeries.kt │ │ │ │ │ │ │ │ │ ├── MUStatus.kt │ │ │ │ │ │ │ │ │ └── MUUrl.kt │ │ │ │ │ │ │ ├── model │ │ │ │ │ │ │ │ └── TrackSearch.kt │ │ │ │ │ │ │ ├── myanimelist │ │ │ │ │ │ │ │ ├── MyAnimeList.kt │ │ │ │ │ │ │ │ ├── MyAnimeListApi.kt │ │ │ │ │ │ │ │ ├── MyAnimeListInterceptor.kt │ │ │ │ │ │ │ │ ├── MyAnimeListUtils.kt │ │ │ │ │ │ │ │ └── dto │ │ │ │ │ │ │ │ │ ├── MALList.kt │ │ │ │ │ │ │ │ │ ├── MALManga.kt │ │ │ │ │ │ │ │ │ ├── MALOAuth.kt │ │ │ │ │ │ │ │ │ ├── MALSearch.kt │ │ │ │ │ │ │ │ │ ├── MALUser.kt │ │ │ │ │ │ │ │ │ └── MALUserListSearch.kt │ │ │ │ │ │ │ ├── shikimori │ │ │ │ │ │ │ │ ├── Shikimori.kt │ │ │ │ │ │ │ │ ├── ShikimoriApi.kt │ │ │ │ │ │ │ │ ├── ShikimoriInterceptor.kt │ │ │ │ │ │ │ │ ├── ShikimoriUtils.kt │ │ │ │ │ │ │ │ └── dto │ │ │ │ │ │ │ │ │ ├── SMAddMangaResponse.kt │ │ │ │ │ │ │ │ │ ├── SMManga.kt │ │ │ │ │ │ │ │ │ ├── SMOAuth.kt │ │ │ │ │ │ │ │ │ ├── SMUser.kt │ │ │ │ │ │ │ │ │ └── SMUserListEntry.kt │ │ │ │ │ │ │ └── suwayomi │ │ │ │ │ │ │ │ ├── Suwayomi.kt │ │ │ │ │ │ │ │ ├── SuwayomiApi.kt │ │ │ │ │ │ │ │ └── SuwayomiModels.kt │ │ │ │ │ │ └── updater │ │ │ │ │ │ │ ├── AppUpdateChecker.kt │ │ │ │ │ │ │ ├── AppUpdateDownloadJob.kt │ │ │ │ │ │ │ └── AppUpdateNotifier.kt │ │ │ │ │ ├── di │ │ │ │ │ │ ├── AppModule.kt │ │ │ │ │ │ └── PreferenceModule.kt │ │ │ │ │ ├── extension │ │ │ │ │ │ ├── ExtensionManager.kt │ │ │ │ │ │ ├── api │ │ │ │ │ │ │ ├── ExtensionApi.kt │ │ │ │ │ │ │ └── ExtensionUpdateNotifier.kt │ │ │ │ │ │ ├── installer │ │ │ │ │ │ │ ├── Installer.kt │ │ │ │ │ │ │ ├── PackageInstallerInstaller.kt │ │ │ │ │ │ │ └── ShizukuInstaller.kt │ │ │ │ │ │ ├── model │ │ │ │ │ │ │ ├── Extension.kt │ │ │ │ │ │ │ ├── InstallStep.kt │ │ │ │ │ │ │ └── LoadResult.kt │ │ │ │ │ │ └── util │ │ │ │ │ │ │ ├── ExtensionInstallActivity.kt │ │ │ │ │ │ │ ├── ExtensionInstallReceiver.kt │ │ │ │ │ │ │ ├── ExtensionInstallService.kt │ │ │ │ │ │ │ ├── ExtensionInstaller.kt │ │ │ │ │ │ │ └── ExtensionLoader.kt │ │ │ │ │ ├── source │ │ │ │ │ │ ├── AndroidSourceManager.kt │ │ │ │ │ │ └── SourceExtensions.kt │ │ │ │ │ ├── ui │ │ │ │ │ │ ├── base │ │ │ │ │ │ │ ├── activity │ │ │ │ │ │ │ │ └── BaseActivity.kt │ │ │ │ │ │ │ └── delegate │ │ │ │ │ │ │ │ ├── SecureActivityDelegate.kt │ │ │ │ │ │ │ │ └── ThemingDelegate.kt │ │ │ │ │ │ ├── browse │ │ │ │ │ │ │ ├── BrowseTab.kt │ │ │ │ │ │ │ ├── extension │ │ │ │ │ │ │ │ ├── ExtensionFilterScreen.kt │ │ │ │ │ │ │ │ ├── ExtensionFilterScreenModel.kt │ │ │ │ │ │ │ │ ├── ExtensionsScreenModel.kt │ │ │ │ │ │ │ │ ├── ExtensionsTab.kt │ │ │ │ │ │ │ │ └── details │ │ │ │ │ │ │ │ │ ├── ExtensionDetailsScreen.kt │ │ │ │ │ │ │ │ │ ├── ExtensionDetailsScreenModel.kt │ │ │ │ │ │ │ │ │ └── SourcePreferencesScreen.kt │ │ │ │ │ │ │ ├── migration │ │ │ │ │ │ │ │ ├── MigrationFlags.kt │ │ │ │ │ │ │ │ ├── manga │ │ │ │ │ │ │ │ │ ├── MigrateMangaScreen.kt │ │ │ │ │ │ │ │ │ └── MigrateMangaScreenModel.kt │ │ │ │ │ │ │ │ ├── search │ │ │ │ │ │ │ │ │ ├── MigrateDialog.kt │ │ │ │ │ │ │ │ │ ├── MigrateSearchScreen.kt │ │ │ │ │ │ │ │ │ ├── MigrateSearchScreenDialogScreenModel.kt │ │ │ │ │ │ │ │ │ ├── MigrateSearchScreenModel.kt │ │ │ │ │ │ │ │ │ └── SourceSearchScreen.kt │ │ │ │ │ │ │ │ └── sources │ │ │ │ │ │ │ │ │ ├── MigrateSourceScreenModel.kt │ │ │ │ │ │ │ │ │ └── MigrateSourceTab.kt │ │ │ │ │ │ │ └── source │ │ │ │ │ │ │ │ ├── SourcesFilterScreen.kt │ │ │ │ │ │ │ │ ├── SourcesFilterScreenModel.kt │ │ │ │ │ │ │ │ ├── SourcesScreenModel.kt │ │ │ │ │ │ │ │ ├── SourcesTab.kt │ │ │ │ │ │ │ │ ├── browse │ │ │ │ │ │ │ │ ├── BrowseSourceScreen.kt │ │ │ │ │ │ │ │ ├── BrowseSourceScreenModel.kt │ │ │ │ │ │ │ │ └── SourceFilterDialog.kt │ │ │ │ │ │ │ │ └── globalsearch │ │ │ │ │ │ │ │ ├── GlobalSearchScreen.kt │ │ │ │ │ │ │ │ ├── GlobalSearchScreenModel.kt │ │ │ │ │ │ │ │ └── SearchScreenModel.kt │ │ │ │ │ │ ├── category │ │ │ │ │ │ │ ├── CategoryScreen.kt │ │ │ │ │ │ │ └── CategoryScreenModel.kt │ │ │ │ │ │ ├── deeplink │ │ │ │ │ │ │ ├── DeepLinkActivity.kt │ │ │ │ │ │ │ ├── DeepLinkScreen.kt │ │ │ │ │ │ │ └── DeepLinkScreenModel.kt │ │ │ │ │ │ ├── download │ │ │ │ │ │ │ ├── DownloadAdapter.kt │ │ │ │ │ │ │ ├── DownloadHeaderHolder.kt │ │ │ │ │ │ │ ├── DownloadHeaderItem.kt │ │ │ │ │ │ │ ├── DownloadHolder.kt │ │ │ │ │ │ │ ├── DownloadItem.kt │ │ │ │ │ │ │ ├── DownloadQueueScreen.kt │ │ │ │ │ │ │ └── DownloadQueueScreenModel.kt │ │ │ │ │ │ ├── history │ │ │ │ │ │ │ ├── HistoryScreenModel.kt │ │ │ │ │ │ │ └── HistoryTab.kt │ │ │ │ │ │ ├── home │ │ │ │ │ │ │ └── HomeScreen.kt │ │ │ │ │ │ ├── library │ │ │ │ │ │ │ ├── LibraryItem.kt │ │ │ │ │ │ │ ├── LibraryScreenModel.kt │ │ │ │ │ │ │ ├── LibrarySettingsScreenModel.kt │ │ │ │ │ │ │ └── LibraryTab.kt │ │ │ │ │ │ ├── main │ │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ │ │ ├── manga │ │ │ │ │ │ │ ├── MangaCoverScreenModel.kt │ │ │ │ │ │ │ ├── MangaScreen.kt │ │ │ │ │ │ │ ├── MangaScreenModel.kt │ │ │ │ │ │ │ └── track │ │ │ │ │ │ │ │ ├── TrackInfoDialog.kt │ │ │ │ │ │ │ │ └── TrackItem.kt │ │ │ │ │ │ ├── more │ │ │ │ │ │ │ ├── MoreTab.kt │ │ │ │ │ │ │ ├── NewUpdateScreen.kt │ │ │ │ │ │ │ └── OnboardingScreen.kt │ │ │ │ │ │ ├── reader │ │ │ │ │ │ │ ├── ReaderActivity.kt │ │ │ │ │ │ │ ├── ReaderNavigationOverlayView.kt │ │ │ │ │ │ │ ├── ReaderViewModel.kt │ │ │ │ │ │ │ ├── SaveImageNotifier.kt │ │ │ │ │ │ │ ├── loader │ │ │ │ │ │ │ │ ├── ArchivePageLoader.kt │ │ │ │ │ │ │ │ ├── ChapterLoader.kt │ │ │ │ │ │ │ │ ├── DirectoryPageLoader.kt │ │ │ │ │ │ │ │ ├── DownloadPageLoader.kt │ │ │ │ │ │ │ │ ├── EpubPageLoader.kt │ │ │ │ │ │ │ │ ├── HttpPageLoader.kt │ │ │ │ │ │ │ │ └── PageLoader.kt │ │ │ │ │ │ │ ├── model │ │ │ │ │ │ │ │ ├── ChapterTransition.kt │ │ │ │ │ │ │ │ ├── InsertPage.kt │ │ │ │ │ │ │ │ ├── ReaderChapter.kt │ │ │ │ │ │ │ │ ├── ReaderPage.kt │ │ │ │ │ │ │ │ └── ViewerChapters.kt │ │ │ │ │ │ │ ├── setting │ │ │ │ │ │ │ │ ├── ReaderOrientation.kt │ │ │ │ │ │ │ │ ├── ReaderPreferences.kt │ │ │ │ │ │ │ │ ├── ReaderSettingsScreenModel.kt │ │ │ │ │ │ │ │ └── ReadingMode.kt │ │ │ │ │ │ │ └── viewer │ │ │ │ │ │ │ │ ├── GestureDetectorWithLongTap.kt │ │ │ │ │ │ │ │ ├── MissingChapters.kt │ │ │ │ │ │ │ │ ├── ReaderButton.kt │ │ │ │ │ │ │ │ ├── ReaderPageImageView.kt │ │ │ │ │ │ │ │ ├── ReaderProgressIndicator.kt │ │ │ │ │ │ │ │ ├── ReaderTransitionView.kt │ │ │ │ │ │ │ │ ├── Viewer.kt │ │ │ │ │ │ │ │ ├── ViewerConfig.kt │ │ │ │ │ │ │ │ ├── ViewerNavigation.kt │ │ │ │ │ │ │ │ ├── navigation │ │ │ │ │ │ │ │ ├── DisabledNavigation.kt │ │ │ │ │ │ │ │ ├── EdgeNavigation.kt │ │ │ │ │ │ │ │ ├── KindlishNavigation.kt │ │ │ │ │ │ │ │ ├── LNavigation.kt │ │ │ │ │ │ │ │ └── RightAndLeftNavigation.kt │ │ │ │ │ │ │ │ ├── pager │ │ │ │ │ │ │ │ ├── Pager.kt │ │ │ │ │ │ │ │ ├── PagerConfig.kt │ │ │ │ │ │ │ │ ├── PagerPageHolder.kt │ │ │ │ │ │ │ │ ├── PagerTransitionHolder.kt │ │ │ │ │ │ │ │ ├── PagerViewer.kt │ │ │ │ │ │ │ │ ├── PagerViewerAdapter.kt │ │ │ │ │ │ │ │ └── PagerViewers.kt │ │ │ │ │ │ │ │ └── webtoon │ │ │ │ │ │ │ │ ├── WebtoonAdapter.kt │ │ │ │ │ │ │ │ ├── WebtoonBaseHolder.kt │ │ │ │ │ │ │ │ ├── WebtoonConfig.kt │ │ │ │ │ │ │ │ ├── WebtoonFrame.kt │ │ │ │ │ │ │ │ ├── WebtoonLayoutManager.kt │ │ │ │ │ │ │ │ ├── WebtoonPageHolder.kt │ │ │ │ │ │ │ │ ├── WebtoonRecyclerView.kt │ │ │ │ │ │ │ │ ├── WebtoonSubsamplingImageView.kt │ │ │ │ │ │ │ │ ├── WebtoonTransitionHolder.kt │ │ │ │ │ │ │ │ └── WebtoonViewer.kt │ │ │ │ │ │ ├── security │ │ │ │ │ │ │ └── UnlockActivity.kt │ │ │ │ │ │ ├── setting │ │ │ │ │ │ │ ├── SettingsScreen.kt │ │ │ │ │ │ │ └── track │ │ │ │ │ │ │ │ ├── BaseOAuthLoginActivity.kt │ │ │ │ │ │ │ │ └── TrackLoginActivity.kt │ │ │ │ │ │ ├── stats │ │ │ │ │ │ │ ├── StatsScreen.kt │ │ │ │ │ │ │ └── StatsScreenModel.kt │ │ │ │ │ │ ├── updates │ │ │ │ │ │ │ ├── UpdatesScreenModel.kt │ │ │ │ │ │ │ └── UpdatesTab.kt │ │ │ │ │ │ └── webview │ │ │ │ │ │ │ ├── WebViewActivity.kt │ │ │ │ │ │ │ ├── WebViewScreen.kt │ │ │ │ │ │ │ └── WebViewScreenModel.kt │ │ │ │ │ ├── util │ │ │ │ │ │ ├── CrashLogUtil.kt │ │ │ │ │ │ ├── MangaExtensions.kt │ │ │ │ │ │ ├── PkceUtil.kt │ │ │ │ │ │ ├── chapter │ │ │ │ │ │ │ ├── ChapterFilterDownloaded.kt │ │ │ │ │ │ │ ├── ChapterGetNextUnread.kt │ │ │ │ │ │ │ └── ChapterRemoveDuplicates.kt │ │ │ │ │ │ ├── lang │ │ │ │ │ │ │ ├── CloseableExtensions.kt │ │ │ │ │ │ │ ├── DateExtensions.kt │ │ │ │ │ │ │ └── RectFExtensions.kt │ │ │ │ │ │ ├── storage │ │ │ │ │ │ │ ├── FileExtensions.kt │ │ │ │ │ │ │ └── OkioExtensions.kt │ │ │ │ │ │ ├── system │ │ │ │ │ │ │ ├── AnimationExtensions.kt │ │ │ │ │ │ │ ├── AuthenticatorUtil.kt │ │ │ │ │ │ │ ├── BuildConfig.kt │ │ │ │ │ │ │ ├── ChildFirstPathClassLoader.kt │ │ │ │ │ │ │ ├── ContextExtensions.kt │ │ │ │ │ │ │ ├── DeviceUtilExtensions.kt │ │ │ │ │ │ │ ├── DisplayExtensions.kt │ │ │ │ │ │ │ ├── DrawableExtensions.kt │ │ │ │ │ │ │ ├── IntentExtensions.kt │ │ │ │ │ │ │ ├── InternalResourceHelper.kt │ │ │ │ │ │ │ ├── LocaleHelper.kt │ │ │ │ │ │ │ ├── NetworkExtensions.kt │ │ │ │ │ │ │ ├── NetworkStateTracker.kt │ │ │ │ │ │ │ ├── NotificationExtensions.kt │ │ │ │ │ │ │ └── WorkManagerExtensions.kt │ │ │ │ │ │ └── view │ │ │ │ │ │ │ ├── EditTextPreferenceExtensions.kt │ │ │ │ │ │ │ ├── ViewExtensions.kt │ │ │ │ │ │ │ └── WindowExtensions.kt │ │ │ │ │ └── widget │ │ │ │ │ │ ├── TachiyomiTextInputEditText.kt │ │ │ │ │ │ └── ViewPagerAdapter.kt │ │ │ │ │ ├── test │ │ │ │ │ └── DummyTracker.kt │ │ │ │ │ └── translation │ │ │ │ │ ├── ChapterTranslator.kt │ │ │ │ │ ├── TranslationManager.kt │ │ │ │ │ ├── data │ │ │ │ │ ├── TranslationFont.kt │ │ │ │ │ └── TranslationProvider.kt │ │ │ │ │ ├── model │ │ │ │ │ ├── PageTranslation.kt │ │ │ │ │ ├── PageTranslationHelper.kt │ │ │ │ │ └── Translation.kt │ │ │ │ │ ├── presentation │ │ │ │ │ ├── PagerTranslationsView.kt │ │ │ │ │ ├── SmartTranslationBlock.kt │ │ │ │ │ ├── Utils.kt │ │ │ │ │ └── WebtoonTranslationsView.kt │ │ │ │ │ ├── recognizer │ │ │ │ │ ├── TextRecognizer.kt │ │ │ │ │ └── TextRecognizerLanguage.kt │ │ │ │ │ └── translator │ │ │ │ │ ├── GeminiTranslator.kt │ │ │ │ │ ├── GoogleTranslator.kt │ │ │ │ │ ├── MLKitTranslator.kt │ │ │ │ │ ├── OpenRouterTranslator.kt │ │ │ │ │ ├── TextTranslator.kt │ │ │ │ │ └── TextTranslatorLanguage.kt │ │ │ └── mihon │ │ │ │ ├── core │ │ │ │ ├── designsystem │ │ │ │ │ └── utils │ │ │ │ │ │ └── WindowSize.kt │ │ │ │ └── migration │ │ │ │ │ ├── Migration.kt │ │ │ │ │ ├── MigrationCompletedListener.kt │ │ │ │ │ ├── MigrationContext.kt │ │ │ │ │ ├── MigrationJobFactory.kt │ │ │ │ │ ├── MigrationStrategy.kt │ │ │ │ │ ├── MigrationStrategyFactory.kt │ │ │ │ │ ├── Migrator.kt │ │ │ │ │ └── migrations │ │ │ │ │ ├── Migrations.kt │ │ │ │ │ ├── SetupBackupCreateMigration.kt │ │ │ │ │ ├── SetupLibraryUpdateMigration.kt │ │ │ │ │ └── TrustExtensionRepositoryMigration.kt │ │ │ │ └── feature │ │ │ │ └── upcoming │ │ │ │ ├── UpcomingScreen.kt │ │ │ │ ├── UpcomingScreenContent.kt │ │ │ │ ├── UpcomingScreenModel.kt │ │ │ │ ├── UpcomingUIModel.kt │ │ │ │ └── components │ │ │ │ ├── UpcomingItem.kt │ │ │ │ └── calendar │ │ │ │ ├── Calendar.kt │ │ │ │ ├── CalendarDay.kt │ │ │ │ ├── CalendarHeader.kt │ │ │ │ └── CalendarIndicator.kt │ │ └── res │ │ │ ├── anim-v33 │ │ │ ├── shared_axis_x_pop_enter.xml │ │ │ ├── shared_axis_x_pop_exit.xml │ │ │ ├── shared_axis_x_push_enter.xml │ │ │ └── shared_axis_x_push_exit.xml │ │ │ ├── anim │ │ │ ├── shared_axis_x_pop_enter.xml │ │ │ ├── shared_axis_x_pop_exit.xml │ │ │ ├── shared_axis_x_push_enter.xml │ │ │ └── shared_axis_x_push_exit.xml │ │ │ ├── color │ │ │ └── draggable_card_foreground.xml │ │ │ ├── drawable-nodpi │ │ │ ├── ic_manga_updates.webp │ │ │ ├── ic_tracker_anilist.webp │ │ │ ├── ic_tracker_bangumi.webp │ │ │ ├── ic_tracker_kavita.webp │ │ │ ├── ic_tracker_kitsu.webp │ │ │ ├── ic_tracker_komga.webp │ │ │ ├── ic_tracker_mal.webp │ │ │ ├── ic_tracker_shikimori.webp │ │ │ └── ic_tracker_suwayomi.webp │ │ │ ├── drawable │ │ │ ├── anim_browse_enter.xml │ │ │ ├── anim_caret_down.xml │ │ │ ├── anim_history_enter.xml │ │ │ ├── anim_library_enter.xml │ │ │ ├── anim_more_enter.xml │ │ │ ├── anim_updates_enter.xml │ │ │ ├── cover_error.xml │ │ │ ├── ic_book_24dp.xml │ │ │ ├── ic_close_24dp.xml │ │ │ ├── ic_crop_24dp.xml │ │ │ ├── ic_crop_off_24dp.xml │ │ │ ├── ic_done_24dp.xml │ │ │ ├── ic_done_prev_24dp.xml │ │ │ ├── ic_download_chapter_24dp.xml │ │ │ ├── ic_drag_handle_24dp.xml │ │ │ ├── ic_extension_24dp.xml │ │ │ ├── ic_folder_24dp.xml │ │ │ ├── ic_glasses_24dp.xml │ │ │ ├── ic_info_24dp.xml │ │ │ ├── ic_launcher_background.xml │ │ │ ├── ic_launcher_foreground.xml │ │ │ ├── ic_launcher_monochrome.xml │ │ │ ├── ic_mihon.xml │ │ │ ├── ic_mihon_splash.xml │ │ │ ├── ic_overflow_24dp.xml │ │ │ ├── ic_pause_24dp.xml │ │ │ ├── ic_photo_24dp.xml │ │ │ ├── ic_play_arrow_24dp.xml │ │ │ ├── ic_reader_continuous_vertical_24dp.xml │ │ │ ├── ic_reader_default_24dp.xml │ │ │ ├── ic_reader_ltr_24dp.xml │ │ │ ├── ic_reader_rtl_24dp.xml │ │ │ ├── ic_reader_vertical_24dp.xml │ │ │ ├── ic_reader_webtoon_24dp.xml │ │ │ ├── ic_refresh_24dp.xml │ │ │ ├── ic_share_24dp.xml │ │ │ ├── ic_system_update_alt_white_24dp.xml │ │ │ ├── ic_translate.xml │ │ │ ├── ic_translate_circle.xml │ │ │ ├── ic_translate_circle_filled.xml │ │ │ ├── ic_warning_white_24dp.xml │ │ │ ├── line_divider.xml │ │ │ ├── material_popup_background.xml │ │ │ ├── sc_collections_bookmark_48dp.xml │ │ │ ├── sc_explore_48dp.xml │ │ │ ├── sc_history_48dp.xml │ │ │ └── sc_new_releases_48dp.xml │ │ │ ├── font │ │ │ ├── animeace.ttf │ │ │ ├── comic_book.otf │ │ │ └── manga_master_bb.ttf │ │ │ ├── layout │ │ │ ├── download_header.xml │ │ │ ├── download_item.xml │ │ │ ├── download_list.xml │ │ │ ├── pref_widget_switch_material.xml │ │ │ ├── reader_activity.xml │ │ │ └── reader_error.xml │ │ │ ├── menu │ │ │ └── download_single.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_default_source.webp │ │ │ └── ic_local_source.webp │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_default_source.webp │ │ │ └── ic_local_source.webp │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_default_source.webp │ │ │ └── ic_local_source.webp │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_default_source.webp │ │ │ └── ic_local_source.webp │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_default_source.webp │ │ │ └── ic_local_source.webp │ │ │ ├── mipmap │ │ │ └── ic_launcher.xml │ │ │ ├── values-night-v31 │ │ │ └── themes.xml │ │ │ ├── values-night │ │ │ ├── bools.xml │ │ │ └── themes.xml │ │ │ ├── values-v27 │ │ │ ├── bools.xml │ │ │ └── themes.xml │ │ │ ├── values-v31 │ │ │ └── themes.xml │ │ │ ├── values │ │ │ ├── bools.xml │ │ │ ├── dimens.xml │ │ │ ├── ids.xml │ │ │ ├── styles.xml │ │ │ └── themes.xml │ │ │ └── xml │ │ │ ├── network_security_config.xml │ │ │ ├── provider_paths.xml │ │ │ ├── s_pen_actions.xml │ │ │ └── searchable.xml │ ├── standard │ │ ├── AndroidManifest.xml │ │ ├── google-services.json │ │ └── java │ │ │ └── mihon │ │ │ └── core │ │ │ └── firebase │ │ │ └── FirebaseConfig.kt │ └── test │ │ └── java │ │ └── mihon │ │ └── core │ │ └── migration │ │ └── MigratorTest.kt └── standard │ └── .gitignore ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts ├── settings.gradle.kts └── src │ └── main │ └── kotlin │ ├── mihon.android.application.compose.gradle.kts │ ├── mihon.android.application.gradle.kts │ ├── mihon.benchmark.gradle.kts │ ├── mihon.code.lint.gradle.kts │ ├── mihon.library.compose.gradle.kts │ ├── mihon.library.gradle.kts │ └── mihon │ └── buildlogic │ ├── AndroidConfig.kt │ ├── Commands.kt │ ├── ProjectExtensions.kt │ └── tasks │ └── LocalesConfigTask.kt ├── core-metadata ├── build.gradle.kts ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── tachiyomi │ └── core │ └── metadata │ ├── comicinfo │ └── ComicInfo.kt │ └── tachiyomi │ └── MangaDetails.kt ├── core ├── archive │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── mihon │ │ └── core │ │ └── archive │ │ ├── ArchiveEntry.kt │ │ ├── ArchiveInputStream.kt │ │ ├── ArchiveReader.kt │ │ ├── EpubReader.kt │ │ ├── UniFileExtensions.kt │ │ └── ZipWriter.kt └── common │ ├── build.gradle.kts │ └── src │ └── main │ ├── AndroidManifest.xml │ └── kotlin │ ├── eu │ └── kanade │ │ └── tachiyomi │ │ ├── core │ │ └── security │ │ │ ├── PrivacyPreferences.kt │ │ │ └── SecurityPreferences.kt │ │ ├── network │ │ ├── AndroidCookieJar.kt │ │ ├── DohProviders.kt │ │ ├── JavaScriptEngine.kt │ │ ├── NetworkHelper.kt │ │ ├── NetworkPreferences.kt │ │ ├── OkHttpExtensions.kt │ │ ├── ProgressListener.kt │ │ ├── ProgressResponseBody.kt │ │ ├── Requests.kt │ │ └── interceptor │ │ │ ├── CloudflareInterceptor.kt │ │ │ ├── IgnoreGzipInterceptor.kt │ │ │ ├── RateLimitInterceptor.kt │ │ │ ├── SpecificHostRateLimitInterceptor.kt │ │ │ ├── UncaughtExceptionInterceptor.kt │ │ │ ├── UserAgentInterceptor.kt │ │ │ └── WebViewInterceptor.kt │ │ └── util │ │ ├── lang │ │ ├── Hash.kt │ │ └── StringExtensions.kt │ │ ├── storage │ │ └── DiskUtil.kt │ │ └── system │ │ ├── DensityExtensions.kt │ │ ├── DeviceUtil.kt │ │ ├── GLUtil.kt │ │ ├── ToastExtensions.kt │ │ └── WebViewUtil.kt │ └── tachiyomi │ └── core │ └── common │ ├── Constants.kt │ ├── i18n │ └── Localize.kt │ ├── preference │ ├── AndroidPreference.kt │ ├── AndroidPreferenceStore.kt │ ├── CheckboxState.kt │ ├── InMemoryPreferenceStore.kt │ ├── Preference.kt │ ├── PreferenceStore.kt │ └── TriState.kt │ ├── storage │ ├── AndroidStorageFolderProvider.kt │ ├── FolderProvider.kt │ └── UniFileExtensions.kt │ └── util │ ├── lang │ ├── BooleanExtensions.kt │ ├── CoroutinesExtensions.kt │ ├── RxCoroutineBridge.kt │ └── SortUtil.kt │ └── system │ ├── ImageUtil.kt │ └── LogcatExtensions.kt ├── data ├── build.gradle.kts ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ ├── mihon │ │ └── data │ │ │ └── repository │ │ │ └── ExtensionRepoRepositoryImpl.kt │ └── tachiyomi │ │ └── data │ │ ├── AndroidDatabaseHandler.kt │ │ ├── DatabaseAdapter.kt │ │ ├── DatabaseHandler.kt │ │ ├── QueryPagingSource.kt │ │ ├── TransactionContext.kt │ │ ├── category │ │ └── CategoryRepositoryImpl.kt │ │ ├── chapter │ │ ├── ChapterRepositoryImpl.kt │ │ └── ChapterSanitizer.kt │ │ ├── history │ │ ├── HistoryMapper.kt │ │ └── HistoryRepositoryImpl.kt │ │ ├── manga │ │ ├── MangaMapper.kt │ │ └── MangaRepositoryImpl.kt │ │ ├── release │ │ ├── GithubRelease.kt │ │ └── ReleaseServiceImpl.kt │ │ ├── source │ │ ├── SourcePagingSource.kt │ │ ├── SourceRepositoryImpl.kt │ │ └── StubSourceRepositoryImpl.kt │ │ ├── track │ │ ├── TrackMapper.kt │ │ └── TrackRepositoryImpl.kt │ │ └── updates │ │ └── UpdatesRepositoryImpl.kt │ └── sqldelight │ └── tachiyomi │ ├── data │ ├── categories.sq │ ├── chapters.sq │ ├── excluded_scanlators.sq │ ├── extension_repos.sq │ ├── history.sq │ ├── manga_sync.sq │ ├── mangas.sq │ ├── mangas_categories.sq │ └── sources.sq │ ├── migrations │ ├── 1.sqm │ ├── 2.sqm │ └── 3.sqm │ └── view │ ├── historyView.sq │ ├── libraryView.sq │ └── updatesView.sq ├── domain ├── build.gradle.kts ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ ├── mihon │ │ └── domain │ │ │ ├── chapter │ │ │ └── interactor │ │ │ │ └── FilterChaptersForDownload.kt │ │ │ ├── extensionrepo │ │ │ ├── exception │ │ │ │ └── SaveExtensionRepoException.kt │ │ │ ├── interactor │ │ │ │ ├── CreateExtensionRepo.kt │ │ │ │ ├── DeleteExtensionRepo.kt │ │ │ │ ├── GetExtensionRepo.kt │ │ │ │ ├── GetExtensionRepoCount.kt │ │ │ │ ├── ReplaceExtensionRepo.kt │ │ │ │ └── UpdateExtensionRepo.kt │ │ │ ├── model │ │ │ │ └── ExtensionRepo.kt │ │ │ ├── repository │ │ │ │ └── ExtensionRepoRepository.kt │ │ │ └── service │ │ │ │ ├── ExtensionRepoDto.kt │ │ │ │ └── ExtensionRepoService.kt │ │ │ └── upcoming │ │ │ └── interactor │ │ │ └── GetUpcomingManga.kt │ │ └── tachiyomi │ │ └── domain │ │ ├── backup │ │ └── service │ │ │ └── BackupPreferences.kt │ │ ├── category │ │ ├── interactor │ │ │ ├── CreateCategoryWithName.kt │ │ │ ├── DeleteCategory.kt │ │ │ ├── GetCategories.kt │ │ │ ├── RenameCategory.kt │ │ │ ├── ReorderCategory.kt │ │ │ ├── ResetCategoryFlags.kt │ │ │ ├── SetDisplayMode.kt │ │ │ ├── SetMangaCategories.kt │ │ │ ├── SetSortModeForCategory.kt │ │ │ └── UpdateCategory.kt │ │ ├── model │ │ │ ├── Category.kt │ │ │ └── CategoryUpdate.kt │ │ └── repository │ │ │ └── CategoryRepository.kt │ │ ├── chapter │ │ ├── interactor │ │ │ ├── GetChapter.kt │ │ │ ├── GetChapterByUrlAndMangaId.kt │ │ │ ├── GetChaptersByMangaId.kt │ │ │ ├── SetMangaDefaultChapterFlags.kt │ │ │ ├── ShouldUpdateDbChapter.kt │ │ │ └── UpdateChapter.kt │ │ ├── model │ │ │ ├── Chapter.kt │ │ │ ├── ChapterUpdate.kt │ │ │ └── NoChaptersException.kt │ │ ├── repository │ │ │ └── ChapterRepository.kt │ │ └── service │ │ │ ├── ChapterRecognition.kt │ │ │ ├── ChapterSort.kt │ │ │ └── MissingChapters.kt │ │ ├── download │ │ └── service │ │ │ └── DownloadPreferences.kt │ │ ├── history │ │ ├── interactor │ │ │ ├── GetHistory.kt │ │ │ ├── GetNextChapters.kt │ │ │ ├── GetTotalReadDuration.kt │ │ │ ├── RemoveHistory.kt │ │ │ └── UpsertHistory.kt │ │ ├── model │ │ │ ├── History.kt │ │ │ ├── HistoryUpdate.kt │ │ │ └── HistoryWithRelations.kt │ │ └── repository │ │ │ └── HistoryRepository.kt │ │ ├── library │ │ ├── model │ │ │ ├── Flag.kt │ │ │ ├── LibraryDisplayMode.kt │ │ │ ├── LibraryManga.kt │ │ │ └── LibrarySortMode.kt │ │ └── service │ │ │ └── LibraryPreferences.kt │ │ ├── manga │ │ ├── interactor │ │ │ ├── FetchInterval.kt │ │ │ ├── GetDuplicateLibraryManga.kt │ │ │ ├── GetFavorites.kt │ │ │ ├── GetLibraryManga.kt │ │ │ ├── GetManga.kt │ │ │ ├── GetMangaByUrlAndSourceId.kt │ │ │ ├── GetMangaWithChapters.kt │ │ │ ├── NetworkToLocalManga.kt │ │ │ ├── ResetViewerFlags.kt │ │ │ └── SetMangaChapterFlags.kt │ │ ├── model │ │ │ ├── Manga.kt │ │ │ ├── MangaCover.kt │ │ │ ├── MangaUpdate.kt │ │ │ └── TriState.kt │ │ └── repository │ │ │ └── MangaRepository.kt │ │ ├── release │ │ ├── interactor │ │ │ └── GetApplicationRelease.kt │ │ ├── model │ │ │ └── Release.kt │ │ └── service │ │ │ └── ReleaseService.kt │ │ ├── source │ │ ├── interactor │ │ │ ├── GetRemoteManga.kt │ │ │ └── GetSourcesWithNonLibraryManga.kt │ │ ├── model │ │ │ ├── Pin.kt │ │ │ ├── Source.kt │ │ │ ├── SourceWithCount.kt │ │ │ └── StubSource.kt │ │ ├── repository │ │ │ ├── SourceRepository.kt │ │ │ └── StubSourceRepository.kt │ │ └── service │ │ │ └── SourceManager.kt │ │ ├── storage │ │ └── service │ │ │ ├── StorageManager.kt │ │ │ └── StoragePreferences.kt │ │ ├── track │ │ ├── interactor │ │ │ ├── DeleteTrack.kt │ │ │ ├── GetTracks.kt │ │ │ ├── GetTracksPerManga.kt │ │ │ └── InsertTrack.kt │ │ ├── model │ │ │ └── Track.kt │ │ └── repository │ │ │ └── TrackRepository.kt │ │ ├── translation │ │ └── TranslationPreferences.kt │ │ └── updates │ │ ├── interactor │ │ └── GetUpdates.kt │ │ ├── model │ │ └── UpdatesWithRelations.kt │ │ └── repository │ │ └── UpdatesRepository.kt │ └── test │ └── java │ └── tachiyomi │ └── domain │ ├── chapter │ └── service │ │ ├── ChapterRecognitionTest.kt │ │ └── MissingChaptersTest.kt │ ├── library │ └── model │ │ └── LibraryFlagsTest.kt │ ├── manga │ └── interactor │ │ └── FetchIntervalTest.kt │ └── release │ └── interactor │ └── GetApplicationReleaseTest.kt ├── gradle.properties ├── gradle ├── androidx.versions.toml ├── compose.versions.toml ├── kotlinx.versions.toml ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── i18n-at ├── build.gradle.kts └── src │ └── commonMain │ └── moko-resources │ └── base │ └── strings.xml ├── i18n ├── README.md ├── build.gradle.kts └── src │ ├── androidMain │ └── AndroidManifest.xml │ └── commonMain │ └── moko-resources │ ├── am │ ├── plurals.xml │ └── strings.xml │ ├── ar │ ├── plurals.xml │ └── strings.xml │ ├── as │ ├── plurals.xml │ └── strings.xml │ ├── base │ ├── plurals.xml │ └── strings.xml │ ├── be │ ├── plurals.xml │ └── strings.xml │ ├── bg │ ├── plurals.xml │ └── strings.xml │ ├── bn │ ├── plurals.xml │ └── strings.xml │ ├── ca │ ├── plurals.xml │ └── strings.xml │ ├── ceb │ ├── plurals.xml │ └── strings.xml │ ├── cs │ ├── plurals.xml │ └── strings.xml │ ├── cv │ ├── plurals.xml │ └── strings.xml │ ├── da │ ├── plurals.xml │ └── strings.xml │ ├── de │ ├── plurals.xml │ └── strings.xml │ ├── el │ ├── plurals.xml │ └── strings.xml │ ├── eo │ ├── plurals.xml │ └── strings.xml │ ├── es │ ├── plurals.xml │ └── strings.xml │ ├── eu │ ├── plurals.xml │ └── strings.xml │ ├── fa │ ├── plurals.xml │ └── strings.xml │ ├── fi │ ├── plurals.xml │ └── strings.xml │ ├── fil │ ├── plurals.xml │ └── strings.xml │ ├── fr │ ├── plurals.xml │ └── strings.xml │ ├── gl │ ├── plurals.xml │ └── strings.xml │ ├── he │ ├── plurals.xml │ └── strings.xml │ ├── hi │ ├── plurals.xml │ └── strings.xml │ ├── hr │ ├── plurals.xml │ └── strings.xml │ ├── hu │ ├── plurals.xml │ └── strings.xml │ ├── in │ ├── plurals.xml │ └── strings.xml │ ├── it │ ├── plurals.xml │ └── strings.xml │ ├── ja │ ├── plurals.xml │ └── strings.xml │ ├── jv │ ├── plurals.xml │ └── strings.xml │ ├── ka-rGE │ ├── plurals.xml │ └── strings.xml │ ├── kk │ ├── plurals.xml │ └── strings.xml │ ├── km │ ├── plurals.xml │ └── strings.xml │ ├── kn │ ├── plurals.xml │ └── strings.xml │ ├── ko │ ├── plurals.xml │ └── strings.xml │ ├── lt │ ├── plurals.xml │ └── strings.xml │ ├── lv │ ├── plurals.xml │ └── strings.xml │ ├── ml │ ├── plurals.xml │ └── strings.xml │ ├── mr │ ├── plurals.xml │ └── strings.xml │ ├── ms │ ├── plurals.xml │ └── strings.xml │ ├── my │ └── strings.xml │ ├── nb-rNO │ ├── plurals.xml │ └── strings.xml │ ├── ne │ ├── plurals.xml │ └── strings.xml │ ├── nl │ ├── plurals.xml │ └── strings.xml │ ├── nn │ ├── plurals.xml │ └── strings.xml │ ├── pl │ ├── plurals.xml │ └── strings.xml │ ├── pt-rBR │ ├── plurals.xml │ └── strings.xml │ ├── pt │ ├── plurals.xml │ └── strings.xml │ ├── ro │ ├── plurals.xml │ └── strings.xml │ ├── ru │ ├── plurals.xml │ └── strings.xml │ ├── sa │ ├── plurals.xml │ └── strings.xml │ ├── sah │ ├── plurals.xml │ └── strings.xml │ ├── sc │ ├── plurals.xml │ └── strings.xml │ ├── sdh │ ├── plurals.xml │ └── strings.xml │ ├── sk │ ├── plurals.xml │ └── strings.xml │ ├── sq │ ├── plurals.xml │ └── strings.xml │ ├── sr │ ├── plurals.xml │ └── strings.xml │ ├── sv │ ├── plurals.xml │ └── strings.xml │ ├── te │ ├── plurals.xml │ └── strings.xml │ ├── th │ ├── plurals.xml │ └── strings.xml │ ├── tr │ ├── plurals.xml │ └── strings.xml │ ├── uk │ ├── plurals.xml │ └── strings.xml │ ├── uz │ ├── plurals.xml │ └── strings.xml │ ├── vi │ ├── plurals.xml │ └── strings.xml │ ├── zh-rCN │ ├── plurals.xml │ └── strings.xml │ └── zh-rTW │ ├── plurals.xml │ └── strings.xml ├── macrobenchmark ├── README.md ├── build.gradle.kts └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── tachiyomi │ └── macrobenchmark │ ├── BaselineProfileGenerator.kt │ └── StartupBenchmark.kt ├── presentation-core ├── build.gradle.kts ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ ├── mihon │ │ └── presentation │ │ │ └── core │ │ │ └── util │ │ │ └── PagingDataUtil.kt │ └── tachiyomi │ │ └── presentation │ │ └── core │ │ ├── components │ │ ├── ActionButton.kt │ │ ├── AdaptiveSheet.kt │ │ ├── Badges.kt │ │ ├── CircularProgressIndicator.kt │ │ ├── CollapsibleBox.kt │ │ ├── LabeledCheckbox.kt │ │ ├── LazyColumnWithAction.kt │ │ ├── LazyGrid.kt │ │ ├── LazyList.kt │ │ ├── LinkIcon.kt │ │ ├── ListGroupHeader.kt │ │ ├── Pill.kt │ │ ├── SectionCard.kt │ │ ├── SettingsItems.kt │ │ ├── TwoPanelBox.kt │ │ ├── VerticalFastScroller.kt │ │ ├── WheelPicker.kt │ │ └── material │ │ │ ├── AlertDialog.kt │ │ │ ├── Button.kt │ │ │ ├── Constants.kt │ │ │ ├── FloatingActionButton.kt │ │ │ ├── IconButtonTokens.kt │ │ │ ├── IconToggleButton.kt │ │ │ ├── NavigationBar.kt │ │ │ ├── NavigationRail.kt │ │ │ ├── PullRefresh.kt │ │ │ ├── Scaffold.kt │ │ │ ├── Slider.kt │ │ │ ├── Surface.kt │ │ │ └── Tabs.kt │ │ ├── i18n │ │ └── Localize.kt │ │ ├── icons │ │ ├── CustomIcons.kt │ │ ├── Discord.kt │ │ ├── Facebook.kt │ │ ├── Github.kt │ │ ├── Reddit.kt │ │ └── X.kt │ │ ├── screens │ │ ├── EmptyScreen.kt │ │ ├── InfoScreen.kt │ │ └── LoadingScreen.kt │ │ ├── theme │ │ ├── Color.kt │ │ └── Typography.kt │ │ └── util │ │ ├── Elevation.kt │ │ ├── LazyListState.kt │ │ ├── Modifier.kt │ │ ├── PaddingValues.kt │ │ ├── Preference.kt │ │ └── Scrollbar.kt │ └── res │ ├── values-night │ ├── colors.xml │ ├── colors_greenapple.xml │ ├── colors_lavender.xml │ ├── colors_midnightdusk.xml │ ├── colors_nord.xml │ ├── colors_strawberry.xml │ ├── colors_tachiyomi.xml │ ├── colors_tako.xml │ ├── colors_tealturqoise.xml │ ├── colors_tidalwave.xml │ ├── colors_yinyang.xml │ └── colors_yotsuba.xml │ └── values │ ├── colors.xml │ ├── colors_greenapple.xml │ ├── colors_lavender.xml │ ├── colors_midnightdusk.xml │ ├── colors_nord.xml │ ├── colors_strawberry.xml │ ├── colors_tachiyomi.xml │ ├── colors_tako.xml │ ├── colors_tealturqoise.xml │ ├── colors_tidalwave.xml │ ├── colors_yinyang.xml │ └── colors_yotsuba.xml ├── presentation-widget ├── build.gradle.kts ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── tachiyomi │ │ └── presentation │ │ └── widget │ │ ├── BaseUpdatesGridGlanceWidget.kt │ │ ├── UpdatesGridCoverScreenGlanceReceiver.kt │ │ ├── UpdatesGridCoverScreenGlanceWidget.kt │ │ ├── UpdatesGridGlanceReceiver.kt │ │ ├── UpdatesGridGlanceWidget.kt │ │ ├── WidgetManager.kt │ │ ├── components │ │ ├── LockedWidget.kt │ │ ├── UpdatesMangaCover.kt │ │ └── UpdatesWidget.kt │ │ └── util │ │ └── GlanceUtils.kt │ └── res │ ├── drawable-nodpi │ ├── updates_grid_coverscreen_widget_preview.webp │ └── updates_grid_widget_preview.webp │ ├── drawable │ ├── appwidget_background.xml │ ├── appwidget_cover_error.xml │ └── appwidget_coverscreen_background.xml │ ├── layout │ ├── appwidget_coverscreen_loading.xml │ └── appwidget_loading.xml │ ├── values-night-v31 │ └── colors_appwidget.xml │ ├── values-v31 │ ├── colors_appwidget.xml │ └── dimens.xml │ ├── values │ ├── colors_appwidget.xml │ └── dimens.xml │ └── xml │ ├── updates_grid_homescreen_widget_info.xml │ ├── updates_grid_lockscreen_widget_info.xml │ └── updates_grid_samsung_cover_widget_info.xml ├── settings.gradle.kts ├── source-api ├── build.gradle.kts ├── consumer-proguard.pro └── src │ ├── androidMain │ ├── AndroidManifest.xml │ └── kotlin │ │ └── eu │ │ └── kanade │ │ └── tachiyomi │ │ ├── source │ │ └── PreferenceScreen.kt │ │ └── util │ │ └── RxExtension.kt │ └── commonMain │ └── kotlin │ └── eu │ └── kanade │ └── tachiyomi │ ├── source │ ├── CatalogueSource.kt │ ├── ConfigurableSource.kt │ ├── PreferenceScreen.kt │ ├── Source.kt │ ├── SourceFactory.kt │ ├── UnmeteredSource.kt │ ├── model │ │ ├── Filter.kt │ │ ├── FilterList.kt │ │ ├── MangasPage.kt │ │ ├── Page.kt │ │ ├── SChapter.kt │ │ ├── SChapterImpl.kt │ │ ├── SManga.kt │ │ ├── SMangaImpl.kt │ │ └── UpdateStrategy.kt │ └── online │ │ ├── HttpSource.kt │ │ ├── ParsedHttpSource.kt │ │ └── ResolvableSource.kt │ └── util │ ├── JsoupExtensions.kt │ └── RxExtension.kt └── source-local ├── build.gradle.kts ├── consumer-rules.pro ├── proguard-rules.pro └── src ├── androidMain ├── AndroidManifest.xml └── kotlin │ └── tachiyomi │ └── source │ └── local │ ├── LocalSource.kt │ ├── filter │ └── OrderBy.kt │ ├── image │ └── LocalCoverManager.kt │ ├── io │ └── LocalSourceFileSystem.kt │ └── metadata │ └── EpubReaderExtensions.kt └── commonMain └── kotlin └── tachiyomi └── source └── local ├── LocalSource.kt ├── image └── LocalCoverManager.kt └── io ├── Archive.kt ├── Format.kt └── LocalSourceFileSystem.kt /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{kt,kts}] 2 | max_line_length = 120 3 | indent_size = 4 4 | insert_final_newline = true 5 | ij_kotlin_allow_trailing_comma = true 6 | ij_kotlin_allow_trailing_comma_on_call_site = true 7 | ij_kotlin_name_count_to_use_star_import = 2147483647 8 | ij_kotlin_name_count_to_use_star_import_for_members = 2147483647 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | * text eol=lf 3 | 4 | # Windows forced line-endings 5 | /.idea/* text eol=crlf 6 | 7 | # Gradle wrapper 8 | *.jar binary 9 | 10 | # Images 11 | *.webp binary 12 | *.png binary 13 | *.jpg binary 14 | *.jpeg binary 15 | *.gif binary 16 | *.ico binary 17 | *.gz binary 18 | *.zip binary 19 | *.7z binary 20 | *.ttf binary 21 | *.eot binary 22 | *.woff binary 23 | *.pyc binary 24 | *.swp binary 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 🖥️ Mihon website 4 | url: https://mihon.app/ 5 | about: Guides, troubleshooting, and answers to common questions 6 | -------------------------------------------------------------------------------- /.github/assets/gemini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/.github/assets/gemini.png -------------------------------------------------------------------------------- /.github/assets/gt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/.github/assets/gt.png -------------------------------------------------------------------------------- /.github/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/.github/assets/logo.png -------------------------------------------------------------------------------- /.github/assets/mlkit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/.github/assets/mlkit.png -------------------------------------------------------------------------------- /.github/assets/raw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/.github/assets/raw.png -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:recommended"], 4 | "labels": ["Dependencies"], 5 | "semanticCommits": "disabled", 6 | "packageRules": [ 7 | { 8 | "groupName": "GitHub Actions", 9 | "matchManagers": ["github-actions"], 10 | "pinDigests": true, 11 | }, 12 | ], 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/lock.yml: -------------------------------------------------------------------------------- 1 | name: Lock threads 2 | 3 | on: 4 | # Daily 5 | schedule: 6 | - cron: '0 0 * * *' 7 | # Manual trigger 8 | workflow_dispatch: 9 | inputs: 10 | 11 | jobs: 12 | lock: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1 16 | with: 17 | github-token: ${{ github.token }} 18 | issue-inactive-days: '2' 19 | pr-inactive-days: '2' 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build files 2 | .gradle 3 | .kotlin 4 | build 5 | 6 | # IDE files 7 | *.iml 8 | .idea/* 9 | !.idea/icon.svg 10 | /captures 11 | 12 | # Configuration files 13 | local.properties 14 | 15 | # macOS specific files 16 | .DS_Store 17 | -------------------------------------------------------------------------------- /app/proguard-android-optimize.txt: -------------------------------------------------------------------------------- 1 | -dontusemixedcaseclassnames 2 | -ignorewarnings 3 | -verbose 4 | 5 | -keepattributes *Annotation* 6 | 7 | -keepclasseswithmembernames,includedescriptorclasses class * { 8 | native ; 9 | } 10 | 11 | -keepclassmembers enum * { 12 | public static **[] values(); 13 | public static ** valueOf(java.lang.String); 14 | } 15 | 16 | -keepclassmembers class * implements android.os.Parcelable { 17 | public static final ** CREATOR; 18 | } 19 | 20 | -keep class androidx.annotation.Keep 21 | 22 | -keep @androidx.annotation.Keep class * {*;} 23 | 24 | -keepclasseswithmembers class * { 25 | @androidx.annotation.Keep ; 26 | } 27 | 28 | -keepclasseswithmembers class * { 29 | @androidx.annotation.Keep ; 30 | } 31 | 32 | -keepclasseswithmembers class * { 33 | @androidx.annotation.Keep (...); 34 | } -------------------------------------------------------------------------------- /app/src/dev/java/mihon/core/firebase/FirebaseConfig.kt: -------------------------------------------------------------------------------- 1 | package mihon.core.firebase 2 | 3 | import android.content.Context 4 | 5 | object FirebaseConfig { 6 | fun init(context: Context) = Unit 7 | 8 | fun setAnalyticsEnabled(enabled: Boolean) = Unit 9 | 10 | fun setCrashlyticsEnabled(enabled: Boolean) = Unit 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/core/preference/CheckboxState.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.core.preference 2 | 3 | import androidx.compose.ui.state.ToggleableState 4 | import tachiyomi.core.common.preference.CheckboxState 5 | 6 | fun CheckboxState.TriState.asToggleableState() = when (this) { 7 | is CheckboxState.TriState.Exclude -> ToggleableState.Indeterminate 8 | is CheckboxState.TriState.Include -> ToggleableState.On 9 | is CheckboxState.TriState.None -> ToggleableState.Off 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/core/util/SourceUtil.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.core.util 2 | 3 | import androidx.compose.runtime.Composable 4 | import androidx.compose.runtime.collectAsState 5 | import androidx.compose.runtime.remember 6 | import tachiyomi.domain.source.service.SourceManager 7 | import uy.kohesive.injekt.Injekt 8 | import uy.kohesive.injekt.api.get 9 | 10 | @Composable 11 | fun ifSourcesLoaded(): Boolean { 12 | return remember { Injekt.get().isInitialized }.collectAsState().value 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/domain/chapter/interactor/GetAvailableScanlators.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.domain.chapter.interactor 2 | 3 | import kotlinx.coroutines.flow.Flow 4 | import kotlinx.coroutines.flow.map 5 | import tachiyomi.domain.chapter.repository.ChapterRepository 6 | 7 | class GetAvailableScanlators( 8 | private val repository: ChapterRepository, 9 | ) { 10 | 11 | private fun List.cleanupAvailableScanlators(): Set { 12 | return mapNotNull { it.ifBlank { null } }.toSet() 13 | } 14 | 15 | suspend fun await(mangaId: Long): Set { 16 | return repository.getScanlatorsByMangaId(mangaId) 17 | .cleanupAvailableScanlators() 18 | } 19 | 20 | fun subscribe(mangaId: Long): Flow> { 21 | return repository.getScanlatorsByMangaIdAsFlow(mangaId) 22 | .map { it.cleanupAvailableScanlators() } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/domain/download/interactor/DeleteDownload.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.domain.download.interactor 2 | 3 | import eu.kanade.tachiyomi.data.download.DownloadManager 4 | import tachiyomi.core.common.util.lang.withNonCancellableContext 5 | import tachiyomi.domain.chapter.model.Chapter 6 | import tachiyomi.domain.manga.model.Manga 7 | import tachiyomi.domain.source.service.SourceManager 8 | 9 | class DeleteDownload( 10 | private val sourceManager: SourceManager, 11 | private val downloadManager: DownloadManager, 12 | ) { 13 | 14 | suspend fun awaitAll(manga: Manga, vararg chapters: Chapter) = withNonCancellableContext { 15 | sourceManager.get(manga.source)?.let { source -> 16 | downloadManager.deleteChapters(chapters.toList(), manga, source) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/domain/extension/model/Extensions.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.domain.extension.model 2 | 3 | import eu.kanade.tachiyomi.extension.model.Extension 4 | 5 | data class Extensions( 6 | val updates: List, 7 | val installed: List, 8 | val available: List, 9 | val untrusted: List, 10 | ) 11 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/domain/manga/interactor/GetExcludedScanlators.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.domain.manga.interactor 2 | 3 | import kotlinx.coroutines.flow.Flow 4 | import kotlinx.coroutines.flow.map 5 | import tachiyomi.data.DatabaseHandler 6 | 7 | class GetExcludedScanlators( 8 | private val handler: DatabaseHandler, 9 | ) { 10 | 11 | suspend fun await(mangaId: Long): Set { 12 | return handler.awaitList { 13 | excluded_scanlatorsQueries.getExcludedScanlatorsByMangaId(mangaId) 14 | } 15 | .toSet() 16 | } 17 | 18 | fun subscribe(mangaId: Long): Flow> { 19 | return handler.subscribeToList { 20 | excluded_scanlatorsQueries.getExcludedScanlatorsByMangaId(mangaId) 21 | } 22 | .map { it.toSet() } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/domain/manga/interactor/SetExcludedScanlators.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.domain.manga.interactor 2 | 3 | import tachiyomi.data.DatabaseHandler 4 | 5 | class SetExcludedScanlators( 6 | private val handler: DatabaseHandler, 7 | ) { 8 | 9 | suspend fun await(mangaId: Long, excludedScanlators: Set) { 10 | handler.await(inTransaction = true) { 11 | val currentExcluded = handler.awaitList { 12 | excluded_scanlatorsQueries.getExcludedScanlatorsByMangaId(mangaId) 13 | }.toSet() 14 | val toAdd = excludedScanlators.minus(currentExcluded) 15 | for (scanlator in toAdd) { 16 | excluded_scanlatorsQueries.insert(mangaId, scanlator) 17 | } 18 | val toRemove = currentExcluded.minus(excludedScanlators) 19 | excluded_scanlatorsQueries.remove(mangaId, toRemove) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/domain/source/interactor/SetMigrateSorting.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.domain.source.interactor 2 | 3 | import eu.kanade.domain.source.service.SourcePreferences 4 | 5 | class SetMigrateSorting( 6 | private val preferences: SourcePreferences, 7 | ) { 8 | 9 | fun await(mode: Mode, direction: Direction) { 10 | preferences.migrationSortingMode().set(mode) 11 | preferences.migrationSortingDirection().set(direction) 12 | } 13 | 14 | enum class Mode { 15 | ALPHABETICAL, 16 | TOTAL, 17 | } 18 | 19 | enum class Direction { 20 | ASCENDING, 21 | DESCENDING, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/domain/source/interactor/ToggleLanguage.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.domain.source.interactor 2 | 3 | import eu.kanade.domain.source.service.SourcePreferences 4 | import tachiyomi.core.common.preference.getAndSet 5 | 6 | class ToggleLanguage( 7 | val preferences: SourcePreferences, 8 | ) { 9 | 10 | fun await(language: String) { 11 | val isEnabled = language in preferences.enabledLanguages().get() 12 | preferences.enabledLanguages().getAndSet { enabled -> 13 | if (isEnabled) enabled.minus(language) else enabled.plus(language) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/domain/source/interactor/ToggleSourcePin.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.domain.source.interactor 2 | 3 | import eu.kanade.domain.source.service.SourcePreferences 4 | import tachiyomi.core.common.preference.getAndSet 5 | import tachiyomi.domain.source.model.Source 6 | 7 | class ToggleSourcePin( 8 | private val preferences: SourcePreferences, 9 | ) { 10 | 11 | fun await(source: Source) { 12 | val isPinned = source.id.toString() in preferences.pinnedSources().get() 13 | preferences.pinnedSources().getAndSet { pinned -> 14 | if (isPinned) pinned.minus("${source.id}") else pinned.plus("${source.id}") 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/domain/source/model/Source.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.domain.source.model 2 | 3 | import androidx.compose.ui.graphics.ImageBitmap 4 | import androidx.compose.ui.graphics.asImageBitmap 5 | import androidx.core.graphics.drawable.toBitmap 6 | import eu.kanade.tachiyomi.extension.ExtensionManager 7 | import tachiyomi.domain.source.model.Source 8 | import uy.kohesive.injekt.Injekt 9 | import uy.kohesive.injekt.api.get 10 | 11 | val Source.icon: ImageBitmap? 12 | get() { 13 | return Injekt.get().getAppIconForSource(id) 14 | ?.toBitmap() 15 | ?.asImageBitmap() 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/domain/track/model/AutoTrackState.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.domain.track.model 2 | 3 | import dev.icerock.moko.resources.StringResource 4 | import tachiyomi.i18n.MR 5 | 6 | enum class AutoTrackState(val titleRes: StringResource) { 7 | ALWAYS(MR.strings.lock_always), 8 | ASK(MR.strings.default_category_summary), 9 | NEVER(MR.strings.lock_never), 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/domain/ui/model/TabletUiMode.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.domain.ui.model 2 | 3 | import dev.icerock.moko.resources.StringResource 4 | import tachiyomi.i18n.MR 5 | 6 | enum class TabletUiMode(val titleRes: StringResource) { 7 | AUTOMATIC(MR.strings.automatic_background), 8 | ALWAYS(MR.strings.lock_always), 9 | LANDSCAPE(MR.strings.landscape), 10 | NEVER(MR.strings.lock_never), 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/domain/ui/model/ThemeMode.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.domain.ui.model 2 | 3 | import androidx.appcompat.app.AppCompatDelegate 4 | 5 | enum class ThemeMode { 6 | LIGHT, 7 | DARK, 8 | SYSTEM, 9 | } 10 | 11 | fun setAppCompatDelegateThemeMode(themeMode: ThemeMode) { 12 | AppCompatDelegate.setDefaultNightMode( 13 | when (themeMode) { 14 | ThemeMode.LIGHT -> AppCompatDelegate.MODE_NIGHT_NO 15 | ThemeMode.DARK -> AppCompatDelegate.MODE_NIGHT_YES 16 | ThemeMode.SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM 17 | }, 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/presentation/browse/components/BrowseBadges.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.presentation.browse.components 2 | 3 | import androidx.compose.material.icons.Icons 4 | import androidx.compose.material.icons.outlined.CollectionsBookmark 5 | import androidx.compose.runtime.Composable 6 | import tachiyomi.presentation.core.components.Badge 7 | 8 | @Composable 9 | internal fun InLibraryBadge(enabled: Boolean) { 10 | if (enabled) { 11 | Badge( 12 | imageVector = Icons.Outlined.CollectionsBookmark, 13 | ) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceLoadingItem.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.presentation.browse.components 2 | 3 | import androidx.compose.foundation.layout.Arrangement 4 | import androidx.compose.foundation.layout.Row 5 | import androidx.compose.foundation.layout.fillMaxWidth 6 | import androidx.compose.foundation.layout.padding 7 | import androidx.compose.material3.CircularProgressIndicator 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.ui.Modifier 10 | import androidx.compose.ui.unit.dp 11 | 12 | @Composable 13 | internal fun BrowseSourceLoadingItem() { 14 | Row( 15 | modifier = Modifier 16 | .fillMaxWidth() 17 | .padding(vertical = 16.dp), 18 | horizontalArrangement = Arrangement.Center, 19 | ) { 20 | CircularProgressIndicator() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/presentation/category/CategoryExtensions.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.presentation.category 2 | 3 | import android.content.Context 4 | import androidx.compose.runtime.Composable 5 | import tachiyomi.core.common.i18n.stringResource 6 | import tachiyomi.domain.category.model.Category 7 | import tachiyomi.i18n.MR 8 | import tachiyomi.presentation.core.i18n.stringResource 9 | 10 | val Category.visualName: String 11 | @Composable 12 | get() = when { 13 | isSystemCategory -> stringResource(MR.strings.label_default) 14 | else -> name 15 | } 16 | 17 | fun Category.visualName(context: Context): String = 18 | when { 19 | isSystemCategory -> context.stringResource(MR.strings.label_default) 20 | else -> name 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/presentation/library/components/GlobalSearchItem.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.presentation.library.components 2 | 3 | import androidx.compose.material3.Text 4 | import androidx.compose.material3.TextButton 5 | import androidx.compose.runtime.Composable 6 | import androidx.compose.ui.Modifier 7 | import androidx.compose.ui.zIndex 8 | import tachiyomi.i18n.MR 9 | import tachiyomi.presentation.core.i18n.stringResource 10 | 11 | @Composable 12 | internal fun GlobalSearchItem( 13 | searchQuery: String, 14 | onClick: () -> Unit, 15 | modifier: Modifier = Modifier, 16 | ) { 17 | TextButton( 18 | modifier = modifier, 19 | onClick = onClick, 20 | ) { 21 | Text( 22 | text = stringResource(MR.strings.action_global_search_query, searchQuery), 23 | modifier = Modifier.zIndex(99f), 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/presentation/manga/MangaScreenConstants.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.presentation.manga 2 | 3 | enum class DownloadAction { 4 | NEXT_1_CHAPTER, 5 | NEXT_5_CHAPTERS, 6 | NEXT_10_CHAPTERS, 7 | NEXT_25_CHAPTERS, 8 | UNREAD_CHAPTERS, 9 | } 10 | 11 | enum class EditCoverAction { 12 | EDIT, 13 | DELETE, 14 | } 15 | 16 | enum class MangaScreenItem { 17 | INFO_BOX, 18 | ACTION_ROW, 19 | DESCRIPTION_WITH_TAG, 20 | CHAPTER_HEADER, 21 | CHAPTER, 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/presentation/manga/components/DotSeparatorText.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.presentation.manga.components 2 | 3 | import androidx.compose.material3.Text 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.ui.Modifier 6 | 7 | @Composable 8 | fun DotSeparatorText( 9 | modifier: Modifier = Modifier, 10 | ) { 11 | Text( 12 | text = " • ", 13 | modifier = modifier, 14 | ) 15 | } 16 | 17 | @Composable 18 | fun DotSeparatorNoSpaceText( 19 | modifier: Modifier = Modifier, 20 | ) { 21 | Text( 22 | text = "•", 23 | modifier = modifier, 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingStep.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.presentation.more.onboarding 2 | 3 | import androidx.compose.runtime.Composable 4 | 5 | internal interface OnboardingStep { 6 | 7 | val isComplete: Boolean 8 | 9 | @Composable 10 | fun Content() 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/presentation/more/stats/StatsScreenState.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.presentation.more.stats 2 | 3 | import androidx.compose.runtime.Immutable 4 | import eu.kanade.presentation.more.stats.data.StatsData 5 | 6 | sealed interface StatsScreenState { 7 | @Immutable 8 | data object Loading : StatsScreenState 9 | 10 | @Immutable 11 | data class Success( 12 | val overview: StatsData.Overview, 13 | val titles: StatsData.Titles, 14 | val chapters: StatsData.Chapters, 15 | val trackers: StatsData.Trackers, 16 | ) : StatsScreenState 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/presentation/more/stats/data/StatsData.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.presentation.more.stats.data 2 | 3 | sealed interface StatsData { 4 | 5 | data class Overview( 6 | val libraryMangaCount: Int, 7 | val completedMangaCount: Int, 8 | val totalReadDuration: Long, 9 | ) : StatsData 10 | 11 | data class Titles( 12 | val globalUpdateItemCount: Int, 13 | val startedMangaCount: Int, 14 | val localMangaCount: Int, 15 | ) : StatsData 16 | 17 | data class Chapters( 18 | val totalChapterCount: Int, 19 | val readChapterCount: Int, 20 | val downloadCount: Int, 21 | ) : StatsData 22 | 23 | data class Trackers( 24 | val trackedTitleCount: Int, 25 | val meanScore: Double, 26 | val trackerCount: Int, 27 | ) : StatsData 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIconPreviewProvider.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.presentation.track.components 2 | 3 | import android.graphics.Color 4 | import androidx.compose.ui.tooling.preview.PreviewParameterProvider 5 | import eu.kanade.tachiyomi.R 6 | import eu.kanade.tachiyomi.data.track.Tracker 7 | import eu.kanade.test.DummyTracker 8 | 9 | internal class TrackLogoIconPreviewProvider : PreviewParameterProvider { 10 | 11 | override val values: Sequence 12 | get() = sequenceOf( 13 | DummyTracker( 14 | id = 1L, 15 | name = "Dummy Tracker", 16 | valLogoColor = Color.rgb(18, 25, 35), 17 | valLogo = R.drawable.ic_tracker_anilist, 18 | ), 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/presentation/util/ChapterNumberFormatter.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.presentation.util 2 | 3 | import java.text.DecimalFormat 4 | import java.text.DecimalFormatSymbols 5 | 6 | private val formatter = DecimalFormat( 7 | "#.###", 8 | DecimalFormatSymbols().apply { decimalSeparator = '.' }, 9 | ) 10 | 11 | fun formatChapterNumber(chapterNumber: Double): String { 12 | return formatter.format(chapterNumber) 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/presentation/util/FastScrollAnimateItem.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.presentation.util 2 | 3 | import androidx.compose.foundation.lazy.LazyItemScope 4 | import androidx.compose.ui.Modifier 5 | 6 | // https://issuetracker.google.com/352584409 7 | context(LazyItemScope) 8 | fun Modifier.animateItemFastScroll() = this.animateItem(fadeInSpec = null, fadeOutSpec = null) 9 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/presentation/util/WindowSize.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.presentation.util 2 | 3 | import androidx.compose.runtime.Composable 4 | import androidx.compose.runtime.ReadOnlyComposable 5 | import androidx.compose.ui.platform.LocalConfiguration 6 | import eu.kanade.tachiyomi.util.system.isTabletUi 7 | 8 | @Composable 9 | @ReadOnlyComposable 10 | fun isTabletUi(): Boolean { 11 | return LocalConfiguration.current.isTabletUi() 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/CategoriesBackupCreator.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.backup.create.creators 2 | 3 | import eu.kanade.tachiyomi.data.backup.models.BackupCategory 4 | import eu.kanade.tachiyomi.data.backup.models.backupCategoryMapper 5 | import tachiyomi.domain.category.interactor.GetCategories 6 | import tachiyomi.domain.category.model.Category 7 | import uy.kohesive.injekt.Injekt 8 | import uy.kohesive.injekt.api.get 9 | 10 | class CategoriesBackupCreator( 11 | private val getCategories: GetCategories = Injekt.get(), 12 | ) { 13 | 14 | suspend operator fun invoke(): List { 15 | return getCategories.await() 16 | .filterNot(Category::isSystemCategory) 17 | .map(backupCategoryMapper) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/ExtensionRepoBackupCreator.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.backup.create.creators 2 | 3 | import eu.kanade.tachiyomi.data.backup.models.BackupExtensionRepos 4 | import eu.kanade.tachiyomi.data.backup.models.backupExtensionReposMapper 5 | import mihon.domain.extensionrepo.interactor.GetExtensionRepo 6 | import uy.kohesive.injekt.Injekt 7 | import uy.kohesive.injekt.api.get 8 | 9 | class ExtensionRepoBackupCreator( 10 | private val getExtensionRepos: GetExtensionRepo = Injekt.get(), 11 | ) { 12 | 13 | suspend operator fun invoke(): List { 14 | return getExtensionRepos.getAll() 15 | .map(backupExtensionReposMapper) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.backup.models 2 | 3 | import kotlinx.serialization.Serializable 4 | import kotlinx.serialization.protobuf.ProtoNumber 5 | 6 | @Serializable 7 | data class Backup( 8 | @ProtoNumber(1) val backupManga: List, 9 | @ProtoNumber(2) var backupCategories: List = emptyList(), 10 | // @ProtoNumber(100) var backupBrokenSources, legacy source model with non-compliant proto number, 11 | @ProtoNumber(101) var backupSources: List = emptyList(), 12 | @ProtoNumber(104) var backupPreferences: List = emptyList(), 13 | @ProtoNumber(105) var backupSourcePreferences: List = emptyList(), 14 | @ProtoNumber(106) var backupExtensionRepo: List = emptyList(), 15 | ) 16 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupExtensionRepos.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.backup.models 2 | 3 | import kotlinx.serialization.Serializable 4 | import kotlinx.serialization.protobuf.ProtoNumber 5 | import mihon.domain.extensionrepo.model.ExtensionRepo 6 | 7 | @Serializable 8 | class BackupExtensionRepos( 9 | @ProtoNumber(1) var baseUrl: String, 10 | @ProtoNumber(2) var name: String, 11 | @ProtoNumber(3) var shortName: String?, 12 | @ProtoNumber(4) var website: String, 13 | @ProtoNumber(5) var signingKeyFingerprint: String, 14 | ) 15 | 16 | val backupExtensionReposMapper = { repo: ExtensionRepo -> 17 | BackupExtensionRepos( 18 | baseUrl = repo.baseUrl, 19 | name = repo.name, 20 | shortName = repo.shortName, 21 | website = repo.website, 22 | signingKeyFingerprint = repo.signingKeyFingerprint, 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupHistory.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.backup.models 2 | 3 | import kotlinx.serialization.Serializable 4 | import kotlinx.serialization.protobuf.ProtoNumber 5 | import tachiyomi.domain.history.model.History 6 | import java.util.Date 7 | 8 | @Serializable 9 | data class BackupHistory( 10 | @ProtoNumber(1) var url: String, 11 | @ProtoNumber(2) var lastRead: Long, 12 | @ProtoNumber(3) var readDuration: Long = 0, 13 | ) { 14 | fun getHistoryImpl(): History { 15 | return History.create().copy( 16 | readAt = Date(lastRead), 17 | readDuration = readDuration, 18 | ) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupSource.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.backup.models 2 | 3 | import kotlinx.serialization.Serializable 4 | import kotlinx.serialization.protobuf.ProtoNumber 5 | 6 | @Serializable 7 | data class BackupSource( 8 | @ProtoNumber(1) var name: String = "", 9 | @ProtoNumber(2) var sourceId: Long, 10 | ) 11 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/database/models/TrackImpl.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("PropertyName") 2 | 3 | package eu.kanade.tachiyomi.data.database.models 4 | 5 | class TrackImpl : Track { 6 | 7 | override var id: Long? = null 8 | 9 | override var manga_id: Long = 0 10 | 11 | override var tracker_id: Long = 0 12 | 13 | override var remote_id: Long = 0 14 | 15 | override var library_id: Long? = null 16 | 17 | override lateinit var title: String 18 | 19 | override var last_chapter_read: Double = 0.0 20 | 21 | override var total_chapters: Long = 0 22 | 23 | override var score: Double = 0.0 24 | 25 | override var status: Long = 0 26 | 27 | override var started_reading_date: Long = 0 28 | 29 | override var finished_reading_date: Long = 0 30 | 31 | override var tracking_url: String = "" 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/DeletableTracker.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track 2 | 3 | import tachiyomi.domain.track.model.Track 4 | 5 | /** 6 | * Tracker that support deleting am entry from a user's list. 7 | */ 8 | interface DeletableTracker { 9 | 10 | suspend fun delete(track: Track) 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALAddManga.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.anilist.dto 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class ALAddMangaResult( 8 | val data: ALAddMangaData, 9 | ) 10 | 11 | @Serializable 12 | data class ALAddMangaData( 13 | @SerialName("SaveMediaListEntry") 14 | val entry: ALAddMangaEntry, 15 | ) 16 | 17 | @Serializable 18 | data class ALAddMangaEntry( 19 | val id: Long, 20 | ) 21 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALFuzzyDate.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.anilist.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | import java.time.LocalDate 5 | import java.time.ZoneId 6 | 7 | @Serializable 8 | data class ALFuzzyDate( 9 | val year: Int?, 10 | val month: Int?, 11 | val day: Int?, 12 | ) { 13 | fun toEpochMilli(): Long = try { 14 | LocalDate.of(year!!, month!!, day!!) 15 | .atStartOfDay(ZoneId.systemDefault()) 16 | .toInstant() 17 | .toEpochMilli() 18 | } catch (_: Exception) { 19 | 0L 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALOAuth.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.anilist.dto 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class ALOAuth( 8 | @SerialName("access_token") 9 | val accessToken: String, 10 | @SerialName("token_type") 11 | val tokenType: String, 12 | val expires: Long, 13 | @SerialName("expires_in") 14 | val expiresIn: Long, 15 | ) 16 | 17 | fun ALOAuth.isExpired() = System.currentTimeMillis() > expires 18 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALSearch.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.anilist.dto 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class ALSearchResult( 8 | val data: ALSearchPage, 9 | ) 10 | 11 | @Serializable 12 | data class ALSearchPage( 13 | @SerialName("Page") 14 | val page: ALSearchMedia, 15 | ) 16 | 17 | @Serializable 18 | data class ALSearchMedia( 19 | val media: List, 20 | ) 21 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALUser.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.anilist.dto 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class ALCurrentUserResult( 8 | val data: ALUserViewer, 9 | ) 10 | 11 | @Serializable 12 | data class ALUserViewer( 13 | @SerialName("Viewer") 14 | val viewer: ALUserViewerData, 15 | ) 16 | 17 | @Serializable 18 | data class ALUserViewerData( 19 | val id: Int, 20 | val mediaListOptions: ALUserListOptions, 21 | ) 22 | 23 | @Serializable 24 | data class ALUserListOptions( 25 | val scoreFormat: String, 26 | ) 27 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiUtils.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.bangumi 2 | 3 | import eu.kanade.tachiyomi.data.database.models.Track 4 | 5 | fun Track.toApiStatus() = when (status) { 6 | Bangumi.READING -> "do" 7 | Bangumi.COMPLETED -> "collect" 8 | Bangumi.ON_HOLD -> "on_hold" 9 | Bangumi.DROPPED -> "dropped" 10 | Bangumi.PLAN_TO_READ -> "wish" 11 | else -> throw NotImplementedError("Unknown status: $status") 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/dto/BGMCollectionResponse.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.bangumi.dto 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class BGMCollectionResponse( 8 | val code: Int?, 9 | val `private`: Int? = 0, 10 | val comment: String? = "", 11 | @SerialName("ep_status") 12 | val epStatus: Int? = 0, 13 | @SerialName("lasttouch") 14 | val lastTouch: Int? = 0, 15 | val rating: Double? = 0.0, 16 | val status: Status? = Status(), 17 | val tag: List? = emptyList(), 18 | val user: User? = User(), 19 | @SerialName("vol_status") 20 | val volStatus: Int? = 0, 21 | ) 22 | 23 | @Serializable 24 | data class Status( 25 | val id: Long? = 0, 26 | val name: String? = "", 27 | val type: String? = "", 28 | ) 29 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/dto/BGMOAuth.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.bangumi.dto 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class BGMOAuth( 8 | @SerialName("access_token") 9 | val accessToken: String, 10 | @SerialName("token_type") 11 | val tokenType: String, 12 | @SerialName("created_at") 13 | val createdAt: Long = System.currentTimeMillis() / 1000, 14 | @SerialName("expires_in") 15 | val expiresIn: Long, 16 | @SerialName("refresh_token") 17 | val refreshToken: String?, 18 | @SerialName("user_id") 19 | val userId: Long?, 20 | ) 21 | 22 | // Access token refresh before expired 23 | fun BGMOAuth.isExpired() = (System.currentTimeMillis() / 1000) > (createdAt + expiresIn - 3600) 24 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/dto/BGMUser.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.bangumi.dto 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class Avatar( 8 | val large: String? = "", 9 | val medium: String? = "", 10 | val small: String? = "", 11 | ) 12 | 13 | @Serializable 14 | data class User( 15 | val avatar: Avatar? = Avatar(), 16 | val id: Int? = 0, 17 | val nickname: String? = "", 18 | val sign: String? = "", 19 | val url: String? = "", 20 | @SerialName("usergroup") 21 | val userGroup: Int? = 0, 22 | val username: String? = "", 23 | ) 24 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuDateHelper.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.kitsu 2 | 3 | import java.text.SimpleDateFormat 4 | import java.util.Date 5 | import java.util.Locale 6 | 7 | object KitsuDateHelper { 8 | 9 | private const val PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" 10 | private val formatter = SimpleDateFormat(PATTERN, Locale.ENGLISH) 11 | 12 | fun convert(dateValue: Long): String? { 13 | if (dateValue == 0L) return null 14 | 15 | return formatter.format(Date(dateValue)) 16 | } 17 | 18 | fun parse(dateString: String?): Long { 19 | if (dateString == null) return 0L 20 | 21 | val dateValue = formatter.parse(dateString) 22 | 23 | return dateValue?.time ?: return 0 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuUtils.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.kitsu 2 | 3 | import eu.kanade.tachiyomi.data.database.models.Track 4 | 5 | fun Track.toApiStatus() = when (status) { 6 | Kitsu.READING -> "current" 7 | Kitsu.COMPLETED -> "completed" 8 | Kitsu.ON_HOLD -> "on_hold" 9 | Kitsu.DROPPED -> "dropped" 10 | Kitsu.PLAN_TO_READ -> "planned" 11 | else -> throw Exception("Unknown status") 12 | } 13 | 14 | fun Track.toApiScore(): String? { 15 | return if (score > 0) (score * 2).toInt().toString() else null 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/dto/KitsuAddManga.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.kitsu.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class KitsuAddMangaResult( 7 | val data: KitsuAddMangaItem, 8 | ) 9 | 10 | @Serializable 11 | data class KitsuAddMangaItem( 12 | val id: Long, 13 | ) 14 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/dto/KitsuOAuth.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.kitsu.dto 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class KitsuOAuth( 8 | @SerialName("access_token") 9 | val accessToken: String, 10 | @SerialName("token_type") 11 | val tokenType: String, 12 | @SerialName("created_at") 13 | val createdAt: Long, 14 | @SerialName("expires_in") 15 | val expiresIn: Long, 16 | @SerialName("refresh_token") 17 | val refreshToken: String?, 18 | ) 19 | 20 | fun KitsuOAuth.isExpired() = (System.currentTimeMillis() / 1000) > (createdAt + expiresIn - 3600) 21 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/dto/KitsuSearchItemCover.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.kitsu.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class KitsuSearchItemCover( 7 | val original: String?, 8 | ) 9 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/dto/KitsuUser.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.kitsu.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class KitsuCurrentUserResult( 7 | val data: List, 8 | ) 9 | 10 | @Serializable 11 | data class KitsuUser( 12 | val id: String, 13 | ) 14 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/dto/MUContext.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.mangaupdates.dto 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class MUContext( 8 | @SerialName("session_token") 9 | val sessionToken: String, 10 | val uid: Long, 11 | ) 12 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/dto/MUImage.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.mangaupdates.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class MUImage( 7 | val url: MUUrl? = null, 8 | val height: Int? = null, 9 | val width: Int? = null, 10 | ) 11 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/dto/MUListItem.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.mangaupdates.dto 2 | 3 | import eu.kanade.tachiyomi.data.database.models.Track 4 | import eu.kanade.tachiyomi.data.track.mangaupdates.MangaUpdates.Companion.READING_LIST 5 | import kotlinx.serialization.SerialName 6 | import kotlinx.serialization.Serializable 7 | 8 | @Serializable 9 | data class MUListItem( 10 | val series: MUSeries? = null, 11 | @SerialName("list_id") 12 | val listId: Long? = null, 13 | val status: MUStatus? = null, 14 | val priority: Int? = null, 15 | ) 16 | 17 | fun MUListItem.copyTo(track: Track): Track { 18 | return track.apply { 19 | this.status = listId ?: READING_LIST 20 | this.last_chapter_read = this@copyTo.status?.chapter?.toDouble() ?: 0.0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/dto/MULoginResponse.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.mangaupdates.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class MULoginResponse( 7 | val context: MUContext, 8 | ) 9 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/dto/MURating.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.mangaupdates.dto 2 | 3 | import eu.kanade.tachiyomi.data.database.models.Track 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class MURating( 8 | val rating: Double? = null, 9 | ) 10 | 11 | fun MURating.copyTo(track: Track): Track { 12 | return track.apply { 13 | this.score = rating ?: 0.0 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/dto/MUSearch.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.mangaupdates.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class MUSearchResult( 7 | val results: List, 8 | ) 9 | 10 | @Serializable 11 | data class MUSearchResultItem( 12 | val record: MURecord, 13 | ) 14 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/dto/MUSeries.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.mangaupdates.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class MUSeries( 7 | val id: Long? = null, 8 | val title: String? = null, 9 | ) 10 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/dto/MUStatus.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.mangaupdates.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class MUStatus( 7 | val volume: Int? = null, 8 | val chapter: Int? = null, 9 | ) 10 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/dto/MUUrl.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.mangaupdates.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class MUUrl( 7 | val original: String? = null, 8 | val thumb: String? = null, 9 | ) 10 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListUtils.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.myanimelist 2 | 3 | import eu.kanade.tachiyomi.data.database.models.Track 4 | 5 | fun Track.toMyAnimeListStatus() = when (status) { 6 | MyAnimeList.READING -> "reading" 7 | MyAnimeList.COMPLETED -> "completed" 8 | MyAnimeList.ON_HOLD -> "on_hold" 9 | MyAnimeList.DROPPED -> "dropped" 10 | MyAnimeList.PLAN_TO_READ -> "plan_to_read" 11 | MyAnimeList.REREADING -> "reading" 12 | else -> null 13 | } 14 | 15 | fun getStatus(status: String?) = when (status) { 16 | "reading" -> MyAnimeList.READING 17 | "completed" -> MyAnimeList.COMPLETED 18 | "on_hold" -> MyAnimeList.ON_HOLD 19 | "dropped" -> MyAnimeList.DROPPED 20 | "plan_to_read" -> MyAnimeList.PLAN_TO_READ 21 | else -> MyAnimeList.READING 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/dto/MALList.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.myanimelist.dto 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class MALListItem( 8 | @SerialName("num_chapters") 9 | val numChapters: Long, 10 | @SerialName("my_list_status") 11 | val myListStatus: MALListItemStatus?, 12 | ) 13 | 14 | @Serializable 15 | data class MALListItemStatus( 16 | @SerialName("is_rereading") 17 | val isRereading: Boolean, 18 | val status: String, 19 | @SerialName("num_chapters_read") 20 | val numChaptersRead: Double, 21 | val score: Int, 22 | @SerialName("start_date") 23 | val startDate: String?, 24 | @SerialName("finish_date") 25 | val finishDate: String?, 26 | ) 27 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/dto/MALManga.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.myanimelist.dto 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class MALManga( 8 | val id: Long, 9 | val title: String, 10 | val synopsis: String = "", 11 | @SerialName("num_chapters") 12 | val numChapters: Long, 13 | val mean: Double = -1.0, 14 | @SerialName("main_picture") 15 | val covers: MALMangaCovers, 16 | val status: String, 17 | @SerialName("media_type") 18 | val mediaType: String, 19 | @SerialName("start_date") 20 | val startDate: String?, 21 | ) 22 | 23 | @Serializable 24 | data class MALMangaCovers( 25 | val large: String = "", 26 | ) 27 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/dto/MALOAuth.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.myanimelist.dto 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class MALOAuth( 8 | @SerialName("token_type") 9 | val tokenType: String, 10 | @SerialName("refresh_token") 11 | val refreshToken: String, 12 | @SerialName("access_token") 13 | val accessToken: String, 14 | @SerialName("expires_in") 15 | val expiresIn: Long, 16 | @SerialName("created_at") 17 | val createdAt: Long = System.currentTimeMillis(), 18 | ) { 19 | // Assumes expired a minute earlier 20 | private val adjustedExpiresIn: Long = (expiresIn - 60) * 1000 21 | 22 | fun isExpired() = createdAt + adjustedExpiresIn < System.currentTimeMillis() 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/dto/MALSearch.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.myanimelist.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class MALSearchResult( 7 | val data: List, 8 | ) 9 | 10 | @Serializable 11 | data class MALSearchResultNode( 12 | val node: MALSearchResultItem, 13 | ) 14 | 15 | @Serializable 16 | data class MALSearchResultItem( 17 | val id: Int, 18 | ) 19 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/dto/MALUser.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.myanimelist.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class MALUser( 7 | val name: String, 8 | ) 9 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/dto/MALUserListSearch.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.myanimelist.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class MALUserSearchResult( 7 | val data: List, 8 | val paging: MALUserSearchPaging, 9 | ) 10 | 11 | @Serializable 12 | data class MALUserSearchItem( 13 | val node: MALUserSearchItemNode, 14 | ) 15 | 16 | @Serializable 17 | data class MALUserSearchPaging( 18 | val next: String?, 19 | ) 20 | 21 | @Serializable 22 | data class MALUserSearchItemNode( 23 | val id: Int, 24 | val title: String, 25 | ) 26 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMAddMangaResponse.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.shikimori.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class SMAddMangaResponse( 7 | val id: Long, 8 | ) 9 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMOAuth.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.shikimori.dto 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class SMOAuth( 8 | @SerialName("access_token") 9 | val accessToken: String, 10 | @SerialName("token_type") 11 | val tokenType: String, 12 | @SerialName("created_at") 13 | val createdAt: Long, 14 | @SerialName("expires_in") 15 | val expiresIn: Long, 16 | @SerialName("refresh_token") 17 | val refreshToken: String?, 18 | ) 19 | 20 | // Access token lives 1 day 21 | fun SMOAuth.isExpired() = (System.currentTimeMillis() / 1000) > (createdAt + expiresIn - 3600) 22 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMUser.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.data.track.shikimori.dto 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class SMUser( 7 | val id: Int, 8 | ) 9 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/extension/model/InstallStep.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.extension.model 2 | 3 | enum class InstallStep { 4 | Idle, 5 | Pending, 6 | Downloading, 7 | Installing, 8 | Installed, 9 | Error, 10 | ; 11 | 12 | fun isCompleted(): Boolean { 13 | return this == Installed || this == Error || this == Idle 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/extension/model/LoadResult.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.extension.model 2 | 3 | sealed interface LoadResult { 4 | data class Success(val extension: Extension.Installed) : LoadResult 5 | data class Untrusted(val extension: Extension.Untrusted) : LoadResult 6 | data object Error : LoadResult 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkActivity.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.ui.deeplink 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import eu.kanade.tachiyomi.ui.main.MainActivity 7 | 8 | class DeepLinkActivity : Activity() { 9 | 10 | override fun onCreate(savedInstanceState: Bundle?) { 11 | super.onCreate(savedInstanceState) 12 | 13 | intent.apply { 14 | flags = flags or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK 15 | setClass(applicationContext, MainActivity::class.java) 16 | } 17 | startActivity(intent) 18 | finish() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackItem.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.ui.manga.track 2 | 3 | import eu.kanade.tachiyomi.data.track.Tracker 4 | import tachiyomi.domain.track.model.Track 5 | 6 | data class TrackItem(val track: Track?, val tracker: Tracker) 7 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/InsertPage.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.ui.reader.model 2 | 3 | class InsertPage(val parent: ReaderPage) : ReaderPage(parent.index, parent.url, parent.imageUrl) { 4 | 5 | override var chapter: ReaderChapter = parent.chapter 6 | 7 | init { 8 | status = State.READY 9 | stream = parent.stream 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/ReaderPage.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.ui.reader.model 2 | 3 | import eu.kanade.tachiyomi.source.model.Page 4 | import eu.kanade.translation.model.PageTranslation 5 | import java.io.InputStream 6 | 7 | open class ReaderPage( 8 | index: Int, 9 | url: String = "", 10 | imageUrl: String? = null, 11 | var translation: PageTranslation? = null, 12 | var stream: (() -> InputStream)? = null, 13 | ) : Page(index, url, imageUrl, null) { 14 | 15 | open lateinit var chapter: ReaderChapter 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/ViewerChapters.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.ui.reader.model 2 | 3 | data class ViewerChapters( 4 | val currChapter: ReaderChapter, 5 | val prevChapter: ReaderChapter?, 6 | val nextChapter: ReaderChapter?, 7 | ) { 8 | 9 | fun ref() { 10 | currChapter.ref() 11 | prevChapter?.ref() 12 | nextChapter?.ref() 13 | } 14 | 15 | fun unref() { 16 | currChapter.unref() 17 | prevChapter?.unref() 18 | nextChapter?.unref() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/MissingChapters.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.ui.reader.viewer 2 | 3 | import eu.kanade.tachiyomi.data.database.models.toDomainChapter 4 | import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter 5 | import tachiyomi.domain.chapter.service.calculateChapterGap as domainCalculateChapterGap 6 | 7 | fun calculateChapterGap(higherReaderChapter: ReaderChapter?, lowerReaderChapter: ReaderChapter?): Int { 8 | return domainCalculateChapterGap( 9 | higherReaderChapter?.chapter?.toDomainChapter(), 10 | lowerReaderChapter?.chapter?.toDomainChapter(), 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/navigation/DisabledNavigation.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.ui.reader.viewer.navigation 2 | 3 | import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation 4 | 5 | /** 6 | * Visualization of default state without any inversion 7 | * +---+---+---+ 8 | * | M | M | M | P: Previous 9 | * +---+---+---+ 10 | * | M | M | M | M: Menu 11 | * +---+---+---+ 12 | * | M | M | M | N: Next 13 | * +---+---+---+ 14 | */ 15 | class DisabledNavigation : ViewerNavigation() { 16 | 17 | override var regionList: List = emptyList() 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/navigation/KindlishNavigation.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.ui.reader.viewer.navigation 2 | 3 | import android.graphics.RectF 4 | import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation 5 | 6 | /** 7 | * Visualization of default state without any inversion 8 | * +---+---+---+ 9 | * | M | M | M | P: Previous 10 | * +---+---+---+ 11 | * | P | N | N | M: Menu 12 | * +---+---+---+ 13 | * | P | N | N | N: Next 14 | * +---+---+---+ 15 | */ 16 | class KindlishNavigation : ViewerNavigation() { 17 | 18 | override var regionList: List = listOf( 19 | Region( 20 | rectF = RectF(0.33f, 0.33f, 1f, 1f), 21 | type = NavigationRegion.NEXT, 22 | ), 23 | Region( 24 | rectF = RectF(0f, 0.33f, 0.33f, 1f), 25 | type = NavigationRegion.PREV, 26 | ), 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/navigation/RightAndLeftNavigation.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.ui.reader.viewer.navigation 2 | 3 | import android.graphics.RectF 4 | import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation 5 | 6 | /** 7 | * Visualization of default state without any inversion 8 | * +---+---+---+ 9 | * | N | M | P | P: Move Right 10 | * +---+---+---+ 11 | * | N | M | P | M: Menu 12 | * +---+---+---+ 13 | * | N | M | P | N: Move Left 14 | * +---+---+---+ 15 | */ 16 | class RightAndLeftNavigation : ViewerNavigation() { 17 | 18 | override var regionList: List = listOf( 19 | Region( 20 | rectF = RectF(0f, 0f, 0.33f, 1f), 21 | type = NavigationRegion.LEFT, 22 | ), 23 | Region( 24 | rectF = RectF(0.66f, 0f, 1f, 1f), 25 | type = NavigationRegion.RIGHT, 26 | ), 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonSubsamplingImageView.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.ui.reader.viewer.webtoon 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.MotionEvent 6 | import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView 7 | 8 | /** 9 | * Implementation of subsampling scale image view that ignores all touch events, because the 10 | * webtoon viewer handles all the gestures. 11 | */ 12 | class WebtoonSubsamplingImageView @JvmOverloads constructor( 13 | context: Context, 14 | attrs: AttributeSet? = null, 15 | ) : SubsamplingScaleImageView(context, attrs) { 16 | 17 | override fun onTouchEvent(event: MotionEvent): Boolean { 18 | return false 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/util/PkceUtil.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.util 2 | 3 | import java.security.SecureRandom 4 | import java.util.Base64 5 | 6 | object PkceUtil { 7 | 8 | fun generateCodeVerifier(): String { 9 | val codeVerifier = ByteArray(50) 10 | SecureRandom().nextBytes(codeVerifier) 11 | return Base64.getUrlEncoder() 12 | .withoutPadding() 13 | .encodeToString(codeVerifier) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterFilterDownloaded.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.util.chapter 2 | 3 | import eu.kanade.tachiyomi.data.download.DownloadCache 4 | import tachiyomi.domain.chapter.model.Chapter 5 | import tachiyomi.domain.manga.model.Manga 6 | import tachiyomi.source.local.isLocal 7 | import uy.kohesive.injekt.Injekt 8 | import uy.kohesive.injekt.api.get 9 | 10 | /** 11 | * Returns a copy of the list with not downloaded chapters removed. 12 | */ 13 | fun List.filterDownloaded(manga: Manga): List { 14 | if (manga.isLocal()) return this 15 | 16 | val downloadCache: DownloadCache = Injekt.get() 17 | 18 | return filter { downloadCache.isChapterDownloaded(it.name, it.scanlator, manga.title, manga.source, false) } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterRemoveDuplicates.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.util.chapter 2 | 3 | import tachiyomi.domain.chapter.model.Chapter 4 | 5 | /** 6 | * Returns a copy of the list with duplicate chapters removed 7 | */ 8 | fun List.removeDuplicates(currentChapter: Chapter): List { 9 | return groupBy { it.chapterNumber } 10 | .map { (_, chapters) -> 11 | chapters.find { it.id == currentChapter.id } 12 | ?: chapters.find { it.scanlator == currentChapter.scanlator } 13 | ?: chapters.first() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/util/lang/RectFExtensions.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.util.lang 2 | 3 | import android.graphics.RectF 4 | import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences 5 | 6 | fun RectF.invert(invertMode: ReaderPreferences.TappingInvertMode): RectF { 7 | val horizontal = invertMode.shouldInvertHorizontal 8 | val vertical = invertMode.shouldInvertVertical 9 | return when { 10 | horizontal && vertical -> RectF(1f - this.right, 1f - this.bottom, 1f - this.left, 1f - this.top) 11 | vertical -> RectF(this.left, 1f - this.bottom, this.right, 1f - this.top) 12 | horizontal -> RectF(1f - this.right, this.top, 1f - this.left, this.bottom) 13 | else -> this 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/util/system/AnimationExtensions.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.util.system 2 | 3 | import android.content.Context 4 | import android.provider.Settings 5 | 6 | /** 7 | * Gets the duration multiplier for general animations on the device 8 | * @see Settings.Global.ANIMATOR_DURATION_SCALE 9 | */ 10 | val Context.animatorDurationScale: Float 11 | get() = Settings.Global.getFloat(this.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1f) 12 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/util/system/BuildConfig.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.util.system 2 | 3 | import eu.kanade.tachiyomi.BuildConfig 4 | 5 | val isDevFlavor: Boolean 6 | get() = BuildConfig.FLAVOR == "dev" 7 | 8 | val isPreviewBuildType: Boolean 9 | get() = BuildConfig.BUILD_TYPE == "preview" 10 | 11 | val isReleaseBuildType: Boolean 12 | get() = BuildConfig.BUILD_TYPE == "release" 13 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/util/system/DeviceUtilExtensions.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.util.system 2 | 3 | import android.os.Build 4 | import com.google.android.material.color.DynamicColors 5 | 6 | val DeviceUtil.isDynamicColorAvailable by lazy { 7 | DynamicColors.isDynamicColorAvailable() || (DeviceUtil.isSamsung && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/util/system/DrawableExtensions.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.util.system 2 | 3 | import android.graphics.Bitmap 4 | import android.graphics.drawable.BitmapDrawable 5 | import android.graphics.drawable.Drawable 6 | import androidx.core.graphics.drawable.toBitmap 7 | import coil3.size.ScaleDrawable 8 | 9 | fun Drawable.getBitmapOrNull(): Bitmap? = when (this) { 10 | is BitmapDrawable -> bitmap 11 | is ScaleDrawable -> child.toBitmap() 12 | else -> null 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/util/view/EditTextPreferenceExtensions.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("PackageDirectoryMismatch") 2 | 3 | package androidx.preference 4 | 5 | /** 6 | * Returns package-private [EditTextPreference.getOnBindEditTextListener] 7 | */ 8 | fun EditTextPreference.getOnBindEditTextListener(): EditTextPreference.OnBindEditTextListener? { 9 | return onBindEditTextListener 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/tachiyomi/util/view/WindowExtensions.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.tachiyomi.util.view 2 | 3 | import android.view.Window 4 | import android.view.WindowManager 5 | 6 | fun Window.setSecureScreen(enabled: Boolean) { 7 | if (enabled) { 8 | setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE) 9 | } else { 10 | clearFlags(WindowManager.LayoutParams.FLAG_SECURE) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/translation/data/TranslationFont.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.translation.data 2 | import eu.kanade.tachiyomi.R 3 | import tachiyomi.core.common.preference.Preference 4 | 5 | enum class TranslationFont(var label: String, var res: Int) { 6 | ANIME_ACE("Anime Ace", R.font.animeace), 7 | MANGA_MASTER_BB("Manga Master BB", R.font.manga_master_bb), 8 | COMIC_FONT("Comic Font", R.font.comic_book), 9 | ; 10 | 11 | companion object { 12 | fun fromPref(pref: Preference): TranslationFont { 13 | var font = TranslationFont.entries.getOrNull(pref.get()) 14 | if (font == null) { 15 | pref.set(0) 16 | return ANIME_ACE 17 | } 18 | return font 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/translation/model/PageTranslation.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.translation.model 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class PageTranslation( 7 | var blocks: MutableList = mutableListOf(), 8 | var imgWidth: Float = 0f, 9 | var imgHeight: Float = 0f, 10 | ) { 11 | companion object { 12 | val EMPTY = PageTranslation() 13 | } 14 | } 15 | 16 | @Serializable 17 | data class TranslationBlock( 18 | var text: String, 19 | var translation: String = "", 20 | var width: Float, 21 | var height: Float, 22 | var x: Float, 23 | var y: Float, 24 | var symHeight: Float, 25 | var symWidth: Float, 26 | val angle: Float, 27 | 28 | ) 29 | -------------------------------------------------------------------------------- /app/src/main/java/eu/kanade/translation/presentation/Utils.kt: -------------------------------------------------------------------------------- 1 | package eu.kanade.translation.presentation 2 | import androidx.compose.runtime.Composable 3 | import androidx.compose.ui.platform.LocalDensity 4 | import androidx.compose.ui.unit.Dp 5 | import androidx.compose.ui.unit.dp 6 | 7 | @Composable 8 | fun Float.pxToDp(): Dp { 9 | return (this / LocalDensity.current.density).dp 10 | // val density = LocalDensity.current.density 11 | // return (this / (density / DisplayMetrics.DENSITY_DEFAULT)).dp 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/mihon/core/designsystem/utils/WindowSize.kt: -------------------------------------------------------------------------------- 1 | package mihon.core.designsystem.utils 2 | 3 | import androidx.compose.runtime.Composable 4 | import androidx.compose.runtime.ReadOnlyComposable 5 | import androidx.compose.ui.platform.LocalConfiguration 6 | import androidx.compose.ui.unit.dp 7 | 8 | @Composable 9 | @ReadOnlyComposable 10 | fun isMediumWidthWindow(): Boolean { 11 | val configuration = LocalConfiguration.current 12 | return configuration.screenWidthDp > MediumWidthWindowSize.value 13 | } 14 | 15 | @Composable 16 | @ReadOnlyComposable 17 | fun isExpandedWidthWindow(): Boolean { 18 | val configuration = LocalConfiguration.current 19 | return configuration.screenWidthDp > ExpandedWidthWindowSize.value 20 | } 21 | 22 | val MediumWidthWindowSize = 600.dp 23 | val ExpandedWidthWindowSize = 840.dp 24 | -------------------------------------------------------------------------------- /app/src/main/java/mihon/core/migration/Migration.kt: -------------------------------------------------------------------------------- 1 | package mihon.core.migration 2 | 3 | interface Migration { 4 | val version: Float 5 | 6 | suspend operator fun invoke(migrationContext: MigrationContext): Boolean 7 | 8 | val isAlways: Boolean 9 | get() = version == ALWAYS 10 | 11 | companion object { 12 | const val ALWAYS = -1f 13 | 14 | fun of(version: Float, action: suspend (MigrationContext) -> Boolean): Migration = object : Migration { 15 | override val version: Float = version 16 | 17 | override suspend operator fun invoke(migrationContext: MigrationContext): Boolean { 18 | return action(migrationContext) 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/mihon/core/migration/MigrationCompletedListener.kt: -------------------------------------------------------------------------------- 1 | package mihon.core.migration 2 | 3 | typealias MigrationCompletedListener = () -> Unit 4 | -------------------------------------------------------------------------------- /app/src/main/java/mihon/core/migration/MigrationContext.kt: -------------------------------------------------------------------------------- 1 | package mihon.core.migration 2 | 3 | import uy.kohesive.injekt.Injekt 4 | 5 | class MigrationContext(val dryrun: Boolean) { 6 | 7 | inline fun get(): T? { 8 | return Injekt.getInstanceOrNull(T::class.java) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/mihon/core/migration/MigrationStrategyFactory.kt: -------------------------------------------------------------------------------- 1 | package mihon.core.migration 2 | 3 | class MigrationStrategyFactory( 4 | private val factory: MigrationJobFactory, 5 | private val migrationCompletedListener: MigrationCompletedListener, 6 | ) { 7 | 8 | fun create(old: Int, new: Int): MigrationStrategy { 9 | val strategy = when { 10 | old == 0 -> InitialMigrationStrategy( 11 | strategy = DefaultMigrationStrategy(factory, migrationCompletedListener, Migrator.scope), 12 | ) 13 | old >= new -> NoopMigrationStrategy(false) 14 | else -> VersionRangeMigrationStrategy( 15 | versions = (old + 1)..new, 16 | strategy = DefaultMigrationStrategy(factory, migrationCompletedListener, Migrator.scope), 17 | ) 18 | } 19 | return strategy 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/mihon/core/migration/migrations/Migrations.kt: -------------------------------------------------------------------------------- 1 | package mihon.core.migration.migrations 2 | 3 | import mihon.core.migration.Migration 4 | 5 | val migrations: List 6 | get() = listOf( 7 | SetupBackupCreateMigration(), 8 | SetupLibraryUpdateMigration(), 9 | TrustExtensionRepositoryMigration(), 10 | ) 11 | -------------------------------------------------------------------------------- /app/src/main/java/mihon/core/migration/migrations/SetupBackupCreateMigration.kt: -------------------------------------------------------------------------------- 1 | package mihon.core.migration.migrations 2 | 3 | import android.app.Application 4 | import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob 5 | import mihon.core.migration.Migration 6 | import mihon.core.migration.MigrationContext 7 | 8 | class SetupBackupCreateMigration : Migration { 9 | override val version: Float = Migration.ALWAYS 10 | 11 | override suspend fun invoke(migrationContext: MigrationContext): Boolean { 12 | val context = migrationContext.get() ?: return false 13 | BackupCreateJob.setupTask(context) 14 | return true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/mihon/core/migration/migrations/SetupLibraryUpdateMigration.kt: -------------------------------------------------------------------------------- 1 | package mihon.core.migration.migrations 2 | 3 | import android.app.Application 4 | import eu.kanade.tachiyomi.data.library.LibraryUpdateJob 5 | import mihon.core.migration.Migration 6 | import mihon.core.migration.MigrationContext 7 | 8 | class SetupLibraryUpdateMigration : Migration { 9 | override val version: Float = Migration.ALWAYS 10 | 11 | override suspend fun invoke(migrationContext: MigrationContext): Boolean { 12 | val context = migrationContext.get() ?: return false 13 | LibraryUpdateJob.setupTask(context) 14 | return true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/mihon/feature/upcoming/UpcomingUIModel.kt: -------------------------------------------------------------------------------- 1 | package mihon.feature.upcoming 2 | 3 | import tachiyomi.domain.manga.model.Manga 4 | import java.time.LocalDate 5 | 6 | sealed interface UpcomingUIModel { 7 | data class Header(val date: LocalDate, val mangaCount: Int) : UpcomingUIModel 8 | data class Item(val manga: Manga) : UpcomingUIModel 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim-v33/shared_axis_x_pop_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/anim-v33/shared_axis_x_pop_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim-v33/shared_axis_x_push_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/anim-v33/shared_axis_x_push_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/shared_axis_x_pop_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/anim/shared_axis_x_pop_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/shared_axis_x_push_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/anim/shared_axis_x_push_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/color/draggable_card_foreground.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_manga_updates.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/drawable-nodpi/ic_manga_updates.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_tracker_anilist.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/drawable-nodpi/ic_tracker_anilist.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_tracker_bangumi.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/drawable-nodpi/ic_tracker_bangumi.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_tracker_kavita.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/drawable-nodpi/ic_tracker_kavita.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_tracker_kitsu.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/drawable-nodpi/ic_tracker_kitsu.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_tracker_komga.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/drawable-nodpi/ic_tracker_komga.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_tracker_mal.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/drawable-nodpi/ic_tracker_mal.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_tracker_shikimori.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/drawable-nodpi/ic_tracker_shikimori.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_tracker_suwayomi.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/drawable-nodpi/ic_tracker_suwayomi.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_book_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_close_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_crop_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_crop_off_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_done_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_done_prev_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_download_chapter_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_drag_handle_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_extension_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_folder_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_mihon_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_overflow_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_pause_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_photo_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_play_arrow_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reader_continuous_vertical_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reader_vertical_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reader_webtoon_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_refresh_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_system_update_alt_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_warning_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/line_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/material_popup_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/font/animeace.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/font/animeace.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/comic_book.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/font/comic_book.otf -------------------------------------------------------------------------------- /app/src/main/res/font/manga_master_bb.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/font/manga_master_bb.ttf -------------------------------------------------------------------------------- /app/src/main/res/layout/download_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/pref_widget_switch_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/menu/download_single.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 11 | 12 | 15 | 16 | 19 | 20 | 23 | 24 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_default_source.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/mipmap-hdpi/ic_default_source.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_local_source.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/mipmap-hdpi/ic_local_source.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_default_source.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/mipmap-mdpi/ic_default_source.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_local_source.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/mipmap-mdpi/ic_local_source.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_default_source.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/mipmap-xhdpi/ic_default_source.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_local_source.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/mipmap-xhdpi/ic_local_source.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_default_source.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/mipmap-xxhdpi/ic_default_source.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_local_source.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/mipmap-xxhdpi/ic_local_source.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_default_source.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/mipmap-xxxhdpi/ic_default_source.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_local_source.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mannu691/TachiyomiAT/10c782836c26352c87bb2a912efc003be849f6e4/app/src/main/res/mipmap-xxxhdpi/ic_local_source.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/bools.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | false 5 | true 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/values-v27/bools.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | true 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values-v27/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 |