From 9dbb59f337b539d39aee037488812cc34d48dfe1 Mon Sep 17 00:00:00 2001 From: NerdNumber9 Date: Thu, 4 May 2017 23:38:17 -0400 Subject: [PATCH] Upstream merge Internal permission change Fix url adder --- .github/CONTRIBUTING.md | 0 .github/ISSUE_TEMPLATE.md | 0 .gitignore | 4 +- .travis.yml | 0 LICENSE | 0 README.md | 46 +- app/.gitignore | 3 +- app/build.gradle | 36 +- app/proguard-rules.pro | 9 +- app/src/main/AndroidManifest.xml | 58 +++ app/src/main/assets/fonts/PTSans-Narrow.ttf | Bin .../main/assets/fonts/PTSans-NarrowBold.ttf | Bin app/src/main/ic_launcher-web.png | Bin app/src/main/java/eu/kanade/tachiyomi/App.kt | 16 +- .../java/eu/kanade/tachiyomi/AppModule.kt | 0 .../java/eu/kanade/tachiyomi/Constants.kt | 0 .../tachiyomi/data/backup/BackupManager.kt | 0 .../tachiyomi/data/cache/ChapterCache.kt | 0 .../kanade/tachiyomi/data/cache/CoverCache.kt | 0 .../tachiyomi/data/database/DatabaseHelper.kt | 0 .../tachiyomi/data/database/DbExtensions.kt | 0 .../tachiyomi/data/database/DbOpenHelper.kt | 0 .../tachiyomi/data/database/DbProvider.kt | 0 .../database/mappers/CategoryTypeMapping.kt | 0 .../database/mappers/ChapterTypeMapping.kt | 0 .../database/mappers/HistoryTypeMapping.kt | 0 .../mappers/MangaCategoryTypeMapping.kt | 0 .../data/database/mappers/MangaTypeMapping.kt | 0 .../data/database/mappers/TrackTypeMapping.kt | 0 .../data/database/models/Category.kt | 0 .../data/database/models/CategoryImpl.kt | 0 .../tachiyomi/data/database/models/Chapter.kt | 0 .../data/database/models/ChapterImpl.kt | 0 .../tachiyomi/data/database/models/History.kt | 0 .../tachiyomi/data/database/models/Manga.kt | 0 .../data/database/models/MangaCategory.kt | 0 .../data/database/models/MangaChapter.kt | 0 .../database/models/MangaChapterHistory.kt | 0 .../data/database/models/MangaImpl.kt | 0 .../tachiyomi/data/database/models/Track.kt | 0 .../data/database/models/TrackImpl.kt | 0 .../data/database/queries/CategoryQueries.kt | 0 .../data/database/queries/ChapterQueries.kt | 0 .../data/database/queries/HistoryQueries.kt | 0 .../database/queries/MangaCategoryQueries.kt | 0 .../data/database/queries/MangaQueries.kt | 0 .../data/database/queries/RawQueries.kt | 0 .../data/database/queries/TrackQueries.kt | 0 .../resolvers/ChapterProgressPutResolver.kt | 0 .../ChapterSourceOrderPutResolver.kt | 0 .../resolvers/HistoryLastReadPutResolver.kt | 0 .../resolvers/LibraryMangaGetResolver.kt | 0 .../resolvers/MangaChapterGetResolver.kt | 0 .../MangaChapterHistoryGetResolver.kt | 0 .../resolvers/MangaFlagsPutResolver.kt | 0 .../resolvers/MangaLastUpdatedPutResolver.kt | 0 .../data/database/tables/CategoryTable.kt | 0 .../data/database/tables/ChapterTable.kt | 0 .../data/database/tables/HistoryTable.kt | 0 .../database/tables/MangaCategoryTable.kt | 0 .../data/database/tables/MangaTable.kt | 0 .../data/database/tables/TrackTable.kt | 0 .../data/download/DownloadManager.kt | 0 .../data/download/DownloadNotifier.kt | 0 .../data/download/DownloadProvider.kt | 0 .../data/download/DownloadService.kt | 0 .../tachiyomi/data/download/DownloadStore.kt | 0 .../tachiyomi/data/download/Downloader.kt | 0 .../tachiyomi/data/download/model/Download.kt | 0 .../data/download/model/DownloadQueue.kt | 0 .../tachiyomi/data/glide/AppGlideModule.kt | 0 .../tachiyomi/data/glide/FileFetcher.kt | 0 .../tachiyomi/data/glide/MangaFileFetcher.kt | 0 .../tachiyomi/data/glide/MangaModelLoader.kt | 0 .../tachiyomi/data/glide/MangaUrlFetcher.kt | 0 .../data/library/LibraryUpdateJob.kt | 0 .../data/library/LibraryUpdateService.kt | 0 .../data/notification/NotificationHandler.kt | 0 .../data/notification/NotificationReceiver.kt | 0 .../data/preference/PreferenceKeys.kt | 0 .../data/preference/PreferencesHelper.kt | 37 +- .../tachiyomi/data/track/TrackManager.kt | 0 .../tachiyomi/data/track/TrackService.kt | 0 .../tachiyomi/data/track/anilist/Anilist.kt | 0 .../data/track/anilist/AnilistApi.kt | 0 .../data/track/anilist/AnilistInterceptor.kt | 0 .../data/track/anilist/AnilistModels.kt | 0 .../tachiyomi/data/track/anilist/OAuth.kt | 0 .../tachiyomi/data/track/kitsu/Kitsu.kt | 0 .../tachiyomi/data/track/kitsu/KitsuApi.kt | 0 .../data/track/kitsu/KitsuInterceptor.kt | 0 .../tachiyomi/data/track/kitsu/KitsuModels.kt | 0 .../tachiyomi/data/track/kitsu/OAuth.kt | 0 .../data/track/myanimelist/MyAnimeList.kt | 0 .../data/track/myanimelist/MyanimelistApi.kt | 0 .../tachiyomi/data/updater/GithubRelease.kt | 0 .../tachiyomi/data/updater/GithubService.kt | 2 +- .../data/updater/GithubUpdateChecker.kt | 2 +- .../data/updater/GithubUpdateResult.kt | 0 .../data/updater/UpdateCheckerJob.kt | 0 .../data/updater/UpdateDownloaderReceiver.kt | 0 .../data/updater/UpdateDownloaderService.kt | 0 .../network/CloudflareInterceptor.kt | 0 .../kanade/tachiyomi/network/NetworkHelper.kt | 0 .../tachiyomi/network/OkHttpExtensions.kt | 0 .../tachiyomi/network/PersistentCookieJar.kt | 0 .../network/PersistentCookieStore.kt | 0 .../tachiyomi/network/ProgressListener.kt | 0 .../tachiyomi/network/ProgressResponseBody.kt | 0 .../eu/kanade/tachiyomi/network/Requests.kt | 0 .../tachiyomi/source/CatalogueSource.kt | 0 .../eu/kanade/tachiyomi/source/LocalSource.kt | 0 .../java/eu/kanade/tachiyomi/source/Source.kt | 0 .../kanade/tachiyomi/source/SourceManager.kt | 43 +- .../kanade/tachiyomi/source/model/Filter.kt | 0 .../tachiyomi/source/model/FilterList.kt | 0 .../tachiyomi/source/model/MangasPage.kt | 0 .../eu/kanade/tachiyomi/source/model/Page.kt | 94 ++-- .../kanade/tachiyomi/source/model/SChapter.kt | 0 .../tachiyomi/source/model/SChapterImpl.kt | 0 .../kanade/tachiyomi/source/model/SManga.kt | 0 .../tachiyomi/source/model/SMangaImpl.kt | 0 .../tachiyomi/source/online/HttpSource.kt | 0 .../source/online/HttpSourceFetcher.kt | 0 .../tachiyomi/source/online/LoginSource.kt | 0 .../source/online/ParsedHttpSource.kt | 0 .../tachiyomi/source/online/YamlHttpSource.kt | 0 .../source/online/YamlHttpSourceMappings.kt | 0 .../tachiyomi/source/online/all/EHentai.kt | 476 ++++++++++++++++++ .../source/online/all/EHentaiMetadata.kt | 127 +++++ .../tachiyomi/source/online/all/NHentai.kt | 237 +++++++++ .../tachiyomi/source/online/all/PervEden.kt | 282 +++++++++++ .../tachiyomi/source/online/english/Batoto.kt | 0 .../source/online/english/Kissmanga.kt | 0 .../source/online/english/Mangafox.kt | 0 .../source/online/english/Mangahere.kt | 0 .../source/online/english/Mangasee.kt | 0 .../source/online/english/Readmangatoday.kt | 0 .../source/online/german/WieManga.kt | 0 .../source/online/russian/Mangachan.kt | 0 .../source/online/russian/Mintmanga.kt | 0 .../source/online/russian/Readmanga.kt | 0 .../ui/base/activity/ActivityMixin.kt | 0 .../ui/base/activity/BaseActivity.kt | 53 ++ .../ui/base/activity/BaseRxActivity.kt | 0 .../ui/base/adapter/FlexibleViewHolder.kt | 0 .../adapter/SmartFragmentStatePagerAdapter.kt | 0 .../ui/base/fragment/BaseFragment.kt | 0 .../ui/base/fragment/BaseRxFragment.kt | 0 .../ui/base/fragment/FragmentMixin.kt | 0 .../ui/base/presenter/BasePresenter.kt | 0 .../ui/catalogue/CatalogueFragment.kt | 0 .../ui/catalogue/CatalogueGridHolder.kt | 0 .../tachiyomi/ui/catalogue/CatalogueHolder.kt | 0 .../tachiyomi/ui/catalogue/CatalogueItem.kt | 0 .../ui/catalogue/CatalogueListHolder.kt | 0 .../ui/catalogue/CatalogueNavigationView.kt | 0 .../tachiyomi/ui/catalogue/CataloguePager.kt | 0 .../ui/catalogue/CataloguePresenter.kt | 0 .../ui/catalogue/NoResultsException.kt | 0 .../eu/kanade/tachiyomi/ui/catalogue/Pager.kt | 0 .../tachiyomi/ui/catalogue/ProgressItem.kt | 0 .../ui/catalogue/filter/CheckboxItem.kt | 0 .../ui/catalogue/filter/GroupItem.kt | 0 .../ui/catalogue/filter/HeaderItem.kt | 0 .../ui/catalogue/filter/SectionItems.kt | 0 .../ui/catalogue/filter/SelectItem.kt | 0 .../ui/catalogue/filter/SeparatorItem.kt | 0 .../ui/catalogue/filter/SortGroup.kt | 0 .../tachiyomi/ui/catalogue/filter/SortItem.kt | 0 .../tachiyomi/ui/catalogue/filter/TextItem.kt | 0 .../ui/catalogue/filter/TriStateItem.kt | 0 .../tachiyomi/ui/category/CategoryActivity.kt | 0 .../tachiyomi/ui/category/CategoryAdapter.kt | 0 .../tachiyomi/ui/category/CategoryHolder.kt | 0 .../tachiyomi/ui/category/CategoryItem.kt | 0 .../ui/category/CategoryPresenter.kt | 0 .../tachiyomi/ui/download/DownloadActivity.kt | 0 .../tachiyomi/ui/download/DownloadAdapter.kt | 0 .../tachiyomi/ui/download/DownloadHolder.kt | 0 .../ui/download/DownloadPresenter.kt | 0 .../latest_updates/LatestUpdatesFragment.kt | 0 .../ui/latest_updates/LatestUpdatesPager.kt | 0 .../latest_updates/LatestUpdatesPresenter.kt | 0 .../tachiyomi/ui/library/LibraryAdapter.kt | 0 .../ui/library/LibraryCategoryAdapter.kt | 42 +- .../ui/library/LibraryCategoryView.kt | 9 +- .../tachiyomi/ui/library/LibraryFragment.kt | 6 + .../tachiyomi/ui/library/LibraryGridHolder.kt | 0 .../tachiyomi/ui/library/LibraryHolder.kt | 0 .../tachiyomi/ui/library/LibraryListHolder.kt | 0 .../tachiyomi/ui/library/LibraryMangaEvent.kt | 0 .../ui/library/LibraryNavigationView.kt | 0 .../tachiyomi/ui/library/LibraryPresenter.kt | 0 .../ui/library/LibrarySelectionEvent.kt | 0 .../tachiyomi/ui/library/LibrarySort.kt | 0 .../ui/main/ChangelogDialogFragment.kt | 2 +- .../kanade/tachiyomi/ui/main/MainActivity.kt | 20 + .../tachiyomi/ui/manga/MangaActivity.kt | 0 .../kanade/tachiyomi/ui/manga/MangaEvent.kt | 0 .../tachiyomi/ui/manga/MangaPresenter.kt | 0 .../ui/manga/chapter/ChapterHolder.kt | 0 .../ui/manga/chapter/ChaptersAdapter.kt | 0 .../ui/manga/chapter/ChaptersFragment.kt | 0 .../ui/manga/chapter/ChaptersPresenter.kt | 0 .../ui/manga/info/ChapterCountEvent.kt | 0 .../ui/manga/info/MangaFavoriteEvent.kt | 0 .../ui/manga/info/MangaInfoFragment.kt | 0 .../ui/manga/info/MangaInfoPresenter.kt | 6 +- .../tachiyomi/ui/manga/track/TrackAdapter.kt | 0 .../tachiyomi/ui/manga/track/TrackFragment.kt | 0 .../tachiyomi/ui/manga/track/TrackHolder.kt | 0 .../tachiyomi/ui/manga/track/TrackItem.kt | 0 .../ui/manga/track/TrackPresenter.kt | 0 .../ui/manga/track/TrackSearchAdapter.kt | 0 .../ui/manga/track/TrackSearchDialog.kt | 0 .../tachiyomi/ui/reader/ChapterLoader.kt | 0 .../tachiyomi/ui/reader/ReaderActivity.kt | 4 + .../tachiyomi/ui/reader/ReaderChapter.kt | 0 .../ui/reader/ReaderCustomFilterDialog.kt | 0 .../kanade/tachiyomi/ui/reader/ReaderEvent.kt | 0 .../tachiyomi/ui/reader/ReaderPresenter.kt | 6 + .../ui/reader/ReaderSettingsDialog.kt | 0 .../tachiyomi/ui/reader/SaveImageNotifier.kt | 0 .../ui/reader/viewer/base/BaseReader.kt | 0 .../viewer/base/PageDecodeErrorLayout.kt | 0 .../pager/OnChapterBoundariesOutListener.kt | 0 .../ui/reader/viewer/pager/PageView.kt | 0 .../ui/reader/viewer/pager/Pager.java | 0 .../ui/reader/viewer/pager/PagerReader.kt | 0 .../reader/viewer/pager/PagerReaderAdapter.kt | 0 .../pager/horizontal/HorizontalPager.kt | 0 .../pager/horizontal/LeftToRightReader.kt | 0 .../pager/horizontal/RightToLeftReader.kt | 0 .../viewer/pager/vertical/VerticalPager.kt | 0 .../viewer/pager/vertical/VerticalReader.kt | 0 .../pager/vertical/VerticalViewPagerImpl.java | 0 .../reader/viewer/webtoon/WebtoonAdapter.kt | 0 .../ui/reader/viewer/webtoon/WebtoonHolder.kt | 0 .../ui/reader/viewer/webtoon/WebtoonReader.kt | 0 .../tachiyomi/ui/recent_updates/DateItem.kt | 0 .../ui/recent_updates/RecentChapterHolder.kt | 0 .../ui/recent_updates/RecentChapterItem.kt | 0 .../recent_updates/RecentChaptersAdapter.kt | 0 .../recent_updates/RecentChaptersFragment.kt | 0 .../recent_updates/RecentChaptersPresenter.kt | 0 .../ui/recently_read/RecentlyReadAdapter.kt | 0 .../ui/recently_read/RecentlyReadFragment.kt | 0 .../ui/recently_read/RecentlyReadHolder.kt | 0 .../ui/recently_read/RecentlyReadPresenter.kt | 0 .../ui/setting/AnilistLoginActivity.kt | 0 .../ui/setting/SettingsAboutFragment.kt | 0 .../tachiyomi/ui/setting/SettingsActivity.kt | 2 + .../ui/setting/SettingsAdvancedFragment.kt | 0 .../ui/setting/SettingsDownloadsFragment.kt | 0 .../ui/setting/SettingsEhFragment.kt | 73 +++ .../tachiyomi/ui/setting/SettingsFragment.kt | 1 + .../ui/setting/SettingsGeneralFragment.kt | 0 .../ui/setting/SettingsSourcesFragment.kt | 0 .../ui/setting/SettingsTrackingFragment.kt | 0 .../tachiyomi/util/AndroidComponentUtil.java | 0 .../tachiyomi/util/ChapterRecognition.kt | 0 .../tachiyomi/util/ChapterSourceSync.kt | 0 .../tachiyomi/util/ContextExtensions.kt | 0 .../java/eu/kanade/tachiyomi/util/DiskUtil.kt | 0 .../util/DynamicConcurrentMergeOperator.java | 0 .../kanade/tachiyomi/util/FileExtensions.kt | 0 .../java/eu/kanade/tachiyomi/util/GLUtil.java | 0 .../tachiyomi/util/ImageViewExtensions.kt | 0 .../kanade/tachiyomi/util/JsoupExtensions.kt | 0 .../eu/kanade/tachiyomi/util/LocaleHelper.kt | 0 .../kanade/tachiyomi/util/OkioExtensions.kt | 0 .../tachiyomi/util/RarContentProvider.kt | 0 .../kanade/tachiyomi/util/RetryWithDelay.kt | 0 .../eu/kanade/tachiyomi/util/RxExtensions.kt | 0 .../eu/kanade/tachiyomi/util/SharedData.kt | 0 .../kanade/tachiyomi/util/StringExtensions.kt | 0 .../kanade/tachiyomi/util/ViewExtensions.kt | 0 .../tachiyomi/util/ViewGroupExtensions.kt | 0 .../tachiyomi/util/ZipContentProvider.kt | 0 .../tachiyomi/widget/AutofitRecyclerView.kt | 0 .../widget/DeletingChaptersDialog.kt | 0 .../tachiyomi/widget/DialogCheckboxView.kt | 0 .../tachiyomi/widget/ElevationAppBarLayout.kt | 0 .../eu/kanade/tachiyomi/widget/EmptyView.kt | 0 .../widget/ExtendedNavigationView.kt | 0 .../tachiyomi/widget/FABAnimationBase.kt | 0 .../tachiyomi/widget/FABAnimationUpDown.kt | 0 .../widget/IgnoreFirstSpinnerListener.kt | 0 .../tachiyomi/widget/MinMaxNumberPicker.kt | 0 .../tachiyomi/widget/NegativeSeekBar.kt | 0 .../kanade/tachiyomi/widget/PTSansTextView.kt | 0 .../widget/PreCachingLayoutManager.kt | 0 .../widget/RecyclerViewPagerAdapter.kt | 0 .../tachiyomi/widget/RevealAnimationView.kt | 0 .../widget/SimpleAnimationListener.kt | 0 .../tachiyomi/widget/SimpleNavigationView.kt | 0 .../tachiyomi/widget/SimpleSeekBarListener.kt | 0 .../tachiyomi/widget/SimpleTextWatcher.kt | 0 .../tachiyomi/widget/StateImageViewTarget.kt | 0 .../tachiyomi/widget/ViewPagerAdapter.kt | 0 .../widget/preference/IntListPreference.kt | 0 .../widget/preference/LibraryColumnsDialog.kt | 0 .../preference/LoginCheckBoxPreference.kt | 0 .../preference/LoginDialogPreference.kt | 0 .../widget/preference/LoginPreference.kt | 0 .../preference/SimpleDialogPreference.kt | 0 .../widget/preference/SourceLoginDialog.kt | 0 .../preference/SwitchPreferenceCategory.kt | 0 .../widget/preference/TrackLoginDialog.kt | 0 app/src/main/java/exh/EHSourceHelpers.kt | 29 ++ app/src/main/java/exh/FavoritesSyncHelper.kt | 135 +++++ .../main/java/exh/FavoritesSyncManager.java | 192 +++++++ app/src/main/java/exh/GalleryAdder.kt | 80 +++ .../main/java/exh/StringBuilderExtensions.kt | 3 + .../java/exh/VerbelExpressionExtensions.kt | 5 + .../main/java/exh/metadata/MetadataHelper.kt | 62 +++ .../main/java/exh/metadata/MetadataUtil.kt | 47 ++ .../main/java/exh/metadata/MetdataCopier.kt | 218 ++++++++ .../exh/metadata/models/ExGalleryMetadata.kt | 51 ++ .../exh/metadata/models/NHentaiMetadata.kt | 48 ++ .../models/PervEdenGalleryMetadata.kt | 32 ++ .../models/SearchableGalleryMetadata.kt | 18 + app/src/main/java/exh/metadata/models/Tag.kt | 7 + app/src/main/java/exh/search/MultiWildcard.kt | 3 + app/src/main/java/exh/search/Namespace.kt | 4 + .../main/java/exh/search/QueryComponent.kt | 6 + app/src/main/java/exh/search/SearchEngine.kt | 150 ++++++ .../main/java/exh/search/SingleWildcard.kt | 3 + .../java/exh/search/StringTextComponent.kt | 3 + app/src/main/java/exh/search/Text.kt | 49 ++ app/src/main/java/exh/search/TextComponent.kt | 3 + .../java/exh/ui/batchadd/BatchAddFragment.kt | 131 +++++ .../exh/ui/intercept/InterceptActivity.kt | 82 +++ app/src/main/java/exh/ui/lock/LockActivity.kt | 60 +++ .../main/java/exh/ui/lock/LockPreference.kt | 85 ++++ app/src/main/java/exh/ui/lock/LockUtils.kt | 91 ++++ .../main/java/exh/ui/login/LoginActivity.kt | 218 ++++++++ .../exh/ui/migration/MetadataFetchDialog.kt | 136 +++++ .../java/exh/ui/migration/MigrationStatus.kt | 16 + .../main/java/exh/ui/migration/UrlMigrator.kt | 79 +++ app/src/main/java/exh/util/UriFilter.kt | 10 + app/src/main/java/exh/util/UriGroup.kt | 15 + app/src/main/res/anim/enter_from_bottom.xml | 0 app/src/main/res/anim/enter_from_left.xml | 0 app/src/main/res/anim/enter_from_right.xml | 0 app/src/main/res/anim/enter_from_top.xml | 0 app/src/main/res/anim/exit_to_bottom.xml | 0 app/src/main/res/anim/exit_to_left.xml | 0 app/src/main/res/anim/exit_to_right.xml | 0 app/src/main/res/anim/exit_to_top.xml | 0 app/src/main/res/anim/fab_hide_to_bottom.xml | 0 .../main/res/anim/fab_show_from_bottom.xml | 0 app/src/main/res/anim/fade_in.xml | 0 app/src/main/res/anim/fade_in_long.xml | 0 .../color/abc_primary_text_material_dark.xml | 0 .../ic_av_pause_grey_24dp_img.png | Bin .../ic_av_play_arrow_grey_img.png | Bin .../drawable-hdpi/ic_clear_grey_24dp_img.png | Bin .../res/drawable-hdpi/ic_delete_grey_24dp.png | Bin .../ic_insert_photo_white_24dp.png | Bin .../ic_refresh_grey_24dp_img.png | Bin .../ic_refresh_white_24dp_img.png | Bin .../res/drawable-hdpi/ic_share_grey_24dp.png | Bin .../ic_system_update_grey_24dp_img.png | Bin .../ic_av_pause_grey_24dp_img.png | Bin .../ic_av_play_arrow_grey_img.png | Bin .../drawable-mdpi/ic_clear_grey_24dp_img.png | Bin .../res/drawable-mdpi/ic_delete_grey_24dp.png | Bin .../ic_insert_photo_white_24dp.png | Bin .../ic_refresh_grey_24dp_img.png | Bin .../ic_refresh_white_24dp_img.png | Bin .../res/drawable-mdpi/ic_share_grey_24dp.png | Bin .../ic_system_update_grey_24dp_img.png | Bin .../library_item_selector_dark.xml | 0 .../library_item_selector_light.xml | 0 .../drawable-v21/list_item_selector_dark.xml | 0 .../drawable-v21/list_item_selector_light.xml | 0 .../res/drawable-xhdpi/card_background.9.png | Bin .../ic_av_pause_grey_24dp_img.png | Bin .../ic_av_play_arrow_grey_img.png | Bin .../drawable-xhdpi/ic_clear_grey_24dp_img.png | Bin .../drawable-xhdpi/ic_delete_grey_24dp.png | Bin .../ic_insert_photo_white_24dp.png | Bin .../ic_refresh_grey_24dp_img.png | Bin .../ic_refresh_white_24dp_img.png | Bin .../res/drawable-xhdpi/ic_share_grey_24dp.png | Bin .../ic_system_update_grey_24dp_img.png | Bin .../ic_av_pause_grey_24dp_img.png | Bin .../ic_av_play_arrow_grey_img.png | Bin .../ic_clear_grey_24dp_img.png | Bin .../drawable-xxhdpi/ic_delete_grey_24dp.png | Bin .../ic_insert_photo_white_24dp.png | Bin .../ic_refresh_grey_24dp_img.png | Bin .../ic_refresh_white_24dp_img.png | Bin .../drawable-xxhdpi/ic_share_grey_24dp.png | Bin .../ic_system_update_grey_24dp_img.png | Bin app/src/main/res/drawable-xxxhdpi/al.png | Bin .../ic_av_pause_grey_24dp_img.png | Bin .../ic_av_play_arrow_grey_img.png | Bin .../ic_clear_grey_24dp_img.png | Bin .../drawable-xxxhdpi/ic_delete_grey_24dp.png | Bin .../ic_insert_photo_white_24dp.png | Bin .../ic_refresh_grey_24dp_img.png | Bin .../ic_refresh_white_24dp_img.png | Bin .../drawable-xxxhdpi/ic_share_grey_24dp.png | Bin .../ic_system_update_grey_24dp_img.png | Bin app/src/main/res/drawable-xxxhdpi/kitsu.png | Bin app/src/main/res/drawable-xxxhdpi/mal.png | Bin app/src/main/res/drawable/branded_logo.xml | 0 .../res/drawable/eh_ic_ehlogo_red_24dp.xml | 42 ++ .../main/res/drawable/eh_migration_backup.png | Bin 0 -> 30201 bytes .../drawable/eh_migration_backup_button.png | Bin 0 -> 4700 bytes .../res/drawable/eh_migration_hamburgers.png | Bin 0 -> 6818 bytes .../res/drawable/eh_migration_share_icon.png | Bin 0 -> 9088 bytes app/src/main/res/drawable/empty_divider.xml | 0 .../main/res/drawable/empty_drawable_32dp.xml | 0 app/src/main/res/drawable/filter_mock.png | Bin app/src/main/res/drawable/gradient_shape.xml | 0 .../drawable/ic_account_circle_black_24dp.xml | 0 .../main/res/drawable/ic_add_white_24dp.xml | 0 .../res/drawable/ic_backup_black_24dp.xml | 0 .../main/res/drawable/ic_book_black_128dp.xml | 0 .../main/res/drawable/ic_book_black_24dp.xml | 0 .../ic_bookmark_border_white_24dp.xml | 0 .../res/drawable/ic_bookmark_white_24dp.xml | 0 .../drawable/ic_brightness_4_white_24dp.xml | 0 .../drawable/ic_brightness_5_black_24dp.xml | 0 .../drawable/ic_broken_image_grey_24dp.xml | 0 .../main/res/drawable/ic_check_box_24dp.xml | 0 .../ic_check_box_outline_blank_24dp.xml | 0 .../main/res/drawable/ic_check_box_x_24dp.xml | 0 .../drawable/ic_chevron_right_white_24dp.xml | 0 .../ic_chrome_reader_mode_black_24dp.xml | 0 .../drawable/ic_cloud_download_white_24dp.xml | 9 + .../main/res/drawable/ic_code_black_24dp.xml | 0 .../res/drawable/ic_create_white_24dp.xml | 0 .../res/drawable/ic_delete_white_24dp.xml | 0 .../res/drawable/ic_done_all_grey_24dp.xml | 0 .../res/drawable/ic_done_all_white_24dp.xml | 0 .../main/res/drawable/ic_done_green_24dp.xml | 0 .../main/res/drawable/ic_done_white_18dp.xml | 0 .../drawable/ic_expand_more_white_24dp.xml | 0 .../res/drawable/ic_explore_black_24dp.xml | 0 .../drawable/ic_file_download_black_128dp.xml | 0 .../drawable/ic_file_download_black_24dp.xml | 0 .../drawable/ic_file_download_white_24dp.xml | 0 .../drawable/ic_filter_list_white_24dp.xml | 0 .../res/drawable/ic_glasses_black_128dp.xml | 0 .../res/drawable/ic_glasses_black_24dp.xml | 0 .../main/res/drawable/ic_help_black_24dp.xml | 0 .../drawable/ic_insert_photo_white_24dp.png | Bin .../ic_keyboard_arrow_down_black_32dp.xml | 0 .../ic_keyboard_arrow_up_black_32dp.xml | 0 .../main/res/drawable/ic_label_white_24dp.xml | 0 .../res/drawable/ic_language_black_24dp.xml | 0 .../main/res/drawable/ic_menu_white_24dp.xml | 0 .../res/drawable/ic_more_horiz_black_24dp.xml | 0 .../main/res/drawable/ic_pause_white_24dp.xml | 0 .../res/drawable/ic_play_arrow_white_24dp.xml | 0 .../drawable/ic_playlist_add_black_24dp.xml | 9 + .../res/drawable/ic_refresh_white_24dp.xml | 0 .../res/drawable/ic_reorder_grey_24dp.xml | 0 .../res/drawable/ic_search_white_24dp.xml | 0 .../res/drawable/ic_select_all_white_24dp.xml | 0 .../res/drawable/ic_settings_black_24dp.xml | 0 .../res/drawable/ic_settings_white_24dp.xml | 0 .../main/res/drawable/ic_share_white_24dp.xml | 0 .../res/drawable/ic_skip_next_white_24dp.xml | 0 .../drawable/ic_skip_previous_white_24dp.xml | 0 .../ic_sort_by_numeric_white_24dp.xml | 0 .../main/res/drawable/ic_sort_white_24dp.xml | 0 .../main/res/drawable/ic_sync_black_24dp.xml | 0 .../main/res/drawable/ic_tune_black_24dp.xml | 0 .../res/drawable/ic_update_black_128dp.xml | 0 .../res/drawable/ic_update_black_24dp.xml | 0 .../res/drawable/ic_view_list_white_24dp.xml | 0 .../drawable/ic_view_module_white_24dp.xml | 0 .../drawable/ic_watch_later_black_24dp.xml | 0 .../drawable/library_item_selector_dark.xml | 0 .../drawable/library_item_selector_light.xml | 0 .../main/res/drawable/line_divider_dark.xml | 0 .../main/res/drawable/line_divider_light.xml | 0 .../res/drawable/list_item_selector_dark.xml | 0 .../res/drawable/list_item_selector_light.xml | 0 app/src/main/res/drawable/mask_star.png | Bin .../res/layout/activity_download_manager.xml | 0 .../res/layout/activity_edit_categories.xml | 0 app/src/main/res/layout/activity_lock.xml | 29 ++ app/src/main/res/layout/activity_main.xml | 0 app/src/main/res/layout/activity_manga.xml | 0 .../main/res/layout/activity_preferences.xml | 0 app/src/main/res/layout/activity_reader.xml | 0 app/src/main/res/layout/catalogue_drawer.xml | 0 .../res/layout/catalogue_drawer_content.xml | 0 .../res/layout/changelog_header_layout.xml | 0 .../main/res/layout/changelog_row_layout.xml | 0 app/src/main/res/layout/chapter_image.xml | 0 .../layout/dialog_reader_custom_filter.xml | 0 .../res/layout/dialog_reader_settings.xml | 0 .../main/res/layout/dialog_track_chapters.xml | 0 .../main/res/layout/dialog_track_score.xml | 0 .../main/res/layout/dialog_track_search.xml | 0 .../main/res/layout/dialog_with_checkbox.xml | 0 .../layout/eh_activity_finish_migration.xml | 48 ++ .../main/res/layout/eh_activity_intercept.xml | 48 ++ app/src/main/res/layout/eh_activity_login.xml | 67 +++ .../main/res/layout/eh_fragment_batch_add.xml | 54 ++ app/src/main/res/layout/fragment_backup.xml | 0 .../main/res/layout/fragment_catalogue.xml | 0 .../res/layout/fragment_download_queue.xml | 0 app/src/main/res/layout/fragment_library.xml | 0 .../res/layout/fragment_library_category.xml | 0 .../res/layout/fragment_manga_chapters.xml | 0 .../main/res/layout/fragment_manga_info.xml | 4 +- .../res/layout/fragment_recent_chapters.xml | 0 .../res/layout/fragment_recently_read.xml | 0 app/src/main/res/layout/fragment_track.xml | 0 .../main/res/layout/item_catalogue_grid.xml | 0 .../main/res/layout/item_catalogue_list.xml | 0 app/src/main/res/layout/item_chapter.xml | 0 app/src/main/res/layout/item_download.xml | 0 .../main/res/layout/item_edit_categories.xml | 0 .../main/res/layout/item_library_category.xml | 0 app/src/main/res/layout/item_pager_reader.xml | 0 .../layout/item_recent_chapter_section.xml | 0 .../main/res/layout/item_recent_chapters.xml | 0 .../main/res/layout/item_recently_read.xml | 0 app/src/main/res/layout/item_track.xml | 0 app/src/main/res/layout/item_track_search.xml | 0 .../main/res/layout/item_webtoon_reader.xml | 0 app/src/main/res/layout/library_drawer.xml | 0 .../main/res/layout/library_grid_recycler.xml | 0 .../main/res/layout/library_list_recycler.xml | 0 app/src/main/res/layout/listitem_dir.xml | 0 app/src/main/res/layout/navigation_header.xml | 0 .../res/layout/navigation_view_checkbox.xml | 0 .../layout/navigation_view_checkedtext.xml | 0 .../main/res/layout/navigation_view_group.xml | 0 .../main/res/layout/navigation_view_radio.xml | 0 .../res/layout/navigation_view_spinner.xml | 0 .../main/res/layout/navigation_view_text.xml | 0 app/src/main/res/layout/page_decode_error.xml | 0 .../main/res/layout/pref_account_login.xml | 0 app/src/main/res/layout/pref_item_source.xml | 0 .../main/res/layout/pref_library_columns.xml | 0 .../layout/preference_widget_imageview.xml | 0 app/src/main/res/layout/progress_item.xml | 0 app/src/main/res/layout/recycler_autofit.xml | 0 app/src/main/res/layout/spinner_item.xml | 0 app/src/main/res/layout/toolbar.xml | 0 app/src/main/res/layout/view_empty.xml | 0 app/src/main/res/menu/catalogue_list.xml | 0 app/src/main/res/menu/category_selection.xml | 0 app/src/main/res/menu/chapter_recent.xml | 0 .../res/menu/chapter_recent_selection.xml | 0 app/src/main/res/menu/chapter_selection.xml | 0 app/src/main/res/menu/chapter_single.xml | 0 app/src/main/res/menu/chapters.xml | 0 app/src/main/res/menu/download_queue.xml | 0 app/src/main/res/menu/library.xml | 7 +- app/src/main/res/menu/library_selection.xml | 0 app/src/main/res/menu/manga_info.xml | 0 app/src/main/res/menu/menu_navigation.xml | 6 +- app/src/main/res/menu/reader.xml | 0 app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin app/src/main/res/raw/changelog_debug.xml | 3 +- app/src/main/res/raw/changelog_release.xml | 179 ++----- app/src/main/res/values-bg/strings.xml | 0 app/src/main/res/values-es/strings.xml | 0 app/src/main/res/values-fr/strings.xml | 0 app/src/main/res/values-it/strings.xml | 0 app/src/main/res/values-land/dimens.xml | 0 app/src/main/res/values-pt/strings.xml | 0 app/src/main/res/values-ru/strings.xml | 0 app/src/main/res/values-sw600dp/dimens.xml | 0 app/src/main/res/values-v21/dimens.xml | 0 app/src/main/res/values-v21/keys.xml | 0 app/src/main/res/values-v21/themes.xml | 0 app/src/main/res/values-vi/strings.xml | 0 app/src/main/res/values-w820dp/dimens.xml | 0 app/src/main/res/values/arrays.xml | 43 ++ app/src/main/res/values/attrs.xml | 0 app/src/main/res/values/colors.xml | 0 app/src/main/res/values/dimens.xml | 0 app/src/main/res/values/ids.xml | 0 app/src/main/res/values/keys.xml | 0 app/src/main/res/values/strings.xml | 5 +- app/src/main/res/values/styles.xml | 0 app/src/main/res/values/themes.xml | 0 app/src/main/res/xml/eh_pref_eh.xml | 77 +++ app/src/main/res/xml/pref_about.xml | 6 - app/src/main/res/xml/pref_advanced.xml | 0 app/src/main/res/xml/pref_downloads.xml | 0 app/src/main/res/xml/pref_general.xml | 5 + app/src/main/res/xml/pref_reader.xml | 0 app/src/main/res/xml/pref_sources.xml | 0 app/src/main/res/xml/pref_tracking.xml | 0 app/src/main/res/xml/provider_paths.xml | 0 .../CustomRobolectricGradleTestRunner.kt | 0 .../test/java/eu/kanade/tachiyomi/TestApp.kt | 0 .../tachiyomi/data/backup/BackupTest.kt | 0 .../tachiyomi/data/database/CategoryTest.kt | 0 .../data/database/ChapterRecognitionTest.kt | 0 .../data/library/LibraryUpdateServiceTest.kt | 0 branding/teh-banner.png | Bin 0 -> 274450 bytes build.gradle | 3 + gradle.properties | 5 +- gradle/wrapper/gradle-wrapper.jar | Bin gradle/wrapper/gradle-wrapper.properties | 0 gradlew.bat | 0 settings.gradle | 0 616 files changed, 4186 insertions(+), 230 deletions(-) mode change 100644 => 100755 .github/CONTRIBUTING.md mode change 100644 => 100755 .github/ISSUE_TEMPLATE.md mode change 100644 => 100755 .gitignore mode change 100644 => 100755 .travis.yml mode change 100644 => 100755 LICENSE mode change 100644 => 100755 README.md mode change 100644 => 100755 app/.gitignore mode change 100644 => 100755 app/build.gradle mode change 100644 => 100755 app/proguard-rules.pro mode change 100644 => 100755 app/src/main/AndroidManifest.xml mode change 100644 => 100755 app/src/main/assets/fonts/PTSans-Narrow.ttf mode change 100644 => 100755 app/src/main/assets/fonts/PTSans-NarrowBold.ttf mode change 100644 => 100755 app/src/main/ic_launcher-web.png mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/App.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/AppModule.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/Constants.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/DbExtensions.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenHelper.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/DbProvider.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/CategoryTypeMapping.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/ChapterTypeMapping.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/HistoryTypeMapping.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaCategoryTypeMapping.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/models/CategoryImpl.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/models/ChapterImpl.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/models/History.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaCategory.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaChapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaChapterHistory.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/models/Track.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/models/TrackImpl.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/queries/CategoryQueries.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaCategoryQueries.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/queries/TrackQueries.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterProgressPutResolver.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterSourceOrderPutResolver.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/HistoryLastReadPutResolver.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/LibraryMangaGetResolver.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaChapterGetResolver.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaChapterHistoryGetResolver.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaLastUpdatedPutResolver.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/tables/CategoryTable.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/tables/ChapterTable.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/tables/HistoryTable.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaCategoryTable.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaTable.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadService.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/download/model/Download.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/download/model/DownloadQueue.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/glide/AppGlideModule.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/glide/FileFetcher.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaFileFetcher.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaModelLoader.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaUrlFetcher.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationHandler.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/track/TrackManager.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistInterceptor.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/OAuth.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/OAuth.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyanimelistApi.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubRelease.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubService.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateChecker.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateResult.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateCheckerJob.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloaderReceiver.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloaderService.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/network/CloudflareInterceptor.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/network/PersistentCookieJar.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/network/PersistentCookieStore.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/network/ProgressListener.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/network/Requests.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/CatalogueSource.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/Source.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/model/Filter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/model/FilterList.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/model/MangasPage.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/model/Page.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/model/SChapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/model/SChapterImpl.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/model/SMangaImpl.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/LoginSource.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/ParsedHttpSource.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/YamlHttpSource.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/YamlHttpSourceMappings.kt create mode 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt create mode 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentaiMetadata.kt create mode 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt create mode 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/all/PervEden.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/english/Batoto.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangafox.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangahere.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangasee.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/english/Readmangatoday.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/german/WieManga.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Mangachan.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Mintmanga.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Readmanga.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/ActivityMixin.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/base/adapter/FlexibleViewHolder.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/base/adapter/SmartFragmentStatePagerAdapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/BaseFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/BaseRxFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/FragmentMixin.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueGridHolder.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueHolder.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueItem.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueListHolder.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueNavigationView.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePager.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/NoResultsException.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/Pager.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/ProgressItem.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/CheckboxItem.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/GroupItem.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/HeaderItem.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SectionItems.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SelectItem.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SeparatorItem.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortGroup.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortItem.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TextItem.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TriStateItem.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryActivity.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryHolder.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryItem.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadActivity.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadAdapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHolder.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadPresenter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/latest_updates/LatestUpdatesFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/latest_updates/LatestUpdatesPager.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/latest_updates/LatestUpdatesPresenter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryAdapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryMangaEvent.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryNavigationView.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySelectionEvent.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySort.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/main/ChangelogDialogFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaActivity.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaEvent.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersPresenter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/ChapterCountEvent.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaFavoriteEvent.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackAdapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackHolder.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackItem.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackPresenter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchAdapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/ChapterLoader.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderChapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderCustomFilterDialog.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderEvent.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsDialog.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/BaseReader.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/PageDecodeErrorLayout.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/OnChapterBoundariesOutListener.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PageView.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/Pager.java mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderAdapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalPager.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/LeftToRightReader.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/RightToLeftReader.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalPager.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalReader.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalViewPagerImpl.java mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonHolder.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/DateItem.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterHolder.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterItem.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersAdapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersPresenter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadAdapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadHolder.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadPresenter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/setting/AnilistLoginActivity.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsActivity.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadsFragment.kt create mode 100755 app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSourcesFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsTrackingFragment.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/AndroidComponentUtil.java mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/ChapterSourceSync.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/ContextExtensions.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/DiskUtil.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/DynamicConcurrentMergeOperator.java mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/FileExtensions.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/GLUtil.java mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/ImageViewExtensions.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/JsoupExtensions.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/LocaleHelper.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/OkioExtensions.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/RarContentProvider.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/RetryWithDelay.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/RxExtensions.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/SharedData.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/StringExtensions.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/ViewExtensions.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/ViewGroupExtensions.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/util/ZipContentProvider.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/DeletingChaptersDialog.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/DialogCheckboxView.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/ElevationAppBarLayout.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/EmptyView.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/ExtendedNavigationView.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/FABAnimationBase.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/FABAnimationUpDown.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/IgnoreFirstSpinnerListener.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/MinMaxNumberPicker.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/NegativeSeekBar.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/PTSansTextView.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/PreCachingLayoutManager.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/RecyclerViewPagerAdapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/RevealAnimationView.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/SimpleAnimationListener.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/SimpleNavigationView.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/SimpleSeekBarListener.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/SimpleTextWatcher.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/StateImageViewTarget.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/ViewPagerAdapter.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListPreference.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/preference/LibraryColumnsDialog.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginCheckBoxPreference.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginPreference.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/preference/SimpleDialogPreference.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/preference/SourceLoginDialog.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/preference/SwitchPreferenceCategory.kt mode change 100644 => 100755 app/src/main/java/eu/kanade/tachiyomi/widget/preference/TrackLoginDialog.kt create mode 100755 app/src/main/java/exh/EHSourceHelpers.kt create mode 100755 app/src/main/java/exh/FavoritesSyncHelper.kt create mode 100755 app/src/main/java/exh/FavoritesSyncManager.java create mode 100755 app/src/main/java/exh/GalleryAdder.kt create mode 100755 app/src/main/java/exh/StringBuilderExtensions.kt create mode 100755 app/src/main/java/exh/VerbelExpressionExtensions.kt create mode 100755 app/src/main/java/exh/metadata/MetadataHelper.kt create mode 100755 app/src/main/java/exh/metadata/MetadataUtil.kt create mode 100755 app/src/main/java/exh/metadata/MetdataCopier.kt create mode 100755 app/src/main/java/exh/metadata/models/ExGalleryMetadata.kt create mode 100755 app/src/main/java/exh/metadata/models/NHentaiMetadata.kt create mode 100755 app/src/main/java/exh/metadata/models/PervEdenGalleryMetadata.kt create mode 100755 app/src/main/java/exh/metadata/models/SearchableGalleryMetadata.kt create mode 100755 app/src/main/java/exh/metadata/models/Tag.kt create mode 100755 app/src/main/java/exh/search/MultiWildcard.kt create mode 100755 app/src/main/java/exh/search/Namespace.kt create mode 100755 app/src/main/java/exh/search/QueryComponent.kt create mode 100755 app/src/main/java/exh/search/SearchEngine.kt create mode 100755 app/src/main/java/exh/search/SingleWildcard.kt create mode 100755 app/src/main/java/exh/search/StringTextComponent.kt create mode 100755 app/src/main/java/exh/search/Text.kt create mode 100755 app/src/main/java/exh/search/TextComponent.kt create mode 100755 app/src/main/java/exh/ui/batchadd/BatchAddFragment.kt create mode 100755 app/src/main/java/exh/ui/intercept/InterceptActivity.kt create mode 100755 app/src/main/java/exh/ui/lock/LockActivity.kt create mode 100755 app/src/main/java/exh/ui/lock/LockPreference.kt create mode 100755 app/src/main/java/exh/ui/lock/LockUtils.kt create mode 100755 app/src/main/java/exh/ui/login/LoginActivity.kt create mode 100755 app/src/main/java/exh/ui/migration/MetadataFetchDialog.kt create mode 100755 app/src/main/java/exh/ui/migration/MigrationStatus.kt create mode 100755 app/src/main/java/exh/ui/migration/UrlMigrator.kt create mode 100755 app/src/main/java/exh/util/UriFilter.kt create mode 100755 app/src/main/java/exh/util/UriGroup.kt mode change 100644 => 100755 app/src/main/res/anim/enter_from_bottom.xml mode change 100644 => 100755 app/src/main/res/anim/enter_from_left.xml mode change 100644 => 100755 app/src/main/res/anim/enter_from_right.xml mode change 100644 => 100755 app/src/main/res/anim/enter_from_top.xml mode change 100644 => 100755 app/src/main/res/anim/exit_to_bottom.xml mode change 100644 => 100755 app/src/main/res/anim/exit_to_left.xml mode change 100644 => 100755 app/src/main/res/anim/exit_to_right.xml mode change 100644 => 100755 app/src/main/res/anim/exit_to_top.xml mode change 100644 => 100755 app/src/main/res/anim/fab_hide_to_bottom.xml mode change 100644 => 100755 app/src/main/res/anim/fab_show_from_bottom.xml mode change 100644 => 100755 app/src/main/res/anim/fade_in.xml mode change 100644 => 100755 app/src/main/res/anim/fade_in_long.xml mode change 100644 => 100755 app/src/main/res/color/abc_primary_text_material_dark.xml mode change 100644 => 100755 app/src/main/res/drawable-hdpi/ic_av_pause_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-hdpi/ic_av_play_arrow_grey_img.png mode change 100644 => 100755 app/src/main/res/drawable-hdpi/ic_clear_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-hdpi/ic_delete_grey_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-hdpi/ic_insert_photo_white_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-hdpi/ic_refresh_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-hdpi/ic_refresh_white_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-hdpi/ic_share_grey_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-hdpi/ic_system_update_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-mdpi/ic_av_pause_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-mdpi/ic_av_play_arrow_grey_img.png mode change 100644 => 100755 app/src/main/res/drawable-mdpi/ic_clear_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-mdpi/ic_delete_grey_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-mdpi/ic_insert_photo_white_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-mdpi/ic_refresh_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-mdpi/ic_refresh_white_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-mdpi/ic_share_grey_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-mdpi/ic_system_update_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-v21/library_item_selector_dark.xml mode change 100644 => 100755 app/src/main/res/drawable-v21/library_item_selector_light.xml mode change 100644 => 100755 app/src/main/res/drawable-v21/list_item_selector_dark.xml mode change 100644 => 100755 app/src/main/res/drawable-v21/list_item_selector_light.xml mode change 100644 => 100755 app/src/main/res/drawable-xhdpi/card_background.9.png mode change 100644 => 100755 app/src/main/res/drawable-xhdpi/ic_av_pause_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xhdpi/ic_av_play_arrow_grey_img.png mode change 100644 => 100755 app/src/main/res/drawable-xhdpi/ic_clear_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xhdpi/ic_delete_grey_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-xhdpi/ic_insert_photo_white_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-xhdpi/ic_refresh_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xhdpi/ic_refresh_white_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xhdpi/ic_share_grey_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-xhdpi/ic_system_update_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xxhdpi/ic_av_pause_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xxhdpi/ic_av_play_arrow_grey_img.png mode change 100644 => 100755 app/src/main/res/drawable-xxhdpi/ic_clear_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xxhdpi/ic_delete_grey_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-xxhdpi/ic_insert_photo_white_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-xxhdpi/ic_refresh_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xxhdpi/ic_share_grey_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-xxhdpi/ic_system_update_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xxxhdpi/al.png mode change 100644 => 100755 app/src/main/res/drawable-xxxhdpi/ic_av_pause_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xxxhdpi/ic_av_play_arrow_grey_img.png mode change 100644 => 100755 app/src/main/res/drawable-xxxhdpi/ic_clear_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xxxhdpi/ic_delete_grey_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-xxxhdpi/ic_insert_photo_white_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-xxxhdpi/ic_refresh_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xxxhdpi/ic_refresh_white_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xxxhdpi/ic_share_grey_24dp.png mode change 100644 => 100755 app/src/main/res/drawable-xxxhdpi/ic_system_update_grey_24dp_img.png mode change 100644 => 100755 app/src/main/res/drawable-xxxhdpi/kitsu.png mode change 100644 => 100755 app/src/main/res/drawable-xxxhdpi/mal.png mode change 100644 => 100755 app/src/main/res/drawable/branded_logo.xml create mode 100755 app/src/main/res/drawable/eh_ic_ehlogo_red_24dp.xml create mode 100755 app/src/main/res/drawable/eh_migration_backup.png create mode 100755 app/src/main/res/drawable/eh_migration_backup_button.png create mode 100755 app/src/main/res/drawable/eh_migration_hamburgers.png create mode 100755 app/src/main/res/drawable/eh_migration_share_icon.png mode change 100644 => 100755 app/src/main/res/drawable/empty_divider.xml mode change 100644 => 100755 app/src/main/res/drawable/empty_drawable_32dp.xml mode change 100644 => 100755 app/src/main/res/drawable/filter_mock.png mode change 100644 => 100755 app/src/main/res/drawable/gradient_shape.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_account_circle_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_add_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_backup_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_book_black_128dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_book_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_bookmark_border_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_bookmark_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_brightness_4_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_brightness_5_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_broken_image_grey_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_check_box_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_check_box_outline_blank_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_check_box_x_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_chevron_right_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_chrome_reader_mode_black_24dp.xml create mode 100755 app/src/main/res/drawable/ic_cloud_download_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_code_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_create_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_delete_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_done_all_grey_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_done_all_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_done_green_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_done_white_18dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_expand_more_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_explore_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_file_download_black_128dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_file_download_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_file_download_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_filter_list_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_glasses_black_128dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_glasses_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_help_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_insert_photo_white_24dp.png mode change 100644 => 100755 app/src/main/res/drawable/ic_keyboard_arrow_down_black_32dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_keyboard_arrow_up_black_32dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_label_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_language_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_menu_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_more_horiz_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_pause_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_play_arrow_white_24dp.xml create mode 100755 app/src/main/res/drawable/ic_playlist_add_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_refresh_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_reorder_grey_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_search_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_select_all_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_settings_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_settings_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_share_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_skip_next_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_skip_previous_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_sort_by_numeric_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_sort_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_sync_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_tune_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_update_black_128dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_update_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_view_list_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_view_module_white_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/ic_watch_later_black_24dp.xml mode change 100644 => 100755 app/src/main/res/drawable/library_item_selector_dark.xml mode change 100644 => 100755 app/src/main/res/drawable/library_item_selector_light.xml mode change 100644 => 100755 app/src/main/res/drawable/line_divider_dark.xml mode change 100644 => 100755 app/src/main/res/drawable/line_divider_light.xml mode change 100644 => 100755 app/src/main/res/drawable/list_item_selector_dark.xml mode change 100644 => 100755 app/src/main/res/drawable/list_item_selector_light.xml mode change 100644 => 100755 app/src/main/res/drawable/mask_star.png mode change 100644 => 100755 app/src/main/res/layout/activity_download_manager.xml mode change 100644 => 100755 app/src/main/res/layout/activity_edit_categories.xml create mode 100755 app/src/main/res/layout/activity_lock.xml mode change 100644 => 100755 app/src/main/res/layout/activity_main.xml mode change 100644 => 100755 app/src/main/res/layout/activity_manga.xml mode change 100644 => 100755 app/src/main/res/layout/activity_preferences.xml mode change 100644 => 100755 app/src/main/res/layout/activity_reader.xml mode change 100644 => 100755 app/src/main/res/layout/catalogue_drawer.xml mode change 100644 => 100755 app/src/main/res/layout/catalogue_drawer_content.xml mode change 100644 => 100755 app/src/main/res/layout/changelog_header_layout.xml mode change 100644 => 100755 app/src/main/res/layout/changelog_row_layout.xml mode change 100644 => 100755 app/src/main/res/layout/chapter_image.xml mode change 100644 => 100755 app/src/main/res/layout/dialog_reader_custom_filter.xml mode change 100644 => 100755 app/src/main/res/layout/dialog_reader_settings.xml mode change 100644 => 100755 app/src/main/res/layout/dialog_track_chapters.xml mode change 100644 => 100755 app/src/main/res/layout/dialog_track_score.xml mode change 100644 => 100755 app/src/main/res/layout/dialog_track_search.xml mode change 100644 => 100755 app/src/main/res/layout/dialog_with_checkbox.xml create mode 100755 app/src/main/res/layout/eh_activity_finish_migration.xml create mode 100755 app/src/main/res/layout/eh_activity_intercept.xml create mode 100755 app/src/main/res/layout/eh_activity_login.xml create mode 100755 app/src/main/res/layout/eh_fragment_batch_add.xml mode change 100644 => 100755 app/src/main/res/layout/fragment_backup.xml mode change 100644 => 100755 app/src/main/res/layout/fragment_catalogue.xml mode change 100644 => 100755 app/src/main/res/layout/fragment_download_queue.xml mode change 100644 => 100755 app/src/main/res/layout/fragment_library.xml mode change 100644 => 100755 app/src/main/res/layout/fragment_library_category.xml mode change 100644 => 100755 app/src/main/res/layout/fragment_manga_chapters.xml mode change 100644 => 100755 app/src/main/res/layout/fragment_manga_info.xml mode change 100644 => 100755 app/src/main/res/layout/fragment_recent_chapters.xml mode change 100644 => 100755 app/src/main/res/layout/fragment_recently_read.xml mode change 100644 => 100755 app/src/main/res/layout/fragment_track.xml mode change 100644 => 100755 app/src/main/res/layout/item_catalogue_grid.xml mode change 100644 => 100755 app/src/main/res/layout/item_catalogue_list.xml mode change 100644 => 100755 app/src/main/res/layout/item_chapter.xml mode change 100644 => 100755 app/src/main/res/layout/item_download.xml mode change 100644 => 100755 app/src/main/res/layout/item_edit_categories.xml mode change 100644 => 100755 app/src/main/res/layout/item_library_category.xml mode change 100644 => 100755 app/src/main/res/layout/item_pager_reader.xml mode change 100644 => 100755 app/src/main/res/layout/item_recent_chapter_section.xml mode change 100644 => 100755 app/src/main/res/layout/item_recent_chapters.xml mode change 100644 => 100755 app/src/main/res/layout/item_recently_read.xml mode change 100644 => 100755 app/src/main/res/layout/item_track.xml mode change 100644 => 100755 app/src/main/res/layout/item_track_search.xml mode change 100644 => 100755 app/src/main/res/layout/item_webtoon_reader.xml mode change 100644 => 100755 app/src/main/res/layout/library_drawer.xml mode change 100644 => 100755 app/src/main/res/layout/library_grid_recycler.xml mode change 100644 => 100755 app/src/main/res/layout/library_list_recycler.xml mode change 100644 => 100755 app/src/main/res/layout/listitem_dir.xml mode change 100644 => 100755 app/src/main/res/layout/navigation_header.xml mode change 100644 => 100755 app/src/main/res/layout/navigation_view_checkbox.xml mode change 100644 => 100755 app/src/main/res/layout/navigation_view_checkedtext.xml mode change 100644 => 100755 app/src/main/res/layout/navigation_view_group.xml mode change 100644 => 100755 app/src/main/res/layout/navigation_view_radio.xml mode change 100644 => 100755 app/src/main/res/layout/navigation_view_spinner.xml mode change 100644 => 100755 app/src/main/res/layout/navigation_view_text.xml mode change 100644 => 100755 app/src/main/res/layout/page_decode_error.xml mode change 100644 => 100755 app/src/main/res/layout/pref_account_login.xml mode change 100644 => 100755 app/src/main/res/layout/pref_item_source.xml mode change 100644 => 100755 app/src/main/res/layout/pref_library_columns.xml mode change 100644 => 100755 app/src/main/res/layout/preference_widget_imageview.xml mode change 100644 => 100755 app/src/main/res/layout/progress_item.xml mode change 100644 => 100755 app/src/main/res/layout/recycler_autofit.xml mode change 100644 => 100755 app/src/main/res/layout/spinner_item.xml mode change 100644 => 100755 app/src/main/res/layout/toolbar.xml mode change 100644 => 100755 app/src/main/res/layout/view_empty.xml mode change 100644 => 100755 app/src/main/res/menu/catalogue_list.xml mode change 100644 => 100755 app/src/main/res/menu/category_selection.xml mode change 100644 => 100755 app/src/main/res/menu/chapter_recent.xml mode change 100644 => 100755 app/src/main/res/menu/chapter_recent_selection.xml mode change 100644 => 100755 app/src/main/res/menu/chapter_selection.xml mode change 100644 => 100755 app/src/main/res/menu/chapter_single.xml mode change 100644 => 100755 app/src/main/res/menu/chapters.xml mode change 100644 => 100755 app/src/main/res/menu/download_queue.xml mode change 100644 => 100755 app/src/main/res/menu/library.xml mode change 100644 => 100755 app/src/main/res/menu/library_selection.xml mode change 100644 => 100755 app/src/main/res/menu/manga_info.xml mode change 100644 => 100755 app/src/main/res/menu/menu_navigation.xml mode change 100644 => 100755 app/src/main/res/menu/reader.xml mode change 100644 => 100755 app/src/main/res/mipmap-hdpi/ic_launcher.png mode change 100644 => 100755 app/src/main/res/mipmap-mdpi/ic_launcher.png mode change 100644 => 100755 app/src/main/res/mipmap-xhdpi/ic_launcher.png mode change 100644 => 100755 app/src/main/res/mipmap-xxhdpi/ic_launcher.png mode change 100644 => 100755 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png mode change 100644 => 100755 app/src/main/res/raw/changelog_debug.xml mode change 100644 => 100755 app/src/main/res/raw/changelog_release.xml mode change 100644 => 100755 app/src/main/res/values-bg/strings.xml mode change 100644 => 100755 app/src/main/res/values-es/strings.xml mode change 100644 => 100755 app/src/main/res/values-fr/strings.xml mode change 100644 => 100755 app/src/main/res/values-it/strings.xml mode change 100644 => 100755 app/src/main/res/values-land/dimens.xml mode change 100644 => 100755 app/src/main/res/values-pt/strings.xml mode change 100644 => 100755 app/src/main/res/values-ru/strings.xml mode change 100644 => 100755 app/src/main/res/values-sw600dp/dimens.xml mode change 100644 => 100755 app/src/main/res/values-v21/dimens.xml mode change 100644 => 100755 app/src/main/res/values-v21/keys.xml mode change 100644 => 100755 app/src/main/res/values-v21/themes.xml mode change 100644 => 100755 app/src/main/res/values-vi/strings.xml mode change 100644 => 100755 app/src/main/res/values-w820dp/dimens.xml mode change 100644 => 100755 app/src/main/res/values/arrays.xml mode change 100644 => 100755 app/src/main/res/values/attrs.xml mode change 100644 => 100755 app/src/main/res/values/colors.xml mode change 100644 => 100755 app/src/main/res/values/dimens.xml mode change 100644 => 100755 app/src/main/res/values/ids.xml mode change 100644 => 100755 app/src/main/res/values/keys.xml mode change 100644 => 100755 app/src/main/res/values/strings.xml mode change 100644 => 100755 app/src/main/res/values/styles.xml mode change 100644 => 100755 app/src/main/res/values/themes.xml create mode 100755 app/src/main/res/xml/eh_pref_eh.xml mode change 100644 => 100755 app/src/main/res/xml/pref_about.xml mode change 100644 => 100755 app/src/main/res/xml/pref_advanced.xml mode change 100644 => 100755 app/src/main/res/xml/pref_downloads.xml mode change 100644 => 100755 app/src/main/res/xml/pref_general.xml mode change 100644 => 100755 app/src/main/res/xml/pref_reader.xml mode change 100644 => 100755 app/src/main/res/xml/pref_sources.xml mode change 100644 => 100755 app/src/main/res/xml/pref_tracking.xml mode change 100644 => 100755 app/src/main/res/xml/provider_paths.xml mode change 100644 => 100755 app/src/test/java/eu/kanade/tachiyomi/CustomRobolectricGradleTestRunner.kt mode change 100644 => 100755 app/src/test/java/eu/kanade/tachiyomi/TestApp.kt mode change 100644 => 100755 app/src/test/java/eu/kanade/tachiyomi/data/backup/BackupTest.kt mode change 100644 => 100755 app/src/test/java/eu/kanade/tachiyomi/data/database/CategoryTest.kt mode change 100644 => 100755 app/src/test/java/eu/kanade/tachiyomi/data/database/ChapterRecognitionTest.kt mode change 100644 => 100755 app/src/test/java/eu/kanade/tachiyomi/data/library/LibraryUpdateServiceTest.kt create mode 100755 branding/teh-banner.png mode change 100644 => 100755 build.gradle mode change 100644 => 100755 gradle.properties mode change 100644 => 100755 gradle/wrapper/gradle-wrapper.jar mode change 100644 => 100755 gradle/wrapper/gradle-wrapper.properties mode change 100644 => 100755 gradlew.bat mode change 100644 => 100755 settings.gradle diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md old mode 100644 new mode 100755 diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index af291a578..2b4add534 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ .idea/ *iml *.iml -*/build \ No newline at end of file +*/build +/mainframer.sh +*.apk \ No newline at end of file diff --git a/.travis.yml b/.travis.yml old mode 100644 new mode 100755 diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 6c4ed5e34..9af91415f --- a/README.md +++ b/README.md @@ -1,24 +1,52 @@ -| Build | Download | F-Droid | -|-------|----------|-------------| -| [![TeamCity (simple build status)](https://img.shields.io/teamcity/https/teamcity.kanade.eu/s/tachiyomi_Build.svg)](https://teamcity.kanade.eu/project.html?projectId=tachiyomi) [![Travis](https://img.shields.io/travis/inorichi/tachiyomi.svg)](https://travis-ci.org/inorichi/tachiyomi) | [![stable release](https://img.shields.io/github/release/inorichi/tachiyomi.svg?maxAge=3600&label=stable)](https://github.com/inorichi/tachiyomi/releases) [![latest dev build](https://img.shields.io/badge/dev-latest%20build-blue.svg)](http://tachiyomi.kanade.eu/latest/app-debug.apk) | [![fdroid release](https://img.shields.io/badge/stable-f--droid.org-blue.svg)](https://f-droid.org/repository/browse/?fdid=eu.kanade.tachiyomi) [![fdroid dev](https://img.shields.io/badge/dev-wiki-blue.svg)](//github.com/inorichi/tachiyomi/wiki/FDroid-for-dev-versions) | +
+
-## [Report an issue](https://github.com/inorichi/tachiyomi/blob/master/.github/CONTRIBUTING.md) +TachiyomiEH is a free and open source E-Hentai, ExHentai and PervEden galleries reader for Android. -**Before reporting a new issue, take a look at the [FAQ](https://github.com/inorichi/tachiyomi/wiki/FAQ), the [changelog](https://github.com/inorichi/tachiyomi/releases) and the already opened issues.** +TachiyomiEH is a fork of the [original Tachiyomi app](https://github.com/inorichi/tachiyomi). +### E-Hentai Thread +[https://forums.e-hentai.org/index.php?showtopic=185421](https://forums.e-hentai.org/index.php?showtopic=185421) -Tachiyomi is a free and open source manga reader for Android. - -Keep in mind it's still a beta, so expect it to crash sometimes. +# Download +[![stable release](https://img.shields.io/github/release/NerdNumber9/TachiyomiEH.svg?maxAge=3600&label=stable)](https://github.com/NerdNumber9/TachiyomiEH/releases) # Features * Online and offline reading * Configurable reader with multiple viewers and settings * MyAnimeList support -* Resume from the next unread chapter +* Track your reading position * Chapter filtering * Schedule searching for updates * Categories to organize your library +* Log into ExHentai +* Read both NSFW and SFW manga/doujinshi +* Full offline tag/namespace searching support +* Batch import galleries +* Automatically open E-Hentai/ExHentai links +* Lock the app with a PIN code + +### Built-in manga sources +##### SFW +* Batoto +* Mangahere +* Mangafox +* Kissmanga +* Readmanga +* Mintmanga +* Mangachan +* Readmangatoday +* Mangasee +* Wiemanga + +##### NSFW +* E-Hentai +* ExHentai +* PervEden +* nhentai + +TachiyomiEH is fully compatible with Tachiyomi source extensions. +Backups from Tachiyomi are also compatible with TachiyomiEH (and vice versa). ## License diff --git a/app/.gitignore b/app/.gitignore old mode 100644 new mode 100755 index 90de2b9c8..012bccc6a --- a/app/.gitignore +++ b/app/.gitignore @@ -1,4 +1,5 @@ /build *iml *.iml -custom.gradle \ No newline at end of file +custom.gradle +google-services.json \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle old mode 100644 new mode 100755 index f8db49c32..4368b0753 --- a/app/build.gradle +++ b/app/build.gradle @@ -33,18 +33,22 @@ android { buildToolsVersion "25.0.2" publishNonDefault true + dexOptions { + javaMaxHeapSize "4g" + } + defaultConfig { - applicationId "eu.kanade.tachiyomi" + applicationId "eu.kanade.tachiyomi.eh2" minSdkVersion 16 targetSdkVersion 25 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - versionCode 22 - versionName "0.5.2" + versionCode 5003 + versionName "v5.0.3-EH" buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\"" buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\"" buildConfigField "String", "BUILD_TIME", "\"${getBuildTime()}\"" - buildConfigField "boolean", "INCLUDE_UPDATER", "false" + buildConfigField "boolean", "INCLUDE_UPDATER", "true" vectorDrawables.useSupportLibrary = true @@ -198,15 +202,31 @@ dependencies { compile 'me.zhanghai.android.systemuihelper:library:1.0.0' compile 'de.hdodenhof:circleimageview:2.1.0' + //Firebase (EH) + final firebase_version = '10.0.1' + releaseCompile "com.google.firebase:firebase-core:$firebase_version" + releaseCompile "com.google.firebase:firebase-messaging:$firebase_version" + releaseCompile "com.google.firebase:firebase-crash:$firebase_version" + + //SnappyDB (EH) + compile 'io.paperdb:paperdb:2.0' + + //JVE (Regex) (EH) + compile 'ru.lanwen.verbalregex:java-verbal-expressions:1.4' + + //Pin lock view + compile 'com.andrognito.pinlockview:pinlockview:1.0.1' + // Tests - testCompile 'junit:junit:4.12' + //Paper DB screws up tests + /*testCompile 'junit:junit:4.12' testCompile 'org.assertj:assertj-core:1.7.1' testCompile 'org.mockito:mockito-core:1.10.19' final robolectric_version = '3.1.4' testCompile "org.robolectric:robolectric:$robolectric_version" testCompile "org.robolectric:shadows-multidex:$robolectric_version" - testCompile "org.robolectric:shadows-play-services:$robolectric_version" + testCompile "org.robolectric:shadows-play-services:$robolectric_version"*/ compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" } @@ -270,4 +290,6 @@ afterEvaluate { } } } -} \ No newline at end of file +} +//Firebase (EH) +apply plugin: 'com.google.gms.google-services' diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro old mode 100644 new mode 100755 index f07a94d09..ffe90a1ee --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -96,4 +96,11 @@ -dontwarn org.yaml.snakeyaml.** # Duktape --keep class com.squareup.duktape.** { *; } \ No newline at end of file +-keep class com.squareup.duktape.** { *; } + +# [EH] +-keep class exh.** { *; } + +# Keep google stuff +-dontwarn com.google.android.gms.** +-dontwarn com.google.firebase.** \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml old mode 100644 new mode 100755 index 21627600d..fef49b7ab --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,6 +13,9 @@ android:name="android.permission.READ_PHONE_STATE" tools:node="remove" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/assets/fonts/PTSans-Narrow.ttf b/app/src/main/assets/fonts/PTSans-Narrow.ttf old mode 100644 new mode 100755 diff --git a/app/src/main/assets/fonts/PTSans-NarrowBold.ttf b/app/src/main/assets/fonts/PTSans-NarrowBold.ttf old mode 100644 new mode 100755 diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt old mode 100644 new mode 100755 index 9fd73b878..af89227b6 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -9,20 +9,12 @@ import eu.kanade.tachiyomi.data.backup.BackupCreatorJob import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.data.updater.UpdateCheckerJob import eu.kanade.tachiyomi.util.LocaleHelper -import org.acra.ACRA -import org.acra.annotation.ReportsCrashes +import io.paperdb.Paper import timber.log.Timber import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.InjektScope import uy.kohesive.injekt.registry.default.DefaultRegistrar -@ReportsCrashes( - formUri = "http://tachiyomi.kanade.eu/crash_report", - reportType = org.acra.sender.HttpSender.Type.JSON, - httpMethod = org.acra.sender.HttpSender.Method.PUT, - buildConfigClass = BuildConfig::class, - excludeMatchingSharedPreferencesKeys = arrayOf(".*username.*", ".*password.*", ".*token.*") -) open class App : Application() { override fun onCreate() { @@ -32,8 +24,8 @@ open class App : Application() { if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree()) - setupAcra() setupJobManager() + Paper.init(this) //Setup metadata DB (EH) LocaleHelper.updateConfiguration(this, resources.configuration) } @@ -50,10 +42,6 @@ open class App : Application() { LocaleHelper.updateConfiguration(this, newConfig, true) } - protected open fun setupAcra() { - ACRA.init(this) - } - protected open fun setupJobManager() { JobManager.create(this).addJobCreator { tag -> when (tag) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt b/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/Constants.kt b/app/src/main/java/eu/kanade/tachiyomi/Constants.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbExtensions.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenHelper.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbProvider.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbProvider.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/CategoryTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/CategoryTypeMapping.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/ChapterTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/ChapterTypeMapping.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/HistoryTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/HistoryTypeMapping.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaCategoryTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaCategoryTypeMapping.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/CategoryImpl.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/CategoryImpl.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/ChapterImpl.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/ChapterImpl.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/History.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/History.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaCategory.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaCategory.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaChapter.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaChapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaChapterHistory.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaChapterHistory.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Track.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Track.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/TrackImpl.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/TrackImpl.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/CategoryQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/CategoryQueries.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaCategoryQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaCategoryQueries.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/TrackQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/TrackQueries.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterProgressPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterProgressPutResolver.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterSourceOrderPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterSourceOrderPutResolver.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/HistoryLastReadPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/HistoryLastReadPutResolver.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/LibraryMangaGetResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/LibraryMangaGetResolver.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaChapterGetResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaChapterGetResolver.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaChapterHistoryGetResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaChapterHistoryGetResolver.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaLastUpdatedPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaLastUpdatedPutResolver.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/CategoryTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/CategoryTable.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/ChapterTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/ChapterTable.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/HistoryTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/HistoryTable.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaCategoryTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaCategoryTable.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaTable.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadService.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/model/Download.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/model/Download.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/model/DownloadQueue.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/model/DownloadQueue.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/glide/AppGlideModule.kt b/app/src/main/java/eu/kanade/tachiyomi/data/glide/AppGlideModule.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/glide/FileFetcher.kt b/app/src/main/java/eu/kanade/tachiyomi/data/glide/FileFetcher.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaFileFetcher.kt b/app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaFileFetcher.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaModelLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaModelLoader.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaUrlFetcher.kt b/app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaUrlFetcher.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationHandler.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationHandler.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt old mode 100644 new mode 100755 index de56700f4..0d6568058 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -9,6 +9,7 @@ import com.f2prateek.rx.preferences.RxSharedPreferences import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.source.Source +import exh.ui.migration.MigrationStatus import java.io.File fun Preference.getOrDefault(): T = get() ?: defaultValue()!! @@ -88,7 +89,7 @@ class PreferencesHelper(val context: Context) { fun catalogueAsList() = rxPrefs.getBoolean(keys.catalogueAsList, false) - fun enabledLanguages() = rxPrefs.getStringSet(keys.enabledLanguages, setOf("en")) + fun enabledLanguages() = rxPrefs.getStringSet(keys.enabledLanguages, setOf("all")) fun sourceUsername(source: Source) = prefs.getString(keys.sourceUsername(source.id), "") @@ -160,4 +161,38 @@ class PreferencesHelper(val context: Context) { fun defaultCategory() = prefs.getInt(keys.defaultCategory, -1) + //EH + fun enableExhentai() = rxPrefs.getBoolean("enable_exhentai", false) + + fun secureEXH() = rxPrefs.getBoolean("secure_exh", true) + + fun imageQuality() = rxPrefs.getString("ehentai_quality", "auto") + + fun useHentaiAtHome() = rxPrefs.getBoolean("enable_hah", true) + + fun useJapaneseTitle() = rxPrefs.getBoolean("use_jp_title", false) + + fun ehSearchSize() = rxPrefs.getString("ex_search_size", "rc_0") + + fun thumbnailRows() = rxPrefs.getString("ex_thumb_rows", "tr_2") + + fun migrateLibraryAsked() = rxPrefs.getBoolean("ex_migrate_library", false) + + fun migrationStatus() = rxPrefs.getInteger("migration_status", MigrationStatus.NOT_INITIALIZED) + + fun hasPerformedURLMigration() = rxPrefs.getBoolean("performed_url_migration", false) + + fun hasPerformedSourceMigration() = rxPrefs.getBoolean("performed_source_migration", false) + + //EH Cookies + fun memberIdVal() = rxPrefs.getString("eh_ipb_member_id", null) + fun passHashVal() = rxPrefs.getString("eh_ipb_pass_hash", null) + fun igneousVal() = rxPrefs.getString("eh_igneous", null) + + //Lock + fun lockHash() = rxPrefs.getString("lock_hash", null) + + fun lockSalt() = rxPrefs.getString("lock_salt", null) + + fun lockLength() = rxPrefs.getInteger("lock_length", -1) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackManager.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistInterceptor.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/OAuth.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/OAuth.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/OAuth.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/OAuth.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyanimelistApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyanimelistApi.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubRelease.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubRelease.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubService.kt old mode 100644 new mode 100755 index 42ff97324..5e0aa932e --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubService.kt @@ -23,7 +23,7 @@ interface GithubService { } } - @GET("/repos/inorichi/tachiyomi/releases/latest") + @GET("/repos/NerdNumber9/tachiyomi/releases/latest") fun getLatestVersion(): Observable } \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateChecker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateChecker.kt old mode 100644 new mode 100755 index 8d6210845..c8a029acc --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateChecker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateChecker.kt @@ -12,7 +12,7 @@ class GithubUpdateChecker() { */ fun checkForUpdate(): Observable { return service.getLatestVersion().map { release -> - val newVersion = release.version.replace("[^\\d.]".toRegex(), "") + val newVersion = release.version // Check if latest version is different from current version if (newVersion != BuildConfig.VERSION_NAME) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateResult.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateResult.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateCheckerJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateCheckerJob.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloaderReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloaderReceiver.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloaderService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloaderService.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/CloudflareInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/network/CloudflareInterceptor.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/PersistentCookieJar.kt b/app/src/main/java/eu/kanade/tachiyomi/network/PersistentCookieJar.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/PersistentCookieStore.kt b/app/src/main/java/eu/kanade/tachiyomi/network/PersistentCookieStore.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/ProgressListener.kt b/app/src/main/java/eu/kanade/tachiyomi/network/ProgressListener.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt b/app/src/main/java/eu/kanade/tachiyomi/network/ProgressResponseBody.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/Requests.kt b/app/src/main/java/eu/kanade/tachiyomi/network/Requests.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/CatalogueSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/CatalogueSource.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/Source.kt b/app/src/main/java/eu/kanade/tachiyomi/source/Source.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt b/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt old mode 100644 new mode 100755 index 0b31a27a3..497d43b8f --- a/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt @@ -7,24 +7,48 @@ import android.content.pm.PackageManager import android.os.Environment import dalvik.system.PathClassLoader import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.source.online.all.EHentai +import eu.kanade.tachiyomi.source.online.all.EHentaiMetadata import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.YamlHttpSource +import eu.kanade.tachiyomi.source.online.all.NHentai +import eu.kanade.tachiyomi.source.online.all.PervEden import eu.kanade.tachiyomi.source.online.english.* import eu.kanade.tachiyomi.source.online.german.WieManga import eu.kanade.tachiyomi.source.online.russian.Mangachan import eu.kanade.tachiyomi.source.online.russian.Mintmanga import eu.kanade.tachiyomi.source.online.russian.Readmanga import eu.kanade.tachiyomi.util.hasPermission +import exh.* import org.yaml.snakeyaml.Yaml +import rx.Observable import timber.log.Timber +import uy.kohesive.injekt.injectLazy import java.io.File open class SourceManager(private val context: Context) { + private val prefs: PreferencesHelper by injectLazy() + private val sourcesMap = mutableMapOf() init { - createSources() + //Recreate sources when they change + val prefEntries = arrayOf( + prefs.enableExhentai(), + prefs.imageQuality(), + prefs.useHentaiAtHome(), + prefs.useJapaneseTitle(), + prefs.ehSearchSize(), + prefs.thumbnailRows() + ).map { it.asObservable() } + + Observable.merge(prefEntries).skip(prefEntries.size - 1).subscribe { + sourcesMap.clear() + createSources() + } } open fun get(sourceKey: Long): Source? { @@ -39,6 +63,8 @@ open class SourceManager(private val context: Context) { createExtensionSources().forEach { registerSource(it) } createYamlSources().forEach { registerSource(it) } createInternalSources().forEach { registerSource(it) } + //EH + createEHSources().forEach { registerSource(it) } } private fun registerSource(source: Source, overwrite: Boolean = false) { @@ -61,6 +87,21 @@ open class SourceManager(private val context: Context) { WieManga() ) + private fun createEHSources(): List { + val exSrcs = mutableListOf( + EHentai(EH_SOURCE_ID, false, context), + EHentaiMetadata(EH_METADATA_SOURCE_ID, false, context) + ) + if(prefs.enableExhentai().getOrDefault()) { + exSrcs += EHentai(EXH_SOURCE_ID, true, context) + exSrcs += EHentaiMetadata(EXH_METADATA_SOURCE_ID, true, context) + } + exSrcs += PervEden(PERV_EDEN_EN_SOURCE_ID, "en") + exSrcs += PervEden(PERV_EDEN_IT_SOURCE_ID, "it") + exSrcs += NHentai(context) + return exSrcs + } + private fun createYamlSources(): List { val sources = mutableListOf() diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/Filter.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/Filter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/FilterList.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/FilterList.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/MangasPage.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/MangasPage.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/Page.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/Page.kt old mode 100644 new mode 100755 index 16a76b96b..618684d11 --- a/app/src/main/java/eu/kanade/tachiyomi/source/model/Page.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/model/Page.kt @@ -1,47 +1,47 @@ -package eu.kanade.tachiyomi.source.model - -import android.net.Uri -import eu.kanade.tachiyomi.network.ProgressListener -import eu.kanade.tachiyomi.ui.reader.ReaderChapter -import rx.subjects.Subject - -class Page( - val index: Int, - val url: String = "", - var imageUrl: String? = null, - @Transient var uri: Uri? = null -) : ProgressListener { - - val number: Int - get() = index + 1 - - @Transient lateinit var chapter: ReaderChapter - - @Transient @Volatile var status: Int = 0 - set(value) { - field = value - statusSubject?.onNext(value) - } - - @Transient @Volatile var progress: Int = 0 - - @Transient private var statusSubject: Subject? = null - - override fun update(bytesRead: Long, contentLength: Long, done: Boolean) { - progress = (100 * bytesRead / contentLength).toInt() - } - - fun setStatusSubject(subject: Subject?) { - this.statusSubject = subject - } - - companion object { - - const val QUEUE = 0 - const val LOAD_PAGE = 1 - const val DOWNLOAD_IMAGE = 2 - const val READY = 3 - const val ERROR = 4 - } - -} +package eu.kanade.tachiyomi.source.model + +import android.net.Uri +import eu.kanade.tachiyomi.network.ProgressListener +import eu.kanade.tachiyomi.ui.reader.ReaderChapter +import rx.subjects.Subject + +class Page( + val index: Int, + var url: String = "", + var imageUrl: String? = null, + @Transient var uri: Uri? = null +) : ProgressListener { + + val number: Int + get() = index + 1 + + @Transient lateinit var chapter: ReaderChapter + + @Transient @Volatile var status: Int = 0 + set(value) { + field = value + statusSubject?.onNext(value) + } + + @Transient @Volatile var progress: Int = 0 + + @Transient private var statusSubject: Subject? = null + + override fun update(bytesRead: Long, contentLength: Long, done: Boolean) { + progress = (100 * bytesRead / contentLength).toInt() + } + + fun setStatusSubject(subject: Subject?) { + this.statusSubject = subject + } + + companion object { + + const val QUEUE = 0 + const val LOAD_PAGE = 1 + const val DOWNLOAD_IMAGE = 2 + const val READY = 3 + const val ERROR = 4 + } + +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/SChapter.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/SChapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/SChapterImpl.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/SChapterImpl.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/SMangaImpl.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/SMangaImpl.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/LoginSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/LoginSource.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/ParsedHttpSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/ParsedHttpSource.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/YamlHttpSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/YamlHttpSource.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/YamlHttpSourceMappings.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/YamlHttpSourceMappings.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt new file mode 100755 index 000000000..3c7080380 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt @@ -0,0 +1,476 @@ +package eu.kanade.tachiyomi.source.online.all + +import android.content.Context +import android.net.Uri +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.source.model.* +import eu.kanade.tachiyomi.source.online.HttpSource +import eu.kanade.tachiyomi.util.asJsoup +import exh.metadata.* +import exh.metadata.models.ExGalleryMetadata +import exh.metadata.models.Tag +import okhttp3.Response +import org.jsoup.nodes.Element +import rx.Observable +import uy.kohesive.injekt.injectLazy +import java.net.URLEncoder +import java.util.* +import exh.ui.login.LoginActivity +import exh.util.UriFilter +import exh.util.UriGroup +import okhttp3.CacheControl +import okhttp3.Headers +import okhttp3.Request +import org.jsoup.nodes.Document + +class EHentai(override val id: Long, + val exh: Boolean, + val context: Context) : HttpSource() { + + val schema: String + get() = if(prefs.secureEXH().getOrDefault()) + "https" + else + "http" + + override val baseUrl: String + get() = if(exh) + "$schema://exhentai.org" + else + "$schema://e-hentai.org" + + override val lang = "all" + override val supportsLatest = true + + val prefs: PreferencesHelper by injectLazy() + + val metadataHelper = MetadataHelper() + + /** + * Gallery list entry + */ + data class ParsedManga(val fav: String?, val manga: Manga) + + fun extendedGenericMangaParse(doc: Document) + = with(doc) { + //Parse mangas + val parsedMangas = select(".gtr0,.gtr1").map { + ParsedManga( + fav = it.select(".itd .it3 > .i[id]").first()?.attr("title"), + manga = Manga.create(id).apply { + //Get title + it.select(".itd .it5 a").first()?.apply { + title = text() + setUrlWithoutDomain(addParam(attr("href"), "nw", "always")) + } + //Get image + it.select(".itd .it2").first()?.apply { + children().first()?.let { + thumbnail_url = it.attr("src") + } ?: let { + text().split("~").apply { + thumbnail_url = "http://${this[1]}/${this[2]}" + } + } + } + }) + + } + //Add to page if required + val hasNextPage = select("a[onclick=return false]").last()?.let { + it.text() == ">" + } ?: false + Pair(parsedMangas, hasNextPage) + } + + /** + * Parse a list of galleries + */ + fun genericMangaParse(response: Response) + = extendedGenericMangaParse(response.asJsoup()).let { + MangasPage(it.first.map { it.manga }, it.second) + } + + override fun fetchChapterList(manga: SManga): Observable> + = Observable.just(listOf(SChapter.create().apply { + url = manga.url + name = "Chapter" + chapter_number = 1f + })) + + override fun fetchPageList(chapter: SChapter) + = fetchChapterPage(chapter, "$baseUrl/${chapter.url}").map { + it.mapIndexed { i, s -> + Page(i, s) + } + }!! + + private fun fetchChapterPage(chapter: SChapter, np: String, + pastUrls: List = emptyList()): Observable> { + val urls = ArrayList(pastUrls) + return chapterPageCall(np).flatMap { + val jsoup = it.asJsoup() + urls += parseChapterPage(jsoup) + val nextUrl = nextPageUrl(jsoup) + if(nextUrl != null) { + fetchChapterPage(chapter, nextUrl, urls) + } else { + Observable.just(urls) + } + } + } + private fun parseChapterPage(response: Element) + = with(response) { + select(".gdtm a").map { + Pair(it.child(0).attr("alt").toInt(), it.attr("href")) + }.sortedBy(Pair::first).map { it.second } + } + private fun chapterPageCall(np: String) = client.newCall(chapterPageRequest(np)).asObservableSuccess() + private fun chapterPageRequest(np: String) = exGet(np, null, headers) + + private fun nextPageUrl(element: Element): String? + = element.select("a[onclick=return false]").last()?.let { + return if (it.text() == ">") it.attr("href") else null + } + + override fun popularMangaRequest(page: Int) = if(exh) + latestUpdatesRequest(page) + else + exGet("$baseUrl/toplist.php?tl=15", page) + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val uri = Uri.parse("$baseUrl$QUERY_PREFIX").buildUpon() + uri.appendQueryParameter("f_search", query) + filters.forEach { + if(it is UriFilter) it.addToUri(uri) + } + return exGet(uri.toString(), page) + } + + override fun latestUpdatesRequest(page: Int) = exGet(baseUrl, page) + + override fun popularMangaParse(response: Response) = genericMangaParse(response) + override fun searchMangaParse(response: Response) = genericMangaParse(response) + override fun latestUpdatesParse(response: Response) = genericMangaParse(response) + + fun exGet(url: String, page: Int? = null, additionalHeaders: Headers? = null, cache: Boolean = true) + = GET(page?.let { + addParam(url, "page", Integer.toString(page - 1)) + } ?: url, additionalHeaders?.let { + val headers = headers.newBuilder() + it.toMultimap().forEach { t, u -> + u.forEach { + headers.add(t, it) + } + } + headers.build() + } ?: headers).let { + if(!cache) + it.newBuilder().cacheControl(CacheControl.FORCE_NETWORK).build() + else + it + }!! + + /** + * Parse gallery page to metadata model + */ + override fun mangaDetailsParse(response: Response) = with(response.asJsoup()) { + val metdata = ExGalleryMetadata() + with(metdata) { + url = response.request().url().encodedPath() + exh = this@EHentai.exh + title = select("#gn").text().nullIfBlank()?.trim() + + altTitle = select("#gj").text().nullIfBlank()?.trim() + + thumbnailUrl = select("#gd1 div").attr("style").nullIfBlank()?.let { + it.substring(it.indexOf('(') + 1 until it.lastIndexOf(')')) + } + + genre = select(".ic").parents().attr("href").nullIfBlank()?.trim()?.substringAfterLast('/') + + uploader = select("#gdn").text().nullIfBlank()?.trim() + + //Parse the table + select("#gdd tr").forEach { + it.select(".gdt1") + .text() + .nullIfBlank() + ?.trim() + ?.let { left -> + it.select(".gdt2") + .text() + .nullIfBlank() + ?.trim() + ?.let { right -> + ignore { + when (left.removeSuffix(":") + .toLowerCase()) { + "posted" -> datePosted = EX_DATE_FORMAT.parse(right).time + "visible" -> visible = right.nullIfBlank() + "language" -> { + language = right.removeSuffix(TR_SUFFIX).trim().nullIfBlank() + translated = right.endsWith(TR_SUFFIX, true) + } + "file size" -> size = parseHumanReadableByteCount(right)?.toLong() + "length" -> length = right.removeSuffix("pages").trim().nullIfBlank()?.toInt() + "favorited" -> favorites = right.removeSuffix("times").trim().nullIfBlank()?.toInt() + } + } + } + } + } + + //Parse ratings + ignore { + averageRating = select("#rating_label") + .text() + .removePrefix("Average:") + .trim() + .nullIfBlank() + ?.toDouble() + ratingCount = select("#rating_count") + .text() + .trim() + .nullIfBlank() + ?.toInt() + } + + //Parse tags + tags.clear() + select("#taglist tr").forEach { + val namespace = it.select(".tc").text().removeSuffix(":") + val currentTags = it.select("div").map { + Tag(it.text().trim(), + it.hasClass("gtl")) + } + tags.put(namespace, ArrayList(currentTags)) + } + + //Save metadata + metadataHelper.writeGallery(this, id) + + //Copy metadata to manga + SManga.create().let { + copyTo(it) + it + } + } + } + + override fun chapterListParse(response: Response) + = throw UnsupportedOperationException("Unused method was called somehow!") + + override fun pageListParse(response: Response) + = throw UnsupportedOperationException("Unused method was called somehow!") + + override fun fetchImageUrl(page: Page): Observable { + return client.newCall(imageUrlRequest(page)) + .asObservableSuccess() + .map { realImageUrlParse(it, page) } + } + + fun realImageUrlParse(response: Response, page: Page): String { + with(response.asJsoup()) { + val currentImage = getElementById("img").attr("src") + //Each press of the retry button will choose another server + select("#loadfail").attr("onclick").nullIfBlank()?.let { + page.url = addParam(page.url, "nl", it.substring(it.indexOf('\'') + 1 .. it.lastIndexOf('\'') - 1)) + } + return currentImage + } + } + + override fun imageUrlParse(response: Response): String { + throw UnsupportedOperationException("Unused method was called somehow!") + } + + //Too lazy to write return type + fun fetchFavorites() = { + //Used to get "s" cookie + val favoriteUrl = "$baseUrl/favorites.php" + val result = mutableListOf() + var page = 1 + + var favNames: List? = null + + do { + val response2 = client.newCall(exGet(favoriteUrl, + page = page, + cache = false)).execute() + val doc = response2.asJsoup() + + //Parse favorites + val parsed = extendedGenericMangaParse(doc) + result += parsed.first + + //Parse fav names + if (favNames == null) + favNames = doc.getElementsByClass("nosel").first().children().filter { + it.children().size >= 3 + }.map { it.child(2).text() }.filterNotNull() + + //Next page + page++ + } while (parsed.second) + Pair(result as List, favNames!!) + }() + + val cookiesHeader by lazy { + val cookies: MutableMap = mutableMapOf() + if(prefs.enableExhentai().getOrDefault()) { + cookies.put(LoginActivity.MEMBER_ID_COOKIE, prefs.memberIdVal().get()!!) + cookies.put(LoginActivity.PASS_HASH_COOKIE, prefs.passHashVal().get()!!) + cookies.put(LoginActivity.IGNEOUS_COOKIE, prefs.igneousVal().get()!!) + } + + //Setup settings + val settings = mutableListOf() + //Image quality + settings.add(when(prefs.imageQuality() + .getOrDefault() + .toLowerCase()) { + "ovrs_2400" -> "xr_2400" + "ovrs_1600" -> "xr_1600" + "high" -> "xr_1280" + "med" -> "xr_980" + "low" -> "xr_780" + "auto" -> null + else -> null + }) + //Use Hentai@Home + settings.add(if(prefs.useHentaiAtHome().getOrDefault()) + null + else + "uh_n") + //Japanese titles + settings.add(if(prefs.useJapaneseTitle().getOrDefault()) + "tl_j" + else + null) + //Do not show popular right now pane as we can't parse it + settings.add("prn_n") + //Paging size + settings.add(prefs.ehSearchSize().getOrDefault()) + //Thumbnail rows + settings.add(prefs.thumbnailRows().getOrDefault()) + + cookies.put("uconfig", buildSettings(settings)) + + buildCookies(cookies) + } + + //Headers + override fun headersBuilder() + = super.headersBuilder().add("Cookie", cookiesHeader)!! + + fun buildSettings(settings: List): String { + return settings.filterNotNull().joinToString(separator = "-") + } + + fun buildCookies(cookies: Map) + = cookies.entries.map { + "${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}" + }.joinToString(separator = "; ", postfix = ";") + + fun addParam(url: String, param: String, value: String) + = Uri.parse(url) + .buildUpon() + .appendQueryParameter(param, value) + .toString() + + override val client = network.client.newBuilder() + .addInterceptor { chain -> + val newReq = chain + .request() + .newBuilder() + .addHeader("Cookie", cookiesHeader) + .build() + + chain.proceed(newReq) + }.build()!! + + //Filters + override fun getFilterList() = FilterList( + GenreGroup(), + AdvancedGroup() + ) + + class GenreOption(name: String, val genreId: String): Filter.CheckBox(name, false), UriFilter { + override fun addToUri(builder: Uri.Builder) { + builder.appendQueryParameter("f_" + genreId, if(state) "1" else "0") + } + } + class GenreGroup : UriGroup("Genres", listOf( + GenreOption("Dōjinshi", "doujinshi"), + GenreOption("Manga", "manga"), + GenreOption("Artist CG", "artistcg"), + GenreOption("Game CG", "gamecg"), + GenreOption("Western", "western"), + GenreOption("Non-H", "non-h"), + GenreOption("Image Set", "imageset"), + GenreOption("Cosplay", "cosplay"), + GenreOption("Asian Porn", "asianporn"), + GenreOption("Misc", "misc") + )) + + class AdvancedOption(name: String, val param: String, defValue: Boolean = false): Filter.CheckBox(name, defValue), UriFilter { + override fun addToUri(builder: Uri.Builder) { + if(state) + builder.appendQueryParameter(param, "on") + } + } + class RatingOption : Filter.Select("Minimum Rating", arrayOf( + "Any", + "2 stars", + "3 stars", + "4 stars", + "5 stars" + )), UriFilter { + override fun addToUri(builder: Uri.Builder) { + if(state > 0) builder.appendQueryParameter("f_srdd", Integer.toString(state + 1)) + } + } + + //Explicit type arg for listOf() to workaround this: KT-16570 + class AdvancedGroup : UriGroup>("Advanced Options", listOf>( + AdvancedOption("Search Gallery Name", "f_sname", true), + AdvancedOption("Search Gallery Tags", "f_stags", true), + AdvancedOption("Search Gallery Description", "f_sdesc"), + AdvancedOption("Search Torrent Filenames", "f_storr"), + AdvancedOption("Only Show Galleries With Torrents", "f_sto"), + AdvancedOption("Search Low-Power Tags", "f_sdt1"), + AdvancedOption("Search Downvoted Tags", "f_sdt2"), + AdvancedOption("Show Expunged Galleries", "f_sh"), + RatingOption() + )) + + override val name = if(exh) + "ExHentai" + else + "E-Hentai" + + companion object { + val QUERY_PREFIX = "?f_apply=Apply+Filter" + val TR_SUFFIX = "TR" + + fun getCookies(cookies: String): Map? { + val foundCookies = HashMap() + for (cookie in cookies.split(";".toRegex()).dropLastWhile(String::isEmpty).toTypedArray()) { + val splitCookie = cookie.split("=".toRegex()).dropLastWhile(String::isEmpty).toTypedArray() + if (splitCookie.size < 2) { + return null + } + val trimmedKey = splitCookie[0].trim { it <= ' ' } + if (!foundCookies.containsKey(trimmedKey)) { + foundCookies.put(trimmedKey, splitCookie[1].trim { it <= ' ' }) + } + } + return foundCookies + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentaiMetadata.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentaiMetadata.kt new file mode 100755 index 000000000..d053dc9d4 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentaiMetadata.kt @@ -0,0 +1,127 @@ +package eu.kanade.tachiyomi.source.online.all + +import android.content.Context +import eu.kanade.tachiyomi.data.database.models.Chapter +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.source.model.* +import eu.kanade.tachiyomi.source.online.HttpSource +import exh.metadata.MetadataHelper +import exh.metadata.copyTo +import exh.metadata.models.ExGalleryMetadata +import exh.search.SearchEngine +import okhttp3.Response +import rx.Observable + +/** + * Offline metadata store source + * + * TODO This no longer fakes an online source because of technical reasons. + * If we still want offline search, we must find out a way to rearchitecture the source system so it supports + * online source faking again. + */ + +class EHentaiMetadata(override val id: Long, + val exh: Boolean, + val context: Context) : HttpSource() { + override fun popularMangaRequest(page: Int) + = throw UnsupportedOperationException("Unused method called!") + override fun popularMangaParse(response: Response) + = throw UnsupportedOperationException("Unused method called!") + override fun searchMangaRequest(page: Int, query: String, filters: FilterList) + = throw UnsupportedOperationException("Unused method called!") + override fun searchMangaParse(response: Response) + = throw UnsupportedOperationException("Unused method called!") + override fun latestUpdatesRequest(page: Int) + = throw UnsupportedOperationException("Unused method called!") + override fun latestUpdatesParse(response: Response) + = throw UnsupportedOperationException("Unused method called!") + override fun mangaDetailsParse(response: Response) + = throw UnsupportedOperationException("Unused method called!") + override fun chapterListParse(response: Response) + = throw UnsupportedOperationException("Unused method called!") + override fun pageListParse(response: Response) + = throw UnsupportedOperationException("Unused method called!") + override fun imageUrlParse(response: Response) + = throw UnsupportedOperationException("Unused method called!") + + val metadataHelper = MetadataHelper() + + val internalEx = EHentai(id - 2, exh, context) + + val searchEngine = SearchEngine() + + override val baseUrl: String + get() = throw UnsupportedOperationException() + override val lang: String + get() = "advanced" + override val supportsLatest: Boolean + get() = true + + override fun fetchChapterList(manga: SManga): Observable> + = Observable.just(listOf(Chapter.create().apply { + url = manga.url + name = "ONLINE - Chapter" + chapter_number = 1f + })) + + override fun fetchPageList(chapter: SChapter) = internalEx.fetchPageList(chapter) + + override fun fetchImageUrl(page: Page) = internalEx.fetchImageUrl(page) + + fun List.mapToManga() = filter { it.exh == exh } + .map { + Manga.create(id).apply { + it.copyTo(this) + source = this@EHentaiMetadata.id + } + } + + fun sortedByTimeGalleries() = metadataHelper.getAllGalleries().sortedByDescending { + it.datePosted ?: 0 + } + + override fun fetchPopularManga(page: Int) + = Observable.fromCallable { + MangasPage(metadataHelper.getAllGalleries().sortedByDescending { + it.ratingCount ?: 0 + }.mapToManga(), false) + }!! + + override fun fetchSearchManga(page: Int, query: String, filters: FilterList) + = Observable.fromCallable { + val genreGroup = filters.find { + it is EHentai.GenreGroup + }!! as EHentai.GenreGroup + val disableGenreFilter = genreGroup.state.find(EHentai.GenreOption::state) == null + + val parsed = searchEngine.parseQuery(query) + MangasPage(sortedByTimeGalleries().filter { manga -> + disableGenreFilter || genreGroup.state.find { + it.state && it.genreId == manga.genre + } != null + }.filter { + searchEngine.matches(it, parsed) + }.mapToManga(), false) + }!! + + override fun fetchLatestUpdates(page: Int) + = Observable.fromCallable { + MangasPage(sortedByTimeGalleries().mapToManga(), false) + }!! + + override fun fetchMangaDetails(manga: SManga) = Observable.fromCallable { + //Hack to convert the gallery into an online gallery when favoriting it or reading it + metadataHelper.fetchEhMetadata(manga.url, exh)?.copyTo(manga) + manga + }!! + + override fun getFilterList() = FilterList(EHentai.GenreGroup()) + + override val name: String + get() = if(exh) { + "ExHentai" + } else { + "E-Hentai" + } + " - METADATA" + +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt new file mode 100755 index 000000000..35cbb90e3 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt @@ -0,0 +1,237 @@ +package eu.kanade.tachiyomi.source.online.all + +import android.content.Context +import android.net.Uri +import com.github.salomonbrys.kotson.get +import com.github.salomonbrys.kotson.int +import com.github.salomonbrys.kotson.long +import com.github.salomonbrys.kotson.string +import com.google.gson.JsonElement +import com.google.gson.JsonNull +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import eu.kanade.tachiyomi.BuildConfig +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.source.model.* +import eu.kanade.tachiyomi.source.online.HttpSource +import exh.NHENTAI_SOURCE_ID +import exh.metadata.MetadataHelper +import exh.metadata.copyTo +import exh.metadata.models.NHentaiMetadata +import exh.metadata.models.Tag +import okhttp3.Request +import okhttp3.Response +import rx.Observable +import timber.log.Timber + +/** + * NHentai source + */ + +class NHentai(context: Context) : HttpSource() { + override fun fetchPopularManga(page: Int): Observable { + //TODO There is currently no way to get the most popular mangas + //TODO Instead, we delegate this to the latest updates thing to avoid confusing users with an empty screen + return fetchLatestUpdates(page) + } + + override fun popularMangaRequest(page: Int): Request { + TODO("Currently unavailable!") + } + + override fun popularMangaParse(response: Response): MangasPage { + TODO("Currently unavailable!") + } + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + //Currently we have no filters + //TODO Filter builder + val uri = Uri.parse("$baseUrl/api/galleries/search").buildUpon() + uri.appendQueryParameter("query", query) + uri.appendQueryParameter("page", page.toString()) + return nhGet(uri.toString(), page) + } + + override fun searchMangaParse(response: Response) + = parseResultPage(response) + + override fun latestUpdatesRequest(page: Int): Request { + val uri = Uri.parse("$baseUrl/api/galleries/all").buildUpon() + uri.appendQueryParameter("page", page.toString()) + return nhGet(uri.toString(), page) + } + + override fun latestUpdatesParse(response: Response) + = parseResultPage(response) + + override fun mangaDetailsParse(response: Response) + = parseGallery(jsonParser.parse(response.body().string()).asJsonObject) + + //Used so we can use a different URL for fetching manga details and opening the details in the browser + override fun fetchMangaDetails(manga: SManga): Observable { + return client.newCall(urlToDetailsRequest(manga.url)) + .asObservableSuccess() + .map { response -> + mangaDetailsParse(response).apply { initialized = true } + } + } + + override fun mangaDetailsRequest(manga: SManga) + = nhGet(manga.url) + + fun urlToDetailsRequest(url: String) + = nhGet(baseUrl + "/api/gallery/" + url.split("/").last()) + + fun parseResultPage(response: Response): MangasPage { + val res = jsonParser.parse(response.body().string()).asJsonObject + + val error = res.get("error") + if(error == null) { + val results = res.getAsJsonArray("result")?.map { + parseGallery(it.asJsonObject) + } + val numPages = res.get("num_pages")?.int + if(results != null && numPages != null) + return MangasPage(results, numPages > response.request().tag() as Int) + } else { + Timber.w("An error occurred while performing the search: $error") + } + return MangasPage(emptyList(), false) + } + + fun rawParseGallery(obj: JsonObject) = NHentaiMetadata().apply { + uploadDate = obj.get("upload_date")?.notNull()?.long + + favoritesCount = obj.get("num_favorites")?.notNull()?.long + + mediaId = obj.get("media_id")?.notNull()?.string + + obj.get("title")?.asJsonObject?.let { + japaneseTitle = it.get("japanese")?.notNull()?.string + shortTitle = it.get("pretty")?.notNull()?.string + englishTitle = it.get("english")?.notNull()?.string + } + + obj.get("images")?.asJsonObject?.let { + coverImageType = it.get("cover")?.get("t")?.notNull()?.asString + it.get("pages")?.asJsonArray?.map { + it?.asJsonObject?.get("t")?.notNull()?.asString + }?.filterNotNull()?.let { + pageImageTypes.clear() + pageImageTypes.addAll(it) + } + thumbnailImageType = it.get("thumbnail")?.get("t")?.notNull()?.asString + } + + scanlator = obj.get("scanlator")?.notNull()?.asString + + id = obj.get("id")?.asLong + + obj.get("tags")?.asJsonArray?.map { + val asObj = it.asJsonObject + Pair(asObj.get("type")?.string, asObj.get("name")?.string) + }?.apply { + tags.clear() + }?.forEach { + if(it.first != null && it.second != null) + tags.getOrPut(it.first!!, { ArrayList() }).add(Tag(it.second!!, false)) + } + } + + fun parseGallery(obj: JsonObject) = rawParseGallery(obj).let { + metadataHelper.writeGallery(it, id) + + SManga.create().apply { + it.copyTo(this) + } + } + + fun lazyLoadMetadata(url: String) = + Observable.fromCallable { + metadataHelper.fetchNhentaiMetadata(url) + ?: client.newCall(urlToDetailsRequest(url)) + .asObservableSuccess() + .map { + rawParseGallery(jsonParser.parse(it.body().string()).asJsonObject) + }.toBlocking().first() + }!! + + override fun fetchChapterList(manga: SManga) + = lazyLoadMetadata(manga.url).map { + listOf(SChapter.create().apply { + url = manga.url + name = "Chapter" + //TODO Get this working later +// date_upload = it.uploadDate ?: 0 + chapter_number = 1f + }) + }!! + + override fun fetchPageList(chapter: SChapter) + = lazyLoadMetadata(chapter.url).map { metadata -> + if(metadata.mediaId == null) emptyList() + else + metadata.pageImageTypes.mapIndexed { index, s -> + val imageUrl = imageUrlFromType(metadata.mediaId!!, index + 1, s) + Page(index, imageUrl!!, imageUrl) + } + }!! + + override fun fetchImageUrl(page: Page) = Observable.just(page.imageUrl!!)!! + + fun imageUrlFromType(mediaId: String, page: Int, t: String) = NHentaiMetadata.typeToExtension(t)?.let { + "https://i.nhentai.net/galleries/$mediaId/$page.$it" + } + + override fun chapterListParse(response: Response): List { + throw NotImplementedError("Unused method called!") + } + + override fun pageListParse(response: Response): List { + throw NotImplementedError("Unused method called!") + } + + override fun imageUrlParse(response: Response): String { + throw NotImplementedError("Unused method called!") + } + + val appName by lazy { + context.getString(R.string.app_name)!! + } + fun nhGet(url: String, tag: Any? = null) = GET(url) + .newBuilder() + .header("User-Agent", + "Mozilla/5.0 (X11; Linux x86_64) " + + "AppleWebKit/537.36 (KHTML, like Gecko) " + + "Chrome/56.0.2924.87 " + + "Safari/537.36 " + + "$appName/${BuildConfig.VERSION_CODE}") + .tag(tag).build()!! + + override val id = NHENTAI_SOURCE_ID + + override val lang = "all" + + override val name = "nhentai" + + override val baseUrl = NHentaiMetadata.BASE_URL + + override val supportsLatest = true + + companion object { + val jsonParser by lazy { + JsonParser() + } + + val metadataHelper by lazy { + MetadataHelper() + } + } + + fun JsonElement.notNull() = + if(this is JsonNull) + null + else this +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/PervEden.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/PervEden.kt new file mode 100755 index 000000000..c0448207b --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/PervEden.kt @@ -0,0 +1,282 @@ +package eu.kanade.tachiyomi.source.online.all + +import android.net.Uri +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.* +import eu.kanade.tachiyomi.source.online.ParsedHttpSource +import eu.kanade.tachiyomi.util.ChapterRecognition +import eu.kanade.tachiyomi.util.asJsoup +import exh.metadata.MetadataHelper +import exh.metadata.copyTo +import exh.metadata.models.PervEdenGalleryMetadata +import exh.metadata.models.Tag +import exh.util.UriFilter +import exh.util.UriGroup +import okhttp3.Request +import okhttp3.Response +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import org.jsoup.nodes.TextNode +import timber.log.Timber +import java.text.SimpleDateFormat +import java.util.* + +class PervEden(override val id: Long, override val lang: String) : ParsedHttpSource() { + + override val supportsLatest = true + override val name = "Perv Eden" + override val baseUrl = "http://www.perveden.com" + + val metadataHelper by lazy { MetadataHelper() } + + override fun popularMangaSelector() = "#topManga > ul > li" + + override fun popularMangaFromElement(element: Element): SManga { + val manga = SManga.create() + manga.thumbnail_url = "http:" + element.select(".hottestImage > img").attr("data-src") + + val titleElement = element.getElementsByClass("hottestInfo").first().child(0) + manga.url = titleElement.attr("href") + manga.title = titleElement.text() + + return manga + } + + override fun popularMangaNextPageSelector(): String? = null + + override fun searchMangaSelector() = "#mangaList > tbody > tr" + + override fun searchMangaFromElement(element: Element): SManga { + val manga = SManga.create() + val titleElement = element.child(0).child(0) + manga.url = titleElement.attr("href") + manga.title = titleElement.text().trim() + return manga + } + + override fun searchMangaNextPageSelector() = ".next" + + override fun popularMangaRequest(page: Int): Request { + val urlLang = if(lang == "en") + "eng" + else "it" + return GET("$baseUrl/$urlLang/") + } + + override fun latestUpdatesSelector() = ".newsManga" + + override fun latestUpdatesFromElement(element: Element): SManga { + val manga = SManga.create() + val header = element.getElementsByClass("manga_tooltop_header").first() + val titleElement = header.child(0) + manga.url = titleElement.attr("href") + manga.title = titleElement.text().trim() + manga.thumbnail_url = "http:" + titleElement.getElementsByClass("mangaImage").first().attr("tmpsrc") + return manga + } + + override fun latestUpdatesParse(response: Response): MangasPage { + val document = response.asJsoup() + + val mangas = document.select(latestUpdatesSelector()).map { element -> + latestUpdatesFromElement(element) + } + + return MangasPage(mangas, mangas.isNotEmpty()) + } + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val uri = Uri.parse("$baseUrl/$lang/$lang-directory/").buildUpon() + uri.appendQueryParameter("page", page.toString()) + filters.forEach { + if(it is UriFilter) it.addToUri(uri) + } + return GET(uri.toString()) + } + + override fun latestUpdatesNextPageSelector(): String? { + throw NotImplementedError("Unused method called!") + } + + override fun mangaDetailsParse(document: Document): SManga { + val metadata = PervEdenGalleryMetadata() + with(metadata) { + url = document.location() + + lang = this@PervEden.lang + + title = document.getElementsByClass("manga-title").first()?.text() + + thumbnailUrl = "http:" + document.getElementsByClass("mangaImage2").first()?.child(0)?.attr("src") + + val rightBoxElement = document.select(".rightBox:not(.info)").first() + + tags.clear() + var inStatus: String? = null + rightBoxElement.childNodes().forEach { + if(it is Element && it.tagName().toLowerCase() == "h4") { + inStatus = it.text().trim() + } else { + when(inStatus) { + "Alternative name(s)" -> { + if(it is TextNode) { + val text = it.text().trim() + if(!text.isBlank()) + altTitles.add(text) + } + } + "Artist" -> { + if(it is Element && it.tagName() == "a") { + artist = it.text() + tags.getOrPut("artist", { + ArrayList() + }).add(Tag(it.text().toLowerCase(), false)) + } + } + "Genres" -> { + if(it is Element && it.tagName() == "a") + tags.getOrPut("genre", { + ArrayList() + }).add(Tag(it.text().toLowerCase(), false)) + } + "Type" -> { + if(it is TextNode) { + val text = it.text().trim() + if(!text.isBlank()) + type = text + } + } + "Status" -> { + if(it is TextNode) { + val text = it.text().trim() + if(!text.isBlank()) + status = text + } + } + } + } + } + + rating = document.getElementById("rating-score")?.attr("value")?.toFloat() + + //Save metadata + Timber.d("LNG: " + metadata.lang) + metadataHelper.writeGallery(this, id) + + return SManga.create().apply { + copyTo(this) + } + } + } + + override fun latestUpdatesRequest(page: Int): Request { + val num = if(lang == "en") "0" + else if(lang == "it") "1" + else throw NotImplementedError("Unimplemented language!") + + return GET("$baseUrl/ajax/news/$page/$num/0/") + } + + override fun chapterListSelector() = "#leftContent > table > tbody > tr" + + override fun chapterFromElement(element: Element) = SChapter.create().apply { + val linkElement = element.getElementsByClass("chapterLink").first() + + setUrlWithoutDomain(linkElement.attr("href")) + name = "Chapter " + linkElement.getElementsByTag("b").text() + + ChapterRecognition.parseChapterNumber( + this, + SManga.create().apply { + title = "" + }) + + try { + date_upload = DATE_FORMAT.parse(element.getElementsByClass("chapterDate").first().text().trim()).time + } catch(ignored: Exception) {} + } + + override fun pageListParse(document: Document) + = document.getElementById("pageSelect").getElementsByTag("option").map { + Page(it.attr("data-page").toInt() - 1, baseUrl + it.attr("value")) + } + + override fun imageUrlParse(document: Document) + = "http:" + document.getElementById("mainImg").attr("src")!! + + override fun getFilterList() = FilterList ( + AuthorFilter(), + ArtistFilter(), + TypeFilterGroup(), + ReleaseYearGroup(), + StatusFilterGroup() + ) + + class StatusFilterGroup : UriGroup("Status", listOf( + StatusFilter("Ongoing", 1), + StatusFilter("Completed", 2), + StatusFilter("Suspended", 0) + )) + + class StatusFilter(n: String, val id: Int) : Filter.CheckBox(n, false), UriFilter { + override fun addToUri(builder: Uri.Builder) { + if(state) + builder.appendQueryParameter("status", id.toString()) + } + } + + //Explicit type arg for listOf() to workaround this: KT-16570 + class ReleaseYearGroup : UriGroup>("Release Year", listOf>( + ReleaseYearRangeFilter(), + ReleaseYearYearFilter() + )) + + class ReleaseYearRangeFilter : Filter.Select("Range", arrayOf( + "on", + "after", + "before" + )), UriFilter { + override fun addToUri(builder: Uri.Builder) { + builder.appendQueryParameter("releasedType", state.toString()) + } + } + + class ReleaseYearYearFilter : Filter.Text("Year"), UriFilter { + override fun addToUri(builder: Uri.Builder) { + builder.appendQueryParameter("released", state) + } + } + + class AuthorFilter : Filter.Text("Author"), UriFilter { + override fun addToUri(builder: Uri.Builder) { + builder.appendQueryParameter("author", state) + } + } + + class ArtistFilter : Filter.Text("Artist"), UriFilter { + override fun addToUri(builder: Uri.Builder) { + builder.appendQueryParameter("artist", state) + } + } + + class TypeFilterGroup : UriGroup("Type", listOf( + TypeFilter("Japanese Manga", 0), + TypeFilter("Korean Manhwa", 1), + TypeFilter("Chinese Manhua", 2), + TypeFilter("Comic", 3), + TypeFilter("Doujinshi", 4) + )) + + class TypeFilter(n: String, val id: Int) : Filter.CheckBox(n, false), UriFilter { + override fun addToUri(builder: Uri.Builder) { + if(state) + builder.appendQueryParameter("type", id.toString()) + } + } + + companion object { + val DATE_FORMAT = SimpleDateFormat("MMM d, yyyy", Locale.US).apply { + timeZone = TimeZone.getTimeZone("GMT") + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Batoto.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Batoto.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangafox.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangafox.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangahere.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangahere.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangasee.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangasee.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Readmangatoday.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Readmangatoday.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/german/WieManga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/german/WieManga.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Mangachan.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Mangachan.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Mintmanga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Mintmanga.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Readmanga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Readmanga.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/ActivityMixin.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/ActivityMixin.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt old mode 100644 new mode 100755 index 38a4568d0..59a2c317a --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt @@ -2,6 +2,15 @@ package eu.kanade.tachiyomi.ui.base.activity import android.support.v7.app.AppCompatActivity import eu.kanade.tachiyomi.util.LocaleHelper +import exh.ui.lock.lockEnabled +import exh.ui.lock.showLockActivity +import android.app.ActivityManager +import android.app.Service +import android.app.usage.UsageStats +import android.app.usage.UsageStatsManager +import android.os.Build +import java.util.* + abstract class BaseActivity : AppCompatActivity(), ActivityMixin { @@ -23,4 +32,48 @@ abstract class BaseActivity : AppCompatActivity(), ActivityMixin { super.onPause() } + var willLock = false + var disableLock = false + override fun onRestart() { + super.onRestart() + if(willLock && lockEnabled() && !disableLock) { + showLockActivity(this) + } + + willLock = false + } + + override fun onStop() { + super.onStop() + tryLock() + } + + fun tryLock() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + val mUsageStatsManager = getSystemService("usagestats") as UsageStatsManager + val time = System.currentTimeMillis() + // We get usage stats for the last 20 seconds + val stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 20, time) + // Sort the stats by the last time used + if (stats != null) { + val mySortedMap = TreeMap() + for (usageStats in stats) { + mySortedMap.put(usageStats.lastTimeUsed, usageStats) + } + if (!mySortedMap.isEmpty()) { + if(mySortedMap[mySortedMap.lastKey()]?.packageName != packageName) { + willLock = true + } + } + } + } else { + val am = getSystemService(Service.ACTIVITY_SERVICE) as ActivityManager + val tasks: List + tasks = am.getRunningTasks(1) + val running = tasks[0] + if (running.topActivity.packageName != packageName) { + willLock = true + } + } + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/adapter/FlexibleViewHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/adapter/FlexibleViewHolder.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/adapter/SmartFragmentStatePagerAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/adapter/SmartFragmentStatePagerAdapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/BaseFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/BaseFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/BaseRxFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/BaseRxFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/FragmentMixin.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/FragmentMixin.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueGridHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueGridHolder.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueHolder.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueItem.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueListHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueListHolder.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueNavigationView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueNavigationView.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePager.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePager.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/NoResultsException.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/NoResultsException.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/Pager.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/Pager.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/ProgressItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/ProgressItem.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/CheckboxItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/CheckboxItem.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/GroupItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/GroupItem.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/HeaderItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/HeaderItem.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SectionItems.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SectionItems.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SelectItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SelectItem.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SeparatorItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SeparatorItem.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortGroup.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortGroup.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortItem.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TextItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TextItem.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TriStateItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TriStateItem.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryActivity.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryHolder.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryItem.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadActivity.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadAdapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHolder.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadPresenter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/latest_updates/LatestUpdatesFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/latest_updates/LatestUpdatesFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/latest_updates/LatestUpdatesPager.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/latest_updates/LatestUpdatesPager.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/latest_updates/LatestUpdatesPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/latest_updates/LatestUpdatesPresenter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryAdapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt old mode 100644 new mode 100755 index 8aab567e8..5aad6f4cf --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt @@ -1,5 +1,7 @@ package eu.kanade.tachiyomi.ui.library +import android.os.Handler +import android.os.Looper import android.view.Gravity import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.MATCH_PARENT @@ -7,9 +9,16 @@ import android.widget.FrameLayout import eu.davidea.flexibleadapter4.FlexibleAdapter import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.source.SourceManager +import eu.kanade.tachiyomi.source.online.all.EHentai +import eu.kanade.tachiyomi.source.online.all.EHentaiMetadata import eu.kanade.tachiyomi.util.inflate import eu.kanade.tachiyomi.widget.AutofitRecyclerView +import exh.isLewdSource +import exh.metadata.MetadataHelper +import exh.search.SearchEngine import kotlinx.android.synthetic.main.item_catalogue_grid.view.* +import uy.kohesive.injekt.injectLazy import java.util.* /** @@ -25,6 +34,13 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryView) : */ private var mangas: List = emptyList() + private val sourceManager: SourceManager by injectLazy() + + private val searchEngine = SearchEngine() + private val metadataHelper = MetadataHelper() + + var asyncSearchText: String? = null + init { setHasStableIds(true) } @@ -58,8 +74,17 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryView) : * @param param the filter. Not used. */ override fun updateDataSet(param: String?) { - filterItems(mangas) - notifyDataSetChanged() + //Async search filter (EH) + val filtered = asyncSearchText?.let { search -> + mangas.filter { + filterObject(it, search) + } + } ?: mangas + //The rest of the filters run on the main loop + Handler(Looper.getMainLooper()).post { + filterItems(filtered) + notifyDataSetChanged() + } } /** @@ -70,8 +95,17 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryView) : * @return true if the manga should be included, false otherwise. */ override fun filterObject(manga: Manga, query: String): Boolean = with(manga) { - title.toLowerCase().contains(query) || - author != null && author!!.toLowerCase().contains(query) + if(!isLewdSource(manga.source)) { + //Regular searching for normal manga + title.toLowerCase().contains(query) || + author != null && author!!.toLowerCase().contains(query) + } else { + //Use gallery search engine for EH manga + val metadata = metadataHelper.fetchMetadata(manga.url, manga.source) + metadata?.let { + searchEngine.matches(it, searchEngine.parseQuery(query)) + } ?: title.contains(query, ignoreCase = true) //Use regular searching when the metadata is not set up for this gallery + } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt old mode 100644 new mode 100755 index bdafd0bc0..dd7d2eaf2 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt @@ -19,7 +19,9 @@ import eu.kanade.tachiyomi.util.toast import eu.kanade.tachiyomi.widget.AutofitRecyclerView import kotlinx.android.synthetic.main.item_library_category.view.* import rx.Subscription +import rx.android.schedulers.AndroidSchedulers import uy.kohesive.injekt.injectLazy +import java.util.concurrent.TimeUnit /** * Fragment containing the library manga for a certain category. @@ -114,8 +116,11 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att val presenter = fragment.presenter - searchSubscription = presenter.searchSubject.subscribe { text -> - adapter.searchText = text + searchSubscription = presenter + .searchSubject + .debounce(10L, TimeUnit.MILLISECONDS) + .subscribe { text -> //Debounce search (EH) + adapter.asyncSearchText = text?.trim()?.toLowerCase() adapter.updateDataSet() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryFragment.kt old mode 100644 new mode 100755 index 0b6d92fe4..2d334506f --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryFragment.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryFragment.kt @@ -27,6 +27,7 @@ import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.util.inflate import eu.kanade.tachiyomi.util.toast import eu.kanade.tachiyomi.widget.DialogCheckboxView +import exh.FavoritesSyncHelper import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.fragment_library.* import nucleus.factory.RequiresPresenter @@ -267,6 +268,11 @@ class LibraryFragment : BaseRxFragment(), ActionMode.Callback val intent = CategoryActivity.newIntent(activity) startActivity(intent) } + R.id.action_sync -> { + FavoritesSyncHelper(this.activity).guiSyncFavorites({ + //Do we even need stuff in here? + }) + } else -> return super.onOptionsItemSelected(item) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryMangaEvent.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryMangaEvent.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryNavigationView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryNavigationView.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySelectionEvent.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySelectionEvent.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySort.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySort.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/ChangelogDialogFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/ChangelogDialogFragment.kt old mode 100644 new mode 100755 index 08ab144b1..1c6c35861 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/ChangelogDialogFragment.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/ChangelogDialogFragment.kt @@ -25,7 +25,6 @@ class ChangelogDialogFragment : DialogFragment() { preferences.lastVersionCode().set(BuildConfig.VERSION_CODE) ChangelogDialogFragment().show(fm, "changelog") - // TODO better upgrades management if (oldVersion == 0) return if (oldVersion < 14) { @@ -51,6 +50,7 @@ class ChangelogDialogFragment : DialogFragment() { } } } + //TODO Review any other changes below } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt old mode 100644 new mode 100755 index e40a8144e..ef457c843 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -16,6 +16,10 @@ import eu.kanade.tachiyomi.ui.library.LibraryFragment import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersFragment import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadFragment import eu.kanade.tachiyomi.ui.setting.SettingsActivity +import exh.ui.batchadd.BatchAddFragment +import exh.ui.lock.lockEnabled +import exh.ui.lock.notifyLockSecurity +import exh.ui.lock.showLockActivity import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.toolbar.* import uy.kohesive.injekt.injectLazy @@ -65,6 +69,7 @@ class MainActivity : BaseActivity() { R.id.nav_drawer_recently_read -> setFragment(RecentlyReadFragment.newInstance(), id) R.id.nav_drawer_catalogues -> setFragment(CatalogueFragment.newInstance(), id) R.id.nav_drawer_latest_updates -> setFragment(LatestUpdatesFragment.newInstance(), id) + R.id.nav_drawer_batch_add -> setFragment(BatchAddFragment.newInstance(), id) R.id.nav_drawer_downloads -> startActivity(Intent(this, DownloadActivity::class.java)) R.id.nav_drawer_settings -> { val intent = Intent(this, SettingsActivity::class.java) @@ -88,6 +93,16 @@ class MainActivity : BaseActivity() { // Show changelog if needed ChangelogDialogFragment.show(this, preferences, supportFragmentManager) + + //Show lock + val lockEnabled = lockEnabled(preferences) + if(lockEnabled) { + showLockActivity(this) + + //Check lock security + notifyLockSecurity(this) + } + } @@ -126,6 +141,10 @@ class MainActivity : BaseActivity() { nav_view.post { recreate() } } else if (resultCode and SettingsActivity.FLAG_LANG_CHANGED != 0) { nav_view.post { recreate() } + } else if (resultCode and SettingsActivity.FLAG_EH_RECREATE != 0) { + TaskStackBuilder.create(this) + .addNextIntent(Intent(this, MainActivity::class.java)) + .startActivities() } } else { super.onActivityResult(requestCode, resultCode, data) @@ -156,5 +175,6 @@ class MainActivity : BaseActivity() { private const val SHORTCUT_RECENTLY_UPDATED = "eu.kanade.tachiyomi.SHOW_RECENTLY_UPDATED" private const val SHORTCUT_RECENTLY_READ = "eu.kanade.tachiyomi.SHOW_RECENTLY_READ" private const val SHORTCUT_CATALOGUES = "eu.kanade.tachiyomi.SHOW_CATALOGUES" + const val FINALIZE_MIGRATION = "finalize_migration" } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaActivity.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaEvent.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaEvent.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersPresenter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/ChapterCountEvent.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/ChapterCountEvent.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaFavoriteEvent.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaFavoriteEvent.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt old mode 100644 new mode 100755 index f0f896346..846f8fd88 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt @@ -13,6 +13,7 @@ import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.manga.MangaEvent import eu.kanade.tachiyomi.util.SharedData import eu.kanade.tachiyomi.util.isNullOrUnsubscribed +import eu.kanade.tachiyomi.util.toast import rx.Observable import rx.Subscription import rx.android.schedulers.AndroidSchedulers @@ -69,7 +70,10 @@ class MangaInfoPresenter : BasePresenter() { super.onCreate(savedState) manga = SharedData.get(MangaEvent::class.java)?.manga ?: return - source = sourceManager.get(manga.source)!! + source = sourceManager.get(manga.source) ?: run { + context.toast("Could not find manga source!") + return + } sendMangaToView() // Update chapter count diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackAdapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackHolder.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackItem.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackPresenter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchAdapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ChapterLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ChapterLoader.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt old mode 100644 new mode 100755 index 11b27c623..289ea0c14 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -264,6 +264,10 @@ class ReaderActivity : BaseRxActivity() { fun onChapterReady(chapter: ReaderChapter) { please_wait.visibility = View.GONE val pages = chapter.pages ?: run { onChapterError(Exception("Null pages")); return } + if(pages.isEmpty()) { + onChapterError(Exception("Page list empty!")) + return + } val activePage = pages.getOrElse(chapter.requestedPage) { pages.first() } viewer?.onPageListReady(chapter, activePage) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderChapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderChapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderCustomFilterDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderCustomFilterDialog.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderEvent.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderEvent.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt old mode 100644 new mode 100755 index 96f0184ee..38345e9f2 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt @@ -18,6 +18,7 @@ import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.online.HttpSource +import eu.kanade.tachiyomi.source.online.all.EHentai import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.util.DiskUtil import eu.kanade.tachiyomi.util.RetryWithDelay @@ -354,6 +355,11 @@ class ReaderPresenter : BasePresenter() { if (uri != null && !page.chapter.isDownloaded) { chapterCache.removeFileFromCache(uri.encodedPath.substringAfterLast('/')) } + + //If we are using EHentai/ExHentai, get a new image URL + if(source is EHentai) + page.imageUrl = null + loader.retryPage(page) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsDialog.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/BaseReader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/BaseReader.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/PageDecodeErrorLayout.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/PageDecodeErrorLayout.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/OnChapterBoundariesOutListener.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/OnChapterBoundariesOutListener.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PageView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PageView.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/Pager.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/Pager.java old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderAdapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalPager.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalPager.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/LeftToRightReader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/LeftToRightReader.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/RightToLeftReader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/RightToLeftReader.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalPager.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalPager.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalReader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalReader.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalViewPagerImpl.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalViewPagerImpl.java old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonHolder.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/DateItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/DateItem.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterHolder.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterItem.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersAdapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersPresenter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadAdapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadHolder.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadPresenter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/AnilistLoginActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/AnilistLoginActivity.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsActivity.kt old mode 100644 new mode 100755 index 21304dae5..2abc7de8c --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsActivity.kt @@ -68,6 +68,7 @@ class SettingsActivity : BaseActivity(), "backup_screen" -> SettingsBackupFragment.newInstance(key) "advanced_screen" -> SettingsAdvancedFragment.newInstance(key) "about_screen" -> SettingsAboutFragment.newInstance(key) + "eh_screen" -> SettingsEhFragment.newInstance(key) //EH else -> SettingsFragment.newInstance(key) } } @@ -81,6 +82,7 @@ class SettingsActivity : BaseActivity(), const val FLAG_THEME_CHANGED = 0x1 const val FLAG_DATABASE_CLEARED = 0x2 const val FLAG_LANG_CHANGED = 0x4 + const val FLAG_EH_RECREATE = 0x8 } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadsFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadsFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhFragment.kt new file mode 100755 index 000000000..e7df22076 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhFragment.kt @@ -0,0 +1,73 @@ +package eu.kanade.tachiyomi.ui.setting + +import android.content.Intent +import android.os.Bundle +import android.support.v7.preference.XpPreferenceFragment +import android.view.View +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.util.plusAssign +import exh.ui.migration.MetadataFetchDialog +import exh.ui.login.LoginActivity +import net.xpece.android.support.preference.Preference +import net.xpece.android.support.preference.SwitchPreference +import uy.kohesive.injekt.injectLazy + +/** + * EH Settings fragment + */ + +class SettingsEhFragment : SettingsFragment() { + companion object { + fun newInstance(rootKey: String): SettingsEhFragment { + val args = Bundle() + args.putString(XpPreferenceFragment.ARG_PREFERENCE_ROOT, rootKey) + return SettingsEhFragment().apply { arguments = args } + } + } + + private val preferences: PreferencesHelper by injectLazy() + + val enableExhentaiPref by lazy { + findPreference("enable_exhentai") as SwitchPreference + } + + val migrateLibraryPref by lazy { + findPreference("ex_migrate_library") as Preference + } + + val useJpTitlePref by lazy { + findPreference("use_jp_title") as SwitchPreference + } + + override fun onViewCreated(view: View, savedState: Bundle?) { + super.onViewCreated(view, savedState) + + subscriptions += preferences + .enableExhentai() + .asObservable().subscribe { + enableExhentaiPref.isChecked = it + } + + enableExhentaiPref.setOnPreferenceChangeListener { preference, newVal -> + newVal as Boolean + (activity as SettingsActivity).parentFlags = SettingsActivity.FLAG_EH_RECREATE + if(!newVal) { + preferences.enableExhentai().set(false) + true + } else { + startActivity(Intent(context, LoginActivity::class.java)) + false + } + } + + migrateLibraryPref.setOnPreferenceClickListener { + MetadataFetchDialog().askMigration(activity) + true + } + + useJpTitlePref.setOnPreferenceChangeListener { preference, any -> + (activity as SettingsActivity).parentFlags = SettingsActivity.FLAG_EH_RECREATE + true + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsFragment.kt old mode 100644 new mode 100755 index 291db4179..29bf38fad --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsFragment.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsFragment.kt @@ -30,6 +30,7 @@ open class SettingsFragment : XpPreferenceFragment() { addPreferencesFromResource(R.xml.pref_sources) addPreferencesFromResource(R.xml.pref_tracking) addPreferencesFromResource(R.xml.pref_backup) + addPreferencesFromResource(R.xml.eh_pref_eh) //EH addPreferencesFromResource(R.xml.pref_advanced) addPreferencesFromResource(R.xml.pref_about) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSourcesFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSourcesFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsTrackingFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsTrackingFragment.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/AndroidComponentUtil.java b/app/src/main/java/eu/kanade/tachiyomi/util/AndroidComponentUtil.java old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.kt b/app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/ChapterSourceSync.kt b/app/src/main/java/eu/kanade/tachiyomi/util/ChapterSourceSync.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/ContextExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/ContextExtensions.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/DiskUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/DiskUtil.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/DynamicConcurrentMergeOperator.java b/app/src/main/java/eu/kanade/tachiyomi/util/DynamicConcurrentMergeOperator.java old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/FileExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/FileExtensions.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/GLUtil.java b/app/src/main/java/eu/kanade/tachiyomi/util/GLUtil.java old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/ImageViewExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/ImageViewExtensions.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/JsoupExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/JsoupExtensions.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/LocaleHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/util/LocaleHelper.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/OkioExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/OkioExtensions.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/RarContentProvider.kt b/app/src/main/java/eu/kanade/tachiyomi/util/RarContentProvider.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/RetryWithDelay.kt b/app/src/main/java/eu/kanade/tachiyomi/util/RetryWithDelay.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/RxExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/RxExtensions.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/SharedData.kt b/app/src/main/java/eu/kanade/tachiyomi/util/SharedData.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/StringExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/StringExtensions.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/ViewExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/ViewExtensions.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/ViewGroupExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/ViewGroupExtensions.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/ZipContentProvider.kt b/app/src/main/java/eu/kanade/tachiyomi/util/ZipContentProvider.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/DeletingChaptersDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/DeletingChaptersDialog.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCheckboxView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCheckboxView.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/ElevationAppBarLayout.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/ElevationAppBarLayout.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/EmptyView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/EmptyView.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/ExtendedNavigationView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/ExtendedNavigationView.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/FABAnimationBase.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/FABAnimationBase.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/FABAnimationUpDown.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/FABAnimationUpDown.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/IgnoreFirstSpinnerListener.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/IgnoreFirstSpinnerListener.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/MinMaxNumberPicker.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/MinMaxNumberPicker.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/NegativeSeekBar.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/NegativeSeekBar.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/PTSansTextView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/PTSansTextView.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/PreCachingLayoutManager.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/PreCachingLayoutManager.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/RecyclerViewPagerAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/RecyclerViewPagerAdapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/RevealAnimationView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/RevealAnimationView.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleAnimationListener.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleAnimationListener.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleNavigationView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleNavigationView.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleSeekBarListener.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleSeekBarListener.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleTextWatcher.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleTextWatcher.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/StateImageViewTarget.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/StateImageViewTarget.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/ViewPagerAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/ViewPagerAdapter.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListPreference.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LibraryColumnsDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LibraryColumnsDialog.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginCheckBoxPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginCheckBoxPreference.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginPreference.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/SimpleDialogPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/SimpleDialogPreference.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/SourceLoginDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/SourceLoginDialog.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/SwitchPreferenceCategory.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/SwitchPreferenceCategory.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/TrackLoginDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/TrackLoginDialog.kt old mode 100644 new mode 100755 diff --git a/app/src/main/java/exh/EHSourceHelpers.kt b/app/src/main/java/exh/EHSourceHelpers.kt new file mode 100755 index 000000000..bcccc1ded --- /dev/null +++ b/app/src/main/java/exh/EHSourceHelpers.kt @@ -0,0 +1,29 @@ +package exh + +/** + * Source helpers + */ + +val LEWD_SOURCE_SERIES = 6900L +val EH_SOURCE_ID = LEWD_SOURCE_SERIES + 1 +val EXH_SOURCE_ID = LEWD_SOURCE_SERIES + 2 +val EH_METADATA_SOURCE_ID = LEWD_SOURCE_SERIES + 3 +val EXH_METADATA_SOURCE_ID = LEWD_SOURCE_SERIES + 4 + +val PERV_EDEN_EN_SOURCE_ID = LEWD_SOURCE_SERIES + 5 +val PERV_EDEN_IT_SOURCE_ID = LEWD_SOURCE_SERIES + 6 + +val NHENTAI_SOURCE_ID = LEWD_SOURCE_SERIES + 7 + +fun isLewdSource(source: Long) = source in 6900..6999 + +fun isEhSource(source: Long) = source == EH_SOURCE_ID + || source == EH_METADATA_SOURCE_ID + +fun isExSource(source: Long) = source == EXH_SOURCE_ID + || source == EXH_METADATA_SOURCE_ID + +fun isPervEdenSource(source: Long) = source == PERV_EDEN_IT_SOURCE_ID +|| source == PERV_EDEN_EN_SOURCE_ID + +fun isNhentaiSource(source: Long) = source == NHENTAI_SOURCE_ID diff --git a/app/src/main/java/exh/FavoritesSyncHelper.kt b/app/src/main/java/exh/FavoritesSyncHelper.kt new file mode 100755 index 000000000..35a41df44 --- /dev/null +++ b/app/src/main/java/exh/FavoritesSyncHelper.kt @@ -0,0 +1,135 @@ +package exh + +import android.app.Activity +import android.support.v7.app.AlertDialog +import com.afollestad.materialdialogs.MaterialDialog +import eu.kanade.tachiyomi.data.database.DatabaseHelper +import eu.kanade.tachiyomi.data.database.models.Category +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.database.models.MangaCategory +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.source.SourceManager +import eu.kanade.tachiyomi.source.online.all.EHentai +import eu.kanade.tachiyomi.util.syncChaptersWithSource +import timber.log.Timber +import uy.kohesive.injekt.injectLazy +import kotlin.concurrent.thread + +class FavoritesSyncHelper(val activity: Activity) { + + val db: DatabaseHelper by injectLazy() + + val sourceManager: SourceManager by injectLazy() + + val prefs: PreferencesHelper by injectLazy() + + fun guiSyncFavorites(onComplete: () -> Unit) { + //ExHentai must be enabled/user must be logged in + if (!prefs.enableExhentai().getOrDefault()) { + AlertDialog.Builder(activity).setTitle("Error") + .setMessage("You are not logged in! Please log in and try again!") + .setPositiveButton("Ok") { dialog, _ -> dialog.dismiss() }.show() + return + } + val dialog = MaterialDialog.Builder(activity) + .progress(true, 0) + .title("Downloading favorites") + .content("Please wait...") + .cancelable(false) + .show() + thread { + var error = false + try { + syncFavorites() + } catch (e: Exception) { + error = true + Timber.e(e, "Could not sync favorites!") + } + + dialog.dismiss() + + activity.runOnUiThread { + if (error) + MaterialDialog.Builder(activity) + .title("Error") + .content("There was an error downloading your favorites, please try again later!") + .positiveText("Ok") + .show() + onComplete() + } + } + } + + fun syncFavorites() { + val onlineSources = sourceManager.getOnlineSources() + var ehSource: EHentai? = null + var exSource: EHentai? = null + onlineSources.forEach { + if(it.id == EH_SOURCE_ID) + ehSource = it as EHentai + else if(it.id == EXH_SOURCE_ID) + exSource = it as EHentai + } + + (exSource ?: ehSource)?.let { source -> + val favResponse = source.fetchFavorites() + val ourCategories = ArrayList(db.getCategories().executeAsBlocking()) + val ourMangas = ArrayList(db.getMangas().executeAsBlocking()) + //Add required categories (categories do not sync upwards) + favResponse.second.filter { theirCategory -> + ourCategories.find { + it.name.endsWith(theirCategory) + } == null + }.map { + Category.create(it) + }.let { + db.inTransaction { + //Insert new categories + db.insertCategories(it).executeAsBlocking().results().entries.filter { + it.value.wasInserted() + }.forEach { it.key.id = it.value.insertedId()!!.toInt() } + + val categoryMap = (it + ourCategories).associateBy { it.name } + + //Insert new mangas + val mangaToInsert = java.util.ArrayList() + favResponse.first.map { + val category = categoryMap[it.fav]!! + var manga = it.manga + val alreadyHaveManga = ourMangas.find { + it.url == manga.url + }?.apply { + manga = this + } != null + if (!alreadyHaveManga) { + ourMangas.add(manga) + mangaToInsert.add(manga) + } + manga.favorite = true + Pair(manga, category) + }.apply { + //Insert mangas + db.insertMangas(mangaToInsert).executeAsBlocking().results().entries.filter { + it.value.wasInserted() + }.forEach { manga -> + manga.key.id = manga.value.insertedId() + try { + source.fetchChapterList(manga.key).map { + syncChaptersWithSource(db, it, manga.key, source) + }.toBlocking().first() + } catch (e: Exception) { + Timber.w(e, "Failed to update chapters for gallery: ${manga.key.title}!") + } + } + + //Set categories + val categories = map { MangaCategory.create(it.first, it.second) } + val mangas = map { it.first } + db.setMangaCategories(categories, mangas) + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/exh/FavoritesSyncManager.java b/app/src/main/java/exh/FavoritesSyncManager.java new file mode 100755 index 000000000..badc70704 --- /dev/null +++ b/app/src/main/java/exh/FavoritesSyncManager.java @@ -0,0 +1,192 @@ +package exh; + +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Handler; +import android.os.Looper; +import android.support.v7.app.AlertDialog; + +import com.pushtorefresh.storio.sqlite.operations.put.PutResult; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import eu.kanade.tachiyomi.data.database.DatabaseHelper; +import eu.kanade.tachiyomi.data.database.models.Category; +import eu.kanade.tachiyomi.data.database.models.Manga; +import eu.kanade.tachiyomi.data.database.models.MangaCategory; +import eu.kanade.tachiyomi.source.online.all.EHentai; +import kotlin.Pair; +//import eu.kanade.tachiyomi.data.source.online.english.EHentai; + +public class FavoritesSyncManager { + /*Context context; + DatabaseHelper db; + + public FavoritesSyncManager(Context context, DatabaseHelper db) { + this.context = context; + this.db = db; + } + + public void guiSyncFavorites(final Runnable onComplete) { + if(!DialogLogin.isLoggedIn(context, false)) { + new AlertDialog.Builder(context).setTitle("Error") + .setMessage("You are not logged in! Please log in and try again!") + .setPositiveButton("Ok", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }).show(); + return; + } + final ProgressDialog dialog = ProgressDialog.show(context, "Downloading Favorites", "Please wait...", true, false); + new Thread(new Runnable() { + @Override + public void run() { + Handler mainLooper = new Handler(Looper.getMainLooper()); + try { + syncFavorites(); + } catch (Exception e) { + mainLooper.post(new Runnable() { + @Override + public void run() { + new AlertDialog.Builder(context) + .setTitle("Error") + .setMessage("There was an error downloading your favorites, please try again later!") + .setPositiveButton("Ok", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }).show(); + } + }); + e.printStackTrace(); + } + dialog.dismiss(); + mainLooper.post(onComplete); + } + }).start(); + }*/ +/* + public void syncFavorites() throws IOException { + Pair favResponse = EHentai.fetchFavorites(context); + Map> favorites = favResponse.favs; + List ourCategories = new ArrayList<>(db.getCategories().executeAsBlocking()); + List ourMangas = new ArrayList<>(db.getMangas().executeAsBlocking()); + //Add required categories (categories do not sync upwards) + List categoriesToInsert = new ArrayList<>(); + for (String theirCategory : favorites.keySet()) { + boolean haveCategory = false; + for (Category category : ourCategories) { + if (category.getName().endsWith(theirCategory)) { + haveCategory = true; + } + } + if (!haveCategory) { + Category category = Category.Companion.create(theirCategory); + ourCategories.add(category); + categoriesToInsert.add(category); + } + } + if (!categoriesToInsert.isEmpty()) { + for(Map.Entry result : db.insertCategories(categoriesToInsert).executeAsBlocking().results().entrySet()) { + if(result.getValue().wasInserted()) { + result.getKey().setId(result.getValue().insertedId().intValue()); + } + } + } + //Build category map + Map categoryMap = new HashMap<>(); + for (Category category : ourCategories) { + categoryMap.put(category.getName(), category); + } + //Insert new mangas + List mangaToInsert = new ArrayList<>(); + Map mangaToSetCategories = new HashMap<>(); + for (Map.Entry> entry : favorites.entrySet()) { + Category category = categoryMap.get(entry.getKey()); + for (Manga manga : entry.getValue()) { + boolean alreadyHaveManga = false; + for (Manga ourManga : ourMangas) { + if (ourManga.getUrl().equals(manga.getUrl())) { + alreadyHaveManga = true; + manga = ourManga; + break; + } + } + if (!alreadyHaveManga) { + ourMangas.add(manga); + mangaToInsert.add(manga); + } + mangaToSetCategories.put(manga, category); + manga.setFavorite(true); + } + } + for (Map.Entry results : db.insertMangas(mangaToInsert).executeAsBlocking().results().entrySet()) { + if(results.getValue().wasInserted()) { + results.getKey().setId(results.getValue().insertedId()); + } + } + for(Map.Entry entry : mangaToSetCategories.entrySet()) { + db.setMangaCategories(Collections.singletonList(MangaCategory.Companion.create(entry.getKey(), entry.getValue())), + Collections.singletonList(entry.getKey())); + }*/ + //Determines what + /*Map> toUpload = new HashMap<>(); + for (Manga manga : ourMangas) { + if(manga.getFavorite()) { + boolean remoteHasManga = false; + for (List remoteMangas : favorites.values()) { + for (Manga remoteManga : remoteMangas) { + if (remoteManga.getUrl().equals(manga.getUrl())) { + remoteHasManga = true; + break; + } + } + } + if (!remoteHasManga) { + List mangaCategories = db.getCategoriesForManga(manga).executeAsBlocking(); + for (Category category : mangaCategories) { + int categoryIndex = favResponse.favCategories.indexOf(category.getName()); + if (categoryIndex >= 0) { + List uploadMangas = toUpload.get(categoryIndex); + if (uploadMangas == null) { + uploadMangas = new ArrayList<>(); + toUpload.put(categoryIndex, uploadMangas); + } + uploadMangas.add(manga); + } + } + } + } + }*/ + /********** NON-FUNCTIONAL, modifygids[] CANNOT ADD NEW FAVORITES! (or as of my testing it can't, maybe I'll do more testing)**/ + /*PreferencesHelper helper = new PreferencesHelper(context); + for(Map.Entry> entry : toUpload.entrySet()) { + FormBody.Builder formBody = new FormBody.Builder() + .add("ddact", "fav" + entry.getKey()); + for(Manga manga : entry.getValue()) { + List splitUrl = new ArrayList<>(Arrays.asList(manga.getUrl().split("/"))); + splitUrl.removeAll(Collections.singleton("")); + if(splitUrl.size() < 2) { + continue; + } + formBody.add("modifygids[]", splitUrl.get(1).trim()); + } + formBody.add("apply", "Apply"); + Request request = RequestsKt.POST(EHentai.buildFavoritesBase(context, helper.getPrefs()).favoritesBase, + EHentai.getHeadersBuilder(helper).build(), + formBody.build(), + RequestsKt.getDEFAULT_CACHE_CONTROL()); + Response response = NetworkManager.getInstance().getClient().newCall(request).execute(); + Util.d("EHentai", response.body().string()); + }*/ +// } +} diff --git a/app/src/main/java/exh/GalleryAdder.kt b/app/src/main/java/exh/GalleryAdder.kt new file mode 100755 index 000000000..b0e7a9ff9 --- /dev/null +++ b/app/src/main/java/exh/GalleryAdder.kt @@ -0,0 +1,80 @@ +package exh + +import eu.kanade.tachiyomi.data.database.DatabaseHelper +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.source.SourceManager +import eu.kanade.tachiyomi.util.syncChaptersWithSource +import exh.metadata.MetadataHelper +import exh.metadata.copyTo +import timber.log.Timber +import uy.kohesive.injekt.injectLazy +import java.net.MalformedURLException +import java.net.URI +import java.net.URISyntaxException +import java.net.URL + +class GalleryAdder { + + private val db: DatabaseHelper by injectLazy() + + private val sourceManager: SourceManager by injectLazy() + + private val metadataHelper = MetadataHelper() + + fun addGallery(url: String, fav: Boolean = false): Manga { + val source = when(URL(url).host) { + "g.e-hentai.org", "e-hentai.org" -> EH_SOURCE_ID + "exhentai.org" -> EXH_SOURCE_ID + else -> throw MalformedURLException("Not a valid gallery URL!") + } + + val sourceObj = sourceManager.get(source) + ?: throw IllegalStateException("Could not find EH source!") + + val pathOnlyUrl = getUrlWithoutDomain(url) + + //Use manga in DB if possible, otherwise, make a new manga + val manga = db.getManga(pathOnlyUrl, source).executeAsBlocking() + ?: Manga.create(source).apply { + this.url = pathOnlyUrl + title = url + } + + //Copy basics + manga.copyFrom(sourceObj.fetchMangaDetails(manga).toBlocking().first()) + + //Apply metadata + metadataHelper.fetchEhMetadata(url, isExSource(source))?.copyTo(manga) + + if(fav) manga.favorite = true + + db.insertManga(manga).executeAsBlocking().insertedId()?.let { + manga.id = it + } + + //Fetch and copy chapters + try { + sourceObj.fetchChapterList(manga).map { + syncChaptersWithSource(db, it, manga, sourceObj) + }.toBlocking().first() + } catch (e: Exception) { + Timber.w(e, "Failed to update chapters for gallery: ${manga.title}!") + } + + return manga + } + + private fun getUrlWithoutDomain(orig: String): String { + try { + val uri = URI(orig) + var out = uri.path + if (uri.query != null) + out += "?" + uri.query + if (uri.fragment != null) + out += "#" + uri.fragment + return out + } catch (e: URISyntaxException) { + return orig + } + } +} \ No newline at end of file diff --git a/app/src/main/java/exh/StringBuilderExtensions.kt b/app/src/main/java/exh/StringBuilderExtensions.kt new file mode 100755 index 000000000..1dffedbb0 --- /dev/null +++ b/app/src/main/java/exh/StringBuilderExtensions.kt @@ -0,0 +1,3 @@ +package exh + +operator fun StringBuilder.plusAssign(other: String) { append(other) } diff --git a/app/src/main/java/exh/VerbelExpressionExtensions.kt b/app/src/main/java/exh/VerbelExpressionExtensions.kt new file mode 100755 index 000000000..12f060076 --- /dev/null +++ b/app/src/main/java/exh/VerbelExpressionExtensions.kt @@ -0,0 +1,5 @@ +package exh + +import ru.lanwen.verbalregex.VerbalExpression + +fun VerbalExpression.Builder.anyChar() = add(".")!! diff --git a/app/src/main/java/exh/metadata/MetadataHelper.kt b/app/src/main/java/exh/metadata/MetadataHelper.kt new file mode 100755 index 000000000..81150bf02 --- /dev/null +++ b/app/src/main/java/exh/metadata/MetadataHelper.kt @@ -0,0 +1,62 @@ +package exh.metadata + +import exh.* +import exh.metadata.models.ExGalleryMetadata +import exh.metadata.models.NHentaiMetadata +import exh.metadata.models.PervEdenGalleryMetadata +import exh.metadata.models.SearchableGalleryMetadata +import io.paperdb.Paper + +class MetadataHelper { + + fun writeGallery(galleryMetadata: SearchableGalleryMetadata, source: Long) + = (if(isExSource(source) || isEhSource(source)) exGalleryBook() + else if(isPervEdenSource(source)) pervEdenGalleryBook() + else if(isNhentaiSource(source)) nhentaiGalleryBook() + else null)?.write(galleryMetadata.galleryUniqueIdentifier(), galleryMetadata)!! + + fun fetchEhMetadata(url: String, exh: Boolean): ExGalleryMetadata? + = ExGalleryMetadata().let { + it.url = url + it.exh = exh + return exGalleryBook().read(it.galleryUniqueIdentifier()) + } + + fun fetchPervEdenMetadata(url: String, source: Long): PervEdenGalleryMetadata? + = PervEdenGalleryMetadata().let { + it.url = url + if(source == PERV_EDEN_EN_SOURCE_ID) + it.lang = "en" + else if(source == PERV_EDEN_IT_SOURCE_ID) + it.lang = "it" + else throw IllegalArgumentException("Invalid source id!") + return pervEdenGalleryBook().read(it.galleryUniqueIdentifier()) + } + + fun fetchNhentaiMetadata(url: String) = NHentaiMetadata().let { + it.url = url + nhentaiGalleryBook().read(it.galleryUniqueIdentifier()) + } + + fun fetchMetadata(url: String, source: Long): SearchableGalleryMetadata? { + if(isExSource(source) || isEhSource(source)) { + return fetchEhMetadata(url, isExSource(source)) + } else if(isPervEdenSource(source)) { + return fetchPervEdenMetadata(url, source) + } else if(isNhentaiSource(source)) { + return fetchNhentaiMetadata(url) + } else { + return null + } + } + + fun getAllGalleries() = exGalleryBook().allKeys.map { + exGalleryBook().read(it) + } + + fun exGalleryBook() = Paper.book("gallery-ex")!! + + fun pervEdenGalleryBook() = Paper.book("gallery-perveden")!! + + fun nhentaiGalleryBook() = Paper.book("gallery-nhentai")!! +} \ No newline at end of file diff --git a/app/src/main/java/exh/metadata/MetadataUtil.kt b/app/src/main/java/exh/metadata/MetadataUtil.kt new file mode 100755 index 000000000..73a205ea1 --- /dev/null +++ b/app/src/main/java/exh/metadata/MetadataUtil.kt @@ -0,0 +1,47 @@ +package exh.metadata + +/** + * Metadata utils + */ +fun humanReadableByteCount(bytes: Long, si: Boolean): String { + val unit = if (si) 1000 else 1024 + if (bytes < unit) return bytes.toString() + " B" + val exp = (Math.log(bytes.toDouble()) / Math.log(unit.toDouble())).toInt() + val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1] + if (si) "" else "i" + return String.format("%.1f %sB", bytes / Math.pow(unit.toDouble(), exp.toDouble()), pre) +} + +private val KB_FACTOR: Long = 1000 +private val KIB_FACTOR: Long = 1024 +private val MB_FACTOR = 1000 * KB_FACTOR +private val MIB_FACTOR = 1024 * KIB_FACTOR +private val GB_FACTOR = 1000 * MB_FACTOR +private val GIB_FACTOR = 1024 * MIB_FACTOR + +fun parseHumanReadableByteCount(arg0: String): Double? { + val spaceNdx = arg0.indexOf(" ") + val ret = java.lang.Double.parseDouble(arg0.substring(0, spaceNdx)) + when (arg0.substring(spaceNdx + 1)) { + "GB" -> return ret * GB_FACTOR + "GiB" -> return ret * GIB_FACTOR + "MB" -> return ret * MB_FACTOR + "MiB" -> return ret * MIB_FACTOR + "KB" -> return ret * KB_FACTOR + "KiB" -> return ret * KIB_FACTOR + } + return null +} + + +fun String?.nullIfBlank(): String? = if(isNullOrBlank()) + null +else + this + +fun ignore(expr: () -> T): T? { + return try { expr() } catch (t: Throwable) { null } +} + +fun Set>.forEach(action: (K, V) -> Unit) { + forEach { action(it.key, it.value) } +} \ No newline at end of file diff --git a/app/src/main/java/exh/metadata/MetdataCopier.kt b/app/src/main/java/exh/metadata/MetdataCopier.kt new file mode 100755 index 000000000..ed5744983 --- /dev/null +++ b/app/src/main/java/exh/metadata/MetdataCopier.kt @@ -0,0 +1,218 @@ +package exh.metadata + +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.online.all.EHentai +import eu.kanade.tachiyomi.source.online.all.EHentaiMetadata +import eu.kanade.tachiyomi.source.online.all.PervEden +import exh.metadata.models.* +import exh.plusAssign +import uy.kohesive.injekt.injectLazy +import java.text.SimpleDateFormat +import java.util.* + +/** + * Copies gallery metadata to a manga object + */ + +private const val EH_ARTIST_NAMESPACE = "artist" +private const val EH_AUTHOR_NAMESPACE = "author" + +private const val NHENTAI_ARTIST_NAMESPACE = "artist" +private const val NHENTAI_CATEGORIES_NAMESPACE = "category" + +private val ONGOING_SUFFIX = arrayOf( + "[ongoing]", + "(ongoing)", + "{ongoing}" +) + +val EX_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US) + +private val prefs: PreferencesHelper by injectLazy() + +fun ExGalleryMetadata.copyTo(manga: SManga) { + //TODO Find some way to do this with SManga + /*exh?.let { + manga.source = if(it) + 2 + else + 1 + }*/ + url?.let { manga.url = it } + thumbnailUrl?.let { manga.thumbnail_url = it } + + //No title bug? + val titleObj = if(prefs.useJapaneseTitle().getOrDefault()) + altTitle ?: title + else + title + titleObj?.let { manga.title = it } + + //Set artist (if we can find one) + tags[EH_ARTIST_NAMESPACE]?.let { + if(it.isNotEmpty()) manga.artist = it.joinToString(transform = Tag::name) + } + //Set author (if we can find one) + tags[EH_AUTHOR_NAMESPACE]?.let { + if(it.isNotEmpty()) manga.author = it.joinToString(transform = Tag::name) + } + //Set genre + genre?.let { manga.genre = it } + + //Try to automatically identify if it is ongoing, we try not to be too lenient here to avoid making mistakes + //We default to completed + manga.status = SManga.COMPLETED + title?.let { t -> + ONGOING_SUFFIX.find { + t.endsWith(it, ignoreCase = true) + }?.let { + manga.status = SManga.ONGOING + } + } + + //Build a nice looking description out of what we know + val titleDesc = StringBuilder() + title?.let { titleDesc += "Title: $it\n" } + altTitle?.let { titleDesc += "Alternate Title: $it\n" } + + val detailsDesc = StringBuilder() + uploader?.let { detailsDesc += "Uploader: $it\n" } + datePosted?.let { detailsDesc += "Posted: ${EX_DATE_FORMAT.format(Date(it))}\n" } + visible?.let { detailsDesc += "Visible: $it\n" } + language?.let { + detailsDesc += "Language: $it" + if(translated == true) detailsDesc += " TR" + detailsDesc += "\n" + } + size?.let { detailsDesc += "File Size: ${humanReadableByteCount(it, true)}\n" } + length?.let { detailsDesc += "Length: $it pages\n" } + favorites?.let { detailsDesc += "Favorited: $it times\n" } + averageRating?.let { + detailsDesc += "Rating: $it" + ratingCount?.let { detailsDesc += " ($it)" } + detailsDesc += "\n" + } + + val tagsDesc = buildTagsDescription(this) + + manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString()) + .filter(String::isNotBlank) + .joinToString(separator = "\n") +} + +fun PervEdenGalleryMetadata.copyTo(manga: SManga) { + url?.let { manga.url = it } + thumbnailUrl?.let { manga.thumbnail_url = it } + + val titleDesc = StringBuilder() + title?.let { + manga.title = it + titleDesc += "Title: $it\n" + } + if(altTitles.isNotEmpty()) + titleDesc += "Alternate Titles: \n" + altTitles.map { + "▪ $it" + }.joinToString(separator = "\n", postfix = "\n") + + val detailsDesc = StringBuilder() + artist?.let { + manga.artist = it + detailsDesc += "Artist: $it\n" + } + + type?.let { + manga.genre = it + detailsDesc += "Type: $it\n" + } + + status?.let { + manga.status = when(it) { + "Ongoing" -> SManga.ONGOING + "Completed", "Suspended" -> SManga.COMPLETED + else -> SManga.UNKNOWN + } + detailsDesc += "Status: $it\n" + } + + rating?.let { + detailsDesc += "Rating: %.2\n".format(it) + } + + val tagsDesc = buildTagsDescription(this) + + manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString()) + .filter(String::isNotBlank) + .joinToString(separator = "\n") +} + +fun NHentaiMetadata.copyTo(manga: SManga) { + url?.let { manga.url = it } + + //TODO next update allow this to be changed to use HD covers + if(mediaId != null) + NHentaiMetadata.typeToExtension(thumbnailImageType)?.let { + manga.thumbnail_url = "https://t.nhentai.net/galleries/$mediaId/thumb.$it" + } + + manga.title = englishTitle ?: japaneseTitle ?: shortTitle!! + + //Set artist (if we can find one) + tags[NHENTAI_ARTIST_NAMESPACE]?.let { + if(it.isNotEmpty()) manga.artist = it.joinToString(transform = Tag::name) + } + + tags[NHENTAI_CATEGORIES_NAMESPACE]?.let { + if(it.isNotEmpty()) manga.genre = it.joinToString(transform = Tag::name) + } + + //Try to automatically identify if it is ongoing, we try not to be too lenient here to avoid making mistakes + //We default to completed + manga.status = SManga.COMPLETED + englishTitle?.let { t -> + ONGOING_SUFFIX.find { + t.endsWith(it, ignoreCase = true) + }?.let { + manga.status = SManga.ONGOING + } + } + + val titleDesc = StringBuilder() + englishTitle?.let { titleDesc += "English Title: $it\n" } + japaneseTitle?.let { titleDesc += "Japanese Title: $it\n" } + shortTitle?.let { titleDesc += "Short Title: $it\n" } + + val detailsDesc = StringBuilder() + uploadDate?.let { detailsDesc += "Upload Date: ${EX_DATE_FORMAT.format(Date(it))}\n" } + pageImageTypes.size.let { detailsDesc += "Length: $it pages\n" } + favoritesCount?.let { detailsDesc += "Favorited: $it times\n" } + scanlator?.nullIfBlank()?.let { detailsDesc += "Scanlator: $it\n" } + + val tagsDesc = buildTagsDescription(this) + + manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString()) + .filter(String::isNotBlank) + .joinToString(separator = "\n") +} + +fun SearchableGalleryMetadata.genericCopyTo(manga: SManga): Boolean { + when(this) { + is ExGalleryMetadata -> this.copyTo(manga) + is PervEdenGalleryMetadata -> this.copyTo(manga) + is NHentaiMetadata -> this.copyTo(manga) + else -> return false + } + return true +} + +private fun buildTagsDescription(metadata: SearchableGalleryMetadata) + = StringBuilder("Tags:\n").apply { + //BiConsumer only available in Java 8, don't bother calling forEach directly on 'tags' + metadata.tags.entries.forEach { namespace, tags -> + if (tags.isNotEmpty()) { + val joinedTags = tags.joinToString(separator = " ", transform = { "<${it.name}>" }) + this += "▪ $namespace: $joinedTags\n" + } + } + } diff --git a/app/src/main/java/exh/metadata/models/ExGalleryMetadata.kt b/app/src/main/java/exh/metadata/models/ExGalleryMetadata.kt new file mode 100755 index 000000000..2ce181523 --- /dev/null +++ b/app/src/main/java/exh/metadata/models/ExGalleryMetadata.kt @@ -0,0 +1,51 @@ +package exh.metadata.models + +import android.net.Uri +import java.util.* + +/** + * Gallery metadata storage model + */ + +class ExGalleryMetadata : SearchableGalleryMetadata() { + var url: String? = null + + var exh: Boolean? = null + + var thumbnailUrl: String? = null + + var title: String? = null + var altTitle: String? = null + + var genre: String? = null + + var datePosted: Long? = null + var parent: String? = null + var visible: String? = null //Not a boolean + var language: String? = null + var translated: Boolean? = null + var size: Long? = null + var length: Int? = null + var favorites: Int? = null + var ratingCount: Int? = null + var averageRating: Double? = null + + override fun getTitles() = listOf(title, altTitle).filterNotNull() + + private fun splitGalleryUrl() + = url?.let { + Uri.parse(it).pathSegments.filterNot(String::isNullOrBlank) + } + + fun galleryId() = splitGalleryUrl()?.let { it[it.size - 2] } + + fun galleryToken() = + splitGalleryUrl()?.last() + + override fun galleryUniqueIdentifier() = exh?.let { exh -> + url?.let { + //Fuck, this should be EXH and EH but it's too late to change it now... + "${if(exh) "EXH" else "EX"}-${galleryId()}-${galleryToken()}" + } + } +} \ No newline at end of file diff --git a/app/src/main/java/exh/metadata/models/NHentaiMetadata.kt b/app/src/main/java/exh/metadata/models/NHentaiMetadata.kt new file mode 100755 index 000000000..52c7f2000 --- /dev/null +++ b/app/src/main/java/exh/metadata/models/NHentaiMetadata.kt @@ -0,0 +1,48 @@ +package exh.metadata.models + +/** + * NHentai metadata + */ + +class NHentaiMetadata : SearchableGalleryMetadata() { + + var id: Long? = null + + var url get() = id?.let { "$BASE_URL/g/$it" } + set(a) { + a?.let { + id = a.split("/").last().toLong() + } + } + + var uploadDate: Long? = null + + var favoritesCount: Long? = null + + var mediaId: String? = null + + var japaneseTitle: String? = null + var englishTitle: String? = null + var shortTitle: String? = null + + var coverImageType: String? = null + var pageImageTypes: MutableList = mutableListOf() + var thumbnailImageType: String? = null + + var scanlator: String? = null + + override fun galleryUniqueIdentifier(): String? = "NHENTAI-$id" + + override fun getTitles() = listOf(japaneseTitle, englishTitle, shortTitle).filterNotNull() + + companion object { + val BASE_URL = "https://nhentai.net" + + fun typeToExtension(t: String?) = + when(t) { + "p" -> "png" + "j" -> "jpg" + else -> null + } + } +} diff --git a/app/src/main/java/exh/metadata/models/PervEdenGalleryMetadata.kt b/app/src/main/java/exh/metadata/models/PervEdenGalleryMetadata.kt new file mode 100755 index 000000000..b9770aa7a --- /dev/null +++ b/app/src/main/java/exh/metadata/models/PervEdenGalleryMetadata.kt @@ -0,0 +1,32 @@ +package exh.metadata.models + +import android.net.Uri + +class PervEdenGalleryMetadata : SearchableGalleryMetadata() { + var url: String? = null + var thumbnailUrl: String? = null + + var title: String? = null + var altTitles: MutableList = mutableListOf() + + var artist: String? = null + + var type: String? = null + + var rating: Float? = null + + var status: String? = null + + var lang: String? = null + + override fun getTitles() = listOf(title).plus(altTitles).filterNotNull() + + private fun splitGalleryUrl() + = url?.let { + Uri.parse(it).pathSegments.filterNot(String::isNullOrBlank) + } + + override fun galleryUniqueIdentifier() = splitGalleryUrl()?.let { + "PERVEDEN-${lang?.toUpperCase()}-${it.last()}" + } +} diff --git a/app/src/main/java/exh/metadata/models/SearchableGalleryMetadata.kt b/app/src/main/java/exh/metadata/models/SearchableGalleryMetadata.kt new file mode 100755 index 000000000..bc33eef24 --- /dev/null +++ b/app/src/main/java/exh/metadata/models/SearchableGalleryMetadata.kt @@ -0,0 +1,18 @@ +package exh.metadata.models + +import java.util.ArrayList +import java.util.HashMap + +/** + * A gallery that can be searched using the EH search engine + */ +abstract class SearchableGalleryMetadata { + var uploader: String? = null + + //Being specific about which classes are used in generics to make deserialization easier + val tags: HashMap> = HashMap() + + abstract fun galleryUniqueIdentifier(): String? + + abstract fun getTitles(): List +} \ No newline at end of file diff --git a/app/src/main/java/exh/metadata/models/Tag.kt b/app/src/main/java/exh/metadata/models/Tag.kt new file mode 100755 index 000000000..9b78b0c35 --- /dev/null +++ b/app/src/main/java/exh/metadata/models/Tag.kt @@ -0,0 +1,7 @@ +package exh.metadata.models + +/** + * Simple tag model + */ + +data class Tag(var name: String, var light: Boolean) diff --git a/app/src/main/java/exh/search/MultiWildcard.kt b/app/src/main/java/exh/search/MultiWildcard.kt new file mode 100755 index 000000000..b5cecbe57 --- /dev/null +++ b/app/src/main/java/exh/search/MultiWildcard.kt @@ -0,0 +1,3 @@ +package exh.search + +class MultiWildcard : TextComponent() diff --git a/app/src/main/java/exh/search/Namespace.kt b/app/src/main/java/exh/search/Namespace.kt new file mode 100755 index 000000000..e23a0e722 --- /dev/null +++ b/app/src/main/java/exh/search/Namespace.kt @@ -0,0 +1,4 @@ +package exh.search + +class Namespace(var namespace: String, + var tag: Text? = null) : QueryComponent() diff --git a/app/src/main/java/exh/search/QueryComponent.kt b/app/src/main/java/exh/search/QueryComponent.kt new file mode 100755 index 000000000..bfc34eea0 --- /dev/null +++ b/app/src/main/java/exh/search/QueryComponent.kt @@ -0,0 +1,6 @@ +package exh.search + +open class QueryComponent { + var excluded = false + var exact = false +} \ No newline at end of file diff --git a/app/src/main/java/exh/search/SearchEngine.kt b/app/src/main/java/exh/search/SearchEngine.kt new file mode 100755 index 000000000..eb4d6f5a2 --- /dev/null +++ b/app/src/main/java/exh/search/SearchEngine.kt @@ -0,0 +1,150 @@ +package exh.search + +import exh.metadata.models.SearchableGalleryMetadata +import exh.metadata.models.Tag + +class SearchEngine { + + private val queryCache = mutableMapOf>() + + fun matches(metadata: SearchableGalleryMetadata, query: List): Boolean { + + fun matchTagList(tags: Sequence, + component: Text): Boolean { + //Match tags + val tagMatcher = if(!component.exact) + component.asLenientRegex() + else + component.asRegex() + //Match beginning of tag + if (tags.find { + tagMatcher.testExact(it.name) + } != null) { + if(component.excluded) return false + } else { + //No tag matched for this component + return false + } + return true + } + + val cachedTitles = metadata.getTitles().map(String::toLowerCase) + + for(component in query) { + if(component is Text) { + //Match title + if (cachedTitles.find { component.asRegex().test(it) } != null) { + continue + } + //Match tags + if(!matchTagList(metadata.tags.entries.asSequence().flatMap { it.value.asSequence() }, + component)) return false + } else if(component is Namespace) { + if(component.namespace == "uploader") { + //Match uploader + if(!component.tag?.rawTextOnly().equals(metadata.uploader, + ignoreCase = true)) { + return false + } + } else { + if(component.tag!!.components.size > 0) { + //Match namespace + val ns = metadata.tags.entries.asSequence().filter { + it.key == component.namespace + }.flatMap { it.value.asSequence() } + //Match tags + if (!matchTagList(ns, component.tag!!)) + return false + } else { + //Perform namespace search + val hasNs = metadata.tags.entries.find { + it.key == component.namespace + } != null + + if(hasNs && component.excluded) + return false + else if(!hasNs && !component.excluded) + return false + } + } + } + } + return true + } + + fun parseQuery(query: String) = queryCache.getOrPut(query, { + val res = mutableListOf() + + var inQuotes = false + val queuedRawText = StringBuilder() + val queuedText = mutableListOf() + var namespace: Namespace? = null + + var nextIsExcluded = false + var nextIsExact = false + + fun flushText() { + if(queuedRawText.isNotEmpty()) { + queuedText += StringTextComponent(queuedRawText.toString()) + queuedRawText.setLength(0) + } + } + + fun flushToText() = Text().apply { + components += queuedText + queuedText.clear() + } + + fun flushAll() { + flushText() + if (queuedText.isNotEmpty() || namespace != null) { + val component = namespace?.apply { + tag = flushToText() + namespace = null + } ?: flushToText() + component.excluded = nextIsExcluded + component.exact = nextIsExact + res += component + } + } + + for(char in query.toLowerCase()) { + if(char == '"') { + inQuotes = !inQuotes + } else if(char == '?' || char == '_') { + flushText() + queuedText.add(SingleWildcard()) + } else if(char == '*' || char == '%') { + flushText() + queuedText.add(MultiWildcard()) + } else if(char == '-') { + nextIsExcluded = true + } else if(char == '$') { + nextIsExact = true + } else if(char == ':') { + flushText() + var flushed = flushToText().rawTextOnly() + //Map tag aliases + flushed = when(flushed) { + "a" -> "artist" + "c", "char" -> "character" + "f" -> "female" + "g", "creator", "circle" -> "group" + "l", "lang" -> "language" + "m" -> "male" + "p", "series" -> "parody" + "r" -> "reclass" + else -> flushed + } + namespace = Namespace(flushed, null) + } else if(char == ' ' && !inQuotes) { + flushAll() + } else { + queuedRawText.append(char) + } + } + flushAll() + + res + }) +} diff --git a/app/src/main/java/exh/search/SingleWildcard.kt b/app/src/main/java/exh/search/SingleWildcard.kt new file mode 100755 index 000000000..503d751e1 --- /dev/null +++ b/app/src/main/java/exh/search/SingleWildcard.kt @@ -0,0 +1,3 @@ +package exh.search + +class SingleWildcard : TextComponent() diff --git a/app/src/main/java/exh/search/StringTextComponent.kt b/app/src/main/java/exh/search/StringTextComponent.kt new file mode 100755 index 000000000..736f8c225 --- /dev/null +++ b/app/src/main/java/exh/search/StringTextComponent.kt @@ -0,0 +1,3 @@ +package exh.search + +class StringTextComponent(val value: String) : TextComponent() diff --git a/app/src/main/java/exh/search/Text.kt b/app/src/main/java/exh/search/Text.kt new file mode 100755 index 000000000..5bccb2671 --- /dev/null +++ b/app/src/main/java/exh/search/Text.kt @@ -0,0 +1,49 @@ +package exh.search + +import exh.anyChar +import ru.lanwen.verbalregex.VerbalExpression + +class Text: QueryComponent() { + val components = mutableListOf() + + private var regex: VerbalExpression? = null + private var lenientRegex: VerbalExpression? = null + private var rawText: String? = null + + fun asRegex(): VerbalExpression { + if(regex == null) { + regex = baseBuilder().build() + } + return regex!! + } + + fun asLenientRegex(): VerbalExpression { + if(lenientRegex == null) { + lenientRegex = baseBuilder().anything().build() + } + return lenientRegex!! + } + + fun baseBuilder(): VerbalExpression.Builder { + val builder = VerbalExpression.regex() + for(component in components) { + when(component) { + is StringTextComponent -> builder.then(component.value) + is SingleWildcard -> builder.anyChar() + is MultiWildcard -> builder.anything() + } + } + return builder + } + + fun rawTextOnly() = if(rawText != null) + rawText!! + else { + rawText = components + .filter { it is StringTextComponent } + .joinToString(separator = "", transform = { + (it as StringTextComponent).value + }) + rawText!! + } +} diff --git a/app/src/main/java/exh/search/TextComponent.kt b/app/src/main/java/exh/search/TextComponent.kt new file mode 100755 index 000000000..9b50051f5 --- /dev/null +++ b/app/src/main/java/exh/search/TextComponent.kt @@ -0,0 +1,3 @@ +package exh.search + +open class TextComponent diff --git a/app/src/main/java/exh/ui/batchadd/BatchAddFragment.kt b/app/src/main/java/exh/ui/batchadd/BatchAddFragment.kt new file mode 100755 index 000000000..a4d994d0b --- /dev/null +++ b/app/src/main/java/exh/ui/batchadd/BatchAddFragment.kt @@ -0,0 +1,131 @@ +package exh.ui.batchadd + +import android.content.pm.ActivityInfo +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.afollestad.materialdialogs.MaterialDialog +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.ui.base.fragment.BaseFragment +import exh.GalleryAdder +import exh.metadata.nullIfBlank +import kotlinx.android.synthetic.main.eh_fragment_batch_add.* +import timber.log.Timber +import kotlin.concurrent.thread + +/** + * LoginActivity + */ + +class BatchAddFragment : BaseFragment() { + + private val galleryAdder by lazy { GalleryAdder() } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedState: Bundle?) + = inflater.inflate(R.layout.eh_fragment_batch_add, container, false)!! + + override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { + setToolbarTitle("Batch add") + + setup() + } + + fun setup() { + btn_add_galleries.setOnClickListener { + val galleries = galleries_box.text.toString() + //Check text box has content + if(galleries.isNullOrBlank()) { + noGalleriesSpecified() + return@setOnClickListener + } + + //Too lazy to actually deal with orientation changes + activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR + + val splitGalleries = galleries.split("\n").map { + it.trim().nullIfBlank() + }.filterNotNull() + + val dialog = MaterialDialog.Builder(context) + .title("Adding galleries...") + .progress(false, splitGalleries.size, true) + .cancelable(false) + .canceledOnTouchOutside(false) + .show() + + val succeeded = mutableListOf() + val failed = mutableListOf() + + thread { + splitGalleries.forEachIndexed { i, s -> + activity.runOnUiThread { + dialog.setContent("Processing: $s") + } + if(addGallery(s)) { + succeeded.add(s) + } else { + failed.add(s) + } + activity.runOnUiThread { + dialog.setProgress(i + 1) + } + } + + //Show report + val succeededCount = succeeded.size + val failedCount = failed.size + + if(succeeded.isEmpty()) succeeded += "None" + if(failed.isEmpty()) failed += "None" + val succeededReport = succeeded.joinToString(separator = "\n", prefix = "Added:\n") + val failedReport = failed.joinToString(separator = "\n", prefix = "Failed:\n") + + val summary = "Summary:\nAdded: $succeededCount gallerie(s)\nFailed: $failedCount gallerie(s)" + + val report = listOf(succeededReport, failedReport, summary).joinToString(separator = "\n\n") + + activity.runOnUiThread { + //Enable orientation changes again + activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR + + dialog.dismiss() + + MaterialDialog.Builder(context) + .title("Batch add report") + .content(report) + .positiveText("Ok") + .cancelable(true) + .canceledOnTouchOutside(true) + .show() + } + } + + } + } + + fun addGallery(url: String): Boolean { + try { + galleryAdder.addGallery(url, true) + } catch(t: Throwable) { + Timber.e(t, "Could not add gallery!") + return false + } + return true + } + + fun noGalleriesSpecified() { + MaterialDialog.Builder(context) + .title("No galleries to add!") + .content("You must specify at least one gallery to add!") + .positiveText("Ok") + .onPositive { materialDialog, _ -> materialDialog.dismiss() } + .cancelable(true) + .canceledOnTouchOutside(true) + .show() + } + + companion object { + fun newInstance() = BatchAddFragment() + } +} diff --git a/app/src/main/java/exh/ui/intercept/InterceptActivity.kt b/app/src/main/java/exh/ui/intercept/InterceptActivity.kt new file mode 100755 index 000000000..d46811b7d --- /dev/null +++ b/app/src/main/java/exh/ui/intercept/InterceptActivity.kt @@ -0,0 +1,82 @@ +package exh.ui.intercept + +import android.content.Intent +import android.os.Bundle +import android.view.MenuItem +import com.afollestad.materialdialogs.MaterialDialog +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.ui.base.activity.BaseActivity +import eu.kanade.tachiyomi.ui.manga.MangaActivity +import exh.GalleryAdder +import kotlinx.android.synthetic.main.toolbar.* +import timber.log.Timber +import kotlin.concurrent.thread + +class InterceptActivity : BaseActivity() { + + private val galleryAdder = GalleryAdder() + + var finished = false + + override fun onCreate(savedInstanceState: Bundle?) { + setAppTheme() + super.onCreate(savedInstanceState) + setContentView(R.layout.eh_activity_intercept) + + setupToolbar(toolbar, backNavigation = false) + + if(savedInstanceState == null) + thread { setup() } + } + + fun setup() { + try { + processLink() + } catch(t: Throwable) { + Timber.e(t, "Could not intercept link!") + if(!finished) + runOnUiThread { + MaterialDialog.Builder(this) + .title("Error") + .content("Could not load this gallery!") + .cancelable(true) + .canceledOnTouchOutside(true) + .cancelListener { onBackPressed() } + .positiveText("Ok") + .onPositive { _, _ -> onBackPressed() } + .dismissListener { onBackPressed() } + .show() + } + } + } + + fun processLink() { + if(Intent.ACTION_VIEW == intent.action) { + val manga = galleryAdder.addGallery(intent.dataString) + + if(!finished) + startActivity(MangaActivity.newIntent(this, manga, true)) + onBackPressed() + } + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + android.R.id.home -> onBackPressed() + else -> return super.onOptionsItemSelected(item) + } + return true + } + + override fun onBackPressed() { + if(!finished) + runOnUiThread { + super.onBackPressed() + } + } + + override fun onStop() { + super.onStop() + finished = true + } +} diff --git a/app/src/main/java/exh/ui/lock/LockActivity.kt b/app/src/main/java/exh/ui/lock/LockActivity.kt new file mode 100755 index 000000000..a8e428541 --- /dev/null +++ b/app/src/main/java/exh/ui/lock/LockActivity.kt @@ -0,0 +1,60 @@ +package exh.ui.lock + +import android.os.Bundle +import com.afollestad.materialdialogs.MaterialDialog +import com.andrognito.pinlockview.PinLockListener +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.ui.base.activity.BaseActivity +import kotlinx.android.synthetic.main.activity_lock.* +import uy.kohesive.injekt.injectLazy + +class LockActivity : BaseActivity() { + + val prefs: PreferencesHelper by injectLazy() + + override fun onCreate(savedInstanceState: Bundle?) { + disableLock = true + + setTheme(R.style.Theme_Tachiyomi_Dark) + super.onCreate(savedInstanceState) + + if(!lockEnabled(prefs)) { + finish() + return + } + + setContentView(R.layout.activity_lock) + + pin_lock_view.attachIndicatorDots(indicator_dots) + + pin_lock_view.pinLength = prefs.lockLength().getOrDefault() + pin_lock_view.setPinLockListener(object : PinLockListener { + override fun onEmpty() {} + + override fun onComplete(pin: String) { + if(sha512(pin, prefs.lockSalt().get()!!) == prefs.lockHash().get()) { + //Yay! + finish() + } else { + MaterialDialog.Builder(this@LockActivity) + .title("PIN code incorrect") + .content("The PIN code you entered is incorrect. Please try again.") + .cancelable(true) + .canceledOnTouchOutside(true) + .positiveText("Ok") + .autoDismiss(true) + .show() + pin_lock_view.resetPinLockView() + } + } + + override fun onPinChange(pinLength: Int, intermediatePin: String?) {} + }) + } + + override fun onBackPressed() { + moveTaskToBack(true) + } +} diff --git a/app/src/main/java/exh/ui/lock/LockPreference.kt b/app/src/main/java/exh/ui/lock/LockPreference.kt new file mode 100755 index 000000000..cc7da2646 --- /dev/null +++ b/app/src/main/java/exh/ui/lock/LockPreference.kt @@ -0,0 +1,85 @@ +package exh.ui.lock + +import android.content.Context +import android.support.v7.preference.Preference +import android.text.InputType +import android.util.AttributeSet +import com.afollestad.materialdialogs.MaterialDialog +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import rx.Observable +import rx.android.schedulers.AndroidSchedulers +import rx.schedulers.Schedulers +import uy.kohesive.injekt.injectLazy +import java.math.BigInteger +import java.security.SecureRandom + +class LockPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : + Preference(context, attrs) { + + val secureRandom by lazy { SecureRandom() } + + val prefs: PreferencesHelper by injectLazy() + + override fun onAttached() { + super.onAttached() + updateSummary() + } + + fun updateSummary() { + if(lockEnabled(prefs)) { + summary = "Application is locked" + } else { + summary = "Application is not locked, tap to lock" + } + } + + override fun onClick() { + super.onClick() + if(!notifyLockSecurity(context)) { + MaterialDialog.Builder(context) + .title("Lock application") + .content("Enter a pin to lock the application. Enter nothing to disable the pin lock.") + .inputRangeRes(0, 10, R.color.material_red_500) + .inputType(InputType.TYPE_CLASS_NUMBER) + .input("", "", { _, c -> + val progressDialog = MaterialDialog.Builder(context) + .title("Saving password") + .progress(true, 0) + .cancelable(false) + .show() + Observable.fromCallable { + savePassword(c.toString()) + }.subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + progressDialog.dismiss() + updateSummary() + } + }) + .negativeText("Cancel") + .autoDismiss(true) + .cancelable(true) + .canceledOnTouchOutside(true) + .show() + } + } + + fun savePassword(password: String) { + val salt: String? + val hash: String? + val length: Int + if(password.isEmpty()) { + salt = null + hash = null + length = -1 + } else { + salt = BigInteger(130, secureRandom).toString(32) + hash = sha512(password, salt) + length = password.length + } + prefs.lockSalt().set(salt) + prefs.lockHash().set(hash) + prefs.lockLength().set(length) + } +} diff --git a/app/src/main/java/exh/ui/lock/LockUtils.kt b/app/src/main/java/exh/ui/lock/LockUtils.kt new file mode 100755 index 000000000..e2e88897b --- /dev/null +++ b/app/src/main/java/exh/ui/lock/LockUtils.kt @@ -0,0 +1,91 @@ +package exh.ui.lock + +import android.annotation.TargetApi +import android.app.Activity +import android.app.AppOpsManager +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build +import android.provider.Settings +import com.afollestad.materialdialogs.MaterialDialog +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.data.preference.getOrDefault +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get +import java.security.MessageDigest +import kotlin.experimental.and + + +/** + * Password hashing utils + */ + +/** + * Yes, I know SHA512 is fast, but bcrypt on mobile devices is too slow apparently + */ +fun sha512(passwordToHash: String, salt: String): String { + val md = MessageDigest.getInstance("SHA-512") + md.update(salt.toByteArray(charset("UTF-8"))) + val bytes = md.digest(passwordToHash.toByteArray(charset("UTF-8"))) + val sb = StringBuilder() + for (i in bytes.indices) { + sb.append(Integer.toString((bytes[i] and 0xff.toByte()) + 0x100, 16).substring(1)) + } + return sb.toString() +} + +/** + * Check if lock is enabled + */ +fun lockEnabled(prefs: PreferencesHelper = Injekt.get()) + = prefs.lockHash().get() != null + && prefs.lockSalt().get() != null + && prefs.lockLength().getOrDefault() != -1 + +/** + * Lock the screen + */ +fun showLockActivity(activity: Activity) { + activity.startActivity(Intent(activity, LockActivity::class.java)) +} + +/** + * Check if the lock will function properly + * + * @return true if action is required, false if lock is working properly + */ +fun notifyLockSecurity(context: Context): Boolean { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !hasAccessToUsageStats(context)) { + MaterialDialog.Builder(context) + .title("Permission required") + .content("${context.getString(R.string.app_name)} requires the usage stats permission to detect when you leave the app. " + + "This is required for the application lock to function properly. " + + "Press OK to grant this permission now.") + .negativeText("Cancel") + .positiveText("Ok") + .onPositive { _, _ -> + context.startActivity(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)) + } + .autoDismiss(true) + .cancelable(false) + .show() + return true + } else { + return false + } +} + +@TargetApi(Build.VERSION_CODES.LOLLIPOP) +fun hasAccessToUsageStats(context: Context): Boolean { + try { + val packageManager = context.packageManager + val applicationInfo = packageManager.getApplicationInfo(context.packageName, 0) + val appOpsManager = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager + val mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName) + return (mode == AppOpsManager.MODE_ALLOWED) + } catch (e: PackageManager.NameNotFoundException) { + return false + } +} diff --git a/app/src/main/java/exh/ui/login/LoginActivity.kt b/app/src/main/java/exh/ui/login/LoginActivity.kt new file mode 100755 index 000000000..a205b50ec --- /dev/null +++ b/app/src/main/java/exh/ui/login/LoginActivity.kt @@ -0,0 +1,218 @@ +package exh.ui.login + +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.view.MenuItem +import android.webkit.CookieManager +import android.webkit.WebView +import android.webkit.WebViewClient +import com.afollestad.materialdialogs.MaterialDialog +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.source.SourceManager +import eu.kanade.tachiyomi.source.online.all.EHentai +import eu.kanade.tachiyomi.ui.base.activity.BaseActivity +import exh.EXH_SOURCE_ID +import kotlinx.android.synthetic.main.eh_activity_login.* +import kotlinx.android.synthetic.main.toolbar.* +import rx.Observable +import rx.android.schedulers.AndroidSchedulers +import rx.schedulers.Schedulers +import timber.log.Timber +import uy.kohesive.injekt.injectLazy +import java.net.HttpCookie + +/** + * LoginActivity + */ + +class LoginActivity : BaseActivity() { + + val preferenceManager: PreferencesHelper by injectLazy() + + val sourceManager: SourceManager by injectLazy() + + override fun onCreate(savedInstanceState: Bundle?) { + setAppTheme() + super.onCreate(savedInstanceState) + setContentView(R.layout.eh_activity_login) + + setup() + + setupToolbar(toolbar, backNavigation = false) + } + + fun setup() { + btn_cancel.setOnClickListener { onBackPressed() } + btn_recheck.setOnClickListener { webview.loadUrl("http://exhentai.org/") } + + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + CookieManager.getInstance().removeAllCookies { + runOnUiThread { + startWebview() + } + } + } else { + CookieManager.getInstance().removeAllCookie() + startWebview() + } + } + + fun startWebview() { + webview.settings.javaScriptEnabled = true + webview.settings.domStorageEnabled = true + + webview.loadUrl("https://forums.e-hentai.org/index.php?act=Login") + + webview.setWebViewClient(object : WebViewClient() { + override fun onPageFinished(view: WebView, url: String) { + super.onPageFinished(view, url) + Timber.d(url) + val parsedUrl = Uri.parse(url) + if(parsedUrl.host.equals("forums.e-hentai.org", ignoreCase = true)) { + //Hide distracting content + view.loadUrl(HIDE_JS) + + //Check login result + if(parsedUrl.getQueryParameter("code")?.toInt() != 0) { + if(checkLoginCookies(url)) view.loadUrl("http://exhentai.org/") + } + } else if(parsedUrl.host.equals("exhentai.org", ignoreCase = true)) { + //At ExHentai, check that everything worked out... + if(applyExHentaiCookies(url)) { + preferenceManager.enableExhentai().set(true) + finishLogin() + } + } + } + }) + } + + fun finishLogin() { + val progressDialog = MaterialDialog.Builder(this) + .title("Finalizing login") + .progress(true, 0) + .content("Please wait...") + .cancelable(false) + .show() + + val eh = sourceManager + .getOnlineSources() + .find { it.id == EXH_SOURCE_ID } as EHentai + Observable.fromCallable { + //I honestly have no idea why we need to call this twice, but it works, so whatever + try { + eh.fetchFavorites() + } catch(ignored: Exception) {} + try { + eh.fetchFavorites() + } catch(ignored: Exception) {} + }.subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + progressDialog.dismiss() + onBackPressed() + } + } + + /** + * Check if we are logged in + */ + fun checkLoginCookies(url: String): Boolean { + getCookies(url)?.let { parsed -> + return parsed.filter { + (it.name.equals(MEMBER_ID_COOKIE, ignoreCase = true) + || it.name.equals(PASS_HASH_COOKIE, ignoreCase = true)) + && it.value.isNotBlank() + }.count() >= 2 + } + return false + } + + /** + * Parse cookies at ExHentai + */ + fun applyExHentaiCookies(url: String): Boolean { + getCookies(url)?.let { parsed -> + + var memberId: String? = null + var passHash: String? = null + var igneous: String? = null + + parsed.forEach { + when (it.name.toLowerCase()) { + MEMBER_ID_COOKIE -> memberId = it.value + PASS_HASH_COOKIE -> passHash = it.value + IGNEOUS_COOKIE -> igneous = it.value + } + } + + //Missing a cookie + if (memberId == null || passHash == null || igneous == null) return false + + //Update prefs + preferenceManager.memberIdVal().set(memberId) + preferenceManager.passHashVal().set(passHash) + preferenceManager.igneousVal().set(igneous) + + return true + } + return false + } + + fun getCookies(url: String): List? + = CookieManager.getInstance().getCookie(url)?.let { + it.split("; ").flatMap { + HttpCookie.parse(it) + } + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + android.R.id.home -> onBackPressed() + else -> return super.onOptionsItemSelected(item) + } + return true + } + + companion object { + const val MEMBER_ID_COOKIE = "ipb_member_id" + const val PASS_HASH_COOKIE = "ipb_pass_hash" + const val IGNEOUS_COOKIE = "igneous" + + const val HIDE_JS = """ + javascript:(function () { + document.getElementsByTagName('body')[0].style.visibility = 'hidden'; + document.getElementsByName('submit')[0].style.visibility = 'visible'; + document.querySelector('td[width="60%"][valign="top"]').style.visibility = 'visible'; + + function hide(e) {if(e !== null && e !== undefined) e.style.display = 'none';} + + hide(document.querySelector(".errorwrap")); + hide(document.querySelector('td[width="40%"][valign="top"]')); + var child = document.querySelector(".page").querySelector('div'); + child.style.padding = null; + var ft = child.querySelectorAll('table'); + var fd = child.parentNode.querySelectorAll('div > div'); + var fh = document.querySelector('#border').querySelectorAll('td > table'); + hide(ft[0]); + hide(ft[1]); + hide(fd[1]); + hide(fd[2]); + hide(child.querySelector('br')); + var error = document.querySelector(".page > div > .borderwrap"); + if(error !== null) error.style.visibility = 'visible'; + hide(fh[0]); + hide(fh[1]); + hide(document.querySelector("#gfooter")); + hide(document.querySelector(".copyright")); + document.querySelectorAll("td").forEach(function(e) { + e.style.color = "white"; + }); + var pc = document.querySelector(".postcolor"); + if(pc !== null) pc.style.color = "#26353F"; + })() + """ + } +} diff --git a/app/src/main/java/exh/ui/migration/MetadataFetchDialog.kt b/app/src/main/java/exh/ui/migration/MetadataFetchDialog.kt new file mode 100755 index 000000000..75b72e165 --- /dev/null +++ b/app/src/main/java/exh/ui/migration/MetadataFetchDialog.kt @@ -0,0 +1,136 @@ +package exh.ui.migration + +import android.app.Activity +import android.content.pm.ActivityInfo +import android.text.Html +import com.afollestad.materialdialogs.MaterialDialog +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.database.DatabaseHelper +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.source.SourceManager +import eu.kanade.tachiyomi.source.online.all.EHentai +import exh.isExSource +import exh.isLewdSource +import exh.metadata.MetadataHelper +import exh.metadata.copyTo +import exh.metadata.genericCopyTo +import timber.log.Timber +import uy.kohesive.injekt.injectLazy +import kotlin.concurrent.thread + +class MetadataFetchDialog { + + val metadataHelper by lazy { MetadataHelper() } + + val db: DatabaseHelper by injectLazy() + + val sourceManager: SourceManager by injectLazy() + + val preferenceHelper: PreferencesHelper by injectLazy() + + fun show(context: Activity) { + //Too lazy to actually deal with orientation changes + context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR + + val progressDialog = MaterialDialog.Builder(context) + .title("Fetching library metadata") + .content("Preparing library") + .progress(false, 0, true) + .cancelable(false) + .canceledOnTouchOutside(false) + .show() + + thread { + db.deleteMangasNotInLibrary().executeAsBlocking() + + val libraryMangas = db.getLibraryMangas() + .executeAsBlocking() + .filter { + isLewdSource(it.source) + && metadataHelper.fetchMetadata(it.url, it.source) == null + } + + context.runOnUiThread { + progressDialog.maxProgress = libraryMangas.size + } + + //Actual metadata fetch code + libraryMangas.forEachIndexed { i, manga -> + context.runOnUiThread { + progressDialog.setContent("Processing: ${manga.title}") + progressDialog.setProgress(i + 1) + } + try { + val source = sourceManager.get(manga.source) + source?.let { + manga.copyFrom(it.fetchMangaDetails(manga).toBlocking().first()) + metadataHelper.fetchMetadata(manga.url, manga.source)?.genericCopyTo(manga) + } + } catch(t: Throwable) { + Timber.e(t, "Could not migrate manga!") + } + } + + context.runOnUiThread { + progressDialog.dismiss() + + //Enable orientation changes again + context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR + + displayMigrationComplete(context) + } + } + } + + fun askMigration(activity: Activity) { + var extra = "" + db.getLibraryMangas().asRxSingle().subscribe { + //Not logged in but have ExHentai galleries + if(!preferenceHelper.enableExhentai().getOrDefault()) { + it.find { isExSource(it.source) }?.let { + extra = "If you use ExHentai, please log in first before fetching your library metadata!

" + } + } + activity.runOnUiThread { + MaterialDialog.Builder(activity) + .title("Fetch library metadata") + .content(Html.fromHtml("You need to fetch your library's metadata before tag searching in the library will function.

" + + "This process may take a long time depending on your library size and will also use up a significant amount of internet bandwidth.

" + + extra + + "This process can be done later if required.")) + .positiveText("Migrate") + .negativeText("Later") + .onPositive { _, _ -> show(activity) } + .onNegative({ _, _ -> adviseMigrationLater(activity) }) + .cancelable(false) + .canceledOnTouchOutside(false) + .dismissListener { + preferenceHelper.migrateLibraryAsked().set(true) + }.show() + } + } + + } + + fun adviseMigrationLater(activity: Activity) { + MaterialDialog.Builder(activity) + .title("Metadata fetch canceled") + .content("Library metadata fetch has been canceled.\n\n" + + "You can run this operation later by going to: Settings > E-Hentai > Migrate library metadata") + .positiveText("Ok") + .cancelable(true) + .canceledOnTouchOutside(true) + .show() + } + + fun displayMigrationComplete(activity: Activity) { + MaterialDialog.Builder(activity) + .title("Migration complete") + .content("${activity.getString(R.string.app_name)} is now ready for use!") + .positiveText("Ok") + .cancelable(true) + .canceledOnTouchOutside(true) + .show() + } +} diff --git a/app/src/main/java/exh/ui/migration/MigrationStatus.kt b/app/src/main/java/exh/ui/migration/MigrationStatus.kt new file mode 100755 index 000000000..1fa3aa5cf --- /dev/null +++ b/app/src/main/java/exh/ui/migration/MigrationStatus.kt @@ -0,0 +1,16 @@ +package exh.ui.migration + +class MigrationStatus { + companion object { + val NOT_INITIALIZED = -1 + val COMPLETED = 0 + + //Migration process + val NOTIFY_USER = 1 + val OPEN_BACKUP_MENU = 2 + val PERFORM_BACKUP = 3 + val FINALIZE_MIGRATION = 4 + + val MAX_MIGRATION_STEPS = 2 + } +} diff --git a/app/src/main/java/exh/ui/migration/UrlMigrator.kt b/app/src/main/java/exh/ui/migration/UrlMigrator.kt new file mode 100755 index 000000000..2169c555d --- /dev/null +++ b/app/src/main/java/exh/ui/migration/UrlMigrator.kt @@ -0,0 +1,79 @@ +package exh.ui.migration + +import eu.kanade.tachiyomi.data.database.DatabaseHelper +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.data.preference.getOrDefault +import exh.isExSource +import exh.isLewdSource +import exh.metadata.MetadataHelper +import uy.kohesive.injekt.injectLazy + +class UrlMigrator { + private val db: DatabaseHelper by injectLazy() + + private val prefs: PreferencesHelper by injectLazy() + + private val metadataHelper: MetadataHelper by lazy { MetadataHelper() } + + fun perform() { + db.inTransaction { + val dbMangas = db.getMangas() + .executeAsBlocking() + + //Find all EX mangas + val qualifyingMangas = dbMangas.asSequence().filter { + isLewdSource(it.source) + } + + val possibleDups = mutableListOf() + val badMangas = mutableListOf() + + qualifyingMangas.forEach { + if(it.url.startsWith("g/")) //Missing slash at front so we are bad + badMangas.add(it) + else + possibleDups.add(it) + } + + //Sort possible dups so we can use binary search on it + possibleDups.sortBy { it.url } + + badMangas.forEach { manga -> + //Build fixed URL + val urlWithSlash = "/" + manga.url + //Fix metadata if required + val metadata = metadataHelper.fetchEhMetadata(manga.url, isExSource(manga.source)) + metadata?.url?.let { + if(it.startsWith("g/")) { //Check if metadata URL has no slash + metadata.url = urlWithSlash //Fix it + metadataHelper.writeGallery(metadata, manga.source) //Write new metadata to disk + } + } + //If we have a dup (with the fixed url), use the dup instead + val possibleDup = possibleDups.binarySearchBy(urlWithSlash, selector = { it.url }) + if(possibleDup >= 0) { + //Make sure it is favorited if we are + if(manga.favorite) { + val dup = possibleDups[possibleDup] + dup.favorite = true + db.insertManga(dup).executeAsBlocking() //Update DB with changes + } + //Delete ourself (but the dup is still there) + db.deleteManga(manga).executeAsBlocking() + return@forEach + } + //No dup, correct URL and reinsert ourselves + manga.url = urlWithSlash + db.insertManga(manga).executeAsBlocking() + } + } + } + + fun tryMigration() { + if(!prefs.hasPerformedURLMigration().getOrDefault()) { + perform() + prefs.hasPerformedURLMigration().set(true) + } + } +} diff --git a/app/src/main/java/exh/util/UriFilter.kt b/app/src/main/java/exh/util/UriFilter.kt new file mode 100755 index 000000000..655b03996 --- /dev/null +++ b/app/src/main/java/exh/util/UriFilter.kt @@ -0,0 +1,10 @@ +package exh.util + +import android.net.Uri + +/** + * Uri filter + */ +interface UriFilter { + fun addToUri(builder: Uri.Builder) +} \ No newline at end of file diff --git a/app/src/main/java/exh/util/UriGroup.kt b/app/src/main/java/exh/util/UriGroup.kt new file mode 100755 index 000000000..cb9225c40 --- /dev/null +++ b/app/src/main/java/exh/util/UriGroup.kt @@ -0,0 +1,15 @@ +package exh.util + +import android.net.Uri +import eu.kanade.tachiyomi.source.model.Filter + +/** + * UriGroup + */ +open class UriGroup(name: String, state: List) : Filter.Group(name, state), UriFilter { + override fun addToUri(builder: Uri.Builder) { + state.forEach { + if(it is UriFilter) it.addToUri(builder) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/anim/enter_from_bottom.xml b/app/src/main/res/anim/enter_from_bottom.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/anim/enter_from_left.xml b/app/src/main/res/anim/enter_from_left.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/anim/enter_from_right.xml b/app/src/main/res/anim/enter_from_right.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/anim/enter_from_top.xml b/app/src/main/res/anim/enter_from_top.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/anim/exit_to_bottom.xml b/app/src/main/res/anim/exit_to_bottom.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/anim/exit_to_left.xml b/app/src/main/res/anim/exit_to_left.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/anim/exit_to_right.xml b/app/src/main/res/anim/exit_to_right.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/anim/exit_to_top.xml b/app/src/main/res/anim/exit_to_top.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/anim/fab_hide_to_bottom.xml b/app/src/main/res/anim/fab_hide_to_bottom.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/anim/fab_show_from_bottom.xml b/app/src/main/res/anim/fab_show_from_bottom.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/anim/fade_in.xml b/app/src/main/res/anim/fade_in.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/anim/fade_in_long.xml b/app/src/main/res/anim/fade_in_long.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/color/abc_primary_text_material_dark.xml b/app/src/main/res/color/abc_primary_text_material_dark.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_av_pause_grey_24dp_img.png b/app/src/main/res/drawable-hdpi/ic_av_pause_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_av_play_arrow_grey_img.png b/app/src/main/res/drawable-hdpi/ic_av_play_arrow_grey_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_clear_grey_24dp_img.png b/app/src/main/res/drawable-hdpi/ic_clear_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_delete_grey_24dp.png b/app/src/main/res/drawable-hdpi/ic_delete_grey_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_insert_photo_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_insert_photo_white_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_refresh_grey_24dp_img.png b/app/src/main/res/drawable-hdpi/ic_refresh_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_refresh_white_24dp_img.png b/app/src/main/res/drawable-hdpi/ic_refresh_white_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_share_grey_24dp.png b/app/src/main/res/drawable-hdpi/ic_share_grey_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_system_update_grey_24dp_img.png b/app/src/main/res/drawable-hdpi/ic_system_update_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_av_pause_grey_24dp_img.png b/app/src/main/res/drawable-mdpi/ic_av_pause_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_av_play_arrow_grey_img.png b/app/src/main/res/drawable-mdpi/ic_av_play_arrow_grey_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_clear_grey_24dp_img.png b/app/src/main/res/drawable-mdpi/ic_clear_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_delete_grey_24dp.png b/app/src/main/res/drawable-mdpi/ic_delete_grey_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_insert_photo_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_insert_photo_white_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_refresh_grey_24dp_img.png b/app/src/main/res/drawable-mdpi/ic_refresh_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_refresh_white_24dp_img.png b/app/src/main/res/drawable-mdpi/ic_refresh_white_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_share_grey_24dp.png b/app/src/main/res/drawable-mdpi/ic_share_grey_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_system_update_grey_24dp_img.png b/app/src/main/res/drawable-mdpi/ic_system_update_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-v21/library_item_selector_dark.xml b/app/src/main/res/drawable-v21/library_item_selector_dark.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-v21/library_item_selector_light.xml b/app/src/main/res/drawable-v21/library_item_selector_light.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-v21/list_item_selector_dark.xml b/app/src/main/res/drawable-v21/list_item_selector_dark.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-v21/list_item_selector_light.xml b/app/src/main/res/drawable-v21/list_item_selector_light.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/card_background.9.png b/app/src/main/res/drawable-xhdpi/card_background.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_av_pause_grey_24dp_img.png b/app/src/main/res/drawable-xhdpi/ic_av_pause_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_av_play_arrow_grey_img.png b/app/src/main/res/drawable-xhdpi/ic_av_play_arrow_grey_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_clear_grey_24dp_img.png b/app/src/main/res/drawable-xhdpi/ic_clear_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_delete_grey_24dp.png b/app/src/main/res/drawable-xhdpi/ic_delete_grey_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_insert_photo_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_insert_photo_white_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_refresh_grey_24dp_img.png b/app/src/main/res/drawable-xhdpi/ic_refresh_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_refresh_white_24dp_img.png b/app/src/main/res/drawable-xhdpi/ic_refresh_white_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_share_grey_24dp.png b/app/src/main/res/drawable-xhdpi/ic_share_grey_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_system_update_grey_24dp_img.png b/app/src/main/res/drawable-xhdpi/ic_system_update_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_av_pause_grey_24dp_img.png b/app/src/main/res/drawable-xxhdpi/ic_av_pause_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_av_play_arrow_grey_img.png b/app/src/main/res/drawable-xxhdpi/ic_av_play_arrow_grey_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_clear_grey_24dp_img.png b/app/src/main/res/drawable-xxhdpi/ic_clear_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_delete_grey_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_delete_grey_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_insert_photo_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_insert_photo_white_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_refresh_grey_24dp_img.png b/app/src/main/res/drawable-xxhdpi/ic_refresh_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp_img.png b/app/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_share_grey_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_share_grey_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_system_update_grey_24dp_img.png b/app/src/main/res/drawable-xxhdpi/ic_system_update_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxxhdpi/al.png b/app/src/main/res/drawable-xxxhdpi/al.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_av_pause_grey_24dp_img.png b/app/src/main/res/drawable-xxxhdpi/ic_av_pause_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_av_play_arrow_grey_img.png b/app/src/main/res/drawable-xxxhdpi/ic_av_play_arrow_grey_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_clear_grey_24dp_img.png b/app/src/main/res/drawable-xxxhdpi/ic_clear_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_delete_grey_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_delete_grey_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_insert_photo_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_insert_photo_white_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_refresh_grey_24dp_img.png b/app/src/main/res/drawable-xxxhdpi/ic_refresh_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_refresh_white_24dp_img.png b/app/src/main/res/drawable-xxxhdpi/ic_refresh_white_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_share_grey_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_share_grey_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_system_update_grey_24dp_img.png b/app/src/main/res/drawable-xxxhdpi/ic_system_update_grey_24dp_img.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxxhdpi/kitsu.png b/app/src/main/res/drawable-xxxhdpi/kitsu.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxxhdpi/mal.png b/app/src/main/res/drawable-xxxhdpi/mal.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/branded_logo.xml b/app/src/main/res/drawable/branded_logo.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/eh_ic_ehlogo_red_24dp.xml b/app/src/main/res/drawable/eh_ic_ehlogo_red_24dp.xml new file mode 100755 index 000000000..ee5aca6a2 --- /dev/null +++ b/app/src/main/res/drawable/eh_ic_ehlogo_red_24dp.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/eh_migration_backup.png b/app/src/main/res/drawable/eh_migration_backup.png new file mode 100755 index 0000000000000000000000000000000000000000..9d58af1e3e61fbc73e3f1aa1a7f266f476e7e016 GIT binary patch literal 30201 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 VQb4AF{_hU1;Fl1^a`|_`{{y2xGmZcN literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/eh_migration_backup_button.png b/app/src/main/res/drawable/eh_migration_backup_button.png new file mode 100755 index 0000000000000000000000000000000000000000..9903385c9f8dd2d229f5ff841d8c38e65052a834 GIT binary patch literal 4700 zcmbtYXH*kgxQ$8?0Z~AD5e0&X6hV+CSEU6^5C|X`K3^>mSodJPB zoDf4@GZ5&65YT^r`Xq4fa0x~L7dAgb>i`glo#)qa0))W|05@3!Ay7Tm=@TrxH!t<^ z&pZHu&hJBXZ^Qp2({bT&p5dkrS7}GFr`E{#b4z8NuOzM=zt1Tnd9=`ZrN5|r}Qpen7R4YOO;(Ao5znmSK#VAcvWkqz|`xM zEjRCn!oumBB}S!cLWwyrQ0*-asPc7d_6)}6rjvlabXu8Qw<78hE>~ZDQsb3I);;N5 zBHUXMzQ8CDo3iuc)ywMD&;915di5`(I0Q^T0y?3Qy32B#fWZjGe9nGh+=5erTWx5O zx}01ptY7Y7-LkP9TTHQvCR~|+RAiIg-Un$&Py_9?wRb-i%f_wb@T#b&NEwvrT00r)di*SgGqP_ zYT&JbDKAF4@8H~5k5{I_cp9fSuFwBuZ&i@TI-Du4@b1)TAF*zGCJYP`;`~2z4j}Ry zr{6jM7lMCb`xhqwk^hG6zs9swFfT5%Dmu1v1VEvF=chzQ8X65d+PiAqU*$P$@isy_jfigEby=BcbO^2S8CR8( z8lBiZ+}{TKjLFDXZ*9RK5D6;*O&8RtS9KXPCO>YLv9ZC<#`a23z1$#KtZ!iC$Cd^G1^Ii?drIK|w)Pi6#f`D-*|*n&c;)MxMSa>H)Ma zr*eXYrxwY|;#W&gPoMkoW0_J@8g+cM@uQdh%vt?UG*v&5kcFAHx$exB@rsUjYWd>o z>#Ngu6L|I}8gmVjHR?~Xa)}|zoggkQ`SgyStb6$=bHapu?dtbJb51R)vg=o`(ek)J zNXh-yjt*94<~n$zn+j%UXXhV}8-YmW9+!=p$;j}Y^Ma98sK1z!#C4YYXh)SHzBBEK zz?_0h?2o2CM@8&9TUure7}z|xzdBeSq@SCLD*y2nCoCwq@Qjf&u%PNS;y2UE#uQ%i zWoK>nP$T$Y!R#RwMd2^iJmI=NMM|65BUvX_qtLaQFc!Ni>1)+MQ3d`bwYi zu+jB7J3Bk{k2d_a%Q;a21qFq;I}-Bb(HaN@QWv@*ZOyIb3PT{Uty1whROIfLIQCov z)J1j^?9F$>i=rA6v9YlMLY&t9H)Q5>lW!rb!q&F7jz}gtoYg&lI61rItWbac86N&3 za8Y^z`+dIzi^ZbR-2O^(a&jsvo20Lh$J4+nqZ6G{5`g@_R&hrsGF(Y`C?)^kpTe-2?<1Qio7ZB9E~e$oSxifJ+odB23y!Ox~ z{Nm!mb*~Y{jH>w%L!p3qYCHh+!%8b}@`&B!BSmcQS3Z79rMt40tOvC-l}b9u>bXZb zWl!akiC*v-`^^Px5S( zle%0qJhuDYphu}~gMLPAT-<16cWPxNzyz-nV!r%yCElzM4kY88CVY-dOay8YwU(Fp zlWaIG9+i?{yYwbQ$(vmHE!Q9+!RbYBdve=Pl1}FPb!jMOv+HVUZ6w`LKSx_jD?4q` z?BigGbtC3u#njYPL4gcq1&xYsZEZcRkn@}iyus6au%5t)Gg=vw;6Kz1Dz6~W=yZCY zQpw>AJLIye(|liD0Ifcfj_B!4r`n{*gs`obAS5U}_*q$5*)wO@Z>Xy~#f653Hrh|} zz5_75-aAF3sjWgfc`t|_LXqXKiM4*ycii0zlaoz~Dc=?XsSe$i#h95EfIK?`mGw-= z>qG3z9O52+Cr`YMM5{m#_ZTrS`TI((USI21x3}%N#U~p=d?`hF`T1yE&g!b)TGc&i zVF5mA*!AmK_dKfhifbl51ZkpU4a{SeXet(%14T!Q|~x#a)wu%La*;jzd~so~L3P&A}!^d1;cS-*|aU%+1Y- zaC}R(H-#ncMZ+^wfNs&&$08*5ia(G@q$ETu>z=ANSw&5|0k4j$w4t*m@Fxpthkbs= zY?N1CGFV<-?sM)iMc%gF(59mEb4 z{B|$oXf|1g+`LXDrY&-cWDnT4X5Ws%hcBxWxgP6Rv*o6zsRv)zui*vo90e-QBBx>JC)uIa+KFS|`HDsh1x=eynuapk8lWi9^|c zrghZce>r^bh8oUJNI8FK;jwpZ8cN zpir+Qg1WQ<+TB!aSP##{J?lxD=X{?3!8qerky;*aX!8f-XPY1}pc`U446QpG9UbjU z!n%`qjpjEuQ@iIXTuAZ?3MNqK1$Hh`tp`OgV4hSJ*SA~r(jRlS#ol&zJbitYnypMt z{Ws^ol{t184W&}WWZ9~Owh4#0-3{=)*DY%YB~gdQatcwakANjoH2l%O@MpHWO(9&? zLe^gVZFY9H#N8KUwZVF zc+C*8qvHj3bewm<)eVEc;hEt#r-wj{?FP^~Pb^lrlJeib|9h=nIHpcG&9Qsm~(yTM!t4hANv{h&?KJY)L~tlf$r-U__(<*5y^{;Jq8(!oOR5yWTW{2StL-WtZZA_EEGz~K)4<-oh;rYfqoZ>R z)=QeAT7G}@i!cW++>v*2aY082XE+~+?+3r);6B67J{hrXdj$D%zi7}yMTkfxpI1^k zHXhShoFteK2!vtGHQt@bZobP(jra4++S=PS!af0YC@gCF&N`;#?e>be03V-wD0>+o zWA=7-{>sRRm%4K0iUNnA*|1-LhsOu%rO9YUucZFscMf7#7a9c)22`A+WUO2&f;LPr z5&uQ-7kGIkM?24V8^4!{$7lq3JamA8JN$)*N+)Z4-!g_!`m_11y6ev)dG$DjRX?WB zDjz=441BHTE0*Q1_@-Bwheyh)@ILR2Cp&(~wV#7UMV7_rz!Wi>O_C@Di}gx%TVo`K zsrGY_92OaqaRZ#u+`+;>N~V ztmvqScG%|Vl9$=ne$5b7pOIDZ;~myIa^=E6vbYW`a(MxT%F2}2J1Zt4B65HzveeIA z10)JRGGLwrxO)86Rs6k03po6}=q<1CS%v0qzs4)n0>yb!PC*e)q8y|=rYIyYQu-yF=4wZ7h( z%BFz+wA!C%TxFMZD`IbxWL3I6PB3ZIRKFzc;^^Rzd$0c0%a;PjHO;9~fM6RsHSq1* zH@3xLF2U=%NXl~?p{$vo#gd*w*~oOoD>yvRs3Dzz?9(UXzhIXIz440{CRey28a;g^bgPs7K~m7D088 z)Sp$JYDPwZ8n%G4M>zvUo?PR}4`6>@P#smf%kjyrl3w?QOAzcQ0zSC$rgv~~kR|4} zmBrlrM;;J@FWqcmdRij0+d3ni==95?-W^pFW+#Q51V#M+?eTA`_OGP|!vC^rGVwVw zYYS>16&|UjNR0XAMP0xj56ld7o^WH4SK^q(8YgC_t*#ZY^m(}%wzS<`d(53ahg3J# z5)c7xdt<2AY)*5n9u&oB@3C?G==Cg=v-KL04%juojr6)4vCW9(lAm5x zxjh8_w3-qO2w$)bnD$J2s7{o7^P;d!(k!5OXGfA}Zzl0Hf*Vgx6$(pX^JdsHoF7)Y zNmLp;bP(&KJ)Yp)Fw%P5A%-Jdc$z!L#oE#hr;B6Cy`S2W7s!p`#$29e;xp=eM0#gP z+I?h#j!z*v-FbB}S>Wh4cabTGH zQMf?b7iWkQGfAEbEvt|$iD}~TgW@_@jb_pVQt@dTkXuh53*c#S&B*~tOhZzj+9Xr7 z?jLv8&%y6<&!MTYuLb%4MhnDsosxf(aWOFmE7a(Xg)_PHE~Gm_=a~?e1e@bq%(#y_ zW}9aiOk>}Qp1=HlTH{8S7--5&;|9~vjSzNF2-85ziT}NE@;^`p{rASnZxdhg<@l5> X{UY^2rI#kKGX#R@!E{URJbLyYvRMg7 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/eh_migration_hamburgers.png b/app/src/main/res/drawable/eh_migration_hamburgers.png new file mode 100755 index 0000000000000000000000000000000000000000..8e491b1e5ce416da680a17e0f0f907bbb08414b8 GIT binary patch literal 6818 zcmb7}byQT*+wTV$Vd$Z|k(Lr^ff>5HrH2v_kdTrbQW^!MLqSqX8l*#Mq(d5{yW>6l z*1O)j?!D{&ao4Pwb7tq+&))kv&-b$3GfVW!h^P>nHa<1TrHHLKDC?L=oMNHobu{?O|Q68C|Y~jn%^1uCxDCY{&L> zrrh`}uc^Et{e*PtvVE&_gIBq3dTf%L7Bl|SUmLq zkS0lUIHDXOX`}pc ziH&gK9xovj+aZqbE{0QY4POQR&LHRzVQMa59f+OsQ6AYNi{Q5B)!`S>L3z9NvTKbv z7-?QM!z&n!EGO+cgKNBf3d@jf;(ssQ%YO$?XD|p zD#t@h(KX-GDCkZw87@Tdn$)TObqIuogF^7c(z#JUf5xDH!k*?BB|xmr!Lq!S9Ks^M z1lJ<&)et{SI!Ubus|v4c!zPV`IW^h8MX1TkO9{(9hr!!A-rEp*tEME3YoUbJI&@E^ zuOE%_oQF@!2g7(IaeSk4FAjUY^b%a#bXWAe8GEk*l{Ubh zE0LOxn%SD|kjgQ?nxy=5YETQ|vGhoc1JhPbKYrS z!A?y5jT8xexDtzeiU9e7f6&O4!ql4oS9BV9*fq3xCkS2wR6zTy*jZKn1H}4DWjbu7 zOZ*#Z2U`bbFH!K9A@tqyhCpJE{E2LuW8!>1fpbsGH&R@_Ie)v&zPDtyscgLt`dh!a z?eGWrbjeXkV!J~~`wP)I5174JRNQrsdc|k9^!nAD+>>IG$ZxpHfpVm;$Ny@U@4>4Y z35tq+WX$vp&t^83?EDg1v0p?nM|pMJBk5~5eRoU5W0+N|yR+>t@TFzlMayNrmd@w| zlqFEQPv@1w^yXg3;C*{`|0+`)FWY(_rhLc})i%_l%=V23))m;Zd-+6onMXu@xq9H`DJT789JI@$Zlybs zk*#JUr1{(?v2+ragyosWBvm0V{6A>%V-O=DX;gsg2=nbj*t~U!ezQ#>O+1WSGu{c{_y;adZWV!8KG|S<7 z!@0C3lO<3BRxM;V&0{)tVGX;!b* z6U}9}FUy7DtfrGnajb_~M|^j0FkifyFNQ+u!FMA z+>6JWE<$Q_*0GUkSWM9 zF&I!CQ?+*HK9{fjqkX>|{(#3?eUVr<8DS*LcuKpdpgmDNjt#1sE9PBc51Z||KtOji zAfEbUtDjczg>O7esSYQ#e|AiK(>eY_IsT7F-pUSVrO9|%;&;~PuSMIu4DRy1avZ^M zc!iR<(R*4Rv)k0_pHJDa9jyrc@dfndset=!umU8>t8nCYDgf8fTsO zb_IxDPv;M^qiSqA*K>WDughhH0ipK#zx4h(7nm$)P-e&Ebtrf_3PA1xej}F+FVW)E3g!k4cg~wk#$Q>=L_DUX+PDa;-4(6qm(!2Iay- z#8k@`&EI>2&GzB*M?Y%+HIR3=obYWQN`_+p=I+D#=X`~2M|$Z5sDWBUIfk>JcWU*6 zyAn$5=1(cwNmEJPvss1h?h%Ha&lOS%fO8tII_G6C?-whnY z_h@#;3c*Z>`X-BAGL*}jr24xc7s|n&cW85knwRr1C*VZP&#l=@4ppw$`3W(D*cCHz zFaKG4y0|L_AD*v%PsEs{aF)F1XcV6GygfZ;SE5aX-U{>Z4jQVPryWGSqkI2EyGG4? zfp49oqbaU6*uIss`oa7N6OuCh94?#+rLI5Zvz5)bc=t234M?S~?yBSVD4Sv}z;m6rRJ8^Kfz#FP1&~ zVxKSHw)>=F8NuqN7TGeVqvwT1hhNcn*Y?8WY9*a?9ig5qV2WR_yH0Ul!d3ipDQScL53{yE5pRi)t|4&W7q*W%SJY&V!y6(Q~GZsp_*yD|_$fx(D9-LxA0 zaMm$J5j+JC8N%XDBGp+d-%ko70!cx;x)9o89_!ldUtY-4og9~|EKa=$4{k7jOKd}T zJ%a#gS^Fr$1mo)qVM^TGN|rstUmSg>qWtkKm@wL2|KO9z281C-I463&Wtc%PJbv8B zeoSzQDOXh%%#lCN*JhyjD~iIB1{;>w7}+pb&+JcS_-QE`@S0G<2~`BOFF~+M?6H+K z-)DrbWxv5v6pbYf7R<-DOwl+~JXVmDpl-~u3^{&oPNq9z2=8A4(oRU<&G!@)BOibK zjIFL9{53g()~WnBWv&J`CGEMeXwe-3I0~&!`e$(C;L}U!?N!Ny2$zkm5A!_o_R}y# zF!r=M8|CXqI{JY%OkqnTXF&vA{FM(QlZ3l&`KKSBZ}4k%;n22e_y(1iQ_20b1F^MiRe7H0wV zr&!b4XM*xh$igNU*{Px7h~T88B*mK*#*rB@$4n>?fu+}+efYWt>tHmf?1*BQ|JoRu zDNcfQ*{2@&YV^mr<#e3QcB_So%AgS|SR$!_vmL!p z&dLk?E_8Er_qK)7ul0imd`aY`#hBnOI}1J`X?qljo{9(uDlPttvX=v`6>Yc?IEIUJ zpPUqTr*6idyVZNCVxnZ*W~X>FhCRk$KZO9OUc{yRu|n!idE{~ zlh$>`PA^#y{B}m9`BzW5n5APGpgt;VmD1a!m=P{%ipxU?_8SSW~BcN zTH$p1O%_Zw#C;kq&qbwIT4DK1li=_`yvR-U!JB)CZQ9bGDG?alnksCdwdZ_?oL^;; z0M)^aZm1#kjX_Q+j|F?FfkpSn{9y|OkiQ(rx|^t{Kn0{ zeq@}XfoIY32SJ$17Ts9usrzXJw`@%TUo|_a$=J?dmO4v`Q@=LYUh{v;mhx`79^xAO zgl}uhy0b{Bf+c&HDKI}?ORE<)Du|d1B;njyE*lT=5 Ra4Lz{zN8iJ;p}X#f&AgT z5e{WE8Zx~O_))Zz72vxt-)TM(9e75YIvGWj+z~}$6#ljjIxogF5*wYb*u7YgNlgP5 z(m%J-ZBJ&a7f!#gapvM$>X`7|k%^iIPhz7uSd;J3GI52HaMtjDGKPSbw4ODU=QpJX zo|H-XP>Y3+6pZG|`yNE!C#M=b1(*IF;DB=ai* zKXhO!Nu)KJfukcGQ>g?Q_`^4vV*vX2ShFoY7!ui;RZX+=-Hvfs3G@O>rVQ&Gmi)l9 zjioC`9S{Vs4?qlV`mOV&p@UwB^2JI&U*C_9tn|XiXtQr3SbMpmo(5BuZ_AeZ(Y{TbscqH`wVMbH z+{us@J;+)L<`mo-P}wmk_8}rrQw1?7Gr9KrSvo0u=Wr= z5+h~VklB^W_o8T<{zwvRls1V2iQFa{6{+!lH+TR7iQKAwuGf1Q=z+@o!RCjOMa>M*jLF^8BYYEn9+5oWPj1X0d#)$s-1mTcncZ@ERMq2F0fy$6@<2W_1GP9#s8ZXmY1+3xu}} zUQ+_UvBWINgNB&^1$I0K!8V*5- z7;!MAEMYNmB+Fhf)ycG(kxX)}+j$Bp%*AT)ON&xM1dvP7r-=lCqN=jZYn`2%!f0Zw z5l&*(@>UeJZ@Cy(qcA&SLvzL@am>C-4D5;l5%6q0A{>~&$6(mzuYM7J{tF8OeX`r<$eXoCODO;{idVf(fc#PB*gj;X zSpu4c!Mm#mm=WpSBKD2lfSV)z(LrIwchr7x|ncmUy?fdvLDbfEoN-o&*}Em<#FOX0Zu4JoM=D2#7=X<|;7x zmw9^E_0A9M?0?Ozl`On)eL1vw=%Iu{@d0VR4k%x9_}0*ss1mAq>v%>Z&0qYRCXXdh=Nr@6Wh~sU9-p3Z$MnH>2I}=2 zJ1D^3WBR*o|6G<38x+|Hc-Mk-PJ9<%2`Fp2A6&#Q{izaW^l;0grP7LN0dM%tT1Sde zZ)kWZAkda4du7)wkm&v-5&$3E>Cv+A3eVH)CwU?WB0&cu03-1B%HY_=7Z-=i5h4lH z&5q|epspsNfBnyC`E};4H^X0cUDg%ijgDCm2H$kX*UJ&+)E8rNy6?M5A-y~jm@`!;Jif4N${sJb@wW% zNw?AkwBV5jMD*PcJ?*t`xzqUALiY8@xIZ7~Z8~>;#Vs+yW+=rDAJRJ-O!jSw4Kv8; z7;aCH)$B95TfdQG=a<}oab|I}W(bPhW_g5Z^`+PR3W`Jge)$i*y8)$Wj zYwh#`9QBbGzNQfv&zzqLTzEkyOy;lv+7ny5@hS`4o2*t#W&)G99?rX(v z*V)ttI=hih2JUZbo#nZ?&23ko68}k|w`^-R;BLbV==a6~U|_BpO65Hgbh)e%^M9j2 z>vx>Qofrar_C->ra6aA})h8wgsVCTF()?InXn}j?--%brN zlot*b5C3q|0bp?ip#SX$BXle!0cP3E) z$F%GaBxc=!kx1>JKrl#yjR7&i`28RMTO*F-S5=Pe)#4J@-S>dw;N4me2M9gD$N=sEZV z`{9o$Hu177mAFwGLBtH^V!RehnDE3k{`ew3X14ce*T@+Y*fu$gqBJxp%fy2K%YGqq z=0UHk8wX&r4)=wf?Zt`zoxsE36_k$TR4};y@4c>9fiPR`i>U)9fJ-~##B^7XO<2+^ zKqjgGk3)ne=Qu*3E5I)drgnMS$)= zz#tTQ!YY6f9d)ra7xpXxqa588n2&xA9iVE@&JI6WK?Rw&_fxou(?*M<6g+`HQhdNf znh9i&_BtoF8u^WHM287jlK1$@8YmdqrpI^u1laK!Uuiqu{C}Lc{LhKZeD?#Ix5shk URzX`TaGC^ClvR@{hnolg7yOpF!vFvP literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/eh_migration_share_icon.png b/app/src/main/res/drawable/eh_migration_share_icon.png new file mode 100755 index 0000000000000000000000000000000000000000..7749f77976546670fee0f5c37648c972972cad29 GIT binary patch literal 9088 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/empty_divider.xml b/app/src/main/res/drawable/empty_divider.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/empty_drawable_32dp.xml b/app/src/main/res/drawable/empty_drawable_32dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/filter_mock.png b/app/src/main/res/drawable/filter_mock.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/gradient_shape.xml b/app/src/main/res/drawable/gradient_shape.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_account_circle_black_24dp.xml b/app/src/main/res/drawable/ic_account_circle_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_add_white_24dp.xml b/app/src/main/res/drawable/ic_add_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_backup_black_24dp.xml b/app/src/main/res/drawable/ic_backup_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_book_black_128dp.xml b/app/src/main/res/drawable/ic_book_black_128dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_book_black_24dp.xml b/app/src/main/res/drawable/ic_book_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_bookmark_border_white_24dp.xml b/app/src/main/res/drawable/ic_bookmark_border_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_bookmark_white_24dp.xml b/app/src/main/res/drawable/ic_bookmark_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_brightness_4_white_24dp.xml b/app/src/main/res/drawable/ic_brightness_4_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_brightness_5_black_24dp.xml b/app/src/main/res/drawable/ic_brightness_5_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_broken_image_grey_24dp.xml b/app/src/main/res/drawable/ic_broken_image_grey_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_check_box_24dp.xml b/app/src/main/res/drawable/ic_check_box_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_check_box_outline_blank_24dp.xml b/app/src/main/res/drawable/ic_check_box_outline_blank_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_check_box_x_24dp.xml b/app/src/main/res/drawable/ic_check_box_x_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_chevron_right_white_24dp.xml b/app/src/main/res/drawable/ic_chevron_right_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_chrome_reader_mode_black_24dp.xml b/app/src/main/res/drawable/ic_chrome_reader_mode_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_cloud_download_white_24dp.xml b/app/src/main/res/drawable/ic_cloud_download_white_24dp.xml new file mode 100755 index 000000000..0f56a12d0 --- /dev/null +++ b/app/src/main/res/drawable/ic_cloud_download_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_code_black_24dp.xml b/app/src/main/res/drawable/ic_code_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_create_white_24dp.xml b/app/src/main/res/drawable/ic_create_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_delete_white_24dp.xml b/app/src/main/res/drawable/ic_delete_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_done_all_grey_24dp.xml b/app/src/main/res/drawable/ic_done_all_grey_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_done_all_white_24dp.xml b/app/src/main/res/drawable/ic_done_all_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_done_green_24dp.xml b/app/src/main/res/drawable/ic_done_green_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_done_white_18dp.xml b/app/src/main/res/drawable/ic_done_white_18dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_expand_more_white_24dp.xml b/app/src/main/res/drawable/ic_expand_more_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_explore_black_24dp.xml b/app/src/main/res/drawable/ic_explore_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_file_download_black_128dp.xml b/app/src/main/res/drawable/ic_file_download_black_128dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_file_download_black_24dp.xml b/app/src/main/res/drawable/ic_file_download_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_file_download_white_24dp.xml b/app/src/main/res/drawable/ic_file_download_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_filter_list_white_24dp.xml b/app/src/main/res/drawable/ic_filter_list_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_glasses_black_128dp.xml b/app/src/main/res/drawable/ic_glasses_black_128dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_glasses_black_24dp.xml b/app/src/main/res/drawable/ic_glasses_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_help_black_24dp.xml b/app/src/main/res/drawable/ic_help_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_insert_photo_white_24dp.png b/app/src/main/res/drawable/ic_insert_photo_white_24dp.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_down_black_32dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_down_black_32dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_up_black_32dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_up_black_32dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_label_white_24dp.xml b/app/src/main/res/drawable/ic_label_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_language_black_24dp.xml b/app/src/main/res/drawable/ic_language_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_menu_white_24dp.xml b/app/src/main/res/drawable/ic_menu_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_more_horiz_black_24dp.xml b/app/src/main/res/drawable/ic_more_horiz_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_pause_white_24dp.xml b/app/src/main/res/drawable/ic_pause_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_play_arrow_white_24dp.xml b/app/src/main/res/drawable/ic_play_arrow_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_playlist_add_black_24dp.xml b/app/src/main/res/drawable/ic_playlist_add_black_24dp.xml new file mode 100755 index 000000000..0460472b9 --- /dev/null +++ b/app/src/main/res/drawable/ic_playlist_add_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_refresh_white_24dp.xml b/app/src/main/res/drawable/ic_refresh_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_reorder_grey_24dp.xml b/app/src/main/res/drawable/ic_reorder_grey_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_search_white_24dp.xml b/app/src/main/res/drawable/ic_search_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_select_all_white_24dp.xml b/app/src/main/res/drawable/ic_select_all_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_settings_black_24dp.xml b/app/src/main/res/drawable/ic_settings_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_settings_white_24dp.xml b/app/src/main/res/drawable/ic_settings_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_share_white_24dp.xml b/app/src/main/res/drawable/ic_share_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_skip_next_white_24dp.xml b/app/src/main/res/drawable/ic_skip_next_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_skip_previous_white_24dp.xml b/app/src/main/res/drawable/ic_skip_previous_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_sort_by_numeric_white_24dp.xml b/app/src/main/res/drawable/ic_sort_by_numeric_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_sort_white_24dp.xml b/app/src/main/res/drawable/ic_sort_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_sync_black_24dp.xml b/app/src/main/res/drawable/ic_sync_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_tune_black_24dp.xml b/app/src/main/res/drawable/ic_tune_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_update_black_128dp.xml b/app/src/main/res/drawable/ic_update_black_128dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_update_black_24dp.xml b/app/src/main/res/drawable/ic_update_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_view_list_white_24dp.xml b/app/src/main/res/drawable/ic_view_list_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_view_module_white_24dp.xml b/app/src/main/res/drawable/ic_view_module_white_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_watch_later_black_24dp.xml b/app/src/main/res/drawable/ic_watch_later_black_24dp.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/library_item_selector_dark.xml b/app/src/main/res/drawable/library_item_selector_dark.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/library_item_selector_light.xml b/app/src/main/res/drawable/library_item_selector_light.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/line_divider_dark.xml b/app/src/main/res/drawable/line_divider_dark.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/line_divider_light.xml b/app/src/main/res/drawable/line_divider_light.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/list_item_selector_dark.xml b/app/src/main/res/drawable/list_item_selector_dark.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/list_item_selector_light.xml b/app/src/main/res/drawable/list_item_selector_light.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/mask_star.png b/app/src/main/res/drawable/mask_star.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/activity_download_manager.xml b/app/src/main/res/layout/activity_download_manager.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/activity_edit_categories.xml b/app/src/main/res/layout/activity_edit_categories.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/activity_lock.xml b/app/src/main/res/layout/activity_lock.xml new file mode 100755 index 000000000..e6898f560 --- /dev/null +++ b/app/src/main/res/layout/activity_lock.xml @@ -0,0 +1,29 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/activity_manga.xml b/app/src/main/res/layout/activity_manga.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/activity_preferences.xml b/app/src/main/res/layout/activity_preferences.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/activity_reader.xml b/app/src/main/res/layout/activity_reader.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/catalogue_drawer.xml b/app/src/main/res/layout/catalogue_drawer.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/catalogue_drawer_content.xml b/app/src/main/res/layout/catalogue_drawer_content.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/changelog_header_layout.xml b/app/src/main/res/layout/changelog_header_layout.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/changelog_row_layout.xml b/app/src/main/res/layout/changelog_row_layout.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/chapter_image.xml b/app/src/main/res/layout/chapter_image.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/dialog_reader_custom_filter.xml b/app/src/main/res/layout/dialog_reader_custom_filter.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/dialog_reader_settings.xml b/app/src/main/res/layout/dialog_reader_settings.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/dialog_track_chapters.xml b/app/src/main/res/layout/dialog_track_chapters.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/dialog_track_score.xml b/app/src/main/res/layout/dialog_track_score.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/dialog_track_search.xml b/app/src/main/res/layout/dialog_track_search.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/dialog_with_checkbox.xml b/app/src/main/res/layout/dialog_with_checkbox.xml old mode 100644 new mode 100755 diff --git a/app/src/main/res/layout/eh_activity_finish_migration.xml b/app/src/main/res/layout/eh_activity_finish_migration.xml new file mode 100755 index 000000000..e96f46e38 --- /dev/null +++ b/app/src/main/res/layout/eh_activity_finish_migration.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/eh_activity_intercept.xml b/app/src/main/res/layout/eh_activity_intercept.xml new file mode 100755 index 000000000..518bb973e --- /dev/null +++ b/app/src/main/res/layout/eh_activity_intercept.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/eh_activity_login.xml b/app/src/main/res/layout/eh_activity_login.xml new file mode 100755 index 000000000..104324cd3 --- /dev/null +++ b/app/src/main/res/layout/eh_activity_login.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + +