├── .editorconfig
├── .gitattributes
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── report_issue.yml
│ └── request_feature.yml
├── assets
│ └── logo.png
├── pull_request_template.md
├── renovate.json5
└── workflows
│ ├── build_pull_request.yml
│ └── build_push.yml
├── .gitignore
├── .idea
└── icon.png
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── app
├── .idea
│ ├── .gitignore
│ ├── .name
│ ├── discord.xml
│ ├── gradle.xml
│ ├── misc.xml
│ └── vcs.xml
├── build.gradle.kts
├── proguard-android-optimize.txt
├── proguard-rules.pro
├── shortcuts.xml
└── src
│ ├── debug
│ ├── ic_launcher-playstore.png
│ └── res
│ │ ├── drawable
│ │ └── ic_launcher_foreground.xml
│ │ └── mipmap
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── aniyomi.lua
│ ├── baseline-prof.txt
│ ├── java
│ │ ├── aniyomi
│ │ │ └── util
│ │ │ │ └── DataSaver.kt
│ │ ├── eu
│ │ │ └── kanade
│ │ │ │ ├── core
│ │ │ │ ├── preference
│ │ │ │ │ ├── CheckboxState.kt
│ │ │ │ │ └── PreferenceMutableState.kt
│ │ │ │ └── util
│ │ │ │ │ ├── AnimeSourceUtil.kt
│ │ │ │ │ ├── CollectionUtils.kt
│ │ │ │ │ ├── MangaSourceUtil.kt
│ │ │ │ │ └── RxJavaExtensions.kt
│ │ │ │ ├── domain
│ │ │ │ ├── DomainModule.kt
│ │ │ │ ├── SYDomainModule.kt
│ │ │ │ ├── base
│ │ │ │ │ ├── BasePreferences.kt
│ │ │ │ │ └── ExtensionInstallerPreference.kt
│ │ │ │ ├── download
│ │ │ │ │ ├── anime
│ │ │ │ │ │ └── interactor
│ │ │ │ │ │ │ └── DeleteEpisodeDownload.kt
│ │ │ │ │ └── manga
│ │ │ │ │ │ └── interactor
│ │ │ │ │ │ └── DeleteChapterDownload.kt
│ │ │ │ ├── entries
│ │ │ │ │ ├── anime
│ │ │ │ │ │ ├── interactor
│ │ │ │ │ │ │ ├── SetAnimeViewerFlags.kt
│ │ │ │ │ │ │ └── UpdateAnime.kt
│ │ │ │ │ │ └── model
│ │ │ │ │ │ │ └── Anime.kt
│ │ │ │ │ └── manga
│ │ │ │ │ │ ├── interactor
│ │ │ │ │ │ ├── GetExcludedScanlators.kt
│ │ │ │ │ │ ├── SetExcludedScanlators.kt
│ │ │ │ │ │ ├── SetMangaViewerFlags.kt
│ │ │ │ │ │ └── UpdateManga.kt
│ │ │ │ │ │ └── model
│ │ │ │ │ │ └── Manga.kt
│ │ │ │ ├── extension
│ │ │ │ │ ├── anime
│ │ │ │ │ │ ├── interactor
│ │ │ │ │ │ │ ├── GetAnimeExtensionLanguages.kt
│ │ │ │ │ │ │ ├── GetAnimeExtensionSources.kt
│ │ │ │ │ │ │ ├── GetAnimeExtensionsByType.kt
│ │ │ │ │ │ │ └── TrustAnimeExtension.kt
│ │ │ │ │ │ └── model
│ │ │ │ │ │ │ └── AnimeExtensions.kt
│ │ │ │ │ └── manga
│ │ │ │ │ │ ├── interactor
│ │ │ │ │ │ ├── GetMangaExtensionLanguages.kt
│ │ │ │ │ │ ├── GetMangaExtensionSources.kt
│ │ │ │ │ │ ├── GetMangaExtensionsByType.kt
│ │ │ │ │ │ └── TrustMangaExtension.kt
│ │ │ │ │ │ └── model
│ │ │ │ │ │ └── MangaExtensions.kt
│ │ │ │ ├── items
│ │ │ │ │ ├── chapter
│ │ │ │ │ │ ├── interactor
│ │ │ │ │ │ │ ├── GetAvailableScanlators.kt
│ │ │ │ │ │ │ ├── SetReadStatus.kt
│ │ │ │ │ │ │ └── SyncChaptersWithSource.kt
│ │ │ │ │ │ └── model
│ │ │ │ │ │ │ ├── Chapter.kt
│ │ │ │ │ │ │ └── ChapterFilter.kt
│ │ │ │ │ └── episode
│ │ │ │ │ │ ├── interactor
│ │ │ │ │ │ ├── SetSeenStatus.kt
│ │ │ │ │ │ └── SyncEpisodesWithSource.kt
│ │ │ │ │ │ └── model
│ │ │ │ │ │ ├── Episode.kt
│ │ │ │ │ │ └── EpisodeFilter.kt
│ │ │ │ ├── source
│ │ │ │ │ ├── anime
│ │ │ │ │ │ ├── interactor
│ │ │ │ │ │ │ ├── GetAnimeIncognitoState.kt
│ │ │ │ │ │ │ ├── GetAnimeSourcesWithFavoriteCount.kt
│ │ │ │ │ │ │ ├── GetEnabledAnimeSources.kt
│ │ │ │ │ │ │ ├── GetLanguagesWithAnimeSources.kt
│ │ │ │ │ │ │ ├── ToggleAnimeIncognito.kt
│ │ │ │ │ │ │ ├── ToggleAnimeSource.kt
│ │ │ │ │ │ │ └── ToggleAnimeSourcePin.kt
│ │ │ │ │ │ └── model
│ │ │ │ │ │ │ └── AnimeSource.kt
│ │ │ │ │ ├── interactor
│ │ │ │ │ │ ├── SetMigrateSorting.kt
│ │ │ │ │ │ └── ToggleLanguage.kt
│ │ │ │ │ ├── manga
│ │ │ │ │ │ ├── interactor
│ │ │ │ │ │ │ ├── GetEnabledMangaSources.kt
│ │ │ │ │ │ │ ├── GetLanguagesWithMangaSources.kt
│ │ │ │ │ │ │ ├── GetMangaIncognitoState.kt
│ │ │ │ │ │ │ ├── GetMangaSourcesWithFavoriteCount.kt
│ │ │ │ │ │ │ ├── ToggleExcludeFromMangaDataSaver.kt
│ │ │ │ │ │ │ ├── ToggleMangaIncognito.kt
│ │ │ │ │ │ │ ├── ToggleMangaSource.kt
│ │ │ │ │ │ │ └── ToggleMangaSourcePin.kt
│ │ │ │ │ │ └── model
│ │ │ │ │ │ │ └── MangaSource.kt
│ │ │ │ │ └── service
│ │ │ │ │ │ └── SourcePreferences.kt
│ │ │ │ ├── track
│ │ │ │ │ ├── anime
│ │ │ │ │ │ ├── interactor
│ │ │ │ │ │ │ ├── AddAnimeTracks.kt
│ │ │ │ │ │ │ ├── RefreshAnimeTracks.kt
│ │ │ │ │ │ │ ├── SyncEpisodeProgressWithTrack.kt
│ │ │ │ │ │ │ └── TrackEpisode.kt
│ │ │ │ │ │ ├── model
│ │ │ │ │ │ │ └── AnimeTrack.kt
│ │ │ │ │ │ ├── service
│ │ │ │ │ │ │ └── DelayedAnimeTrackingUpdateJob.kt
│ │ │ │ │ │ └── store
│ │ │ │ │ │ │ └── DelayedAnimeTrackingStore.kt
│ │ │ │ │ ├── manga
│ │ │ │ │ │ ├── interactor
│ │ │ │ │ │ │ ├── AddMangaTracks.kt
│ │ │ │ │ │ │ ├── RefreshMangaTracks.kt
│ │ │ │ │ │ │ ├── SyncChapterProgressWithTrack.kt
│ │ │ │ │ │ │ └── TrackChapter.kt
│ │ │ │ │ │ ├── model
│ │ │ │ │ │ │ └── MangaTrack.kt
│ │ │ │ │ │ ├── service
│ │ │ │ │ │ │ └── DelayedMangaTrackingUpdateJob.kt
│ │ │ │ │ │ └── store
│ │ │ │ │ │ │ └── DelayedMangaTrackingStore.kt
│ │ │ │ │ ├── model
│ │ │ │ │ │ └── AutoTrackState.kt
│ │ │ │ │ └── service
│ │ │ │ │ │ └── TrackPreferences.kt
│ │ │ │ └── ui
│ │ │ │ │ ├── UiPreferences.kt
│ │ │ │ │ └── model
│ │ │ │ │ ├── AppTheme.kt
│ │ │ │ │ ├── NavStyle.kt
│ │ │ │ │ ├── StartScreen.kt
│ │ │ │ │ ├── TabletUiMode.kt
│ │ │ │ │ └── ThemeMode.kt
│ │ │ │ ├── presentation
│ │ │ │ ├── browse
│ │ │ │ │ ├── BaseBrowseItem.kt
│ │ │ │ │ ├── BrowseBadges.kt
│ │ │ │ │ ├── GlobalSearchResultItems.kt
│ │ │ │ │ ├── GlobalSerachCard.kt
│ │ │ │ │ ├── anime
│ │ │ │ │ │ ├── AnimeExtensionDetailsScreen.kt
│ │ │ │ │ │ ├── AnimeExtensionFilterScreen.kt
│ │ │ │ │ │ ├── AnimeExtensionsScreen.kt
│ │ │ │ │ │ ├── AnimeSourcesFilterScreen.kt
│ │ │ │ │ │ ├── AnimeSourcesScreen.kt
│ │ │ │ │ │ ├── BrowseAnimeSourceScreen.kt
│ │ │ │ │ │ ├── GlobalAnimeSearchScreen.kt
│ │ │ │ │ │ ├── MigrateAnimeScreen.kt
│ │ │ │ │ │ ├── MigrateAnimeSearchScreen.kt
│ │ │ │ │ │ ├── MigrateAnimeSourceScreen.kt
│ │ │ │ │ │ └── components
│ │ │ │ │ │ │ ├── BaseAnimeSourceItem.kt
│ │ │ │ │ │ │ ├── BrowseAnimeIcons.kt
│ │ │ │ │ │ │ ├── BrowseAnimeSourceComfortableGrid.kt
│ │ │ │ │ │ │ ├── BrowseAnimeSourceCompactGrid.kt
│ │ │ │ │ │ │ ├── BrowseAnimeSourceDialogs.kt
│ │ │ │ │ │ │ ├── BrowseAnimeSourceList.kt
│ │ │ │ │ │ │ ├── BrowseAnimeSourceToolbar.kt
│ │ │ │ │ │ │ ├── GlobalAnimeSearchCardRow.kt
│ │ │ │ │ │ │ └── GlobalAnimeSearchToolbar.kt
│ │ │ │ │ └── manga
│ │ │ │ │ │ ├── BrowseMangaSourceScreen.kt
│ │ │ │ │ │ ├── GlobalMangaSearchScreen.kt
│ │ │ │ │ │ ├── MangaExtensionDetailsScreen.kt
│ │ │ │ │ │ ├── MangaExtensionFilterScreen.kt
│ │ │ │ │ │ ├── MangaExtensionsScreen.kt
│ │ │ │ │ │ ├── MangaSourcesFilterScreen.kt
│ │ │ │ │ │ ├── MangaSourcesScreen.kt
│ │ │ │ │ │ ├── MigrateMangaScreen.kt
│ │ │ │ │ │ ├── MigrateMangaSearchScreen.kt
│ │ │ │ │ │ ├── MigrateMangaSourceScreen.kt
│ │ │ │ │ │ └── components
│ │ │ │ │ │ ├── BaseMangaSourceItem.kt
│ │ │ │ │ │ ├── BrowseMangaIcons.kt
│ │ │ │ │ │ ├── BrowseMangaSourceComfortableGrid.kt
│ │ │ │ │ │ ├── BrowseMangaSourceCompactGrid.kt
│ │ │ │ │ │ ├── BrowseMangaSourceList.kt
│ │ │ │ │ │ ├── BrowseMangaSourceToolbar.kt
│ │ │ │ │ │ ├── BrowseSourceLoadingItem.kt
│ │ │ │ │ │ ├── GlobalMangaSearchCardRow.kt
│ │ │ │ │ │ └── GlobalMangaSearchToolbar.kt
│ │ │ │ ├── category
│ │ │ │ │ ├── AnimeCategoryScreen.kt
│ │ │ │ │ ├── CategoryExtensions.kt
│ │ │ │ │ ├── MangaCategoryScreen.kt
│ │ │ │ │ └── components
│ │ │ │ │ │ ├── CategoryDialogs.kt
│ │ │ │ │ │ ├── CategoryFloatingActionButton.kt
│ │ │ │ │ │ └── CategoryListItem.kt
│ │ │ │ ├── components
│ │ │ │ │ ├── AdaptiveSheet.kt
│ │ │ │ │ ├── AppBar.kt
│ │ │ │ │ ├── Banners.kt
│ │ │ │ │ ├── DateText.kt
│ │ │ │ │ ├── DropdownMenu.kt
│ │ │ │ │ ├── EmptyScreen.kt
│ │ │ │ │ ├── EntryDownloadDropdownMenu.kt
│ │ │ │ │ ├── FloatingActionAddButton.kt
│ │ │ │ │ ├── ItemDownloadIndicator.kt
│ │ │ │ │ ├── TabbedDialog.kt
│ │ │ │ │ └── TabbedScreen.kt
│ │ │ │ ├── crash
│ │ │ │ │ └── CrashScreen.kt
│ │ │ │ ├── entries
│ │ │ │ │ ├── EntryScreenConstants.kt
│ │ │ │ │ ├── anime
│ │ │ │ │ │ ├── AnimeScreen.kt
│ │ │ │ │ │ ├── DuplicateAnimeDialog.kt
│ │ │ │ │ │ ├── EpisodeOptionsDialogScreen.kt
│ │ │ │ │ │ ├── EpisodeSettingsDialog.kt
│ │ │ │ │ │ └── components
│ │ │ │ │ │ │ ├── AnimeCoverDialog.kt
│ │ │ │ │ │ │ ├── AnimeEpisodeListItem.kt
│ │ │ │ │ │ │ ├── AnimeInfoHeader.kt
│ │ │ │ │ │ │ ├── BaseAnimeListItem.kt
│ │ │ │ │ │ │ └── EpisodeDownloadIndicator.kt
│ │ │ │ │ ├── components
│ │ │ │ │ │ ├── DotSeparatorText.kt
│ │ │ │ │ │ ├── EntryBottomActionMenu.kt
│ │ │ │ │ │ ├── EntryToolbar.kt
│ │ │ │ │ │ ├── ItemCover.kt
│ │ │ │ │ │ ├── ItemHeader.kt
│ │ │ │ │ │ ├── ItemsDialogs.kt
│ │ │ │ │ │ └── MissingItemCountListItem.kt
│ │ │ │ │ └── manga
│ │ │ │ │ │ ├── ChapterSettingsDialog.kt
│ │ │ │ │ │ ├── DuplicateMangaDialog.kt
│ │ │ │ │ │ ├── MangaScreen.kt
│ │ │ │ │ │ └── components
│ │ │ │ │ │ ├── BaseMangaListItem.kt
│ │ │ │ │ │ ├── ChapterDownloadIndicator.kt
│ │ │ │ │ │ ├── MangaChapterListItem.kt
│ │ │ │ │ │ ├── MangaCoverDialog.kt
│ │ │ │ │ │ ├── MangaInfoHeader.kt
│ │ │ │ │ │ └── ScanlatorFilterDialog.kt
│ │ │ │ ├── history
│ │ │ │ │ ├── HistoryDialogs.kt
│ │ │ │ │ ├── anime
│ │ │ │ │ │ ├── AnimeHistoryScreen.kt
│ │ │ │ │ │ ├── AnimeHistoryScreenModelStateProvider.kt
│ │ │ │ │ │ └── components
│ │ │ │ │ │ │ ├── AnimeHistoryItem.kt
│ │ │ │ │ │ │ └── AnimeHistoryWithRelationsProvider.kt
│ │ │ │ │ └── manga
│ │ │ │ │ │ ├── MangaHistoryScreen.kt
│ │ │ │ │ │ ├── MangaHistoryScreenModelStateProvider.kt
│ │ │ │ │ │ └── components
│ │ │ │ │ │ ├── MangaHistoryItem.kt
│ │ │ │ │ │ └── MangaHistoryWithRelationsProvider.kt
│ │ │ │ ├── library
│ │ │ │ │ ├── DeleteLibraryEntryDialog.kt
│ │ │ │ │ ├── anime
│ │ │ │ │ │ ├── AnimeLibraryComfortableGrid.kt
│ │ │ │ │ │ ├── AnimeLibraryCompactGrid.kt
│ │ │ │ │ │ ├── AnimeLibraryContent.kt
│ │ │ │ │ │ ├── AnimeLibraryList.kt
│ │ │ │ │ │ ├── AnimeLibraryPager.kt
│ │ │ │ │ │ └── AnimeLibrarySettingsDialog.kt
│ │ │ │ │ ├── components
│ │ │ │ │ │ ├── CommonEntryItem.kt
│ │ │ │ │ │ ├── GlobalSearchItem.kt
│ │ │ │ │ │ ├── LazyLibraryGrid.kt
│ │ │ │ │ │ ├── LibraryBadges.kt
│ │ │ │ │ │ ├── LibraryTabs.kt
│ │ │ │ │ │ └── LibraryToolbar.kt
│ │ │ │ │ └── manga
│ │ │ │ │ │ ├── MangaLibraryComfortableGrid.kt
│ │ │ │ │ │ ├── MangaLibraryCompactGrid.kt
│ │ │ │ │ │ ├── MangaLibraryContent.kt
│ │ │ │ │ │ ├── MangaLibraryList.kt
│ │ │ │ │ │ ├── MangaLibraryPager.kt
│ │ │ │ │ │ └── MangaLibrarySettingsDialog.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
│ │ │ │ │ │ │ ├── about
│ │ │ │ │ │ │ │ ├── AboutScreen.kt
│ │ │ │ │ │ │ │ ├── OpenSourceLibraryLicenseScreen.kt
│ │ │ │ │ │ │ │ └── OpenSourceLicensesScreen.kt
│ │ │ │ │ │ │ ├── advanced
│ │ │ │ │ │ │ │ ├── ClearAnimeDatabaseScreen.kt
│ │ │ │ │ │ │ │ └── ClearDatabaseScreen.kt
│ │ │ │ │ │ │ ├── appearance
│ │ │ │ │ │ │ │ └── AppLanguageScreen.kt
│ │ │ │ │ │ │ ├── browse
│ │ │ │ │ │ │ │ ├── AnimeExtensionReposScreen.kt
│ │ │ │ │ │ │ │ ├── AnimeExtensionReposScreenModel.kt
│ │ │ │ │ │ │ │ ├── MangaExtensionReposScreen.kt
│ │ │ │ │ │ │ │ ├── MangaExtensionReposScreenModel.kt
│ │ │ │ │ │ │ │ └── components
│ │ │ │ │ │ │ │ │ ├── ExtensionReposContent.kt
│ │ │ │ │ │ │ │ │ ├── ExtensionReposDialogs.kt
│ │ │ │ │ │ │ │ │ └── ExtensionReposScreen.kt
│ │ │ │ │ │ │ ├── data
│ │ │ │ │ │ │ │ ├── CreateBackupScreen.kt
│ │ │ │ │ │ │ │ ├── RestoreBackupScreen.kt
│ │ │ │ │ │ │ │ └── StorageInfo.kt
│ │ │ │ │ │ │ ├── debug
│ │ │ │ │ │ │ │ ├── BackupSchemaScreen.kt
│ │ │ │ │ │ │ │ ├── DebugInfoScreen.kt
│ │ │ │ │ │ │ │ └── WorkerInfoScreen.kt
│ │ │ │ │ │ │ └── player
│ │ │ │ │ │ │ │ ├── PlayerSettingsAdvancedScreen.kt
│ │ │ │ │ │ │ │ ├── PlayerSettingsAudioScreen.kt
│ │ │ │ │ │ │ │ ├── PlayerSettingsDecoderScreen.kt
│ │ │ │ │ │ │ │ ├── PlayerSettingsGesturesScreen.kt
│ │ │ │ │ │ │ │ ├── PlayerSettingsMainScreen.kt
│ │ │ │ │ │ │ │ ├── PlayerSettingsPlayerScreen.kt
│ │ │ │ │ │ │ │ ├── PlayerSettingsSubtitleScreen.kt
│ │ │ │ │ │ │ │ ├── custombutton
│ │ │ │ │ │ │ │ ├── PlayerSettingsCustomButtonScreen.kt
│ │ │ │ │ │ │ │ ├── PlayerSettingsCustomButtonScreenModel.kt
│ │ │ │ │ │ │ │ └── components
│ │ │ │ │ │ │ │ │ ├── CustomButtonDialogs.kt
│ │ │ │ │ │ │ │ │ ├── CustomButtonListItem.kt
│ │ │ │ │ │ │ │ │ └── CustomButtonScreen.kt
│ │ │ │ │ │ │ │ └── editor
│ │ │ │ │ │ │ │ ├── PlayerSettingsEditorScreen.kt
│ │ │ │ │ │ │ │ ├── PlayerSettingsEditorScreenModel.kt
│ │ │ │ │ │ │ │ ├── codeeditor
│ │ │ │ │ │ │ │ ├── CodeEditScreen.kt
│ │ │ │ │ │ │ │ ├── CodeEditScreenModel.kt
│ │ │ │ │ │ │ │ ├── Highlight.kt
│ │ │ │ │ │ │ │ └── SyntaxHighlight.kt
│ │ │ │ │ │ │ │ └── components
│ │ │ │ │ │ │ │ ├── EditorDialogs.kt
│ │ │ │ │ │ │ │ ├── EditorScreen.kt
│ │ │ │ │ │ │ │ └── EditorTypeDropdown.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
│ │ │ │ │ │ ├── AnimeStatsScreenContent.kt
│ │ │ │ │ │ ├── MangaStatsScreenContent.kt
│ │ │ │ │ │ ├── StatsScreenState.kt
│ │ │ │ │ │ ├── components
│ │ │ │ │ │ │ └── StatsItem.kt
│ │ │ │ │ │ └── data
│ │ │ │ │ │ │ └── StatsData.kt
│ │ │ │ │ └── storage
│ │ │ │ │ │ ├── CumulativeStorage.kt
│ │ │ │ │ │ ├── SelectStorageCategory.kt
│ │ │ │ │ │ ├── StorageItem.kt
│ │ │ │ │ │ ├── StorageScreenContent.kt
│ │ │ │ │ │ └── StorageScreenState.kt
│ │ │ │ ├── player
│ │ │ │ │ └── components
│ │ │ │ │ │ ├── ExpandableCard.kt
│ │ │ │ │ │ ├── ExposedTextDropDownMenu.kt
│ │ │ │ │ │ ├── OutlinedNumericChooser.kt
│ │ │ │ │ │ ├── OvalBox.kt
│ │ │ │ │ │ ├── PlayerSheet.kt
│ │ │ │ │ │ ├── RepeatingIconButton.kt
│ │ │ │ │ │ ├── SliderItem.kt
│ │ │ │ │ │ ├── SwitchPreference.kt
│ │ │ │ │ │ └── TintedSliderItem.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
│ │ │ │ │ │ ├── CloudflareColorScheme.kt
│ │ │ │ │ │ ├── CottoncandyColorScheme.kt
│ │ │ │ │ │ ├── DoomColorScheme.kt
│ │ │ │ │ │ ├── GreenAppleColorScheme.kt
│ │ │ │ │ │ ├── LavenderColorScheme.kt
│ │ │ │ │ │ ├── MatrixColorScheme.kt
│ │ │ │ │ │ ├── MidnightDuskColorScheme.kt
│ │ │ │ │ │ ├── MochaColorScheme.kt
│ │ │ │ │ │ ├── MonetColorScheme.kt
│ │ │ │ │ │ ├── MonochromeColorScheme.kt
│ │ │ │ │ │ ├── NordColorScheme.kt
│ │ │ │ │ │ ├── SapphireColorScheme.kt
│ │ │ │ │ │ ├── StrawberryColorScheme.kt
│ │ │ │ │ │ ├── TachiyomiColorScheme.kt
│ │ │ │ │ │ ├── TakoColorScheme.kt
│ │ │ │ │ │ ├── TealTurqoiseColorScheme.kt
│ │ │ │ │ │ ├── TidalWaveColorScheme.kt
│ │ │ │ │ │ ├── YinYangColorScheme.kt
│ │ │ │ │ │ └── YotsubaColorScheme.kt
│ │ │ │ ├── track
│ │ │ │ │ ├── TrackInfoDialogSelector.kt
│ │ │ │ │ ├── anime
│ │ │ │ │ │ ├── AnimeTrackInfoDialogHome.kt
│ │ │ │ │ │ ├── AnimeTrackInfoDialogHomePreviewProvider.kt
│ │ │ │ │ │ ├── AnimeTrackerSearch.kt
│ │ │ │ │ │ └── AnimeTrackerSearchPreviewProvider.kt
│ │ │ │ │ ├── components
│ │ │ │ │ │ ├── TrackLogoIcon.kt
│ │ │ │ │ │ └── TrackLogoIconPreviewProvider.kt
│ │ │ │ │ └── manga
│ │ │ │ │ │ ├── MangaTrackInfoDialogHome.kt
│ │ │ │ │ │ ├── MangaTrackInfoDialogHomePreviewProvider.kt
│ │ │ │ │ │ ├── MangaTrackerSearch.kt
│ │ │ │ │ │ └── MangaTrackerSearchPreviewProvider.kt
│ │ │ │ ├── updates
│ │ │ │ │ ├── UpdatesDialog.kt
│ │ │ │ │ ├── anime
│ │ │ │ │ │ ├── AnimeUpdatesScreen.kt
│ │ │ │ │ │ └── AnimeUpdatesUiItem.kt
│ │ │ │ │ └── manga
│ │ │ │ │ │ ├── MangaUpdatesScreen.kt
│ │ │ │ │ │ └── MangaUpdatesUiItem.kt
│ │ │ │ ├── util
│ │ │ │ │ ├── ExceptionFormatter.kt
│ │ │ │ │ ├── FastScrollAnimateItem.kt
│ │ │ │ │ ├── ItemNumberFormatter.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
│ │ │ │ │ │ │ │ ├── AnimeBackupCreator.kt
│ │ │ │ │ │ │ │ ├── AnimeCategoriesBackupCreator.kt
│ │ │ │ │ │ │ │ ├── AnimeExtensionRepoBackupCreator.kt
│ │ │ │ │ │ │ │ ├── AnimeSourcesBackupCreator.kt
│ │ │ │ │ │ │ │ ├── CustomButtonBackupCreator.kt
│ │ │ │ │ │ │ │ ├── ExtensionsBackupCreator.kt
│ │ │ │ │ │ │ │ ├── MangaBackupCreator.kt
│ │ │ │ │ │ │ │ ├── MangaCategoriesBackupCreator.kt
│ │ │ │ │ │ │ │ ├── MangaExtensionRepoBackupCreator.kt
│ │ │ │ │ │ │ │ ├── MangaSourcesBackupCreator.kt
│ │ │ │ │ │ │ │ └── PreferenceBackupCreator.kt
│ │ │ │ │ │ ├── full
│ │ │ │ │ │ │ └── models
│ │ │ │ │ │ │ │ ├── Backup.kt
│ │ │ │ │ │ │ │ └── BackupPreference.kt
│ │ │ │ │ │ ├── models
│ │ │ │ │ │ │ ├── Backup.kt
│ │ │ │ │ │ │ ├── BackupAnime.kt
│ │ │ │ │ │ │ ├── BackupAnimeHistory.kt
│ │ │ │ │ │ │ ├── BackupAnimeSource.kt
│ │ │ │ │ │ │ ├── BackupAnimeTracking.kt
│ │ │ │ │ │ │ ├── BackupCategory.kt
│ │ │ │ │ │ │ ├── BackupChapter.kt
│ │ │ │ │ │ │ ├── BackupCustomButtons.kt
│ │ │ │ │ │ │ ├── BackupEpisode.kt
│ │ │ │ │ │ │ ├── BackupExtension.kt
│ │ │ │ │ │ │ ├── BackupExtensionPreferences.kt
│ │ │ │ │ │ │ ├── BackupExtensionRepos.kt
│ │ │ │ │ │ │ ├── BackupHistory.kt
│ │ │ │ │ │ │ ├── BackupManga.kt
│ │ │ │ │ │ │ ├── BackupPreference.kt
│ │ │ │ │ │ │ ├── BackupSource.kt
│ │ │ │ │ │ │ └── BackupTracking.kt
│ │ │ │ │ │ └── restore
│ │ │ │ │ │ │ ├── BackupRestoreJob.kt
│ │ │ │ │ │ │ ├── BackupRestorer.kt
│ │ │ │ │ │ │ ├── RestoreOptions.kt
│ │ │ │ │ │ │ └── restorers
│ │ │ │ │ │ │ ├── AnimeCategoriesRestorer.kt
│ │ │ │ │ │ │ ├── AnimeExtensionRepoRestorer.kt
│ │ │ │ │ │ │ ├── AnimeRestorer.kt
│ │ │ │ │ │ │ ├── CustomButtonRestorer.kt
│ │ │ │ │ │ │ ├── ExtensionsRestorer.kt
│ │ │ │ │ │ │ ├── MangaCategoriesRestorer.kt
│ │ │ │ │ │ │ ├── MangaExtensionRepoRestorer.kt
│ │ │ │ │ │ │ ├── MangaRestorer.kt
│ │ │ │ │ │ │ └── PreferenceRestorer.kt
│ │ │ │ │ ├── cache
│ │ │ │ │ │ ├── AnimeCoverCache.kt
│ │ │ │ │ │ ├── ChapterCache.kt
│ │ │ │ │ │ └── MangaCoverCache.kt
│ │ │ │ │ ├── coil
│ │ │ │ │ │ ├── AnimeCoverFetcher.kt
│ │ │ │ │ │ ├── AnimeCoverKeyer.kt
│ │ │ │ │ │ ├── BufferedSourceFetcher.kt
│ │ │ │ │ │ ├── MangaCoverFetcher.kt
│ │ │ │ │ │ ├── MangaCoverKeyer.kt
│ │ │ │ │ │ ├── TachiyomiImageDecoder.kt
│ │ │ │ │ │ └── Utils.kt
│ │ │ │ │ ├── database
│ │ │ │ │ │ └── models
│ │ │ │ │ │ │ ├── anime
│ │ │ │ │ │ │ ├── AnimeTrack.kt
│ │ │ │ │ │ │ ├── AnimeTrackImpl.kt
│ │ │ │ │ │ │ ├── Episode.kt
│ │ │ │ │ │ │ └── EpisodeImpl.kt
│ │ │ │ │ │ │ └── manga
│ │ │ │ │ │ │ ├── Chapter.kt
│ │ │ │ │ │ │ ├── ChapterImpl.kt
│ │ │ │ │ │ │ ├── MangaTrack.kt
│ │ │ │ │ │ │ └── MangaTrackImpl.kt
│ │ │ │ │ ├── download
│ │ │ │ │ │ ├── anime
│ │ │ │ │ │ │ ├── AnimeDownloadCache.kt
│ │ │ │ │ │ │ ├── AnimeDownloadJob.kt
│ │ │ │ │ │ │ ├── AnimeDownloadManager.kt
│ │ │ │ │ │ │ ├── AnimeDownloadNotifier.kt
│ │ │ │ │ │ │ ├── AnimeDownloadPendingDeleter.kt
│ │ │ │ │ │ │ ├── AnimeDownloadProvider.kt
│ │ │ │ │ │ │ ├── AnimeDownloadStore.kt
│ │ │ │ │ │ │ ├── AnimeDownloader.kt
│ │ │ │ │ │ │ └── model
│ │ │ │ │ │ │ │ ├── AnimeDownload.kt
│ │ │ │ │ │ │ │ └── AnimeDownloadPart.kt
│ │ │ │ │ │ └── manga
│ │ │ │ │ │ │ ├── MangaDownloadCache.kt
│ │ │ │ │ │ │ ├── MangaDownloadJob.kt
│ │ │ │ │ │ │ ├── MangaDownloadManager.kt
│ │ │ │ │ │ │ ├── MangaDownloadNotifier.kt
│ │ │ │ │ │ │ ├── MangaDownloadPendingDeleter.kt
│ │ │ │ │ │ │ ├── MangaDownloadProvider.kt
│ │ │ │ │ │ │ ├── MangaDownloadStore.kt
│ │ │ │ │ │ │ ├── MangaDownloader.kt
│ │ │ │ │ │ │ └── model
│ │ │ │ │ │ │ └── MangaDownload.kt
│ │ │ │ │ ├── export
│ │ │ │ │ │ └── LibraryExporter.kt
│ │ │ │ │ ├── library
│ │ │ │ │ │ ├── anime
│ │ │ │ │ │ │ ├── AnimeLibraryUpdateJob.kt
│ │ │ │ │ │ │ ├── AnimeLibraryUpdateNotifier.kt
│ │ │ │ │ │ │ └── AnimeMetadataUpdateJob.kt
│ │ │ │ │ │ └── manga
│ │ │ │ │ │ │ ├── MangaLibraryUpdateJob.kt
│ │ │ │ │ │ │ ├── MangaLibraryUpdateNotifier.kt
│ │ │ │ │ │ │ └── MangaMetadataUpdateJob.kt
│ │ │ │ │ ├── notification
│ │ │ │ │ │ ├── NotificationHandler.kt
│ │ │ │ │ │ ├── NotificationReceiver.kt
│ │ │ │ │ │ └── Notifications.kt
│ │ │ │ │ ├── preference
│ │ │ │ │ │ └── SharedPreferencesDataStore.kt
│ │ │ │ │ ├── saver
│ │ │ │ │ │ └── ImageSaver.kt
│ │ │ │ │ ├── track
│ │ │ │ │ │ ├── AnimeTracker.kt
│ │ │ │ │ │ ├── BaseTracker.kt
│ │ │ │ │ │ ├── DeletableAnimeTracker.kt
│ │ │ │ │ │ ├── DeletableMangaTracker.kt
│ │ │ │ │ │ ├── EnhancedAnimeTracker.kt
│ │ │ │ │ │ ├── EnhancedMangaTracker.kt
│ │ │ │ │ │ ├── MangaTracker.kt
│ │ │ │ │ │ ├── Tracker.kt
│ │ │ │ │ │ ├── TrackerManager.kt
│ │ │ │ │ │ ├── anilist
│ │ │ │ │ │ │ ├── Anilist.kt
│ │ │ │ │ │ │ ├── AnilistApi.kt
│ │ │ │ │ │ │ ├── AnilistInterceptor.kt
│ │ │ │ │ │ │ ├── AnilistUtils.kt
│ │ │ │ │ │ │ └── dto
│ │ │ │ │ │ │ │ ├── ALAddEntry.kt
│ │ │ │ │ │ │ │ ├── ALAnime.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
│ │ │ │ │ │ ├── jellyfin
│ │ │ │ │ │ │ ├── Jellyfin.kt
│ │ │ │ │ │ │ ├── JellyfinApi.kt
│ │ │ │ │ │ │ ├── JellyfinInterceptor.kt
│ │ │ │ │ │ │ └── dto
│ │ │ │ │ │ │ │ └── JFItem.kt
│ │ │ │ │ │ ├── kavita
│ │ │ │ │ │ │ ├── Kavita.kt
│ │ │ │ │ │ │ ├── KavitaApi.kt
│ │ │ │ │ │ │ ├── KavitaInterceptor.kt
│ │ │ │ │ │ │ └── KavitaModels.kt
│ │ │ │ │ │ ├── kitsu
│ │ │ │ │ │ │ ├── Kitsu.kt
│ │ │ │ │ │ │ ├── KitsuApi.kt
│ │ │ │ │ │ │ ├── KitsuDateHelper.kt
│ │ │ │ │ │ │ ├── KitsuInterceptor.kt
│ │ │ │ │ │ │ ├── KitsuUtils.kt
│ │ │ │ │ │ │ └── dto
│ │ │ │ │ │ │ │ ├── KitsuAddEntry.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
│ │ │ │ │ │ │ ├── AnimeTrackSearch.kt
│ │ │ │ │ │ │ └── MangaTrackSearch.kt
│ │ │ │ │ │ ├── myanimelist
│ │ │ │ │ │ │ ├── MyAnimeList.kt
│ │ │ │ │ │ │ ├── MyAnimeListApi.kt
│ │ │ │ │ │ │ ├── MyAnimeListInterceptor.kt
│ │ │ │ │ │ │ ├── MyAnimeListUtils.kt
│ │ │ │ │ │ │ └── dto
│ │ │ │ │ │ │ │ ├── MALAnime.kt
│ │ │ │ │ │ │ │ ├── MALList.kt
│ │ │ │ │ │ │ │ ├── MALManga.kt
│ │ │ │ │ │ │ │ ├── MALOAuth.kt
│ │ │ │ │ │ │ │ ├── MALSearch.kt
│ │ │ │ │ │ │ │ ├── MALUser.kt
│ │ │ │ │ │ │ │ └── MALUserListSearch.kt
│ │ │ │ │ │ ├── shikimori
│ │ │ │ │ │ │ ├── Shikimori.kt
│ │ │ │ │ │ │ ├── ShikimoriApi.kt
│ │ │ │ │ │ │ ├── ShikimoriInterceptor.kt
│ │ │ │ │ │ │ ├── ShikimoriUtils.kt
│ │ │ │ │ │ │ └── dto
│ │ │ │ │ │ │ │ ├── SMAddEntryResponse.kt
│ │ │ │ │ │ │ │ ├── SMEntry.kt
│ │ │ │ │ │ │ │ ├── SMOAuth.kt
│ │ │ │ │ │ │ │ ├── SMUser.kt
│ │ │ │ │ │ │ │ └── SMUserListEntry.kt
│ │ │ │ │ │ ├── simkl
│ │ │ │ │ │ │ ├── Simkl.kt
│ │ │ │ │ │ │ ├── SimklApi.kt
│ │ │ │ │ │ │ ├── SimklInterceptor.kt
│ │ │ │ │ │ │ ├── SimklUtils.kt
│ │ │ │ │ │ │ └── dto
│ │ │ │ │ │ │ │ ├── SimklOAuth.kt
│ │ │ │ │ │ │ │ ├── SimklSearch.kt
│ │ │ │ │ │ │ │ ├── SimklSyncItem.kt
│ │ │ │ │ │ │ │ ├── SimklSyncWatched.kt
│ │ │ │ │ │ │ │ └── SimklUser.kt
│ │ │ │ │ │ └── suwayomi
│ │ │ │ │ │ │ ├── Suwayomi.kt
│ │ │ │ │ │ │ ├── SuwayomiApi.kt
│ │ │ │ │ │ │ └── SuwayomiModels.kt
│ │ │ │ │ └── updater
│ │ │ │ │ │ ├── AppUpdateChecker.kt
│ │ │ │ │ │ ├── AppUpdateDownloadJob.kt
│ │ │ │ │ │ └── AppUpdateNotifier.kt
│ │ │ │ ├── di
│ │ │ │ │ ├── AppModule.kt
│ │ │ │ │ └── PreferenceModule.kt
│ │ │ │ ├── extension
│ │ │ │ │ ├── ExtensionUpdateNotifier.kt
│ │ │ │ │ ├── InstallStep.kt
│ │ │ │ │ ├── anime
│ │ │ │ │ │ ├── AnimeExtensionManager.kt
│ │ │ │ │ │ ├── api
│ │ │ │ │ │ │ └── AnimeExtensionApi.kt
│ │ │ │ │ │ ├── installer
│ │ │ │ │ │ │ ├── InstallerAnime.kt
│ │ │ │ │ │ │ ├── PackageInstallerInstallerAnime.kt
│ │ │ │ │ │ │ └── ShizukuInstallerAnime.kt
│ │ │ │ │ │ ├── model
│ │ │ │ │ │ │ ├── AnimeExtension.kt
│ │ │ │ │ │ │ └── AnimeLoadResult.kt
│ │ │ │ │ │ └── util
│ │ │ │ │ │ │ ├── AnimeExtensionInstallActivity.kt
│ │ │ │ │ │ │ ├── AnimeExtensionInstallReceiver.kt
│ │ │ │ │ │ │ ├── AnimeExtensionInstallService.kt
│ │ │ │ │ │ │ ├── AnimeExtensionInstaller.kt
│ │ │ │ │ │ │ └── AnimeExtensionLoader.kt
│ │ │ │ │ └── manga
│ │ │ │ │ │ ├── MangaExtensionManager.kt
│ │ │ │ │ │ ├── api
│ │ │ │ │ │ └── MangaExtensionApi.kt
│ │ │ │ │ │ ├── installer
│ │ │ │ │ │ ├── InstallerManga.kt
│ │ │ │ │ │ ├── PackageInstallerInstallerManga.kt
│ │ │ │ │ │ └── ShizukuInstallerManga.kt
│ │ │ │ │ │ ├── model
│ │ │ │ │ │ ├── MangaExtension.kt
│ │ │ │ │ │ └── MangaLoadResult.kt
│ │ │ │ │ │ └── util
│ │ │ │ │ │ ├── MangaExtensionInstallActivity.kt
│ │ │ │ │ │ ├── MangaExtensionInstallReceiver.kt
│ │ │ │ │ │ ├── MangaExtensionInstallService.kt
│ │ │ │ │ │ ├── MangaExtensionInstaller.kt
│ │ │ │ │ │ └── MangaExtensionLoader.kt
│ │ │ │ ├── source
│ │ │ │ │ ├── anime
│ │ │ │ │ │ ├── AndroidAnimeSourceManager.kt
│ │ │ │ │ │ └── AnimeSourceExtensions.kt
│ │ │ │ │ └── manga
│ │ │ │ │ │ ├── AndroidMangaSourceManager.kt
│ │ │ │ │ │ └── MangaSourceExtensions.kt
│ │ │ │ ├── ui
│ │ │ │ │ ├── base
│ │ │ │ │ │ ├── activity
│ │ │ │ │ │ │ └── BaseActivity.kt
│ │ │ │ │ │ └── delegate
│ │ │ │ │ │ │ ├── SecureActivityDelegate.kt
│ │ │ │ │ │ │ └── ThemingDelegate.kt
│ │ │ │ │ ├── browse
│ │ │ │ │ │ ├── BrowseTab.kt
│ │ │ │ │ │ ├── anime
│ │ │ │ │ │ │ ├── extension
│ │ │ │ │ │ │ │ ├── AnimeExtensionFilterScreen.kt
│ │ │ │ │ │ │ │ ├── AnimeExtensionFilterScreenModel.kt
│ │ │ │ │ │ │ │ ├── AnimeExtensionsScreenModel.kt
│ │ │ │ │ │ │ │ ├── AnimeExtensionsTab.kt
│ │ │ │ │ │ │ │ └── details
│ │ │ │ │ │ │ │ │ ├── AnimeExtensionDetailsScreen.kt
│ │ │ │ │ │ │ │ │ ├── AnimeExtensionDetailsScreenModel.kt
│ │ │ │ │ │ │ │ │ └── AnimeSourcePreferencesScreen.kt
│ │ │ │ │ │ │ ├── migration
│ │ │ │ │ │ │ │ ├── AnimeMigrationFlags.kt
│ │ │ │ │ │ │ │ ├── anime
│ │ │ │ │ │ │ │ │ ├── MigrateAnimeScreen.kt
│ │ │ │ │ │ │ │ │ └── MigrateAnimeScreenModel.kt
│ │ │ │ │ │ │ │ ├── search
│ │ │ │ │ │ │ │ │ ├── AnimeMigrateSearchScreenDialogScreenModel.kt
│ │ │ │ │ │ │ │ │ ├── AnimeSourceSearchScreen.kt
│ │ │ │ │ │ │ │ │ ├── MigrateAnimeDialog.kt
│ │ │ │ │ │ │ │ │ ├── MigrateAnimeSearchScreen.kt
│ │ │ │ │ │ │ │ │ └── MigrateAnimeSearchScreenModel.kt
│ │ │ │ │ │ │ │ └── sources
│ │ │ │ │ │ │ │ │ ├── MigrateAnimeSourceScreenModel.kt
│ │ │ │ │ │ │ │ │ └── MigrateAnimeSourceTab.kt
│ │ │ │ │ │ │ └── source
│ │ │ │ │ │ │ │ ├── AnimeSourcesFilterScreen.kt
│ │ │ │ │ │ │ │ ├── AnimeSourcesFilterScreenModel.kt
│ │ │ │ │ │ │ │ ├── AnimeSourcesScreenModel.kt
│ │ │ │ │ │ │ │ ├── AnimeSourcesTab.kt
│ │ │ │ │ │ │ │ ├── browse
│ │ │ │ │ │ │ │ ├── BrowseAnimeSourceScreen.kt
│ │ │ │ │ │ │ │ ├── BrowseAnimeSourceScreenModel.kt
│ │ │ │ │ │ │ │ └── SourceFilterAnimeDialog.kt
│ │ │ │ │ │ │ │ └── globalsearch
│ │ │ │ │ │ │ │ ├── AnimeSearchScreenModel.kt
│ │ │ │ │ │ │ │ ├── GlobalAnimeSearchScreen.kt
│ │ │ │ │ │ │ │ └── GlobalAnimeSearchScreenModel.kt
│ │ │ │ │ │ └── manga
│ │ │ │ │ │ │ ├── extension
│ │ │ │ │ │ │ ├── MangaExtensionFilterScreen.kt
│ │ │ │ │ │ │ ├── MangaExtensionFilterScreenModel.kt
│ │ │ │ │ │ │ ├── MangaExtensionsScreenModel.kt
│ │ │ │ │ │ │ ├── MangaExtensionsTab.kt
│ │ │ │ │ │ │ └── details
│ │ │ │ │ │ │ │ ├── MangaExtensionDetailsScreen.kt
│ │ │ │ │ │ │ │ ├── MangaExtensionDetailsScreenModel.kt
│ │ │ │ │ │ │ │ └── MangaSourcePreferencesScreen.kt
│ │ │ │ │ │ │ ├── migration
│ │ │ │ │ │ │ ├── MangaMigrationFlags.kt
│ │ │ │ │ │ │ ├── manga
│ │ │ │ │ │ │ │ ├── MigrateMangaScreen.kt
│ │ │ │ │ │ │ │ └── MigrateMangaScreenModel.kt
│ │ │ │ │ │ │ ├── search
│ │ │ │ │ │ │ │ ├── MangaMigrateSearchScreenDialogScreenModel.kt
│ │ │ │ │ │ │ │ ├── MangaSourceSearchScreen.kt
│ │ │ │ │ │ │ │ ├── MigrateMangaDialog.kt
│ │ │ │ │ │ │ │ ├── MigrateMangaSearchScreen.kt
│ │ │ │ │ │ │ │ └── MigrateMangaSearchScreenModel.kt
│ │ │ │ │ │ │ └── sources
│ │ │ │ │ │ │ │ ├── MigrateMangaSourceScreenModel.kt
│ │ │ │ │ │ │ │ └── MigrateMangaSourceTab.kt
│ │ │ │ │ │ │ └── source
│ │ │ │ │ │ │ ├── MangaSourcesFilterScreen.kt
│ │ │ │ │ │ │ ├── MangaSourcesFilterScreenModel.kt
│ │ │ │ │ │ │ ├── MangaSourcesScreenModel.kt
│ │ │ │ │ │ │ ├── MangaSourcesTab.kt
│ │ │ │ │ │ │ ├── browse
│ │ │ │ │ │ │ ├── BrowseMangaSourceScreen.kt
│ │ │ │ │ │ │ ├── BrowseMangaSourceScreenModel.kt
│ │ │ │ │ │ │ └── SourceFilterMangaDialog.kt
│ │ │ │ │ │ │ └── globalsearch
│ │ │ │ │ │ │ ├── GlobalMangaSearchScreen.kt
│ │ │ │ │ │ │ ├── GlobalMangaSearchScreenModel.kt
│ │ │ │ │ │ │ └── MangaSearchScreenModel.kt
│ │ │ │ │ ├── category
│ │ │ │ │ │ ├── CategoriesTab.kt
│ │ │ │ │ │ ├── anime
│ │ │ │ │ │ │ ├── AnimeCategoryScreenModel.kt
│ │ │ │ │ │ │ └── AnimeCategoryTab.kt
│ │ │ │ │ │ └── manga
│ │ │ │ │ │ │ ├── MangaCategoryScreenModel.kt
│ │ │ │ │ │ │ └── MangaCategoryTab.kt
│ │ │ │ │ ├── deeplink
│ │ │ │ │ │ ├── DeepLinkScreenType.kt
│ │ │ │ │ │ ├── anime
│ │ │ │ │ │ │ ├── DeepLinkAnimeActivity.kt
│ │ │ │ │ │ │ ├── DeepLinkAnimeScreen.kt
│ │ │ │ │ │ │ └── DeepLinkAnimeScreenModel.kt
│ │ │ │ │ │ └── manga
│ │ │ │ │ │ │ ├── DeepLinkMangaActivity.kt
│ │ │ │ │ │ │ ├── DeepLinkMangaScreen.kt
│ │ │ │ │ │ │ └── DeepLinkMangaScreenModel.kt
│ │ │ │ │ ├── download
│ │ │ │ │ │ ├── DownloadsTab.kt
│ │ │ │ │ │ ├── anime
│ │ │ │ │ │ │ ├── AnimeDownloadAdapter.kt
│ │ │ │ │ │ │ ├── AnimeDownloadHeaderHolder.kt
│ │ │ │ │ │ │ ├── AnimeDownloadHeaderItem.kt
│ │ │ │ │ │ │ ├── AnimeDownloadHolder.kt
│ │ │ │ │ │ │ ├── AnimeDownloadItem.kt
│ │ │ │ │ │ │ ├── AnimeDownloadQueueScreen.kt
│ │ │ │ │ │ │ ├── AnimeDownloadQueueScreenModel.kt
│ │ │ │ │ │ │ └── AnimeDownloadQueueTab.kt
│ │ │ │ │ │ └── manga
│ │ │ │ │ │ │ ├── MangaDownloadAdapter.kt
│ │ │ │ │ │ │ ├── MangaDownloadHeaderHolder.kt
│ │ │ │ │ │ │ ├── MangaDownloadHeaderItem.kt
│ │ │ │ │ │ │ ├── MangaDownloadHolder.kt
│ │ │ │ │ │ │ ├── MangaDownloadItem.kt
│ │ │ │ │ │ │ ├── MangaDownloadQueueScreen.kt
│ │ │ │ │ │ │ ├── MangaDownloadQueueScreenModel.kt
│ │ │ │ │ │ │ └── MangaDownloadQueueTab.kt
│ │ │ │ │ ├── entries
│ │ │ │ │ │ ├── anime
│ │ │ │ │ │ │ ├── AnimeCoverScreenModel.kt
│ │ │ │ │ │ │ ├── AnimeScreen.kt
│ │ │ │ │ │ │ ├── AnimeScreenModel.kt
│ │ │ │ │ │ │ └── track
│ │ │ │ │ │ │ │ ├── AnimeTrackInfoDialog.kt
│ │ │ │ │ │ │ │ └── AnimeTrackItem.kt
│ │ │ │ │ │ └── manga
│ │ │ │ │ │ │ ├── MangaCoverScreenModel.kt
│ │ │ │ │ │ │ ├── MangaScreen.kt
│ │ │ │ │ │ │ ├── MangaScreenModel.kt
│ │ │ │ │ │ │ └── track
│ │ │ │ │ │ │ ├── MangaTrackInfoDialog.kt
│ │ │ │ │ │ │ └── MangaTrackItem.kt
│ │ │ │ │ ├── history
│ │ │ │ │ │ ├── HistoriesTab.kt
│ │ │ │ │ │ ├── anime
│ │ │ │ │ │ │ ├── AnimeHistoryScreenModel.kt
│ │ │ │ │ │ │ └── AnimeHistoryTab.kt
│ │ │ │ │ │ └── manga
│ │ │ │ │ │ │ ├── MangaHistoryScreenModel.kt
│ │ │ │ │ │ │ └── MangaHistoryTab.kt
│ │ │ │ │ ├── home
│ │ │ │ │ │ └── HomeScreen.kt
│ │ │ │ │ ├── library
│ │ │ │ │ │ ├── anime
│ │ │ │ │ │ │ ├── AnimeLibraryItem.kt
│ │ │ │ │ │ │ ├── AnimeLibraryScreenModel.kt
│ │ │ │ │ │ │ ├── AnimeLibrarySettingsScreenModel.kt
│ │ │ │ │ │ │ └── AnimeLibraryTab.kt
│ │ │ │ │ │ └── manga
│ │ │ │ │ │ │ ├── MangaLibraryItem.kt
│ │ │ │ │ │ │ ├── MangaLibraryScreenModel.kt
│ │ │ │ │ │ │ ├── MangaLibrarySettingsScreenModel.kt
│ │ │ │ │ │ │ └── MangaLibraryTab.kt
│ │ │ │ │ ├── main
│ │ │ │ │ │ └── MainActivity.kt
│ │ │ │ │ ├── more
│ │ │ │ │ │ ├── MoreTab.kt
│ │ │ │ │ │ ├── NewUpdateScreen.kt
│ │ │ │ │ │ └── OnboardingScreen.kt
│ │ │ │ │ ├── player
│ │ │ │ │ │ ├── AniyomiMPVView.kt
│ │ │ │ │ │ ├── ExternalIntents.kt
│ │ │ │ │ │ ├── PipActions.kt
│ │ │ │ │ │ ├── PlayerActivity.kt
│ │ │ │ │ │ ├── PlayerEnums.kt
│ │ │ │ │ │ ├── PlayerObserver.kt
│ │ │ │ │ │ ├── PlayerUtils.kt
│ │ │ │ │ │ ├── PlayerViewModel.kt
│ │ │ │ │ │ ├── controls
│ │ │ │ │ │ │ ├── BottomLeftPlayerControls.kt
│ │ │ │ │ │ │ ├── BottomRightPlayerControls.kt
│ │ │ │ │ │ │ ├── GestureHandler.kt
│ │ │ │ │ │ │ ├── MiddlePlayerControls.kt
│ │ │ │ │ │ │ ├── PlayerControls.kt
│ │ │ │ │ │ │ ├── PlayerDialogs.kt
│ │ │ │ │ │ │ ├── PlayerPanels.kt
│ │ │ │ │ │ │ ├── PlayerSheets.kt
│ │ │ │ │ │ │ ├── TopLeftPlayerControls.kt
│ │ │ │ │ │ │ ├── TopRightPlayerControls.kt
│ │ │ │ │ │ │ └── components
│ │ │ │ │ │ │ │ ├── AutoPlaySwitch.kt
│ │ │ │ │ │ │ │ ├── BrightnessOverlay.kt
│ │ │ │ │ │ │ │ ├── ControlsButton.kt
│ │ │ │ │ │ │ │ ├── CurrentChapter.kt
│ │ │ │ │ │ │ │ ├── DoubleTapSeekTriangles.kt
│ │ │ │ │ │ │ │ ├── PlayerUpdates.kt
│ │ │ │ │ │ │ │ ├── SeekBar.kt
│ │ │ │ │ │ │ │ ├── VerticalSliders.kt
│ │ │ │ │ │ │ │ ├── dialogs
│ │ │ │ │ │ │ │ ├── EpisodeListDialog.kt
│ │ │ │ │ │ │ │ ├── IntegerPickerDialog.kt
│ │ │ │ │ │ │ │ └── PlayerDialog.kt
│ │ │ │ │ │ │ │ ├── panels
│ │ │ │ │ │ │ │ ├── AudioDelayPanel.kt
│ │ │ │ │ │ │ │ ├── SubtitleDelayPanel.kt
│ │ │ │ │ │ │ │ ├── SubtitleSettingsColorsCard.kt
│ │ │ │ │ │ │ │ ├── SubtitleSettingsMiscellaneousCard.kt
│ │ │ │ │ │ │ │ ├── SubtitleSettingsPanel.kt
│ │ │ │ │ │ │ │ ├── SubtitleSettingsTypographyCard.kt
│ │ │ │ │ │ │ │ └── VideoFiltersPanel.kt
│ │ │ │ │ │ │ │ └── sheets
│ │ │ │ │ │ │ │ ├── AudioTracksSheet.kt
│ │ │ │ │ │ │ │ ├── ChaptersSheet.kt
│ │ │ │ │ │ │ │ ├── GenericTracksSheet.kt
│ │ │ │ │ │ │ │ ├── MoreSheet.kt
│ │ │ │ │ │ │ │ ├── PlaybackSpeedSheet.kt
│ │ │ │ │ │ │ │ ├── QualitySheet.kt
│ │ │ │ │ │ │ │ ├── ScreenshotSheet.kt
│ │ │ │ │ │ │ │ └── SubtitleTracksSheet.kt
│ │ │ │ │ │ ├── loader
│ │ │ │ │ │ │ ├── EpisodeLoader.kt
│ │ │ │ │ │ │ └── HosterLoader.kt
│ │ │ │ │ │ ├── settings
│ │ │ │ │ │ │ ├── AdvancedPlayerPreferences.kt
│ │ │ │ │ │ │ ├── AudioPreferences.kt
│ │ │ │ │ │ │ ├── DecoderPreferences.kt
│ │ │ │ │ │ │ ├── GesturePreferences.kt
│ │ │ │ │ │ │ ├── PlayerPreferences.kt
│ │ │ │ │ │ │ └── SubtitlePreferences.kt
│ │ │ │ │ │ └── utils
│ │ │ │ │ │ │ ├── AniSkipApi.kt
│ │ │ │ │ │ │ ├── ChapterUtils.kt
│ │ │ │ │ │ │ └── TrackSelect.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
│ │ │ │ │ │ ├── PlayerSettingsScreen.kt
│ │ │ │ │ │ ├── SettingsScreen.kt
│ │ │ │ │ │ └── track
│ │ │ │ │ │ │ ├── BaseOAuthLoginActivity.kt
│ │ │ │ │ │ │ └── TrackLoginActivity.kt
│ │ │ │ │ ├── stats
│ │ │ │ │ │ ├── StatsTab.kt
│ │ │ │ │ │ ├── anime
│ │ │ │ │ │ │ ├── AnimeStatsScreenModel.kt
│ │ │ │ │ │ │ └── AnimeStatsTab.kt
│ │ │ │ │ │ └── manga
│ │ │ │ │ │ │ ├── MangaStatsScreenModel.kt
│ │ │ │ │ │ │ └── MangaStatsTab.kt
│ │ │ │ │ ├── storage
│ │ │ │ │ │ ├── CommonStorageScreenModel.kt
│ │ │ │ │ │ ├── StorageTab.kt
│ │ │ │ │ │ ├── anime
│ │ │ │ │ │ │ ├── AnimeStorageScreenModel.kt
│ │ │ │ │ │ │ └── AnimeStorageTab.kt
│ │ │ │ │ │ └── manga
│ │ │ │ │ │ │ ├── MangaStorageScreenModel.kt
│ │ │ │ │ │ │ └── MangaStorageTab.kt
│ │ │ │ │ ├── updates
│ │ │ │ │ │ ├── UpdatesTab.kt
│ │ │ │ │ │ ├── anime
│ │ │ │ │ │ │ ├── AnimeUpdatesScreenModel.kt
│ │ │ │ │ │ │ └── AnimeUpdatesTab.kt
│ │ │ │ │ │ └── manga
│ │ │ │ │ │ │ ├── MangaUpdatesScreenModel.kt
│ │ │ │ │ │ │ └── MangaUpdatesTab.kt
│ │ │ │ │ └── webview
│ │ │ │ │ │ ├── WebViewActivity.kt
│ │ │ │ │ │ ├── WebViewScreen.kt
│ │ │ │ │ │ └── WebViewScreenModel.kt
│ │ │ │ ├── util
│ │ │ │ │ ├── AniChartApi.kt
│ │ │ │ │ ├── AnimeExtensions.kt
│ │ │ │ │ ├── CrashLogUtil.kt
│ │ │ │ │ ├── MangaExtensions.kt
│ │ │ │ │ ├── PkceUtil.kt
│ │ │ │ │ ├── StorageUtil.kt
│ │ │ │ │ ├── chapter
│ │ │ │ │ │ ├── ChapterFilterDownloaded.kt
│ │ │ │ │ │ ├── ChapterGetNextUnread.kt
│ │ │ │ │ │ └── ChapterRemoveDuplicates.kt
│ │ │ │ │ ├── episode
│ │ │ │ │ │ ├── EpisodeFilterDownloaded.kt
│ │ │ │ │ │ └── EpsiodeGetNextUnseen.kt
│ │ │ │ │ ├── lang
│ │ │ │ │ │ ├── CloseableExtensions.kt
│ │ │ │ │ │ ├── DateExtensions.kt
│ │ │ │ │ │ └── RectFExtensions.kt
│ │ │ │ │ ├── storage
│ │ │ │ │ │ └── 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
│ │ │ │ │ │ ├── TvUtils.kt
│ │ │ │ │ │ └── WorkManagerExtensions.kt
│ │ │ │ │ └── view
│ │ │ │ │ │ ├── EditTextPreferenceExtensions.kt
│ │ │ │ │ │ ├── ViewExtensions.kt
│ │ │ │ │ │ └── WindowExtensions.kt
│ │ │ │ └── widget
│ │ │ │ │ ├── MinMaxNumberPicker.kt
│ │ │ │ │ ├── RevealAnimationView.kt
│ │ │ │ │ ├── TachiyomiTextInputEditText.kt
│ │ │ │ │ ├── ViewPagerAdapter.kt
│ │ │ │ │ └── listener
│ │ │ │ │ ├── IgnoreFirstSpinnerListener.kt
│ │ │ │ │ └── SimpleSeekBarListener.kt
│ │ │ │ └── test
│ │ │ │ └── DummyTracker.kt
│ │ └── mihon
│ │ │ ├── core
│ │ │ ├── designsystem
│ │ │ │ └── utils
│ │ │ │ │ └── WindowSize.kt
│ │ │ └── migration
│ │ │ │ ├── Migration.kt
│ │ │ │ ├── MigrationCompletedListener.kt
│ │ │ │ ├── MigrationContext.kt
│ │ │ │ ├── MigrationJobFactory.kt
│ │ │ │ ├── MigrationStrategy.kt
│ │ │ │ ├── MigrationStrategyFactory.kt
│ │ │ │ ├── Migrator.kt
│ │ │ │ └── migrations
│ │ │ │ ├── AddAllLangMigration.kt
│ │ │ │ ├── CategoryPreferencesCleanupMigration.kt
│ │ │ │ ├── CombineUpdateRestrictionMigration.kt
│ │ │ │ ├── CoverToExternalFileMigration.kt
│ │ │ │ ├── DOHMigration.kt
│ │ │ │ ├── DeleteExternalChapterCacheDirMigration.kt
│ │ │ │ ├── DontRunJobsMigration.kt
│ │ │ │ ├── EnableAutoBackupMigration.kt
│ │ │ │ ├── EnumsMigration.kt
│ │ │ │ ├── ExternalRepoMigration.kt
│ │ │ │ ├── ForceMALLogOutMigration.kt
│ │ │ │ ├── InternalChapterCacheDirMigration.kt
│ │ │ │ ├── LogOutMALMigration.kt
│ │ │ │ ├── MergeSortTypeDirectionMigration.kt
│ │ │ │ ├── MigrateRotationViewerValuesMigration.kt
│ │ │ │ ├── MigrateSecureScreenMigration.kt
│ │ │ │ ├── MigrateSortingModeMigration.kt
│ │ │ │ ├── MigrateToTriStateMigration.kt
│ │ │ │ ├── MigrateTriStateMigration.kt
│ │ │ │ ├── MigrationUtils.kt
│ │ │ │ ├── Migrations.kt
│ │ │ │ ├── MoveChapterPreferencesMigration.kt
│ │ │ │ ├── MovePlayerPreferencesMigration.kt
│ │ │ │ ├── NavigationOptionsMigration.kt
│ │ │ │ ├── NoAppStateMigration.kt
│ │ │ │ ├── PEMFileMigration.kt
│ │ │ │ ├── PermaTrustExtensionsMigration.kt
│ │ │ │ ├── PlayerPreferenceMigration.kt
│ │ │ │ ├── PrivatePreferenceMigration.kt
│ │ │ │ ├── RelativeTimestampMigration.kt
│ │ │ │ ├── RemoveBackgroundJobsMigration.kt
│ │ │ │ ├── RemoveOneTwoHourUpdateMigration.kt
│ │ │ │ ├── RemoveQuickUpdateMigration.kt
│ │ │ │ ├── RemoveReaderTapMigration.kt
│ │ │ │ ├── RenameEnumMigration.kt
│ │ │ │ ├── ResetRotationMigration.kt
│ │ │ │ ├── ResetSortPreferenceRemovedMigration.kt
│ │ │ │ ├── SetupAnimeLibraryUpdateMigration.kt
│ │ │ │ ├── SetupBackgroundTasksMigration.kt
│ │ │ │ ├── SetupBackupCreateMigration.kt
│ │ │ │ ├── SetupMangaLibraryUpdateMigration.kt
│ │ │ │ ├── SplitPreferencesMigration.kt
│ │ │ │ ├── TrustExtensionRepositoryMigration.kt
│ │ │ │ ├── UseWorkManagerMigration.kt
│ │ │ │ ├── VideoOrientationMigration.kt
│ │ │ │ └── VideoPlayerPreferenceMigration.kt
│ │ │ └── feature
│ │ │ └── upcoming
│ │ │ ├── anime
│ │ │ ├── UpcomingAnimeScreen.kt
│ │ │ ├── UpcomingAnimeScreenContent.kt
│ │ │ ├── UpcomingAnimeScreenModel.kt
│ │ │ ├── UpcomingAnimeUIModel.kt
│ │ │ └── components
│ │ │ │ └── UpcomingItem.kt
│ │ │ ├── components
│ │ │ └── calendar
│ │ │ │ ├── Calendar.kt
│ │ │ │ ├── CalendarDay.kt
│ │ │ │ ├── CalendarHeader.kt
│ │ │ │ └── CalendarIndicator.kt
│ │ │ └── manga
│ │ │ ├── UpcomingMangaScreen.kt
│ │ │ ├── UpcomingMangaScreenContent.kt
│ │ │ ├── UpcomingMangaScreenModel.kt
│ │ │ ├── UpcomingMangaUIModel.kt
│ │ │ └── components
│ │ │ └── UpcomingItem.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
│ │ ├── player_enter_bottom.xml
│ │ ├── player_enter_left.xml
│ │ ├── player_enter_right.xml
│ │ ├── player_enter_top.xml
│ │ ├── player_exit_bottom.xml
│ │ ├── player_exit_left.xml
│ │ ├── player_exit_right.xml
│ │ ├── player_exit_top.xml
│ │ ├── player_fade_in.xml
│ │ ├── player_fade_out.xml
│ │ ├── 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_jellyfin.webp
│ │ ├── ic_tracker_kavita.webp
│ │ ├── ic_tracker_kitsu.webp
│ │ ├── ic_tracker_komga.webp
│ │ ├── ic_tracker_mal.webp
│ │ ├── ic_tracker_shikimori.webp
│ │ ├── ic_tracker_simkl.webp
│ │ └── ic_tracker_suwayomi.webp
│ │ ├── drawable
│ │ ├── anim_animelibrary_enter.xml
│ │ ├── anim_animelibrary_leave.xml
│ │ ├── anim_browse_enter.xml
│ │ ├── anim_caret_down.xml
│ │ ├── anim_history_enter.xml
│ │ ├── anim_library_enter.xml
│ │ ├── anim_more_enter.xml
│ │ ├── anim_play_to_pause.xml
│ │ ├── anim_updates_enter.xml
│ │ ├── cover_error.xml
│ │ ├── ic_ani.xml
│ │ ├── ic_ani_monochrome_launcher.xml
│ │ ├── ic_animelibrary_filled_24dp.xml
│ │ ├── ic_animelibrary_outline_24dp.xml
│ │ ├── ic_animelibrary_selector_24dp.xml
│ │ ├── ic_arrow_back_24dp.xml
│ │ ├── ic_baseline_collections_24.xml
│ │ ├── ic_baseline_input_24.xml
│ │ ├── ic_baseline_open_in_new_24.xml
│ │ ├── ic_book_24dp.xml
│ │ ├── ic_brightness_negative_20dp.xml
│ │ ├── ic_chrome_player_mode_24dp.xml
│ │ ├── ic_circle_200dp.xml
│ │ ├── ic_circle_right_200dp.xml
│ │ ├── ic_close_24dp.xml
│ │ ├── ic_collections_baseline_state.xml
│ │ ├── ic_crop_24dp.xml
│ │ ├── ic_crop_off_24dp.xml
│ │ ├── ic_done_24dp.xml
│ │ ├── ic_done_prev_24dp.xml
│ │ ├── ic_download_item_24dp.xml
│ │ ├── ic_drag_handle_24dp.xml
│ │ ├── ic_extension_24dp.xml
│ │ ├── ic_folder_24dp.xml
│ │ ├── ic_forward_10_24dp.xml
│ │ ├── ic_glasses_24dp.xml
│ │ ├── ic_info_24dp.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_overflow_24dp.xml
│ │ ├── ic_pause_24dp.xml
│ │ ├── ic_pause_circle_filled_24.xml
│ │ ├── ic_photo_24dp.xml
│ │ ├── ic_play_arrow_24dp.xml
│ │ ├── ic_play_circle_filled_24.xml
│ │ ├── ic_play_seek_triangle.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_skip_next_24dp.xml
│ │ ├── ic_skip_previous_24dp.xml
│ │ ├── ic_system_update_alt_white_24dp.xml
│ │ ├── ic_tachi_splash.xml
│ │ ├── ic_updates_outline_24dp.xml
│ │ ├── ic_video_chapter_20dp.xml
│ │ ├── ic_volume_off_24dp.xml
│ │ ├── ic_warning_white_24dp.xml
│ │ ├── line_divider.xml
│ │ ├── material_popup_background.xml
│ │ ├── outline_brand_family_24.xml
│ │ ├── sc_collections_baseline_48dp.xml
│ │ ├── sc_collections_bookmark_48dp.xml
│ │ ├── sc_explore_48dp.xml
│ │ ├── sc_history_48dp.xml
│ │ ├── sc_new_releases_48dp.xml
│ │ └── sharp_shadow_24.xml
│ │ ├── layout
│ │ ├── download_header.xml
│ │ ├── download_item.xml
│ │ ├── download_list.xml
│ │ ├── player_layout.xml
│ │ ├── pref_widget_switch_material.xml
│ │ ├── reader_activity.xml
│ │ └── reader_error.xml
│ │ ├── menu
│ │ ├── chapter_download.xml
│ │ ├── download_single.xml
│ │ └── main_nav.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
│ │ └── ic_launcher_round.xml
│ │ ├── raw
│ │ └── keep.xml
│ │ ├── values-night-v31
│ │ └── themes.xml
│ │ ├── values-night
│ │ ├── bools.xml
│ │ ├── colors_cottoncandy.xml
│ │ ├── colors_mocha.xml
│ │ └── themes.xml
│ │ ├── values-sw720dp
│ │ └── dimens.xml
│ │ ├── values-v27
│ │ ├── bools.xml
│ │ └── themes.xml
│ │ ├── values-v31
│ │ └── themes.xml
│ │ ├── values
│ │ ├── attrs.xml
│ │ ├── bools.xml
│ │ ├── colors_cottoncandy.xml
│ │ ├── colors_mocha.xml
│ │ ├── dimens.xml
│ │ ├── ids.xml
│ │ ├── integers.xml
│ │ ├── styles.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── network_security_config.xml
│ │ ├── provider_paths.xml
│ │ ├── s_pen_actions.xml
│ │ └── searchable.xml
│ └── test
│ └── java
│ └── mihon
│ └── core
│ └── migration
│ └── MigratorTest.kt
├── 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
│ ├── BuildConfig.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
│ ├── AnimeDetails.kt
│ ├── ChapterDetails.kt
│ ├── EpisodeDetails.kt
│ └── 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
│ └── java
│ ├── eu
│ └── kanade
│ │ └── tachiyomi
│ │ ├── core
│ │ ├── Constants.kt
│ │ └── security
│ │ │ └── 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
│ │ ├── FFmpegUtils.kt
│ │ └── FileExtensions.kt
│ │ └── system
│ │ ├── DensityExtensions.kt
│ │ ├── DeviceUtil.kt
│ │ ├── GLUtil.kt
│ │ ├── ToastExtensions.kt
│ │ └── WebViewUtil.kt
│ └── tachiyomi
│ └── core
│ └── common
│ ├── 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
│ └── UniFileTempFileManager.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
│ │ │ ├── anime
│ │ │ └── AnimeExtensionRepoRepositoryImpl.kt
│ │ │ └── manga
│ │ │ └── MangaExtensionRepoRepositoryImpl.kt
│ └── tachiyomi
│ │ └── data
│ │ ├── DatabaseAdapter.kt
│ │ ├── category
│ │ ├── anime
│ │ │ └── AnimeCategoryRepositoryImpl.kt
│ │ └── manga
│ │ │ └── MangaCategoryRepositoryImpl.kt
│ │ ├── custombutton
│ │ └── CustomButtonRepositoryImpl.kt
│ │ ├── entries
│ │ ├── anime
│ │ │ ├── AnimeMapper.kt
│ │ │ └── AnimeRepositoryImpl.kt
│ │ └── manga
│ │ │ ├── MangaMapper.kt
│ │ │ └── MangaRepositoryImpl.kt
│ │ ├── handlers
│ │ ├── anime
│ │ │ ├── AndroidAnimeDatabaseHandler.kt
│ │ │ ├── AnimeDatabaseHandler.kt
│ │ │ ├── AnimeTransactionContext.kt
│ │ │ └── QueryPagingAnimeSource.kt
│ │ └── manga
│ │ │ ├── AndroidMangaDatabaseHandler.kt
│ │ │ ├── MangaDatabaseHandler.kt
│ │ │ ├── MangaTransactionContext.kt
│ │ │ └── QueryPagingMangaSource.kt
│ │ ├── history
│ │ ├── anime
│ │ │ ├── AnimeHistoryMapper.kt
│ │ │ └── AnimeHistoryRepositoryImpl.kt
│ │ └── manga
│ │ │ ├── MangaHistoryMapper.kt
│ │ │ └── MangaHistoryRepositoryImpl.kt
│ │ ├── items
│ │ ├── chapter
│ │ │ ├── ChapterRepositoryImpl.kt
│ │ │ └── ChapterSanitizer.kt
│ │ └── episode
│ │ │ ├── EpisodeRepositoryImpl.kt
│ │ │ └── EpisodeSanitizer.kt
│ │ ├── release
│ │ ├── GithubRelease.kt
│ │ └── ReleaseServiceImpl.kt
│ │ ├── source
│ │ ├── anime
│ │ │ ├── AnimeSourcePagingSource.kt
│ │ │ ├── AnimeSourceRepositoryImpl.kt
│ │ │ └── AnimeStubSourceRepositoryImpl.kt
│ │ └── manga
│ │ │ ├── MangaSourcePagingSource.kt
│ │ │ ├── MangaSourceRepositoryImpl.kt
│ │ │ └── MangaStubSourceRepositoryImpl.kt
│ │ ├── track
│ │ ├── anime
│ │ │ ├── AnimeTrackMapper.kt
│ │ │ └── AnimeTrackRepositoryImpl.kt
│ │ └── manga
│ │ │ ├── MangaTrackMapper.kt
│ │ │ └── MangaTrackRepositoryImpl.kt
│ │ └── updates
│ │ ├── anime
│ │ └── AnimeUpdatesRepositoryImpl.kt
│ │ └── manga
│ │ └── MangaUpdatesRepositoryImpl.kt
│ ├── sqldelight
│ ├── 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
│ │ ├── 10.sqm
│ │ ├── 11.sqm
│ │ ├── 12.sqm
│ │ ├── 13.sqm
│ │ ├── 14.sqm
│ │ ├── 15.sqm
│ │ ├── 16.sqm
│ │ ├── 17.sqm
│ │ ├── 18.sqm
│ │ ├── 19.sqm
│ │ ├── 2.sqm
│ │ ├── 20.sqm
│ │ ├── 21.sqm
│ │ ├── 22.sqm
│ │ ├── 23.sqm
│ │ ├── 24.sqm
│ │ ├── 25.sqm
│ │ ├── 26.sqm
│ │ ├── 27.sqm
│ │ ├── 28.sqm
│ │ ├── 29.sqm
│ │ ├── 3.sqm
│ │ ├── 30.sqm
│ │ ├── 31.sqm
│ │ ├── 32.sqm
│ │ ├── 4.sqm
│ │ ├── 5.sqm
│ │ ├── 6.sqm
│ │ ├── 7.sqm
│ │ ├── 8.sqm
│ │ └── 9.sqm
│ └── view
│ │ ├── historyView.sq
│ │ ├── libraryView.sq
│ │ └── updatesView.sq
│ └── sqldelightanime
│ ├── dataanime
│ ├── anime_sync.sq
│ ├── animehistory.sq
│ ├── animes.sq
│ ├── animes_categories.sq
│ ├── animesources.sq
│ ├── categories.sq
│ ├── custom_buttons.sq
│ ├── episodes.sq
│ └── extension_repos.sq
│ ├── migrations
│ ├── 113.sqm
│ ├── 114.sqm
│ ├── 115.sqm
│ ├── 116.sqm
│ ├── 117.sqm
│ ├── 118.sqm
│ ├── 119.sqm
│ ├── 120.sqm
│ ├── 121.sqm
│ ├── 122.sqm
│ ├── 123.sqm
│ ├── 124.sqm
│ ├── 125.sqm
│ ├── 126.sqm
│ ├── 127.sqm
│ ├── 128.sqm
│ ├── 129.sqm
│ └── 130.sqm
│ └── view
│ ├── animehistoryView.sq
│ ├── animelibView.sq
│ └── animeupdatesView.sq
├── domain
├── build.gradle.kts
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ ├── mihon
│ │ └── domain
│ │ │ ├── extensionrepo
│ │ │ ├── anime
│ │ │ │ ├── interactor
│ │ │ │ │ ├── CreateAnimeExtensionRepo.kt
│ │ │ │ │ ├── DeleteAnimeExtensionRepo.kt
│ │ │ │ │ ├── GetAnimeExtensionRepo.kt
│ │ │ │ │ ├── GetAnimeExtensionRepoCount.kt
│ │ │ │ │ ├── ReplaceAnimeExtensionRepo.kt
│ │ │ │ │ └── UpdateAnimeExtensionRepo.kt
│ │ │ │ └── repository
│ │ │ │ │ └── AnimeExtensionRepoRepository.kt
│ │ │ ├── exception
│ │ │ │ └── SaveExtensionRepoException.kt
│ │ │ ├── manga
│ │ │ │ ├── interactor
│ │ │ │ │ ├── CreateMangaExtensionRepo.kt
│ │ │ │ │ ├── DeleteMangaExtensionRepo.kt
│ │ │ │ │ ├── GetMangaExtensionRepo.kt
│ │ │ │ │ ├── GetMangaExtensionRepoCount.kt
│ │ │ │ │ ├── ReplaceMangaExtensionRepo.kt
│ │ │ │ │ └── UpdateMangaExtensionRepo.kt
│ │ │ │ └── repository
│ │ │ │ │ └── MangaExtensionRepoRepository.kt
│ │ │ ├── model
│ │ │ │ └── ExtensionRepo.kt
│ │ │ └── service
│ │ │ │ ├── ExtensionRepoDto.kt
│ │ │ │ └── ExtensionRepoService.kt
│ │ │ ├── items
│ │ │ ├── chapter
│ │ │ │ └── interactor
│ │ │ │ │ └── FilterChaptersForDownload.kt
│ │ │ └── episode
│ │ │ │ └── interactor
│ │ │ │ └── FilterEpisodesForDownload.kt
│ │ │ └── upcoming
│ │ │ ├── anime
│ │ │ └── interactor
│ │ │ │ └── GetUpcomingAnime.kt
│ │ │ └── manga
│ │ │ └── interactor
│ │ │ └── GetUpcomingManga.kt
│ │ └── tachiyomi
│ │ └── domain
│ │ ├── backup
│ │ └── service
│ │ │ ├── BackupPreferences.kt
│ │ │ └── PreferenceValues.kt
│ │ ├── category
│ │ ├── anime
│ │ │ ├── interactor
│ │ │ │ ├── CreateAnimeCategoryWithName.kt
│ │ │ │ ├── DeleteAnimeCategory.kt
│ │ │ │ ├── GetAnimeCategories.kt
│ │ │ │ ├── GetVisibleAnimeCategories.kt
│ │ │ │ ├── HideAnimeCategory.kt
│ │ │ │ ├── RenameAnimeCategory.kt
│ │ │ │ ├── ReorderAnimeCategory.kt
│ │ │ │ ├── ResetAnimeCategoryFlags.kt
│ │ │ │ ├── SetAnimeCategories.kt
│ │ │ │ ├── SetAnimeDisplayMode.kt
│ │ │ │ ├── SetSortModeForAnimeCategory.kt
│ │ │ │ └── UpdateAnimeCategory.kt
│ │ │ └── repository
│ │ │ │ └── AnimeCategoryRepository.kt
│ │ ├── manga
│ │ │ ├── interactor
│ │ │ │ ├── CreateMangaCategoryWithName.kt
│ │ │ │ ├── DeleteMangaCategory.kt
│ │ │ │ ├── GetMangaCategories.kt
│ │ │ │ ├── GetVisibleMangaCategories.kt
│ │ │ │ ├── HideMangaCategory.kt
│ │ │ │ ├── RenameMangaCategory.kt
│ │ │ │ ├── ReorderMangaCategory.kt
│ │ │ │ ├── ResetMangaCategoryFlags.kt
│ │ │ │ ├── SetMangaCategories.kt
│ │ │ │ ├── SetMangaDisplayMode.kt
│ │ │ │ ├── SetSortModeForMangaCategory.kt
│ │ │ │ └── UpdateMangaCategory.kt
│ │ │ └── repository
│ │ │ │ └── MangaCategoryRepository.kt
│ │ └── model
│ │ │ ├── Category.kt
│ │ │ └── CategoryUpdate.kt
│ │ ├── custombuttons
│ │ ├── exception
│ │ │ └── SaveCustomButtonException.kt
│ │ ├── interactor
│ │ │ ├── CreateCustomButton.kt
│ │ │ ├── DeleteCustomButton.kt
│ │ │ ├── GetCustomButtons.kt
│ │ │ ├── ReorderCustomButton.kt
│ │ │ ├── ToggleFavoriteCustomButton.kt
│ │ │ └── UpdateCustomButton.kt
│ │ ├── model
│ │ │ ├── CustomButton.kt
│ │ │ └── CustomButtonUpdate.kt
│ │ └── repository
│ │ │ └── CustomButtonRepository.kt
│ │ ├── download
│ │ └── service
│ │ │ └── DownloadPreferences.kt
│ │ ├── entries
│ │ ├── EntryCover.kt
│ │ ├── TriState.kt
│ │ ├── anime
│ │ │ ├── interactor
│ │ │ │ ├── AnimeFetchInterval.kt
│ │ │ │ ├── GetAnime.kt
│ │ │ │ ├── GetAnimeByUrlAndSourceId.kt
│ │ │ │ ├── GetAnimeFavorites.kt
│ │ │ │ ├── GetAnimeWithEpisodes.kt
│ │ │ │ ├── GetDuplicateLibraryAnime.kt
│ │ │ │ ├── GetLibraryAnime.kt
│ │ │ │ ├── NetworkToLocalAnime.kt
│ │ │ │ ├── ResetAnimeViewerFlags.kt
│ │ │ │ └── SetAnimeEpisodeFlags.kt
│ │ │ ├── model
│ │ │ │ ├── Anime.kt
│ │ │ │ ├── AnimeCover.kt
│ │ │ │ └── AnimeUpdate.kt
│ │ │ └── repository
│ │ │ │ └── AnimeRepository.kt
│ │ └── manga
│ │ │ ├── interactor
│ │ │ ├── GetDuplicateLibraryManga.kt
│ │ │ ├── GetLibraryManga.kt
│ │ │ ├── GetManga.kt
│ │ │ ├── GetMangaByUrlAndSourceId.kt
│ │ │ ├── GetMangaFavorites.kt
│ │ │ ├── GetMangaWithChapters.kt
│ │ │ ├── MangaFetchInterval.kt
│ │ │ ├── NetworkToLocalManga.kt
│ │ │ ├── ResetMangaViewerFlags.kt
│ │ │ └── SetMangaChapterFlags.kt
│ │ │ ├── model
│ │ │ ├── Manga.kt
│ │ │ ├── MangaCover.kt
│ │ │ └── MangaUpdate.kt
│ │ │ └── repository
│ │ │ └── MangaRepository.kt
│ │ ├── history
│ │ ├── anime
│ │ │ ├── interactor
│ │ │ │ ├── GetAnimeHistory.kt
│ │ │ │ ├── GetNextEpisodes.kt
│ │ │ │ ├── RemoveAnimeHistory.kt
│ │ │ │ └── UpsertAnimeHistory.kt
│ │ │ ├── model
│ │ │ │ ├── AnimeHistory.kt
│ │ │ │ ├── AnimeHistoryUpdate.kt
│ │ │ │ └── AnimeHistoryWithRelations.kt
│ │ │ └── repository
│ │ │ │ └── AnimeHistoryRepository.kt
│ │ └── manga
│ │ │ ├── interactor
│ │ │ ├── GetMangaHistory.kt
│ │ │ ├── GetNextChapters.kt
│ │ │ ├── GetTotalReadDuration.kt
│ │ │ ├── RemoveMangaHistory.kt
│ │ │ └── UpsertMangaHistory.kt
│ │ │ ├── model
│ │ │ ├── MangaHistory.kt
│ │ │ ├── MangaHistoryUpdate.kt
│ │ │ └── MangaHistoryWithRelations.kt
│ │ │ └── repository
│ │ │ └── MangaHistoryRepository.kt
│ │ ├── items
│ │ ├── 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
│ │ │ │ ├── ChapterSorter.kt
│ │ │ │ └── MissingChapters.kt
│ │ └── episode
│ │ │ ├── interactor
│ │ │ ├── GetEpisode.kt
│ │ │ ├── GetEpisodeByUrlAndAnimeId.kt
│ │ │ ├── GetEpisodesByAnimeId.kt
│ │ │ ├── SetAnimeDefaultEpisodeFlags.kt
│ │ │ ├── ShouldUpdateDbEpisode.kt
│ │ │ └── UpdateEpisode.kt
│ │ │ ├── model
│ │ │ ├── Episode.kt
│ │ │ ├── EpisodeUpdate.kt
│ │ │ └── NoEpisodesException.kt
│ │ │ ├── repository
│ │ │ └── EpisodeRepository.kt
│ │ │ └── service
│ │ │ ├── EpisodeRecognition.kt
│ │ │ ├── EpisodeSorter.kt
│ │ │ └── MissingEpisodes.kt
│ │ ├── library
│ │ ├── anime
│ │ │ ├── LibraryAnime.kt
│ │ │ └── model
│ │ │ │ └── AnimeLibrarySortMode.kt
│ │ ├── manga
│ │ │ ├── LibraryManga.kt
│ │ │ └── model
│ │ │ │ └── MangaLibrarySortMode.kt
│ │ ├── model
│ │ │ ├── Flag.kt
│ │ │ └── LibraryDisplayMode.kt
│ │ └── service
│ │ │ └── LibraryPreferences.kt
│ │ ├── release
│ │ ├── interactor
│ │ │ └── GetApplicationRelease.kt
│ │ ├── model
│ │ │ └── Release.kt
│ │ └── service
│ │ │ └── ReleaseService.kt
│ │ ├── source
│ │ ├── anime
│ │ │ ├── interactor
│ │ │ │ ├── GetAnimeSourcesWithNonLibraryAnime.kt
│ │ │ │ └── GetRemoteAnime.kt
│ │ │ ├── model
│ │ │ │ ├── AnimeSource.kt
│ │ │ │ ├── AnimeSourceWithCount.kt
│ │ │ │ ├── Pin.kt
│ │ │ │ └── StubAnimeSource.kt
│ │ │ ├── repository
│ │ │ │ ├── AnimeSourceRepository.kt
│ │ │ │ └── AnimeStubSourceRepository.kt
│ │ │ └── service
│ │ │ │ └── AnimeSourceManager.kt
│ │ └── manga
│ │ │ ├── interactor
│ │ │ ├── GetMangaSourcesWithNonLibraryManga.kt
│ │ │ └── GetRemoteManga.kt
│ │ │ ├── model
│ │ │ ├── MangaSourceWithCount.kt
│ │ │ ├── Pin.kt
│ │ │ ├── Source.kt
│ │ │ └── StubMangaSource.kt
│ │ │ ├── repository
│ │ │ ├── MangaSourceRepository.kt
│ │ │ └── MangaStubSourceRepository.kt
│ │ │ └── service
│ │ │ └── MangaSourceManager.kt
│ │ ├── storage
│ │ └── service
│ │ │ ├── StorageManager.kt
│ │ │ └── StoragePreferences.kt
│ │ ├── track
│ │ ├── anime
│ │ │ ├── interactor
│ │ │ │ ├── DeleteAnimeTrack.kt
│ │ │ │ ├── GetAnimeTracks.kt
│ │ │ │ ├── GetTracksPerAnime.kt
│ │ │ │ └── InsertAnimeTrack.kt
│ │ │ ├── model
│ │ │ │ └── AnimeTrack.kt
│ │ │ └── repository
│ │ │ │ └── AnimeTrackRepository.kt
│ │ └── manga
│ │ │ ├── interactor
│ │ │ ├── DeleteMangaTrack.kt
│ │ │ ├── GetMangaTracks.kt
│ │ │ ├── GetTracksPerManga.kt
│ │ │ └── InsertMangaTrack.kt
│ │ │ ├── model
│ │ │ └── MangaTrack.kt
│ │ │ └── repository
│ │ │ └── MangaTrackRepository.kt
│ │ └── updates
│ │ ├── anime
│ │ ├── interactor
│ │ │ └── GetAnimeUpdates.kt
│ │ ├── model
│ │ │ └── AnimeUpdatesWithRelations.kt
│ │ └── repository
│ │ │ └── AnimeUpdatesRepository.kt
│ │ └── manga
│ │ ├── interactor
│ │ └── GetMangaUpdates.kt
│ │ ├── model
│ │ └── MangaUpdatesWithRelations.kt
│ │ └── repository
│ │ └── MangaUpdatesRepository.kt
│ └── test
│ └── java
│ └── tachiyomi
│ └── domain
│ ├── entries
│ ├── anime
│ │ └── interactor
│ │ │ └── AnimeFetchIntervalTest.kt
│ └── manga
│ │ └── interactor
│ │ └── MangaFetchIntervalTest.kt
│ ├── items
│ ├── chapter
│ │ └── service
│ │ │ └── ChapterRecognitionTest.kt
│ └── service
│ │ └── MissingItemsTest.kt
│ ├── library
│ └── model
│ │ └── LibraryFlagsTest.kt
│ └── release
│ └── interactor
│ └── GetApplicationReleaseTest.kt
├── fastlane
└── metadata
│ └── android
│ └── en-US
│ ├── full_description.txt
│ ├── images
│ └── icon.png
│ └── short_description.txt
├── gradle.properties
├── gradle
├── androidx.versions.toml
├── compose.versions.toml
├── gradle-daemon-jvm.properties
├── kotlinx.versions.toml
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── i18n
├── README.md
├── build.gradle.kts
└── src
│ ├── 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-aniyomi.xml
│ │ ├── plurals.xml
│ │ └── strings.xml
│ │ ├── jv
│ │ ├── plurals-aniyomi.xml
│ │ ├── plurals.xml
│ │ └── strings.xml
│ │ ├── ka-rGE
│ │ ├── plurals.xml
│ │ └── strings.xml
│ │ ├── kk
│ │ ├── plurals.xml
│ │ └── strings.xml
│ │ ├── km
│ │ ├── plurals-aniyomi.xml
│ │ ├── 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-aniyomi.xml
│ │ ├── 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-aniyomi.xml
│ │ ├── 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
│ │ ├── ta
│ │ └── strings.xml
│ │ ├── te
│ │ ├── plurals.xml
│ │ └── strings.xml
│ │ ├── th
│ │ ├── plurals-aniyomi.xml
│ │ ├── plurals.xml
│ │ └── strings.xml
│ │ ├── tr
│ │ ├── plurals.xml
│ │ └── strings.xml
│ │ ├── uk
│ │ ├── plurals.xml
│ │ └── strings.xml
│ │ ├── ur
│ │ └── strings.xml
│ │ ├── uz
│ │ ├── plurals.xml
│ │ └── strings.xml
│ │ ├── vi
│ │ ├── plurals-aniyomi.xml
│ │ ├── plurals.xml
│ │ └── strings.xml
│ │ ├── zh-rCN
│ │ ├── plurals.xml
│ │ └── strings.xml
│ │ └── zh-rTW
│ │ ├── plurals-aniyomi.xml
│ │ ├── plurals.xml
│ │ └── strings.xml
│ └── main
│ └── AndroidManifest.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
│ │ └── Github.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
│ │ └── ThemePreviews.kt
│ └── res
│ ├── values-night
│ ├── color_cloudflare.xml
│ ├── color_doom.xml
│ ├── color_lavender.xml
│ ├── color_matrix.xml
│ ├── color_sapphire.xml
│ ├── colors.xml
│ ├── colors_greenapple.xml
│ ├── colors_midnightdusk.xml
│ ├── colors_monochrome.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
│ ├── color_cloudflare.xml
│ ├── color_doom.xml
│ ├── color_lavender.xml
│ ├── color_matrix.xml
│ ├── color_sapphire.xml
│ ├── colors.xml
│ ├── colors_greenapple.xml
│ ├── colors_midnightdusk.xml
│ ├── colors_monochrome.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
│ │ ├── components
│ │ ├── anime
│ │ │ ├── LockedAnimeWidget.kt
│ │ │ ├── UpdatesAnimeCover.kt
│ │ │ └── UpdatesAnimeWidget.kt
│ │ └── manga
│ │ │ ├── LockedMangaWidget.kt
│ │ │ ├── UpdatesMangaCover.kt
│ │ │ └── UpdatesMangaWidget.kt
│ │ ├── entries
│ │ ├── anime
│ │ │ ├── AnimeUpdatesGridCoverScreenGlanceReceiver.kt
│ │ │ ├── AnimeUpdatesGridCoverScreenGlanceWidget.kt
│ │ │ ├── AnimeUpdatesGridGlanceReceiver.kt
│ │ │ ├── AnimeUpdatesGridGlanceWidget.kt
│ │ │ ├── AnimeWidgetManager.kt
│ │ │ └── BaseAnimeUpdatesGridGlanceWidget.kt
│ │ └── manga
│ │ │ ├── BaseMangaUpdatesGridGlanceWidget.kt
│ │ │ ├── MangaUpdatesGridCoverScreenGlanceReceiver.kt
│ │ │ ├── MangaUpdatesGridCoverScreenGlanceWidget.kt
│ │ │ ├── MangaUpdatesGridGlanceReceiver.kt
│ │ │ ├── MangaUpdatesGridGlanceWidget.kt
│ │ │ └── MangaWidgetManager.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
│ │ ├── animesource
│ │ └── PreferenceScreen.kt
│ │ ├── source
│ │ └── PreferenceScreen.kt
│ │ └── util
│ │ └── RxExtension.kt
│ └── commonMain
│ └── kotlin
│ └── eu
│ └── kanade
│ └── tachiyomi
│ ├── animesource
│ ├── AnimeCatalogueSource.kt
│ ├── AnimeSource.kt
│ ├── AnimeSourceFactory.kt
│ ├── ConfigurableAnimeSource.kt
│ ├── PreferenceScreen.kt
│ ├── UnmeteredSource.kt
│ ├── model
│ │ ├── AnimeFilter.kt
│ │ ├── AnimeFilterList.kt
│ │ ├── AnimeUpdateStrategy.kt
│ │ ├── AnimesPage.kt
│ │ ├── Hoster.kt
│ │ ├── SAnime.kt
│ │ ├── SAnimeImpl.kt
│ │ ├── SEpisode.kt
│ │ ├── SEpisodeImpl.kt
│ │ └── Video.kt
│ ├── online
│ │ ├── AnimeHttpSource.kt
│ │ ├── ParsedAnimeHttpSource.kt
│ │ └── ResolvableAnimeSource.kt
│ └── utils
│ │ └── Preferences.kt
│ ├── source
│ ├── CatalogueSource.kt
│ ├── ConfigurableSource.kt
│ ├── MangaSource.kt
│ ├── PreferenceScreen.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
│ ├── JsonExtensions.kt
│ ├── JsoupExtensions.kt
│ ├── RxExtension.kt
│ └── VideoInfo.kt
└── source-local
├── build.gradle.kts
├── consumer-rules.pro
├── proguard-rules.pro
└── src
├── androidMain
├── AndroidManifest.xml
└── kotlin
│ └── tachiyomi
│ └── source
│ └── local
│ ├── entries
│ ├── anime
│ │ └── LocalAnimeSource.kt
│ └── manga
│ │ └── LocalMangaSource.kt
│ ├── filter
│ ├── anime
│ │ └── AnimeOrderBy.kt
│ └── manga
│ │ └── MangaOrderBy.kt
│ ├── image
│ ├── anime
│ │ └── LocalAnimeCoverManager.kt
│ └── manga
│ │ └── LocalMangaCoverManager.kt
│ ├── io
│ ├── anime
│ │ └── LocalAnimeSourceFileSystem.kt
│ └── manga
│ │ └── LocalMangaSourceFileSystem.kt
│ └── metadata
│ └── EpubReaderExtensions.kt
└── commonMain
└── kotlin
└── tachiyomi
└── source
└── local
├── entries
├── anime
│ └── LocalAnimeSource.kt
└── manga
│ └── LocalMangaSource.kt
├── image
├── anime
│ └── LocalAnimeCoverManager.kt
└── manga
│ └── LocalMangaCoverManager.kt
└── io
├── Archive.kt
├── Format.kt
├── anime
└── LocalAnimeSourceFileSystem.kt
└── manga
└── LocalMangaSourceFileSystem.kt
/.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/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: jmir1
2 | ko_fi: jmir1
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: ❌ Help with Extensions
4 | url: https://aniyomi.org/docs/faq/browse/extensions
5 | about: For extension-related questions/issues
6 | - name: 🧑💻 Aniyomi help discord
7 | url: https://discord.gg/F32UjdJZrR
8 | about: Common questions are answered here
9 | - name: 🖥️ Aniyomi website
10 | url: https://aniyomi.org/
11 | about: Guides, troubleshooting, and answers to common questions
12 |
--------------------------------------------------------------------------------
/.github/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/.github/assets/logo.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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build files
2 | .gradle
3 | .kotlin
4 | build
5 |
6 | # IDE files
7 | *.iml
8 | .idea/*
9 | !.idea/icon.png
10 | /captures
11 |
12 | # Configuration files
13 | local.properties
14 |
15 | # macOS specific files
16 | .DS_Store
17 |
--------------------------------------------------------------------------------
/.idea/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/.idea/icon.png
--------------------------------------------------------------------------------
/app/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/app/.idea/.name:
--------------------------------------------------------------------------------
1 | MangaDownloader.kt
--------------------------------------------------------------------------------
/app/.idea/discord.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/debug/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/debug/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/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(): ToggleableState = 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/AnimeSourceUtil.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.anime.service.AnimeSourceManager
7 | import uy.kohesive.injekt.Injekt
8 | import uy.kohesive.injekt.api.get
9 |
10 | @Composable
11 | fun ifAnimeSourcesLoaded(): Boolean {
12 | return remember { Injekt.get().isInitialized }.collectAsState().value
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/core/util/MangaSourceUtil.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.manga.service.MangaSourceManager
7 | import uy.kohesive.injekt.Injekt
8 | import uy.kohesive.injekt.api.get
9 |
10 | @Composable
11 | fun ifMangaSourcesLoaded(): Boolean {
12 | return remember { Injekt.get().isInitialized }.collectAsState().value
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/domain/SYDomainModule.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.domain
2 |
3 | import eu.kanade.domain.source.manga.interactor.ToggleExcludeFromMangaDataSaver
4 | import uy.kohesive.injekt.api.InjektModule
5 | import uy.kohesive.injekt.api.InjektRegistrar
6 | import uy.kohesive.injekt.api.addFactory
7 | import uy.kohesive.injekt.api.get
8 |
9 | class SYDomainModule : InjektModule {
10 |
11 | override fun InjektRegistrar.registerInjectables() {
12 | addFactory { ToggleExcludeFromMangaDataSaver(get()) }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/domain/extension/anime/model/AnimeExtensions.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.domain.extension.anime.model
2 |
3 | import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
4 |
5 | data class AnimeExtensions(
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/extension/manga/model/MangaExtensions.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.domain.extension.manga.model
2 |
3 | import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
4 |
5 | data class MangaExtensions(
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/source/anime/interactor/ToggleAnimeIncognito.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.domain.source.anime.interactor
2 |
3 | import eu.kanade.domain.source.service.SourcePreferences
4 | import tachiyomi.core.common.preference.getAndSet
5 |
6 | class ToggleAnimeIncognito(
7 | private val preferences: SourcePreferences,
8 | ) {
9 | fun await(extensions: String, enable: Boolean) {
10 | preferences.incognitoAnimeExtensions().getAndSet {
11 | if (enable) it.plus(extensions) else it.minus(extensions)
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/domain/source/anime/interactor/ToggleAnimeSourcePin.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.domain.source.anime.interactor
2 |
3 | import eu.kanade.domain.source.service.SourcePreferences
4 | import tachiyomi.core.common.preference.getAndSet
5 | import tachiyomi.domain.source.anime.model.AnimeSource
6 |
7 | class ToggleAnimeSourcePin(
8 | private val preferences: SourcePreferences,
9 | ) {
10 |
11 | fun await(source: AnimeSource) {
12 | val isPinned = source.id.toString() in preferences.pinnedAnimeSources().get()
13 | preferences.pinnedAnimeSources().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/anime/model/AnimeSource.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.domain.source.anime.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.anime.AnimeExtensionManager
7 | import tachiyomi.domain.source.anime.model.AnimeSource
8 | import uy.kohesive.injekt.Injekt
9 | import uy.kohesive.injekt.api.get
10 |
11 | val AnimeSource.icon: ImageBitmap?
12 | get() {
13 | return Injekt.get().getAppIconForSource(id)
14 | ?.toBitmap()
15 | ?.asImageBitmap()
16 | }
17 |
--------------------------------------------------------------------------------
/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/manga/interactor/ToggleExcludeFromMangaDataSaver.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.domain.source.manga.interactor
2 |
3 | import eu.kanade.domain.source.service.SourcePreferences
4 | import tachiyomi.core.common.preference.getAndSet
5 | import tachiyomi.domain.source.manga.model.Source
6 |
7 | class ToggleExcludeFromMangaDataSaver(
8 | private val preferences: SourcePreferences,
9 | ) {
10 |
11 | fun await(source: Source) {
12 | preferences.dataSaverExcludedSources().getAndSet {
13 | if (source.id.toString() in it) {
14 | it - source.id.toString()
15 | } else {
16 | it + source.id.toString()
17 | }
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/domain/source/manga/interactor/ToggleMangaIncognito.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.domain.source.manga.interactor
2 |
3 | import eu.kanade.domain.source.service.SourcePreferences
4 | import tachiyomi.core.common.preference.getAndSet
5 |
6 | class ToggleMangaIncognito(
7 | private val preferences: SourcePreferences,
8 | ) {
9 | fun await(extensions: String, enable: Boolean) {
10 | preferences.incognitoMangaExtensions().getAndSet {
11 | if (enable) it.plus(extensions) else it.minus(extensions)
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/domain/source/manga/interactor/ToggleMangaSourcePin.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.domain.source.manga.interactor
2 |
3 | import eu.kanade.domain.source.service.SourcePreferences
4 | import tachiyomi.core.common.preference.getAndSet
5 | import tachiyomi.domain.source.manga.model.Source
6 |
7 | class ToggleMangaSourcePin(
8 | private val preferences: SourcePreferences,
9 | ) {
10 |
11 | fun await(source: Source) {
12 | val isPinned = source.id.toString() in preferences.pinnedMangaSources().get()
13 | preferences.pinnedMangaSources().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/manga/model/MangaSource.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.domain.source.manga.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.manga.MangaExtensionManager
7 | import tachiyomi.domain.source.manga.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/BrowseBadges.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.presentation.browse
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 | 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/entries/EntryScreenConstants.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.presentation.entries
2 |
3 | enum class DownloadAction {
4 | NEXT_1_ITEM,
5 | NEXT_5_ITEMS,
6 | NEXT_10_ITEMS,
7 | NEXT_25_ITEMS,
8 | UNVIEWED_ITEMS,
9 | }
10 |
11 | enum class EditCoverAction {
12 | EDIT,
13 | DELETE,
14 | }
15 |
16 | enum class EntryScreenItem {
17 | INFO_BOX,
18 | ACTION_ROW,
19 | DESCRIPTION_WITH_TAG,
20 | ITEM_HEADER,
21 | ITEM,
22 | AIRING_TIME,
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/presentation/entries/components/DotSeparatorText.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.presentation.entries.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/storage/StorageScreenState.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.presentation.more.storage
2 |
3 | import androidx.compose.runtime.Immutable
4 | import tachiyomi.domain.category.model.Category
5 |
6 | sealed class StorageScreenState {
7 | @Immutable
8 | object Loading : StorageScreenState()
9 |
10 | @Immutable
11 | data class Success(
12 | val selectedCategory: Category,
13 | val items: List,
14 | val categories: List,
15 | ) : StorageScreenState()
16 | }
17 |
--------------------------------------------------------------------------------
/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/ItemNumberFormatter.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 |
15 | fun formatEpisodeNumber(episodeNumber: Double): String {
16 | return formatter.format(episodeNumber)
17 | }
18 |
--------------------------------------------------------------------------------
/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/models/BackupAnimeHistory.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.anime.model.AnimeHistory
6 | import java.util.Date
7 |
8 | @Serializable
9 | data class BackupAnimeHistory(
10 | @ProtoNumber(1) var url: String,
11 | @ProtoNumber(2) var lastRead: Long,
12 | @ProtoNumber(3) var readDuration: Long = 0,
13 | ) {
14 | fun getHistoryImpl(): AnimeHistory {
15 | return AnimeHistory.create().copy(
16 | seenAt = Date(lastRead),
17 | )
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupAnimeSource.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 BackupAnimeSource(
8 | @ProtoNumber(1) var name: String = "",
9 | @ProtoNumber(2) var sourceId: Long,
10 | )
11 |
12 | @Serializable
13 | data class BrokenBackupAnimeSource(
14 | @ProtoNumber(0) var name: String = "",
15 | @ProtoNumber(1) var sourceId: Long,
16 | ) {
17 | fun toBackupSource() = BackupAnimeSource(name, sourceId)
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupExtensionPreferences.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 BackupExtensionPreferences(
8 | @ProtoNumber(1) val name: String,
9 | @ProtoNumber(2) val prefs: List,
10 | )
11 |
--------------------------------------------------------------------------------
/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.manga.model.MangaHistory
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(): MangaHistory {
15 | return MangaHistory.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 |
12 | @Serializable
13 | data class BrokenBackupSource(
14 | @ProtoNumber(0) var name: String = "",
15 | @ProtoNumber(1) var sourceId: Long,
16 | ) {
17 | fun toBackupSource() = BackupSource(name, sourceId)
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/data/track/DeletableAnimeTracker.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.data.track
2 |
3 | import tachiyomi.domain.track.anime.model.AnimeTrack
4 |
5 | /**
6 | *Tracker that support deleting am entry from a user's list
7 | */
8 | interface DeletableAnimeTracker {
9 |
10 | suspend fun delete(track: AnimeTrack)
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/data/track/DeletableMangaTracker.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.data.track
2 |
3 | import tachiyomi.domain.track.manga.model.MangaTrack
4 |
5 | /**
6 | * Tracker that support deleting am entry from a user's list
7 | */
8 | interface DeletableMangaTracker {
9 |
10 | suspend fun delete(track: MangaTrack)
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALAddEntry.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 ALAddEntryResult(
8 | val data: ALAddEntryData,
9 | )
10 |
11 | @Serializable
12 | data class ALAddEntryData(
13 | @SerialName("SaveMediaListEntry")
14 | val entry: ALAddEntryEntry,
15 | )
16 |
17 | @Serializable
18 | data class ALAddEntryEntry(
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/dto/BGMUser.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.data.track.bangumi.dto
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | // Incomplete DTO with only our needed attributes
7 | data class BGMUser(
8 | val username: String,
9 | )
10 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/data/track/jellyfin/dto/JFItem.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.data.track.jellyfin.dto
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class JFItem(
8 | @SerialName("Name") val name: String,
9 | @SerialName("Id") val id: String,
10 | @SerialName("UserData") val userData: JFUserData,
11 | @SerialName("IndexNumber") val indexNumber: Long? = null,
12 | )
13 |
14 | @Serializable
15 | data class JFUserData(
16 | @SerialName("Played") val played: Boolean,
17 | )
18 |
19 | @Serializable
20 | data class JFItemList(
21 | @SerialName("Items") val items: List,
22 | )
23 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/dto/KitsuAddEntry.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.data.track.kitsu.dto
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class KitsuAddEntryResult(
7 | val data: KitsuAddEntryItem,
8 | )
9 |
10 | @Serializable
11 | data class KitsuAddEntryItem(
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/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.manga.MangaTrack
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class MURating(
8 | val rating: Double? = null,
9 | )
10 |
11 | fun MURating.copyTo(track: MangaTrack): MangaTrack {
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/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/SMAddEntryResponse.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.data.track.shikimori.dto
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class SMAddEntryResponse(
7 | val id: Long,
8 | )
9 |
--------------------------------------------------------------------------------
/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/data/track/simkl/dto/SimklOAuth.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.data.track.simkl.dto
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class SimklOAuth(
8 | @SerialName("access_token")
9 | val accessToken: String,
10 | )
11 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/data/track/simkl/dto/SimklSyncWatched.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.data.track.simkl.dto
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class SimklSyncWatched(
8 | val result: Boolean?,
9 | @SerialName("last_watched")
10 | val lastWatched: String?,
11 | val list: String?,
12 | )
13 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/data/track/simkl/dto/SimklUser.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.data.track.simkl.dto
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class SimklUser(
7 | val account: SimklUserAccount,
8 | )
9 |
10 | @Serializable
11 | data class SimklUserAccount(
12 | val id: Int,
13 | )
14 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/extension/InstallStep.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.extension
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/anime/model/AnimeLoadResult.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.extension.anime.model
2 |
3 | sealed interface AnimeLoadResult {
4 | data class Success(val extension: AnimeExtension.Installed) : AnimeLoadResult
5 | data class Untrusted(val extension: AnimeExtension.Untrusted) : AnimeLoadResult
6 | data object Error : AnimeLoadResult
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/extension/manga/model/MangaLoadResult.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.extension.manga.model
2 |
3 | sealed interface MangaLoadResult {
4 | data class Success(val extension: MangaExtension.Installed) : MangaLoadResult
5 | data class Untrusted(val extension: MangaExtension.Untrusted) : MangaLoadResult
6 | data object Error : MangaLoadResult
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreenType.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.ui.deeplink
2 |
3 | enum class DeepLinkScreenType {
4 | ANIME,
5 | MANGA,
6 | }
7 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/ui/entries/anime/track/AnimeTrackItem.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.ui.entries.anime.track
2 |
3 | import eu.kanade.tachiyomi.data.track.Tracker
4 | import tachiyomi.domain.track.anime.model.AnimeTrack
5 |
6 | data class AnimeTrackItem(val track: AnimeTrack?, val tracker: Tracker)
7 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/ui/entries/manga/track/MangaTrackItem.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.ui.entries.manga.track
2 |
3 | import eu.kanade.tachiyomi.data.track.Tracker
4 | import tachiyomi.domain.track.manga.model.MangaTrack
5 |
6 | data class MangaTrackItem(val track: MangaTrack?, val tracker: Tracker)
7 |
--------------------------------------------------------------------------------
/app/src/main/java/eu/kanade/tachiyomi/ui/player/settings/AdvancedPlayerPreferences.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.ui.player.settings
2 |
3 | import tachiyomi.core.common.preference.PreferenceStore
4 |
5 | class AdvancedPlayerPreferences(
6 | private val preferenceStore: PreferenceStore,
7 | ) {
8 | fun mpvScripts() = preferenceStore.getBoolean("mpv_scripts", false)
9 | fun mpvConf() = preferenceStore.getString("pref_mpv_conf", "")
10 | fun mpvInput() = preferenceStore.getString("pref_mpv_input", "")
11 |
12 | // Non-preference
13 |
14 | fun playerStatisticsPage() = preferenceStore.getInt("pref_player_statistics_page", 0)
15 | }
16 |
--------------------------------------------------------------------------------
/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 java.io.InputStream
5 |
6 | open class ReaderPage(
7 | index: Int,
8 | url: String = "",
9 | imageUrl: String? = null,
10 | var stream: (() -> InputStream)? = null,
11 | ) : Page(index, url, imageUrl, null) {
12 |
13 | open lateinit var chapter: ReaderChapter
14 | }
15 |
--------------------------------------------------------------------------------
/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.manga.toDomainChapter
4 | import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
5 | import tachiyomi.domain.items.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/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/ChapterRemoveDuplicates.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.util.chapter
2 |
3 | import tachiyomi.domain.items.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/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 | @file:Suppress("UNUSED", "KotlinConstantConditions")
2 |
3 | package eu.kanade.tachiyomi.util.system
4 |
5 | import eu.kanade.tachiyomi.BuildConfig
6 |
7 | val updaterEnabled: Boolean
8 | inline get() = BuildConfig.UPDATER_ENABLED
9 |
10 | val isDebugBuildType: Boolean
11 | inline get() = BuildConfig.BUILD_TYPE == "debug"
12 |
13 | val isPreviewBuildType: Boolean
14 | inline get() = BuildConfig.BUILD_TYPE == "preview"
15 |
16 | val isReleaseBuildType: Boolean
17 | inline get() = BuildConfig.BUILD_TYPE == "release"
18 |
--------------------------------------------------------------------------------
/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/tachiyomi/widget/listener/SimpleSeekBarListener.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.widget.listener
2 |
3 | import android.widget.SeekBar
4 |
5 | open class SimpleSeekBarListener : SeekBar.OnSeekBarChangeListener {
6 | override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
7 | }
8 |
9 | override fun onStartTrackingTouch(seekBar: SeekBar) {
10 | }
11 |
12 | override fun onStopTrackingTouch(seekBar: SeekBar) {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/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/migrations/InternalChapterCacheDirMigration.kt:
--------------------------------------------------------------------------------
1 | package mihon.core.migration.migrations
2 |
3 | import android.app.Application
4 | import mihon.core.migration.Migration
5 | import mihon.core.migration.MigrationContext
6 | import java.io.File
7 |
8 | class InternalChapterCacheDirMigration : Migration {
9 | override val version = 15f
10 |
11 | // Delete internal chapter cache dir.
12 | override suspend fun invoke(migrationContext: MigrationContext): Boolean {
13 | val context = migrationContext.get() ?: return false
14 |
15 | File(context.cacheDir, "chapter_disk_cache").deleteRecursively()
16 |
17 | return true
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/mihon/core/migration/migrations/LogOutMALMigration.kt:
--------------------------------------------------------------------------------
1 | package mihon.core.migration.migrations
2 |
3 | import eu.kanade.tachiyomi.data.track.TrackerManager
4 | import mihon.core.migration.Migration
5 | import mihon.core.migration.MigrationContext
6 |
7 | class LogOutMALMigration : Migration {
8 | override val version = 121f
9 |
10 | override suspend fun invoke(migrationContext: MigrationContext): Boolean {
11 | val trackerManager = migrationContext.get() ?: return false
12 |
13 | if (trackerManager.myAnimeList.isLoggedIn) {
14 | trackerManager.myAnimeList.logout()
15 | }
16 |
17 | return true
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/mihon/core/migration/migrations/SetupAnimeLibraryUpdateMigration.kt:
--------------------------------------------------------------------------------
1 | package mihon.core.migration.migrations
2 |
3 | import android.app.Application
4 | import eu.kanade.tachiyomi.data.library.anime.AnimeLibraryUpdateJob
5 | import mihon.core.migration.Migration
6 | import mihon.core.migration.MigrationContext
7 |
8 | class SetupAnimeLibraryUpdateMigration : 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 |
14 | AnimeLibraryUpdateJob.setupTask(context)
15 |
16 | return true
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/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 |
14 | BackupCreateJob.setupTask(context)
15 |
16 | return true
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/mihon/core/migration/migrations/SetupMangaLibraryUpdateMigration.kt:
--------------------------------------------------------------------------------
1 | package mihon.core.migration.migrations
2 |
3 | import android.app.Application
4 | import eu.kanade.tachiyomi.data.library.manga.MangaLibraryUpdateJob
5 | import mihon.core.migration.Migration
6 | import mihon.core.migration.MigrationContext
7 |
8 | class SetupMangaLibraryUpdateMigration : 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 |
14 | MangaLibraryUpdateJob.setupTask(context)
15 |
16 | return true
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/mihon/feature/upcoming/anime/UpcomingAnimeUIModel.kt:
--------------------------------------------------------------------------------
1 | package mihon.feature.upcoming.anime
2 |
3 | import tachiyomi.domain.entries.anime.model.Anime
4 | import java.time.LocalDate
5 |
6 | sealed interface UpcomingAnimeUIModel {
7 | data class Header(val date: LocalDate, val animeCount: Int) : UpcomingAnimeUIModel
8 | data class Item(val anime: Anime) : UpcomingAnimeUIModel
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/mihon/feature/upcoming/manga/UpcomingMangaUIModel.kt:
--------------------------------------------------------------------------------
1 | package mihon.feature.upcoming.manga
2 |
3 | import tachiyomi.domain.entries.manga.model.Manga
4 | import java.time.LocalDate
5 |
6 | sealed interface UpcomingMangaUIModel {
7 | data class Header(val date: LocalDate, val mangaCount: Int) : UpcomingMangaUIModel
8 | data class Item(val manga: Manga) : UpcomingMangaUIModel
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/player_enter_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/player_enter_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/player_enter_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/player_enter_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/player_exit_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/player_exit_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/player_exit_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/player_exit_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/player_fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/player_fade_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/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/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/drawable-nodpi/ic_manga_updates.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/ic_tracker_anilist.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/drawable-nodpi/ic_tracker_anilist.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/ic_tracker_bangumi.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/drawable-nodpi/ic_tracker_bangumi.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/ic_tracker_jellyfin.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/drawable-nodpi/ic_tracker_jellyfin.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/ic_tracker_kavita.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/drawable-nodpi/ic_tracker_kavita.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/ic_tracker_kitsu.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/drawable-nodpi/ic_tracker_kitsu.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/ic_tracker_komga.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/drawable-nodpi/ic_tracker_komga.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/ic_tracker_mal.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/drawable-nodpi/ic_tracker_mal.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/ic_tracker_shikimori.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/drawable-nodpi/ic_tracker_shikimori.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/ic_tracker_simkl.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/drawable-nodpi/ic_tracker_simkl.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/ic_tracker_suwayomi.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/drawable-nodpi/ic_tracker_suwayomi.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_animelibrary_filled_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_animelibrary_outline_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_back_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_collections_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_input_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_open_in_new_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_book_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_brightness_negative_20dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_chrome_player_mode_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_circle_200dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_circle_right_200dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_close_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_collections_baseline_state.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_crop_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/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_item_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_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_pause_circle_filled_24.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_play_circle_filled_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_play_seek_triangle.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/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_skip_next_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_skip_previous_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_tachi_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_volume_off_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/drawable/sharp_shadow_24.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/download_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/player_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/pref_widget_switch_material.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_default_source.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/mipmap-hdpi/ic_default_source.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_local_source.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/mipmap-hdpi/ic_local_source.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_default_source.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/mipmap-mdpi/ic_default_source.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_local_source.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/mipmap-mdpi/ic_local_source.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_default_source.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/mipmap-xhdpi/ic_default_source.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_local_source.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/mipmap-xhdpi/ic_local_source.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_default_source.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/mipmap-xxhdpi/ic_default_source.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_local_source.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/mipmap-xxhdpi/ic_local_source.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_default_source.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/app/src/main/res/mipmap-xxxhdpi/ic_default_source.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_local_source.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/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/mipmap/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/keep.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/bools.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | false
4 | false
5 | true
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sw720dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 24dp
3 |
4 |
--------------------------------------------------------------------------------
/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 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/bools.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | false
5 | false
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 |
4 | 16dp
5 | 12dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/integers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 200
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/provider_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
9 |
12 |
15 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/searchable.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | buildscript {
2 | dependencies {
3 | classpath(libs.android.shortcut.gradle)
4 | }
5 | }
6 |
7 | plugins {
8 | alias(kotlinx.plugins.serialization) apply false
9 | alias(libs.plugins.aboutLibraries) apply false
10 | alias(libs.plugins.moko) apply false
11 | alias(libs.plugins.sqldelight) apply false
12 | }
13 |
14 | tasks.register("clean") {
15 | delete(rootProject.layout.buildDirectory)
16 | }
17 |
--------------------------------------------------------------------------------
/buildSrc/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | dependencyResolutionManagement {
2 | versionCatalogs {
3 | create("libs") {
4 | from(files("../gradle/libs.versions.toml"))
5 | }
6 | create("androidx") {
7 | from(files("../gradle/androidx.versions.toml"))
8 | }
9 | create("compose") {
10 | from(files("../gradle/compose.versions.toml"))
11 | }
12 | create("kotlinx") {
13 | from(files("../gradle/kotlinx.versions.toml"))
14 | }
15 | }
16 | }
17 |
18 | rootProject.name = "Aniyomi"
19 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/mihon.android.application.compose.gradle.kts:
--------------------------------------------------------------------------------
1 | import mihon.buildlogic.configureCompose
2 |
3 | plugins {
4 | id("com.android.application")
5 | kotlin("android")
6 |
7 | id("mihon.code.lint")
8 | }
9 |
10 | android {
11 | configureCompose(this)
12 | }
13 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/mihon.android.application.gradle.kts:
--------------------------------------------------------------------------------
1 | import mihon.buildlogic.AndroidConfig
2 | import mihon.buildlogic.configureAndroid
3 | import mihon.buildlogic.configureTest
4 |
5 | plugins {
6 | id("com.android.application")
7 | kotlin("android")
8 |
9 | id("mihon.code.lint")
10 | }
11 |
12 | android {
13 | defaultConfig {
14 | targetSdk = AndroidConfig.TARGET_SDK
15 | }
16 | configureAndroid(this)
17 | configureTest()
18 | }
19 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/mihon.benchmark.gradle.kts:
--------------------------------------------------------------------------------
1 | import mihon.buildlogic.configureAndroid
2 | import mihon.buildlogic.configureTest
3 |
4 | plugins {
5 | id("com.android.test")
6 | kotlin("android")
7 |
8 | id("mihon.code.lint")
9 | }
10 |
11 | android {
12 | configureAndroid(this)
13 | configureTest()
14 | }
15 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/mihon.library.compose.gradle.kts:
--------------------------------------------------------------------------------
1 | import mihon.buildlogic.configureCompose
2 |
3 | plugins {
4 | id("com.android.library")
5 |
6 | id("mihon.code.lint")
7 | }
8 |
9 | android {
10 | configureCompose(this)
11 | }
12 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/mihon.library.gradle.kts:
--------------------------------------------------------------------------------
1 | import mihon.buildlogic.configureAndroid
2 | import mihon.buildlogic.configureTest
3 |
4 | plugins {
5 | id("com.android.library")
6 |
7 | id("mihon.code.lint")
8 | }
9 |
10 | android {
11 | configureAndroid(this)
12 | configureTest()
13 | }
14 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/mihon/buildlogic/AndroidConfig.kt:
--------------------------------------------------------------------------------
1 | package mihon.buildlogic
2 |
3 | import org.gradle.api.JavaVersion as GradleJavaVersion
4 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget as KotlinJvmTarget
5 |
6 | object AndroidConfig {
7 | const val COMPILE_SDK = 35
8 | const val TARGET_SDK = 34
9 | const val MIN_SDK = 26
10 | const val NDK = "27.1.12297006"
11 | const val BUILD_TOOLS = "35.0.1"
12 |
13 | // https://youtrack.jetbrains.com/issue/KT-66995/JvmTarget-and-JavaVersion-compatibility-for-easier-JVM-version-setup
14 | val JavaVersion = GradleJavaVersion.VERSION_17
15 | val JvmTarget = KotlinJvmTarget.JVM_17
16 | }
17 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/mihon/buildlogic/BuildConfig.kt:
--------------------------------------------------------------------------------
1 | package mihon.buildlogic
2 |
3 | import org.gradle.api.Project
4 |
5 | interface BuildConfig {
6 | val enableUpdater: Boolean
7 | val enableCodeShrink: Boolean
8 | val includeDependencyInfo: Boolean
9 | }
10 |
11 | val Project.Config: BuildConfig get() = object : BuildConfig {
12 | override val enableUpdater: Boolean = project.hasProperty("enable-updater")
13 | override val enableCodeShrink: Boolean = !project.hasProperty("disable-code-shrink")
14 | override val includeDependencyInfo: Boolean = project.hasProperty("include-dependency-info")
15 | }
16 |
--------------------------------------------------------------------------------
/core-metadata/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("mihon.library")
3 | kotlin("android")
4 | kotlin("plugin.serialization")
5 | }
6 |
7 | android {
8 | namespace = "tachiyomi.core.metadata"
9 |
10 | defaultConfig {
11 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
12 | consumerProguardFiles("consumer-rules.pro")
13 | }
14 | }
15 |
16 | dependencies {
17 | implementation(projects.sourceApi)
18 |
19 | implementation(kotlinx.bundles.serialization)
20 | }
21 |
--------------------------------------------------------------------------------
/core-metadata/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/core-metadata/consumer-rules.pro
--------------------------------------------------------------------------------
/core-metadata/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/core-metadata/src/main/java/tachiyomi/core/metadata/tachiyomi/AnimeDetails.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.core.metadata.tachiyomi
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | class AnimeDetails(
7 | val title: String? = null,
8 | val author: String? = null,
9 | val artist: String? = null,
10 | val description: String? = null,
11 | val genre: List? = null,
12 | val status: Int? = null,
13 | )
14 |
--------------------------------------------------------------------------------
/core-metadata/src/main/java/tachiyomi/core/metadata/tachiyomi/ChapterDetails.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.core.metadata.tachiyomi
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | class ChapterDetails(
7 | val chapter_number: Float,
8 | val name: String? = null,
9 | val date_upload: String? = null,
10 | val scanlator: String? = null,
11 | )
12 |
--------------------------------------------------------------------------------
/core-metadata/src/main/java/tachiyomi/core/metadata/tachiyomi/EpisodeDetails.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.core.metadata.tachiyomi
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | class EpisodeDetails(
7 | val episode_number: Float,
8 | val name: String? = null,
9 | val date_upload: String? = null,
10 | val scanlator: String? = null,
11 | )
12 |
--------------------------------------------------------------------------------
/core-metadata/src/main/java/tachiyomi/core/metadata/tachiyomi/MangaDetails.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.core.metadata.tachiyomi
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | class MangaDetails(
7 | val title: String? = null,
8 | val author: String? = null,
9 | val artist: String? = null,
10 | val description: String? = null,
11 | val genre: List? = null,
12 | val status: Int? = null,
13 | )
14 |
--------------------------------------------------------------------------------
/core/archive/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("mihon.library")
3 | kotlin("android")
4 | kotlin("plugin.serialization")
5 | }
6 |
7 | android {
8 | namespace = "mihon.core.archive"
9 | }
10 |
11 | dependencies {
12 | implementation(libs.jsoup)
13 | implementation(libs.libarchive)
14 | implementation(libs.unifile)
15 | }
16 |
--------------------------------------------------------------------------------
/core/archive/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/core/archive/src/main/kotlin/mihon/core/archive/ArchiveEntry.kt:
--------------------------------------------------------------------------------
1 | package mihon.core.archive
2 |
3 | class ArchiveEntry(
4 | val name: String,
5 | val isFile: Boolean,
6 | )
7 |
--------------------------------------------------------------------------------
/core/archive/src/main/kotlin/mihon/core/archive/UniFileExtensions.kt:
--------------------------------------------------------------------------------
1 | package mihon.core.archive
2 |
3 | import android.content.Context
4 | import android.os.ParcelFileDescriptor
5 | import com.hippo.unifile.UniFile
6 |
7 | fun UniFile.openFileDescriptor(context: Context, mode: String): ParcelFileDescriptor =
8 | context.contentResolver.openFileDescriptor(uri, mode)
9 | ?: error("Failed to open file descriptor: ${filePath ?: uri.toString()}")
10 |
11 | fun UniFile.archiveReader(context: Context) = openFileDescriptor(context, "r").use { ArchiveReader(it) }
12 |
13 | fun UniFile.epubReader(context: Context) = EpubReader(archiveReader(context))
14 |
--------------------------------------------------------------------------------
/core/common/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/core/common/src/main/java/eu/kanade/tachiyomi/network/ProgressListener.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.network
2 |
3 | interface ProgressListener {
4 | fun update(bytesRead: Long, contentLength: Long, done: Boolean)
5 | }
6 |
--------------------------------------------------------------------------------
/core/common/src/main/java/eu/kanade/tachiyomi/util/system/DensityExtensions.kt:
--------------------------------------------------------------------------------
1 | package eu.kanade.tachiyomi.util.system
2 |
3 | import android.content.res.Resources
4 |
5 | /**
6 | * Converts to px.
7 | */
8 | val Int.dpToPx: Int
9 | get() = (this * Resources.getSystem().displayMetrics.density).toInt()
10 |
--------------------------------------------------------------------------------
/core/common/src/main/java/tachiyomi/core/common/preference/TriState.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.core.common.preference
2 |
3 | enum class TriState {
4 | DISABLED, // Disable filter
5 | ENABLED_IS, // Enabled with "is" filter
6 | ENABLED_NOT, // Enabled with "not" filter
7 | ;
8 |
9 | fun next(): TriState {
10 | return when (this) {
11 | DISABLED -> ENABLED_IS
12 | ENABLED_IS -> ENABLED_NOT
13 | ENABLED_NOT -> DISABLED
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/core/common/src/main/java/tachiyomi/core/common/storage/FolderProvider.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.core.common.storage
2 |
3 | import java.io.File
4 |
5 | interface FolderProvider {
6 |
7 | fun directory(): File
8 |
9 | fun path(): String
10 | }
11 |
--------------------------------------------------------------------------------
/core/common/src/main/java/tachiyomi/core/common/storage/UniFileExtensions.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.core.common.storage
2 |
3 | import com.hippo.unifile.UniFile
4 |
5 | val UniFile.extension: String?
6 | get() = name?.substringAfterLast('.')
7 |
8 | val UniFile.nameWithoutExtension: String?
9 | get() = name?.substringBeforeLast('.')
10 |
11 | val UniFile.displayablePath: String
12 | get() = filePath ?: uri.toString()
13 |
--------------------------------------------------------------------------------
/core/common/src/main/java/tachiyomi/core/common/util/lang/BooleanExtensions.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.core.common.util.lang
2 |
3 | fun Boolean.toLong() = if (this) 1L else 0L
4 |
--------------------------------------------------------------------------------
/core/common/src/main/java/tachiyomi/core/common/util/lang/SortUtil.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.core.common.util.lang
2 |
3 | import java.text.Collator
4 | import java.util.Locale
5 |
6 | private val collator by lazy {
7 | val locale = Locale.getDefault()
8 | Collator.getInstance(locale).apply {
9 | strength = Collator.PRIMARY
10 | }
11 | }
12 |
13 | fun String.compareToWithCollator(other: String): Int {
14 | return collator.compare(this, other)
15 | }
16 |
--------------------------------------------------------------------------------
/core/common/src/main/java/tachiyomi/core/common/util/system/LogcatExtensions.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.core.common.util.system
2 |
3 | import logcat.LogPriority
4 | import logcat.asLog
5 | import logcat.logcat
6 |
7 | inline fun Any.logcat(
8 | priority: LogPriority = LogPriority.DEBUG,
9 | throwable: Throwable? = null,
10 | message: () -> String = { "" },
11 | ) = logcat(priority = priority) {
12 | var msg = message()
13 | if (throwable != null) {
14 | if (msg.isNotBlank()) msg += "\n"
15 | msg += throwable.asLog()
16 | }
17 | msg
18 | }
19 |
--------------------------------------------------------------------------------
/data/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/data/consumer-rules.pro
--------------------------------------------------------------------------------
/data/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/data/src/main/sqldelight/data/excluded_scanlators.sq:
--------------------------------------------------------------------------------
1 | CREATE TABLE excluded_scanlators(
2 | manga_id INTEGER NOT NULL,
3 | scanlator TEXT NOT NULL,
4 | FOREIGN KEY(manga_id) REFERENCES mangas (_id)
5 | ON DELETE CASCADE
6 | );
7 |
8 | CREATE INDEX excluded_scanlators_manga_id_index ON excluded_scanlators(manga_id);
9 |
10 | insert:
11 | INSERT INTO excluded_scanlators(manga_id, scanlator)
12 | VALUES (:mangaId, :scanlator);
13 |
14 | remove:
15 | DELETE FROM excluded_scanlators
16 | WHERE manga_id = :mangaId
17 | AND scanlator IN :scanlators;
18 |
19 | getExcludedScanlatorsByMangaId:
20 | SELECT scanlator
21 | FROM excluded_scanlators
22 | WHERE manga_id = :mangaId;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/data/sources.sq:
--------------------------------------------------------------------------------
1 | CREATE TABLE sources(
2 | _id INTEGER NOT NULL PRIMARY KEY,
3 | lang TEXT NOT NULL,
4 | name TEXT NOT NULL
5 | );
6 |
7 | findAll:
8 | SELECT *
9 | FROM sources;
10 |
11 | findOne:
12 | SELECT *
13 | FROM sources
14 | WHERE _id = :id;
15 |
16 | upsert:
17 | INSERT INTO sources(_id, lang, name)
18 | VALUES (:id, :lang, :name)
19 | ON CONFLICT(_id)
20 | DO UPDATE
21 | SET
22 | lang = :lang,
23 | name = :name
24 | WHERE _id = :id;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/1.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE chapters
2 | ADD COLUMN source_order INTEGER DEFAULT 0;
3 |
4 | UPDATE mangas
5 | SET thumbnail_url = replace(thumbnail_url, '93.174.95.110', 'kissmanga.com')
6 | WHERE source = 4;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/10.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE mangas
2 | ADD COLUMN date_added INTEGER NOT NULL DEFAULT 0;
3 |
4 | UPDATE mangas
5 | SET date_added = (
6 | SELECT MIN(date_fetch)
7 | FROM mangas M
8 | INNER JOIN chapters C
9 | ON M._id = C.manga_id
10 | GROUP BY M._id
11 | );
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/11.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE mangas
2 | ADD COLUMN next_update INTEGER DEFAULT 0;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/13.sqm:
--------------------------------------------------------------------------------
1 | UPDATE chapters
2 | SET date_upload = date_fetch
3 | WHERE date_upload = 0;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/16.sqm:
--------------------------------------------------------------------------------
1 | CREATE TABLE sources(
2 | _id INTEGER NOT NULL PRIMARY KEY,
3 | lang TEXT NOT NULL,
4 | name TEXT NOT NULL
5 | );
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/18.sqm:
--------------------------------------------------------------------------------
1 | CREATE VIEW updatesView AS
2 | SELECT
3 | mangas._id AS mangaId,
4 | mangas.title AS mangaTitle,
5 | chapters._id AS chapterId,
6 | chapters.name AS chapterName,
7 | chapters.scanlator,
8 | chapters.read,
9 | chapters.bookmark,
10 | mangas.source,
11 | mangas.favorite,
12 | mangas.thumbnail_url AS thumbnailUrl,
13 | mangas.cover_last_modified AS coverLastModified,
14 | chapters.date_upload AS dateUpload,
15 | chapters.date_fetch AS datefetch
16 | FROM mangas JOIN chapters
17 | ON mangas._id = chapters.manga_id
18 | WHERE favorite = 1
19 | AND date_fetch > date_added
20 | ORDER BY date_fetch DESC;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/19.sqm:
--------------------------------------------------------------------------------
1 | -- Insert Default category
2 | INSERT OR IGNORE INTO categories(_id, name, sort, flags) VALUES (0, "", -1, 0);
3 | -- Disallow deletion of default category
4 | CREATE TRIGGER IF NOT EXISTS system_category_delete_trigger BEFORE DELETE
5 | ON categories
6 | BEGIN SELECT CASE
7 | WHEN old._id <= 0 THEN
8 | RAISE(ABORT, "System category can't be deleted")
9 | END;
10 | END;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/2.sqm:
--------------------------------------------------------------------------------
1 | CREATE TABLE history(
2 | history_id INTEGER NOT NULL PRIMARY KEY,
3 | history_chapter_id INTEGER NOT NULL UNIQUE,
4 | history_last_read INTEGER,
5 | history_time_read INTEGER,
6 | FOREIGN KEY(history_chapter_id) REFERENCES chapters (_id)
7 | ON DELETE CASCADE
8 | );
9 |
10 | CREATE INDEX history_history_chapter_id_index ON history(history_chapter_id);
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/20.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE mangas ADD COLUMN update_strategy INTEGER NOT NULL DEFAULT 0;
2 |
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/24.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE mangas ADD COLUMN calculate_interval INTEGER DEFAULT 0 NOT NULL;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/25.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE categories ADD COLUMN hidden INTEGER DEFAULT 0 NOT NULL;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/28.sqm:
--------------------------------------------------------------------------------
1 | UPDATE chapters
2 | SET scanlator = trim(scanlator)
3 | WHERE scanlator IS NOT NULL;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/29.sqm:
--------------------------------------------------------------------------------
1 | -- MangaUpdates score fixing --
2 | UPDATE manga_sync
3 | SET score = max(score, 0)
4 | WHERE sync_id = 7;
5 |
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/3.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE chapters
2 | ADD COLUMN bookmark INTEGER DEFAULT 0;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/31.sqm:
--------------------------------------------------------------------------------
1 | -- Create ExtensionRepo table --
2 | CREATE TABLE extension_repos (
3 | base_url TEXT NOT NULL PRIMARY KEY,
4 | name TEXT NOT NULL,
5 | short_name TEXT,
6 | website TEXT NOT NULL,
7 | signing_key_fingerprint TEXT UNIQUE NOT NULL
8 | );
9 |
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/32.sqm:
--------------------------------------------------------------------------------
1 | import kotlin.Boolean;
2 |
3 | -- Add private field for tracking
4 | ALTER TABLE manga_sync ADD COLUMN private INTEGER AS Boolean DEFAULT 0 NOT NULL;
5 |
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/4.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE chapters
2 | ADD COLUMN scanlator TEXT DEFAULT NULL;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/5.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE manga_sync
2 | ADD COLUMN remote_url TEXT DEFAULT '';
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/6.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE manga_sync
2 | ADD COLUMN library_id INTEGER;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/7.sqm:
--------------------------------------------------------------------------------
1 | DROP INDEX IF EXISTS mangas_favorite_index;
2 |
3 | CREATE INDEX library_favorite_index
4 | ON mangas(favorite)
5 | WHERE favorite = 1;
6 |
7 | CREATE INDEX chapters_unread_by_manga_index
8 | ON chapters(manga_id, read)
9 | WHERE read = 0;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/8.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE manga_sync
2 | ADD COLUMN start_date INTEGER NOT NULL DEFAULT 0;
3 |
4 | ALTER TABLE manga_sync
5 | ADD COLUMN finish_date INTEGER NOT NULL DEFAULT 0;
--------------------------------------------------------------------------------
/data/src/main/sqldelight/migrations/9.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE mangas
2 | ADD COLUMN cover_last_modified INTEGER NOT NULL DEFAULT 0;
--------------------------------------------------------------------------------
/data/src/main/sqldelightanime/dataanime/animesources.sq:
--------------------------------------------------------------------------------
1 | CREATE TABLE animesources(
2 | _id INTEGER NOT NULL PRIMARY KEY,
3 | lang TEXT NOT NULL,
4 | name TEXT NOT NULL
5 | );
6 |
7 | findAll:
8 | SELECT *
9 | FROM animesources;
10 |
11 | findOne:
12 | SELECT *
13 | FROM animesources
14 | WHERE _id = :id;
15 |
16 | upsert:
17 | INSERT INTO animesources(_id, lang, name)
18 | VALUES (:id, :lang, :name)
19 | ON CONFLICT(_id)
20 | DO UPDATE
21 | SET
22 | lang = :lang,
23 | name = :name
24 | WHERE _id = :id;
--------------------------------------------------------------------------------
/data/src/main/sqldelightanime/migrations/113.sqm:
--------------------------------------------------------------------------------
1 | UPDATE episodes
2 | SET date_upload = date_fetch
3 | WHERE date_upload = 0;
--------------------------------------------------------------------------------
/data/src/main/sqldelightanime/migrations/117.sqm:
--------------------------------------------------------------------------------
1 | CREATE TABLE animesources(
2 | _id INTEGER NOT NULL PRIMARY KEY,
3 | lang TEXT NOT NULL,
4 | name TEXT NOT NULL
5 | );
--------------------------------------------------------------------------------
/data/src/main/sqldelightanime/migrations/119.sqm:
--------------------------------------------------------------------------------
1 | CREATE VIEW animeupdatesView AS
2 | SELECT
3 | animes._id AS animeId,
4 | animes.title AS animeTitle,
5 | episodes._id AS episodeId,
6 | episodes.name AS episodeName,
7 | episodes.scanlator,
8 | episodes.seen,
9 | episodes.bookmark,
10 | animes.source,
11 | animes.favorite,
12 | animes.thumbnail_url AS thumbnailUrl,
13 | animes.cover_last_modified AS coverLastModified,
14 | episodes.date_upload AS dateUpload,
15 | episodes.date_fetch AS datefetch
16 | FROM animes JOIN episodes
17 | ON animes._id = episodes.anime_id
18 | WHERE favorite = 1
19 | AND date_fetch > date_added
20 | ORDER BY date_fetch DESC;
--------------------------------------------------------------------------------
/data/src/main/sqldelightanime/migrations/120.sqm:
--------------------------------------------------------------------------------
1 | -- Insert Default category
2 | INSERT OR IGNORE INTO categories(_id, name, sort, flags) VALUES (0, "", -1, 0);
3 | -- Disallow deletion of default category
4 | CREATE TRIGGER IF NOT EXISTS system_anime_category_delete_trigger BEFORE DELETE
5 | ON categories
6 | BEGIN SELECT CASE
7 | WHEN old._id <= 0 THEN
8 | RAISE(ABORT, "System category can't be deleted")
9 | END;
10 | END;
--------------------------------------------------------------------------------
/data/src/main/sqldelightanime/migrations/121.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE animes ADD COLUMN update_strategy INTEGER NOT NULL DEFAULT 0;
2 |
--------------------------------------------------------------------------------
/data/src/main/sqldelightanime/migrations/124.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE animes ADD COLUMN calculate_interval INTEGER DEFAULT 0 NOT NULL;
--------------------------------------------------------------------------------
/data/src/main/sqldelightanime/migrations/125.sqm:
--------------------------------------------------------------------------------
1 | ALTER TABLE categories ADD COLUMN hidden INTEGER DEFAULT 0 NOT NULL;
--------------------------------------------------------------------------------
/data/src/main/sqldelightanime/migrations/128.sqm:
--------------------------------------------------------------------------------
1 | -- Create ExtensionRepo table --
2 | CREATE TABLE extension_repos (
3 | base_url TEXT NOT NULL PRIMARY KEY,
4 | name TEXT NOT NULL,
5 | short_name TEXT,
6 | website TEXT NOT NULL,
7 | signing_key_fingerprint TEXT UNIQUE NOT NULL
8 | );
9 |
--------------------------------------------------------------------------------
/data/src/main/sqldelightanime/migrations/130.sqm:
--------------------------------------------------------------------------------
1 | import kotlin.Boolean;
2 |
3 | -- Add private field for tracking
4 | ALTER TABLE anime_sync ADD COLUMN private INTEGER AS Boolean DEFAULT 0 NOT NULL;
5 |
--------------------------------------------------------------------------------
/domain/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniyomiorg/aniyomi/0697aad3204cf95547edcde1b98ca80c124d2677/domain/consumer-rules.pro
--------------------------------------------------------------------------------
/domain/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/domain/src/main/java/mihon/domain/extensionrepo/anime/interactor/DeleteAnimeExtensionRepo.kt:
--------------------------------------------------------------------------------
1 | package mihon.domain.extensionrepo.anime.interactor
2 |
3 | import mihon.domain.extensionrepo.anime.repository.AnimeExtensionRepoRepository
4 |
5 | class DeleteAnimeExtensionRepo(
6 | private val repository: AnimeExtensionRepoRepository,
7 | ) {
8 | suspend fun await(baseUrl: String) {
9 | repository.deleteRepo(baseUrl)
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/domain/src/main/java/mihon/domain/extensionrepo/anime/interactor/GetAnimeExtensionRepo.kt:
--------------------------------------------------------------------------------
1 | package mihon.domain.extensionrepo.anime.interactor
2 |
3 | import kotlinx.coroutines.flow.Flow
4 | import mihon.domain.extensionrepo.anime.repository.AnimeExtensionRepoRepository
5 | import mihon.domain.extensionrepo.model.ExtensionRepo
6 |
7 | class GetAnimeExtensionRepo(
8 | private val repository: AnimeExtensionRepoRepository,
9 | ) {
10 | fun subscribeAll(): Flow> = repository.subscribeAll()
11 |
12 | suspend fun getAll(): List = repository.getAll()
13 | }
14 |
--------------------------------------------------------------------------------
/domain/src/main/java/mihon/domain/extensionrepo/anime/interactor/GetAnimeExtensionRepoCount.kt:
--------------------------------------------------------------------------------
1 | package mihon.domain.extensionrepo.anime.interactor
2 |
3 | import mihon.domain.extensionrepo.anime.repository.AnimeExtensionRepoRepository
4 |
5 | class GetAnimeExtensionRepoCount(
6 | private val repository: AnimeExtensionRepoRepository,
7 | ) {
8 | fun subscribe() = repository.getCount()
9 | }
10 |
--------------------------------------------------------------------------------
/domain/src/main/java/mihon/domain/extensionrepo/anime/interactor/ReplaceAnimeExtensionRepo.kt:
--------------------------------------------------------------------------------
1 | package mihon.domain.extensionrepo.anime.interactor
2 |
3 | import mihon.domain.extensionrepo.anime.repository.AnimeExtensionRepoRepository
4 | import mihon.domain.extensionrepo.model.ExtensionRepo
5 |
6 | class ReplaceAnimeExtensionRepo(
7 | private val repository: AnimeExtensionRepoRepository,
8 | ) {
9 | suspend fun await(repo: ExtensionRepo) {
10 | repository.replaceRepo(repo)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/domain/src/main/java/mihon/domain/extensionrepo/exception/SaveExtensionRepoException.kt:
--------------------------------------------------------------------------------
1 | package mihon.domain.extensionrepo.exception
2 |
3 | import java.io.IOException
4 |
5 | /**
6 | * Exception to abstract over SQLiteException and SQLiteConstraintException for multiplatform.
7 | *
8 | * @param throwable the source throwable to include for tracing.
9 | */
10 | class SaveExtensionRepoException(throwable: Throwable) : IOException("Error Saving Repository to Database", throwable)
11 |
--------------------------------------------------------------------------------
/domain/src/main/java/mihon/domain/extensionrepo/manga/interactor/DeleteMangaExtensionRepo.kt:
--------------------------------------------------------------------------------
1 | package mihon.domain.extensionrepo.manga.interactor
2 |
3 | import mihon.domain.extensionrepo.manga.repository.MangaExtensionRepoRepository
4 |
5 | class DeleteMangaExtensionRepo(
6 | private val repository: MangaExtensionRepoRepository,
7 | ) {
8 | suspend fun await(baseUrl: String) {
9 | repository.deleteRepo(baseUrl)
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/domain/src/main/java/mihon/domain/extensionrepo/manga/interactor/GetMangaExtensionRepo.kt:
--------------------------------------------------------------------------------
1 | package mihon.domain.extensionrepo.manga.interactor
2 |
3 | import kotlinx.coroutines.flow.Flow
4 | import mihon.domain.extensionrepo.manga.repository.MangaExtensionRepoRepository
5 | import mihon.domain.extensionrepo.model.ExtensionRepo
6 |
7 | class GetMangaExtensionRepo(
8 | private val repository: MangaExtensionRepoRepository,
9 | ) {
10 | fun subscribeAll(): Flow> = repository.subscribeAll()
11 |
12 | suspend fun getAll(): List = repository.getAll()
13 | }
14 |
--------------------------------------------------------------------------------
/domain/src/main/java/mihon/domain/extensionrepo/manga/interactor/GetMangaExtensionRepoCount.kt:
--------------------------------------------------------------------------------
1 | package mihon.domain.extensionrepo.manga.interactor
2 |
3 | import mihon.domain.extensionrepo.manga.repository.MangaExtensionRepoRepository
4 |
5 | class GetMangaExtensionRepoCount(
6 | private val repository: MangaExtensionRepoRepository,
7 | ) {
8 | fun subscribe() = repository.getCount()
9 | }
10 |
--------------------------------------------------------------------------------
/domain/src/main/java/mihon/domain/extensionrepo/manga/interactor/ReplaceMangaExtensionRepo.kt:
--------------------------------------------------------------------------------
1 | package mihon.domain.extensionrepo.manga.interactor
2 |
3 | import mihon.domain.extensionrepo.manga.repository.MangaExtensionRepoRepository
4 | import mihon.domain.extensionrepo.model.ExtensionRepo
5 |
6 | class ReplaceMangaExtensionRepo(
7 | private val repository: MangaExtensionRepoRepository,
8 | ) {
9 | suspend fun await(repo: ExtensionRepo) {
10 | repository.replaceRepo(repo)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/domain/src/main/java/mihon/domain/extensionrepo/model/ExtensionRepo.kt:
--------------------------------------------------------------------------------
1 | package mihon.domain.extensionrepo.model
2 |
3 | data class ExtensionRepo(
4 | val baseUrl: String,
5 | val name: String,
6 | val shortName: String?,
7 | val website: String,
8 | val signingKeyFingerprint: String,
9 | )
10 |
--------------------------------------------------------------------------------
/domain/src/main/java/mihon/domain/upcoming/anime/interactor/GetUpcomingAnime.kt:
--------------------------------------------------------------------------------
1 | package mihon.domain.upcoming.anime.interactor
2 |
3 | import eu.kanade.tachiyomi.animesource.model.SAnime
4 | import kotlinx.coroutines.flow.Flow
5 | import tachiyomi.domain.entries.anime.model.Anime
6 | import tachiyomi.domain.entries.anime.repository.AnimeRepository
7 |
8 | class GetUpcomingAnime(
9 | private val animeRepository: AnimeRepository,
10 | ) {
11 |
12 | private val includedStatuses = setOf(
13 | SAnime.ONGOING.toLong(),
14 | SAnime.PUBLISHING_FINISHED.toLong(),
15 | )
16 |
17 | suspend fun subscribe(): Flow> {
18 | return animeRepository.getUpcomingAnime(includedStatuses)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/domain/src/main/java/mihon/domain/upcoming/manga/interactor/GetUpcomingManga.kt:
--------------------------------------------------------------------------------
1 | package mihon.domain.upcoming.manga.interactor
2 |
3 | import eu.kanade.tachiyomi.source.model.SManga
4 | import kotlinx.coroutines.flow.Flow
5 | import tachiyomi.domain.entries.manga.model.Manga
6 | import tachiyomi.domain.entries.manga.repository.MangaRepository
7 |
8 | class GetUpcomingManga(
9 | private val mangaRepository: MangaRepository,
10 | ) {
11 |
12 | private val includedStatuses = setOf(
13 | SManga.ONGOING.toLong(),
14 | SManga.PUBLISHING_FINISHED.toLong(),
15 | )
16 |
17 | suspend fun subscribe(): Flow> {
18 | return mangaRepository.getUpcomingManga(includedStatuses)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.backup.service
2 |
3 | import tachiyomi.core.common.preference.Preference
4 | import tachiyomi.core.common.preference.PreferenceStore
5 |
6 | class BackupPreferences(
7 | private val preferenceStore: PreferenceStore,
8 | ) {
9 |
10 | fun backupInterval() = preferenceStore.getInt("backup_interval", 12)
11 |
12 | fun lastAutoBackupTimestamp() = preferenceStore.getLong(Preference.appStateKey("last_auto_backup_timestamp"), 0L)
13 |
14 | fun backupFlags() = preferenceStore.getStringSet(
15 | "backup_flags",
16 | setOf(FLAG_CATEGORIES, FLAG_CHAPTERS, FLAG_HISTORY, FLAG_TRACK),
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/backup/service/PreferenceValues.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.backup.service
2 |
3 | const val FLAG_CATEGORIES = "1"
4 | const val FLAG_CHAPTERS = "2"
5 | const val FLAG_HISTORY = "4"
6 | const val FLAG_TRACK = "8"
7 | const val FLAG_SETTINGS = "10"
8 | const val FLAG_EXT_SETTINGS = "20"
9 | const val FLAG_EXTENSIONS = "40"
10 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/category/anime/interactor/ResetAnimeCategoryFlags.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.category.anime.interactor
2 |
3 | import tachiyomi.domain.category.anime.repository.AnimeCategoryRepository
4 | import tachiyomi.domain.library.model.plus
5 | import tachiyomi.domain.library.service.LibraryPreferences
6 |
7 | class ResetAnimeCategoryFlags(
8 | private val preferences: LibraryPreferences,
9 | private val categoryRepository: AnimeCategoryRepository,
10 | ) {
11 |
12 | suspend fun await() {
13 | val sort = preferences.animeSortingMode().get()
14 | categoryRepository.updateAllAnimeCategoryFlags(sort.type + sort.direction)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetAnimeCategories.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.category.anime.interactor
2 |
3 | import logcat.LogPriority
4 | import tachiyomi.core.common.util.system.logcat
5 | import tachiyomi.domain.entries.anime.repository.AnimeRepository
6 |
7 | class SetAnimeCategories(
8 | private val animeRepository: AnimeRepository,
9 | ) {
10 |
11 | suspend fun await(animeId: Long, categoryIds: List) {
12 | try {
13 | animeRepository.setAnimeCategories(animeId, categoryIds)
14 | } catch (e: Exception) {
15 | logcat(LogPriority.ERROR, e)
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetAnimeDisplayMode.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.category.anime.interactor
2 |
3 | import tachiyomi.domain.library.model.LibraryDisplayMode
4 | import tachiyomi.domain.library.service.LibraryPreferences
5 |
6 | class SetAnimeDisplayMode(
7 | private val preferences: LibraryPreferences,
8 | ) {
9 |
10 | fun await(display: LibraryDisplayMode) {
11 | preferences.displayMode().set(display)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/category/manga/interactor/ResetMangaCategoryFlags.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.category.manga.interactor
2 |
3 | import tachiyomi.domain.category.manga.repository.MangaCategoryRepository
4 | import tachiyomi.domain.library.model.plus
5 | import tachiyomi.domain.library.service.LibraryPreferences
6 |
7 | class ResetMangaCategoryFlags(
8 | private val preferences: LibraryPreferences,
9 | private val categoryRepository: MangaCategoryRepository,
10 | ) {
11 |
12 | suspend fun await() {
13 | val sort = preferences.mangaSortingMode().get()
14 | categoryRepository.updateAllMangaCategoryFlags(sort.type + sort.direction)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetMangaCategories.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.category.manga.interactor
2 |
3 | import logcat.LogPriority
4 | import tachiyomi.core.common.util.system.logcat
5 | import tachiyomi.domain.entries.manga.repository.MangaRepository
6 |
7 | class SetMangaCategories(
8 | private val mangaRepository: MangaRepository,
9 | ) {
10 |
11 | suspend fun await(mangaId: Long, categoryIds: List) {
12 | try {
13 | mangaRepository.setMangaCategories(mangaId, categoryIds)
14 | } catch (e: Exception) {
15 | logcat(LogPriority.ERROR, e)
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetMangaDisplayMode.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.category.manga.interactor
2 |
3 | import tachiyomi.domain.library.model.LibraryDisplayMode
4 | import tachiyomi.domain.library.service.LibraryPreferences
5 |
6 | class SetMangaDisplayMode(
7 | private val preferences: LibraryPreferences,
8 | ) {
9 |
10 | fun await(display: LibraryDisplayMode) {
11 | preferences.displayMode().set(display)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/category/model/Category.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.category.model
2 |
3 | import java.io.Serializable
4 |
5 | data class Category(
6 | val id: Long,
7 | val name: String,
8 | val order: Long,
9 | val flags: Long,
10 | val hidden: Boolean,
11 | ) : Serializable {
12 |
13 | val isSystemCategory: Boolean = id == UNCATEGORIZED_ID
14 |
15 | companion object {
16 | const val UNCATEGORIZED_ID = 0L
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/category/model/CategoryUpdate.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.category.model
2 |
3 | data class CategoryUpdate(
4 | val id: Long,
5 | val name: String? = null,
6 | val order: Long? = null,
7 | val flags: Long? = null,
8 | val hidden: Boolean? = null,
9 | )
10 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/custombuttons/exception/SaveCustomButtonException.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.custombuttons.exception
2 |
3 | import java.io.IOException
4 |
5 | /**
6 | * Exception to abstract over SQLiteException and SQLiteConstraintException for multiplatform.
7 | *
8 | * @param throwable the source throwable to include for tracing.
9 | */
10 | class SaveCustomButtonException(throwable: Throwable) : IOException("Error Saving Custom Button to Database", throwable)
11 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/custombuttons/interactor/GetCustomButtons.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.custombuttons.interactor
2 |
3 | import kotlinx.coroutines.flow.Flow
4 | import tachiyomi.domain.custombuttons.model.CustomButton
5 | import tachiyomi.domain.custombuttons.repository.CustomButtonRepository
6 |
7 | class GetCustomButtons(
8 | private val customButtonRepository: CustomButtonRepository,
9 | ) {
10 | fun subscribeAll(): Flow> {
11 | return customButtonRepository.subscribeAll()
12 | }
13 |
14 | suspend fun getAll(): List {
15 | return customButtonRepository.getAll()
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/custombuttons/model/CustomButtonUpdate.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.custombuttons.model
2 |
3 | data class CustomButtonUpdate(
4 | val id: Long,
5 | val name: String? = null,
6 | val isFavorite: Boolean? = null,
7 | val sortIndex: Long? = null,
8 | val content: String? = null,
9 | val longPressContent: String? = null,
10 | val onStartup: String? = null,
11 | )
12 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/entries/EntryCover.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.entries
2 |
3 | interface EntryCover
4 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/entries/TriState.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.entries
2 |
3 | import tachiyomi.core.common.preference.TriState
4 |
5 | inline fun applyFilter(filter: TriState, predicate: () -> Boolean): Boolean = when (filter) {
6 | TriState.DISABLED -> true
7 | TriState.ENABLED_IS -> predicate()
8 | TriState.ENABLED_NOT -> !predicate()
9 | }
10 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/entries/anime/interactor/GetAnimeByUrlAndSourceId.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.entries.anime.interactor
2 |
3 | import tachiyomi.domain.entries.anime.model.Anime
4 | import tachiyomi.domain.entries.anime.repository.AnimeRepository
5 |
6 | class GetAnimeByUrlAndSourceId(
7 | private val animeRepository: AnimeRepository,
8 | ) {
9 | suspend fun await(url: String, sourceId: Long): Anime? {
10 | return animeRepository.getAnimeByUrlAndSourceId(url, sourceId)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/entries/anime/interactor/GetAnimeFavorites.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.entries.anime.interactor
2 |
3 | import kotlinx.coroutines.flow.Flow
4 | import tachiyomi.domain.entries.anime.model.Anime
5 | import tachiyomi.domain.entries.anime.repository.AnimeRepository
6 |
7 | class GetAnimeFavorites(
8 | private val animeRepository: AnimeRepository,
9 | ) {
10 |
11 | suspend fun await(): List {
12 | return animeRepository.getAnimeFavorites()
13 | }
14 |
15 | fun subscribe(sourceId: Long): Flow> {
16 | return animeRepository.getAnimeFavoritesBySourceId(sourceId)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/entries/anime/interactor/GetDuplicateLibraryAnime.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.entries.anime.interactor
2 |
3 | import tachiyomi.domain.entries.anime.model.Anime
4 | import tachiyomi.domain.entries.anime.repository.AnimeRepository
5 |
6 | class GetDuplicateLibraryAnime(
7 | private val animeRepository: AnimeRepository,
8 | ) {
9 |
10 | suspend fun await(anime: Anime): List {
11 | return animeRepository.getDuplicateLibraryAnime(anime.id, anime.title.lowercase())
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/entries/anime/interactor/ResetAnimeViewerFlags.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.entries.anime.interactor
2 |
3 | import tachiyomi.domain.entries.anime.repository.AnimeRepository
4 |
5 | class ResetAnimeViewerFlags(
6 | private val animeRepository: AnimeRepository,
7 | ) {
8 | suspend fun await(): Boolean {
9 | return animeRepository.resetAnimeViewerFlags()
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/entries/anime/model/AnimeCover.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.entries.anime.model
2 |
3 | import tachiyomi.domain.entries.EntryCover
4 |
5 | /**
6 | * Contains the required data for AnimeCoverFetcher
7 | */
8 | data class AnimeCover(
9 | val animeId: Long,
10 | val sourceId: Long,
11 | val isAnimeFavorite: Boolean,
12 | val url: String?,
13 | val lastModified: Long,
14 | ) : EntryCover
15 |
16 | fun Anime.asAnimeCover(): AnimeCover {
17 | return AnimeCover(
18 | animeId = id,
19 | sourceId = source,
20 | isAnimeFavorite = favorite,
21 | url = thumbnailUrl,
22 | lastModified = coverLastModified,
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/entries/manga/interactor/GetDuplicateLibraryManga.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.entries.manga.interactor
2 |
3 | import tachiyomi.domain.entries.manga.model.Manga
4 | import tachiyomi.domain.entries.manga.repository.MangaRepository
5 |
6 | class GetDuplicateLibraryManga(
7 | private val mangaRepository: MangaRepository,
8 | ) {
9 |
10 | suspend fun await(manga: Manga): List {
11 | return mangaRepository.getDuplicateLibraryManga(manga.id, manga.title.lowercase())
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/entries/manga/interactor/GetMangaByUrlAndSourceId.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.entries.manga.interactor
2 |
3 | import tachiyomi.domain.entries.manga.model.Manga
4 | import tachiyomi.domain.entries.manga.repository.MangaRepository
5 |
6 | class GetMangaByUrlAndSourceId(
7 | private val mangaRepository: MangaRepository,
8 | ) {
9 | suspend fun await(url: String, sourceId: Long): Manga? {
10 | return mangaRepository.getMangaByUrlAndSourceId(url, sourceId)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/entries/manga/interactor/GetMangaFavorites.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.entries.manga.interactor
2 |
3 | import kotlinx.coroutines.flow.Flow
4 | import tachiyomi.domain.entries.manga.model.Manga
5 | import tachiyomi.domain.entries.manga.repository.MangaRepository
6 |
7 | class GetMangaFavorites(
8 | private val mangaRepository: MangaRepository,
9 | ) {
10 |
11 | suspend fun await(): List {
12 | return mangaRepository.getMangaFavorites()
13 | }
14 |
15 | fun subscribe(sourceId: Long): Flow> {
16 | return mangaRepository.getMangaFavoritesBySourceId(sourceId)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/entries/manga/interactor/ResetMangaViewerFlags.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.entries.manga.interactor
2 |
3 | import tachiyomi.domain.entries.manga.repository.MangaRepository
4 |
5 | class ResetMangaViewerFlags(
6 | private val mangaRepository: MangaRepository,
7 | ) {
8 |
9 | suspend fun await(): Boolean {
10 | return mangaRepository.resetMangaViewerFlags()
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/entries/manga/model/MangaCover.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.entries.manga.model
2 |
3 | import tachiyomi.domain.entries.EntryCover
4 |
5 | /**
6 | * Contains the required data for MangaCoverFetcher
7 | */
8 | data class MangaCover(
9 | val mangaId: Long,
10 | val sourceId: Long,
11 | val isMangaFavorite: Boolean,
12 | val url: String?,
13 | val lastModified: Long,
14 | ) : EntryCover
15 |
16 | fun Manga.asMangaCover(): MangaCover {
17 | return MangaCover(
18 | mangaId = id,
19 | sourceId = source,
20 | isMangaFavorite = favorite,
21 | url = thumbnailUrl,
22 | lastModified = coverLastModified,
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/history/anime/interactor/UpsertAnimeHistory.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.history.anime.interactor
2 |
3 | import tachiyomi.domain.history.anime.model.AnimeHistoryUpdate
4 | import tachiyomi.domain.history.anime.repository.AnimeHistoryRepository
5 |
6 | class UpsertAnimeHistory(
7 | private val historyRepository: AnimeHistoryRepository,
8 | ) {
9 |
10 | suspend fun await(historyUpdate: AnimeHistoryUpdate) {
11 | historyRepository.upsertAnimeHistory(historyUpdate)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/history/anime/model/AnimeHistory.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.history.anime.model
2 |
3 | import java.util.Date
4 |
5 | data class AnimeHistory(
6 | val id: Long,
7 | val episodeId: Long,
8 | val seenAt: Date?,
9 | ) {
10 | companion object {
11 | fun create() = AnimeHistory(
12 | id = -1L,
13 | episodeId = -1L,
14 | seenAt = null,
15 | )
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/history/anime/model/AnimeHistoryUpdate.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.history.anime.model
2 |
3 | import java.util.Date
4 |
5 | data class AnimeHistoryUpdate(
6 | val episodeId: Long,
7 | val seenAt: Date,
8 | )
9 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/history/anime/model/AnimeHistoryWithRelations.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.history.anime.model
2 |
3 | import tachiyomi.domain.entries.anime.model.AnimeCover
4 | import java.util.Date
5 |
6 | data class AnimeHistoryWithRelations(
7 | val id: Long,
8 | val episodeId: Long,
9 | val animeId: Long,
10 | val title: String,
11 | val episodeNumber: Double,
12 | val seenAt: Date?,
13 | val coverData: AnimeCover,
14 | )
15 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/history/manga/interactor/GetTotalReadDuration.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.history.manga.interactor
2 |
3 | import tachiyomi.domain.history.manga.repository.MangaHistoryRepository
4 |
5 | class GetTotalReadDuration(
6 | private val repository: MangaHistoryRepository,
7 | ) {
8 |
9 | suspend fun await(): Long {
10 | return repository.getTotalReadDuration()
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/history/manga/interactor/UpsertMangaHistory.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.history.manga.interactor
2 |
3 | import tachiyomi.domain.history.manga.model.MangaHistoryUpdate
4 | import tachiyomi.domain.history.manga.repository.MangaHistoryRepository
5 |
6 | class UpsertMangaHistory(
7 | private val historyRepository: MangaHistoryRepository,
8 | ) {
9 |
10 | suspend fun await(historyUpdate: MangaHistoryUpdate) {
11 | historyRepository.upsertMangaHistory(historyUpdate)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/history/manga/model/MangaHistory.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.history.manga.model
2 |
3 | import java.util.Date
4 |
5 | data class MangaHistory(
6 | val id: Long,
7 | val chapterId: Long,
8 | val readAt: Date?,
9 | val readDuration: Long,
10 | ) {
11 | companion object {
12 | fun create() = MangaHistory(
13 | id = -1L,
14 | chapterId = -1L,
15 | readAt = null,
16 | readDuration = -1L,
17 | )
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/history/manga/model/MangaHistoryUpdate.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.history.manga.model
2 |
3 | import java.util.Date
4 |
5 | data class MangaHistoryUpdate(
6 | val chapterId: Long,
7 | val readAt: Date,
8 | val sessionReadDuration: Long,
9 | )
10 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/history/manga/model/MangaHistoryWithRelations.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.history.manga.model
2 |
3 | import tachiyomi.domain.entries.manga.model.MangaCover
4 | import java.util.Date
5 |
6 | data class MangaHistoryWithRelations(
7 | val id: Long,
8 | val chapterId: Long,
9 | val mangaId: Long,
10 | val title: String,
11 | val chapterNumber: Double,
12 | val readAt: Date?,
13 | val readDuration: Long,
14 | val coverData: MangaCover,
15 | )
16 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/items/chapter/interactor/GetChapterByUrlAndMangaId.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.items.chapter.interactor
2 |
3 | import tachiyomi.domain.items.chapter.model.Chapter
4 | import tachiyomi.domain.items.chapter.repository.ChapterRepository
5 |
6 | class GetChapterByUrlAndMangaId(
7 | private val chapterRepository: ChapterRepository,
8 | ) {
9 |
10 | suspend fun await(url: String, sourceId: Long): Chapter? {
11 | return try {
12 | chapterRepository.getChapterByUrlAndMangaId(url, sourceId)
13 | } catch (e: Exception) {
14 | null
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/items/chapter/interactor/ShouldUpdateDbChapter.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.items.chapter.interactor
2 |
3 | import tachiyomi.domain.items.chapter.model.Chapter
4 |
5 | class ShouldUpdateDbChapter {
6 |
7 | fun await(dbChapter: Chapter, sourceChapter: Chapter): Boolean {
8 | return dbChapter.scanlator != sourceChapter.scanlator ||
9 | dbChapter.name != sourceChapter.name ||
10 | dbChapter.dateUpload != sourceChapter.dateUpload ||
11 | dbChapter.chapterNumber != sourceChapter.chapterNumber ||
12 | dbChapter.sourceOrder != sourceChapter.sourceOrder
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/items/chapter/model/NoChaptersException.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.items.chapter.model
2 |
3 | class NoChaptersException : Exception()
4 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/items/episode/interactor/GetEpisodeByUrlAndAnimeId.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.items.episode.interactor
2 |
3 | import tachiyomi.domain.items.episode.model.Episode
4 | import tachiyomi.domain.items.episode.repository.EpisodeRepository
5 |
6 | class GetEpisodeByUrlAndAnimeId(
7 | private val episodeRepository: EpisodeRepository,
8 | ) {
9 |
10 | suspend fun await(url: String, sourceId: Long): Episode? {
11 | return try {
12 | episodeRepository.getEpisodeByUrlAndAnimeId(url, sourceId)
13 | } catch (e: Exception) {
14 | null
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/items/episode/interactor/ShouldUpdateDbEpisode.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.items.episode.interactor
2 |
3 | import tachiyomi.domain.items.episode.model.Episode
4 |
5 | class ShouldUpdateDbEpisode {
6 |
7 | fun await(dbEpisode: Episode, sourceEpisode: Episode): Boolean {
8 | return dbEpisode.scanlator != sourceEpisode.scanlator ||
9 | dbEpisode.name != sourceEpisode.name ||
10 | dbEpisode.dateUpload != sourceEpisode.dateUpload ||
11 | dbEpisode.episodeNumber != sourceEpisode.episodeNumber ||
12 | dbEpisode.sourceOrder != sourceEpisode.sourceOrder
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/items/episode/model/NoEpisodesException.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.items.episode.model
2 |
3 | class NoEpisodesException : Exception()
4 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/library/anime/LibraryAnime.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.library.anime
2 |
3 | import tachiyomi.domain.entries.anime.model.Anime
4 |
5 | data class LibraryAnime(
6 | val anime: Anime,
7 | val category: Long,
8 | val totalEpisodes: Long,
9 | val seenCount: Long,
10 | val bookmarkCount: Long,
11 | val latestUpload: Long,
12 | val episodeFetchedAt: Long,
13 | val lastSeen: Long,
14 | ) {
15 | val id: Long = anime.id
16 |
17 | val unseenCount
18 | get() = totalEpisodes - seenCount
19 |
20 | val hasBookmarks
21 | get() = bookmarkCount > 0
22 |
23 | val hasStarted = seenCount > 0
24 | }
25 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/library/manga/LibraryManga.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.library.manga
2 |
3 | import tachiyomi.domain.entries.manga.model.Manga
4 |
5 | data class LibraryManga(
6 | val manga: Manga,
7 | val category: Long,
8 | val totalChapters: Long,
9 | val readCount: Long,
10 | val bookmarkCount: Long,
11 | val latestUpload: Long,
12 | val chapterFetchedAt: Long,
13 | val lastRead: Long,
14 | ) {
15 | val id: Long = manga.id
16 |
17 | val unreadCount
18 | get() = totalChapters - readCount
19 |
20 | val hasBookmarks
21 | get() = bookmarkCount > 0
22 |
23 | val hasStarted = readCount > 0
24 | }
25 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/release/model/Release.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.release.model
2 |
3 | /**
4 | * Contains information about the latest release.
5 | */
6 | data class Release(
7 | val version: String,
8 | val info: String,
9 | val releaseLink: String,
10 | val downloadLink: String,
11 | )
12 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/release/service/ReleaseService.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.release.service
2 |
3 | import tachiyomi.domain.release.interactor.GetApplicationRelease
4 | import tachiyomi.domain.release.model.Release
5 |
6 | interface ReleaseService {
7 |
8 | suspend fun latest(arguments: GetApplicationRelease.Arguments): Release?
9 | }
10 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/source/anime/interactor/GetAnimeSourcesWithNonLibraryAnime.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.source.anime.interactor
2 |
3 | import kotlinx.coroutines.flow.Flow
4 | import tachiyomi.domain.source.anime.model.AnimeSourceWithCount
5 | import tachiyomi.domain.source.anime.repository.AnimeSourceRepository
6 |
7 | class GetAnimeSourcesWithNonLibraryAnime(
8 | private val repository: AnimeSourceRepository,
9 | ) {
10 |
11 | fun subscribe(): Flow> {
12 | return repository.getSourcesWithNonLibraryAnime()
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/source/anime/model/AnimeSource.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.source.anime.model
2 |
3 | data class AnimeSource(
4 | val id: Long,
5 | val lang: String,
6 | val name: String,
7 | val supportsLatest: Boolean,
8 | val isStub: Boolean,
9 | val pin: Pins = Pins.unpinned,
10 | val isUsedLast: Boolean = false,
11 | ) {
12 |
13 | val visualName: String
14 | get() = when {
15 | lang.isEmpty() -> name
16 | else -> "$name (${lang.uppercase()})"
17 | }
18 |
19 | val key: () -> String = {
20 | when {
21 | isUsedLast -> "$id-lastused"
22 | else -> "$id"
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/source/anime/model/AnimeSourceWithCount.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.source.anime.model
2 |
3 | data class AnimeSourceWithCount(
4 | val source: AnimeSource,
5 | val count: Long,
6 | ) {
7 |
8 | val id: Long
9 | get() = source.id
10 |
11 | val name: String
12 | get() = source.name
13 | }
14 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/source/anime/repository/AnimeStubSourceRepository.kt:
--------------------------------------------------------------------------------
1 |
2 | package tachiyomi.domain.source.anime.repository
3 |
4 | import kotlinx.coroutines.flow.Flow
5 | import tachiyomi.domain.source.anime.model.StubAnimeSource
6 |
7 | interface AnimeStubSourceRepository {
8 | fun subscribeAllAnime(): Flow>
9 |
10 | suspend fun getStubAnimeSource(id: Long): StubAnimeSource?
11 |
12 | suspend fun upsertStubAnimeSource(id: Long, lang: String, name: String)
13 | }
14 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/source/manga/interactor/GetMangaSourcesWithNonLibraryManga.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.source.manga.interactor
2 |
3 | import kotlinx.coroutines.flow.Flow
4 | import tachiyomi.domain.source.manga.model.MangaSourceWithCount
5 | import tachiyomi.domain.source.manga.repository.MangaSourceRepository
6 |
7 | class GetMangaSourcesWithNonLibraryManga(
8 | private val repository: MangaSourceRepository,
9 | ) {
10 |
11 | fun subscribe(): Flow> {
12 | return repository.getMangaSourcesWithNonLibraryManga()
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/source/manga/model/MangaSourceWithCount.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.source.manga.model
2 |
3 | data class MangaSourceWithCount(
4 | val source: Source,
5 | val count: Long,
6 | ) {
7 |
8 | val id: Long
9 | get() = source.id
10 |
11 | val name: String
12 | get() = source.name
13 | }
14 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/source/manga/repository/MangaStubSourceRepository.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.source.manga.repository
2 |
3 | import kotlinx.coroutines.flow.Flow
4 | import tachiyomi.domain.source.manga.model.StubMangaSource
5 |
6 | interface MangaStubSourceRepository {
7 | fun subscribeAllManga(): Flow>
8 |
9 | suspend fun getStubMangaSource(id: Long): StubMangaSource?
10 |
11 | suspend fun upsertStubMangaSource(id: Long, lang: String, name: String)
12 | }
13 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/storage/service/StoragePreferences.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.storage.service
2 |
3 | import tachiyomi.core.common.preference.Preference
4 | import tachiyomi.core.common.preference.PreferenceStore
5 | import tachiyomi.core.common.storage.FolderProvider
6 |
7 | class StoragePreferences(
8 | private val folderProvider: FolderProvider,
9 | private val preferenceStore: PreferenceStore,
10 | ) {
11 |
12 | fun baseStorageDirectory() = preferenceStore.getString(Preference.appStateKey("storage_dir"), folderProvider.path())
13 | }
14 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/track/anime/interactor/DeleteAnimeTrack.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.track.anime.interactor
2 |
3 | import logcat.LogPriority
4 | import tachiyomi.core.common.util.system.logcat
5 | import tachiyomi.domain.track.anime.repository.AnimeTrackRepository
6 |
7 | class DeleteAnimeTrack(
8 | private val trackRepository: AnimeTrackRepository,
9 | ) {
10 |
11 | suspend fun await(animeId: Long, trackerId: Long) {
12 | try {
13 | trackRepository.delete(animeId, trackerId)
14 | } catch (e: Exception) {
15 | logcat(LogPriority.ERROR, e)
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/domain/src/main/java/tachiyomi/domain/track/anime/interactor/GetTracksPerAnime.kt:
--------------------------------------------------------------------------------
1 | package tachiyomi.domain.track.anime.interactor
2 |
3 | import kotlinx.coroutines.flow.Flow
4 | import kotlinx.coroutines.flow.map
5 | import tachiyomi.domain.track.anime.model.AnimeTrack
6 | import tachiyomi.domain.track.anime.repository.AnimeTrackRepository
7 |
8 | class GetTracksPerAnime(
9 | private val trackRepository: AnimeTrackRepository,
10 | ) {
11 |
12 | fun subscribe(): Flow