Showing preview only (9,673K chars total). Download the full file or copy to clipboard to get everything.
Repository: maxwai/NClientV3
Branch: main
Commit: da29ac75c9a1
Files: 313
Total size: 9.1 MB
Directory structure:
gitextract_atw2n2is/
├── .editorconfig
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yaml
│ │ ├── config.yml
│ │ └── feature_request.yaml
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── android.yml
│ ├── dependencies.yml
│ └── update_data.yml
├── .gitignore
├── DCO
├── LICENSE
├── README.md
├── SECURITY.md
├── app/
│ ├── .gitignore
│ ├── build.gradle.kts
│ ├── proguard-rules.pro
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── maxwai/
│ │ └── nclientv3/
│ │ ├── ApiKeyActivity.java
│ │ ├── BookmarkActivity.java
│ │ ├── CommentActivity.java
│ │ ├── CopyToClipboardActivity.java
│ │ ├── FavoriteActivity.java
│ │ ├── GalleryActivity.java
│ │ ├── HistoryActivity.java
│ │ ├── LocalActivity.java
│ │ ├── MainActivity.java
│ │ ├── PINActivity.java
│ │ ├── RandomActivity.java
│ │ ├── SearchActivity.java
│ │ ├── SettingsActivity.java
│ │ ├── StatusManagerActivity.java
│ │ ├── StatusViewerActivity.java
│ │ ├── TagFilterActivity.java
│ │ ├── ZoomActivity.java
│ │ ├── adapters/
│ │ │ ├── BookmarkAdapter.java
│ │ │ ├── CommentAdapter.java
│ │ │ ├── FavoriteAdapter.java
│ │ │ ├── GalleryAdapter.java
│ │ │ ├── GenericAdapter.java
│ │ │ ├── HistoryAdapter.java
│ │ │ ├── ListAdapter.java
│ │ │ ├── LocalAdapter.java
│ │ │ ├── StatusManagerAdapter.java
│ │ │ ├── StatusViewerAdapter.java
│ │ │ └── TagsAdapter.java
│ │ ├── api/
│ │ │ ├── InspectorV3.java
│ │ │ ├── RandomLoader.java
│ │ │ ├── SimpleGallery.java
│ │ │ ├── comments/
│ │ │ │ ├── Comment.java
│ │ │ │ ├── CommentsFetcher.java
│ │ │ │ └── User.java
│ │ │ ├── components/
│ │ │ │ ├── Gallery.java
│ │ │ │ ├── GalleryData.java
│ │ │ │ ├── GenericGallery.java
│ │ │ │ ├── Page.java
│ │ │ │ ├── Ranges.java
│ │ │ │ ├── Tag.java
│ │ │ │ └── TagList.java
│ │ │ ├── enums/
│ │ │ │ ├── ApiRequestType.java
│ │ │ │ ├── ImageType.java
│ │ │ │ ├── Language.java
│ │ │ │ ├── SortType.java
│ │ │ │ ├── SpecialTagIds.java
│ │ │ │ ├── TagStatus.java
│ │ │ │ ├── TagType.java
│ │ │ │ └── TitleType.java
│ │ │ └── local/
│ │ │ ├── FakeInspector.java
│ │ │ ├── LocalGallery.java
│ │ │ └── LocalSortType.java
│ │ ├── async/
│ │ │ ├── MetadataFetcher.java
│ │ │ ├── ScrapeTags.java
│ │ │ ├── VersionChecker.java
│ │ │ ├── converters/
│ │ │ │ └── CreatePdfOrZip.java
│ │ │ ├── database/
│ │ │ │ ├── DatabaseHelper.java
│ │ │ │ ├── Queries.java
│ │ │ │ └── export/
│ │ │ │ ├── Exporter.java
│ │ │ │ ├── Importer.java
│ │ │ │ └── Manager.java
│ │ │ └── downloader/
│ │ │ ├── DownloadGalleryV2.java
│ │ │ ├── DownloadObserver.java
│ │ │ ├── DownloadQueue.java
│ │ │ ├── GalleryDownloaderManager.java
│ │ │ ├── GalleryDownloaderV2.java
│ │ │ └── PageChecker.java
│ │ ├── components/
│ │ │ ├── CookieInterceptor.java
│ │ │ ├── CustomCookieJar.java
│ │ │ ├── GlideX.java
│ │ │ ├── ThreadAsyncTask.java
│ │ │ ├── activities/
│ │ │ │ ├── BaseActivity.java
│ │ │ │ ├── CrashApplication.java
│ │ │ │ └── GeneralActivity.java
│ │ │ ├── classes/
│ │ │ │ ├── Bookmark.java
│ │ │ │ ├── History.java
│ │ │ │ ├── MultichoiceAdapter.java
│ │ │ │ └── Size.java
│ │ │ ├── launcher/
│ │ │ │ ├── LauncherCalculator.java
│ │ │ │ └── LauncherReal.java
│ │ │ ├── status/
│ │ │ │ ├── Status.java
│ │ │ │ └── StatusManager.java
│ │ │ ├── views/
│ │ │ │ ├── CFTokenView.java
│ │ │ │ ├── GeneralPreferenceFragment.java
│ │ │ │ ├── PageSwitcher.java
│ │ │ │ ├── RangeSelector.java
│ │ │ │ └── ZoomFragment.java
│ │ │ └── widgets/
│ │ │ ├── ChipTag.java
│ │ │ ├── CustomGridLayoutManager.java
│ │ │ ├── CustomImageView.java
│ │ │ ├── CustomLinearLayoutManager.java
│ │ │ ├── CustomSearchView.java
│ │ │ ├── CustomSwipe.java
│ │ │ └── TagTypePage.java
│ │ ├── files/
│ │ │ ├── GalleryFolder.java
│ │ │ └── PageFile.java
│ │ ├── github/
│ │ │ └── chrisbanes/
│ │ │ └── photoview/
│ │ │ ├── Compat.java
│ │ │ ├── CustomGestureDetector.java
│ │ │ ├── OnGestureListener.java
│ │ │ ├── OnMatrixChangedListener.java
│ │ │ ├── OnOutsidePhotoTapListener.java
│ │ │ ├── OnPhotoTapListener.java
│ │ │ ├── OnScaleChangedListener.java
│ │ │ ├── OnSingleFlingListener.java
│ │ │ ├── OnViewDragListener.java
│ │ │ ├── OnViewTapListener.java
│ │ │ ├── PhotoView.java
│ │ │ ├── PhotoViewAttacher.java
│ │ │ └── Util.java
│ │ ├── loginapi/
│ │ │ ├── LoadTags.java
│ │ │ └── User.java
│ │ ├── settings/
│ │ │ ├── ApiAuthInterceptor.java
│ │ │ ├── AuthCredentials.java
│ │ │ ├── AuthStore.java
│ │ │ ├── Database.java
│ │ │ ├── DefaultDialogs.java
│ │ │ ├── Favorites.java
│ │ │ ├── Global.java
│ │ │ ├── Login.java
│ │ │ ├── NotificationSettings.java
│ │ │ └── TagV2.java
│ │ ├── ui/
│ │ │ └── main/
│ │ │ ├── PlaceholderFragment.java
│ │ │ └── SectionsPagerAdapter.java
│ │ └── utility/
│ │ ├── CSRFGet.java
│ │ ├── ImageDownloadUtility.java
│ │ ├── IntentUtility.java
│ │ ├── LogUtility.java
│ │ ├── Utility.java
│ │ └── network/
│ │ └── NetworkUtil.java
│ └── res/
│ ├── drawable/
│ │ ├── ic_access_time.xml
│ │ ├── ic_add.xml
│ │ ├── ic_archive.xml
│ │ ├── ic_arrow_back.xml
│ │ ├── ic_arrow_forward.xml
│ │ ├── ic_backspace.xml
│ │ ├── ic_bookmark.xml
│ │ ├── ic_bookmark_border.xml
│ │ ├── ic_burst_mode.xml
│ │ ├── ic_chat_bubble.xml
│ │ ├── ic_check.xml
│ │ ├── ic_check_circle.xml
│ │ ├── ic_close.xml
│ │ ├── ic_cnbw.xml
│ │ ├── ic_content_copy.xml
│ │ ├── ic_delete.xml
│ │ ├── ic_exit_to_app.xml
│ │ ├── ic_favorite.xml
│ │ ├── ic_favorite_border.xml
│ │ ├── ic_filter_list.xml
│ │ ├── ic_find_in_page.xml
│ │ ├── ic_folder.xml
│ │ ├── ic_gbbw.xml
│ │ ├── ic_hashtag.xml
│ │ ├── ic_help.xml
│ │ ├── ic_jpbw.xml
│ │ ├── ic_keyboard_arrow_left.xml
│ │ ├── ic_keyboard_arrow_right.xml
│ │ ├── ic_launcher_calculator_foreground.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_logo.xml
│ │ ├── ic_mode_edit.xml
│ │ ├── ic_pause.xml
│ │ ├── ic_pdf.xml
│ │ ├── ic_person.xml
│ │ ├── ic_play.xml
│ │ ├── ic_refresh.xml
│ │ ├── ic_rotate_90_degrees.xml
│ │ ├── ic_save.xml
│ │ ├── ic_search.xml
│ │ ├── ic_select_all.xml
│ │ ├── ic_settings.xml
│ │ ├── ic_share.xml
│ │ ├── ic_shuffle.xml
│ │ ├── ic_sort.xml
│ │ ├── ic_sort_by_alpha.xml
│ │ ├── ic_star.xml
│ │ ├── ic_star_border.xml
│ │ ├── ic_view_1.xml
│ │ ├── ic_view_2.xml
│ │ ├── ic_view_3.xml
│ │ ├── ic_view_4.xml
│ │ ├── ic_void.xml
│ │ ├── ic_world.xml
│ │ ├── side_nav_bar.xml
│ │ └── thumb.xml
│ ├── drawable-anydpi/
│ │ ├── ic_archive.xml
│ │ ├── ic_check.xml
│ │ ├── ic_close.xml
│ │ ├── ic_file.xml
│ │ ├── ic_pause.xml
│ │ └── ic_play.xml
│ ├── drawable-night/
│ │ ├── ic_logo.xml
│ │ └── side_nav_bar.xml
│ ├── layout/
│ │ ├── activity_api_key.xml
│ │ ├── activity_bookmark.xml
│ │ ├── activity_comment.xml
│ │ ├── activity_gallery.xml
│ │ ├── activity_main.xml
│ │ ├── activity_pin.xml
│ │ ├── activity_random.xml
│ │ ├── activity_search.xml
│ │ ├── activity_settings.xml
│ │ ├── activity_status_viewer.xml
│ │ ├── activity_tag_filter.xml
│ │ ├── activity_zoom.xml
│ │ ├── app_bar_gallery.xml
│ │ ├── app_bar_main.xml
│ │ ├── autocomplete_entry.xml
│ │ ├── bookmark_layout.xml
│ │ ├── cftoken_layout.xml
│ │ ├── chip_layout.xml
│ │ ├── chip_layout_entry.xml
│ │ ├── comment_layout.xml
│ │ ├── content_gallery.xml
│ │ ├── content_main.xml
│ │ ├── dialog_add_status.xml
│ │ ├── entry_download_layout.xml
│ │ ├── entry_download_layout_compact.xml
│ │ ├── entry_history.xml
│ │ ├── entry_layout.xml
│ │ ├── entry_layout_single.xml
│ │ ├── entry_status.xml
│ │ ├── entry_tag_layout.xml
│ │ ├── fragment_status_viewer.xml
│ │ ├── fragment_tag_filter.xml
│ │ ├── fragment_zoom.xml
│ │ ├── image_void_full.xml
│ │ ├── image_void_static.xml
│ │ ├── info_layout.xml
│ │ ├── local_sort_type.xml
│ │ ├── multichoice_adapter.xml
│ │ ├── nav_header_main.xml
│ │ ├── page_changer.xml
│ │ ├── page_switcher.xml
│ │ ├── range_selector.xml
│ │ ├── related_recycler.xml
│ │ ├── search_options.xml
│ │ ├── search_range.xml
│ │ ├── sub_tag_layout.xml
│ │ ├── tags_layout.xml
│ │ └── zoom_manager.xml
│ ├── layout-land/
│ │ └── activity_random.xml
│ ├── menu/
│ │ ├── activity_main_drawer.xml
│ │ ├── download.xml
│ │ ├── gallery.xml
│ │ ├── history.xml
│ │ ├── local_multichoice.xml
│ │ ├── main.xml
│ │ ├── menu_tag_filter.xml
│ │ ├── menu_zoom.xml
│ │ ├── search.xml
│ │ └── status_viewer.xml
│ ├── mipmap-anydpi/
│ │ ├── ic_launcher.xml
│ │ ├── ic_launcher_calculator.xml
│ │ └── ic_launcher_calculator_round.xml
│ ├── resources.properties
│ ├── values/
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_launcher_calculator_background.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── values-ar-rSA/
│ │ └── strings.xml
│ ├── values-de-rDE/
│ │ └── strings.xml
│ ├── values-es-rES/
│ │ └── strings.xml
│ ├── values-fr-rFR/
│ │ └── strings.xml
│ ├── values-it-rIT/
│ │ └── strings.xml
│ ├── values-ja-rJP/
│ │ └── strings.xml
│ ├── values-night/
│ │ └── colors.xml
│ ├── values-pt-rBR/
│ │ └── strings.xml
│ ├── values-ru-rRU/
│ │ └── strings.xml
│ ├── values-tr-rTR/
│ │ └── strings.xml
│ ├── values-uk-rUA/
│ │ └── strings.xml
│ ├── values-w820dp/
│ │ └── dimens.xml
│ ├── values-zh-rCN/
│ │ └── strings.xml
│ ├── values-zh-rTW/
│ │ └── strings.xml
│ └── xml/
│ ├── backup_content.xml
│ ├── provider_paths.xml
│ ├── settings.xml
│ ├── settings_column.xml
│ └── settings_data.xml
├── build.gradle.kts
├── crowdin.yml
├── data/
│ ├── tags.json
│ ├── tagsPretty.json
│ └── tagsVersion
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── scripts/
│ ├── requirements.txt
│ └── update_tags.py
└── settings.gradle.kts
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
# editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yaml
================================================
name: Bug Report
description: Create a report to help us improve
labels: [ "bug" ]
body:
- type: checkboxes
attributes:
label: Checklist
description: Please confirm that you have done following steps.
options:
- label: I have looked at the common issues and ways to fix them in the [wiki](https://github.com/maxwai/NClientV3/wiki)
required: true
- label: I have searched the existing issues for the same bug
required: true
- label: I have attached the log file as an attachment to this issue
required: true
- type: textarea
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
attributes:
label: Steps To Reproduce
description: Steps to reproduce the behavior.
placeholder: |
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
validations:
required: true
- type: textarea
attributes:
label: Expected behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem.
validations:
required: false
- type: input
attributes:
label: Android Version
description: Android Version of the phone where the App is installed
placeholder: "14"
validations:
required: true
- type: input
attributes:
label: App Version
description: App Version where the bug happens
placeholder: "4.0.9"
validations:
required: true
- type: textarea
attributes:
label: Additional context
description: Add any other context about the problem here.
validations:
required: false
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yaml
================================================
name: Feature request
description: Suggest an idea for this project
labels: [ "enhancement" ]
body:
- type: checkboxes
attributes:
label: Checklist
description: Please confirm that you have done following steps.
options:
- label: I have searched the existing issues for the same feature
required: true
- type: textarea
attributes:
label: Is your feature request related to a problem? Please describe
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
validations:
required: false
- type: textarea
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: false
- type: textarea
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: false
- type: textarea
attributes:
label: Additional context
description: Add any other context about the problem here.
validations:
required: false
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
A similar PR may already be submitted!
Please search among the [Pull request](../) before creating one.
Thanks for submitting a pull request! Please provide enough information so that others can review your pull request:
For more information, see the `CONTRIBUTING` guide.
**Summary**
<!-- Summary of the PR -->
This PR fixes/implements the following **bugs/features**
* [ ] Bug 1
* [ ] Bug 2
* [ ] Feature 1
* [ ] Feature 2
* [ ] Breaking changes
<!-- You can skip this if you're fixing a typo or adding an app to the Showcase. -->
Explain the **motivation** for making this change. What existing problem does the pull request solve?
<!-- Example: When "Adding a function to do X", explain why it is necessary to have a way to do X. -->
**Test plan (required)**
Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI.
<!-- Make sure tests pass on both Travis and Circle CI. -->
**Code formatting**
<!-- See the simple style guide. -->
**Closing issues**
<!-- Put `closes #XXXX` in your comment to auto-close the issue that your PR fixes (if such). -->
Fixes #
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
# Enable version updates for Gradle
- package-ecosystem: "gradle"
# Look for a `build.gradle.kts` in the `root` directory
directory: "/"
# Check for updates once a week
schedule:
interval: "weekly"
# Enable version updates for npm
- package-ecosystem: "pip"
# Look for `package.json` and `lock` files in the `root` directory
directory: "/scripts"
# Check the npm registry for updates every day (weekdays)
schedule:
interval: "weekly"
# Enable version updates for GitHub Actions
- package-ecosystem: "github-actions"
# Workflow files stored in the default location of `.github/workflows`
# You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.
directory: "/"
schedule:
interval: "weekly"
================================================
FILE: .github/workflows/android.yml
================================================
name: Android CI
on:
push:
branches:
- 'main'
pull_request:
branches:
- '*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v6
- name: set up JDK 17
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'temurin'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Add empty keystore.properties
run: |
echo "storePassword=dummy" > keystore.properties
echo "keyPassword=dummy" >> keystore.properties
echo "keyAlias=dummy" >> keystore.properties
echo "storeFile=dummy.jks" >> keystore.properties
- name: Assemble Debug with Gradle
run: ./gradlew assembleDebug
- name: Bundle Debug with Gradle
run: ./gradlew bundleDebug
- name: Upload Artifact
uses: actions/upload-artifact@v7
with:
name: Debug APKs
path: app/build/outputs/apk/
retention-days: 30
================================================
FILE: .github/workflows/dependencies.yml
================================================
name: Dependency Submission
on:
push:
branches:
- 'main'
permissions:
contents: write
jobs:
dependency-submission:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v6
- name: Setup JDK 17
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'temurin'
- name: Add empty keystore.properties
run: |
echo "storePassword=dummy" > keystore.properties
echo "keyPassword=dummy" >> keystore.properties
echo "keyAlias=dummy" >> keystore.properties
echo "storeFile=dummy.jks" >> keystore.properties
- name: Generate and submit dependency graph
uses: gradle/actions/dependency-submission@v6
with:
# Exclude dependencies that are only resolved in test classpaths
dependency-graph-exclude-configurations: '.*([aA]ndroidTest|android-test-plugin|unified-test-platform|lint|UnitTest|^test[A-Z]).*'
================================================
FILE: .github/workflows/update_data.yml
================================================
name: Update Data
on:
schedule:
- cron: "42 1 * * 0"
workflow_dispatch:
jobs:
update:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout sources
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.13"
- name: Install dependencies
run: |
pip install -r scripts/requirements.txt
- name: Run update script
run: python scripts/update_tags.py
- name: Create Pull Request
uses: peter-evans/create-pull-request@v8
with:
commit-message: Update tags.json
branch: ci/update-tags
title: 'Update tags'
body: 'Changed files in data directory'
reviewers: maxwai
================================================
FILE: .gitignore
================================================
*.iml
*.apk
.gradle
/local.properties
.idea/
output.json
.DS_Store
/build
/captures
/svgs
/app/release
/app/debug
/app/schemas
.externalNativeBuild
/crowdin.properties
/keystore.properties
*.jks
================================================
FILE: DCO
================================================
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2024 Maxwai
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# NClientV3
[](https://github.com/maxwai/NClientV3/releases/latest)
An unofficial NHentai Android Client. This is a fork of the original Project by [@Dar9586](https://github.com/Dar9586) found [here](https://github.com/Dar9586/NClientV2)
This app works for devices from API 26 (Android 8) and above.
For Devices Running Android 8 (SDK 26 and 27) there is a separate APK with `pre28` in the name. Support for this Version of the app will be reduced.
Releases: <https://github.com/maxwai/NClientV3/releases>
## Migrate from original NClientV2 to NClientV3
Info can be found in the [wiki](https://github.com/maxwai/NClientV3/wiki/Migrate-from-NClientV2-to-NClientV3)
## Translate App
You can help translate the Project by going to the Crowdin Project [here](https://crowdin.com/project/nclientv3/invite?h=33e3f83681ebaea1bf037ed157d2ea272410538).
If your desired language is missing, write an issue, the language will be added.
## API Features
- Browse main page
- Search by query or tags
- Include or exclude tags
- Blur or hide excluded tags
- Download manga
- Favorite galleries
- Enable PIN to access the app
## Custom feature
- Share galleries
- Open in browser
- Bookmark
## App Screen
| Main page | Lateral menu |
|:-------------------------------------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------:|
|  |  |
| Search | Random manga |
|  |  |
## Contributors
- [shirokun20](https://github.com/shirokun20) for the initial Bug fixes
- [w0x8m](https://github.com/w0x8m) for the new language picker & Chinese Simplified & Traditional translation
- [ananas7](https://github.com/ananas7) for Arabic translation
- [raymi7066](https://github.com/raymi7066) for Chinese Simplified translation
- Худі Таджик (tadzikhudi) for Ukrainian translation
- [PegadaDLancha](https://github.com/PegadaDLancha) for Brazilian Portuguese translation
- Ivan Lost (dovakin1886) for Ukrainian translation
- crorcetn for Japanese translation
- [Inori333](https://github.com/inori-3333) for the initial implementation of the new api
- [Kronos2308](https://github.com/kronos2308) for Spanish translation
- [Locked_Fog](https://github.com/locked-fog) for Chinese Simplified translation
## Contributors of original Project
- [Still34](https://github.com/Still34) for code cleanup & Traditional Chinese translation
- [TacoTheDank](https://github.com/TacoTheDank) for XML and gradle cleanup
- [hmaltr](https://github.com/hmaltr) for Turkish translation and issue moderation
- [ZerOri](https://github.com/ZerOri) and [linsui](https://github.com/linsui) for Chinese translation
- [herrsunchess](https://github.com/herrsunchess) for German translation
- [eme22](https://github.com/herrsunchess) for Spanish translation
- [velosipedistufa](https://github.com/velosipedistufa) for Russian translation
- [bottomtextboy](https://github.com/bottomtextboy) for Arabic translation
- [MaticBabnik](https://github.com/MaticBabnik) for bug fixes
- [DontPayAttention](https://github.com/DontPayAttention) for French translation
- [kuragehimekurara1](https://github.com/kuragehimekurara1) for Japanese translation
- [chayleaf](https://github.com/chayleaf) for Cloudflare bypass
- [Atmosphelen](https://github.com/Atmosphelen) for Ukrainian translation
## Star History
<a href="https://www.star-history.com/#maxwai/NClientV3&type=date&legend=top-left">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=maxwai/NClientV3&type=date&theme=dark&legend=top-left" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=maxwai/NClientV3&type=date&legend=top-left" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=maxwai/NClientV3&type=date&legend=top-left" />
</picture>
</a>
## Libraries
- OKHttp ([License](https://github.com/square/okhttp/blob/master/LICENSE.txt))
- PersistentCookieJar ([License](https://github.com/franmontiel/PersistentCookieJar/blob/master/LICENSE.txt))
- JSoup ([License](https://github.com/jhy/jsoup/blob/master/LICENSE))
- Glide ([License](https://github.com/bumptech/glide/blob/master/LICENSE))
- AmbilWarna ([License](https://github.com/yukuku/ambilwarna/blob/master/LICENSE))
- AndroidFastScroll ([License](https://github.com/zhanghai/AndroidFastScroll/blob/master/LICENSE))
## License
```text
Copyright 2024 maxwai
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```
================================================
FILE: SECURITY.md
================================================
# Security Policy
## Supported Versions
Only the latest version is supported. The `pre28` versions are also not supported.
## Reporting a Vulnerability
If you discover a security vulnerability, please open a private security report in the [Security tab](https://github.com/maxwai/NClientV3/security) of the repo or send an email to [security.penny394@passmail.net](mailto:security.penny394@passmail.net) Please do not create a public issue for the vulnerability.
Your email should include the following information:
- A description of the vulnerability
- Steps to reproduce the vulnerability
- Possible impact of the vulnerability
- Any suggested mitigation or remediation steps
We will respond to your email as soon as possible and work with you to address any security issues.
If there isn't a response within 5 working days (considering public holidays in Germany), please send a follow-up post or email, depending on how you reported the vulnerability.
## Language
All reports must be done in English
================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/build.gradle.kts
================================================
import com.android.build.api.artifact.SingleArtifact
import java.io.FileInputStream
import java.util.Properties
import com.android.build.api.variant.BuiltArtifactsLoader
import java.io.File
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction
import org.gradle.internal.extensions.stdlib.capitalized
plugins {
id("com.android.application")
}
val keystorePropertiesFile: File = rootProject.file("keystore.properties")
val keystoreProperties = Properties().apply {
load(FileInputStream(keystorePropertiesFile))
}
android {
signingConfigs {
create("release") {
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
storeFile = file(keystoreProperties["storeFile"] as String)
storePassword = keystoreProperties["storePassword"] as String
}
}
compileSdk = 36
defaultConfig {
applicationId = "com.maxwai.nclientv3"
// Format: MmPPbb
// M: Major, m: minor, P: Patch, b: build
versionCode = 420500
multiDexEnabled = true
versionName = "4.2.5"
vectorDrawables.useSupportLibrary = true
proguardFiles("proguard-rules.pro")
}
flavorDimensions += "sdk"
productFlavors {
create("post28") {
dimension = "sdk"
targetSdk = 36
minSdk = 28
}
create("pre28") {
dimension = "sdk"
targetSdk = 28
minSdk = 26
}
}
buildTypes {
getByName("release") {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"))
versionNameSuffix = "-release"
resValue("string", "app_name", "NClientV3")
signingConfig = signingConfigs.getByName("release")
}
getByName("debug") {
applicationIdSuffix = ".debug"
versionNameSuffix = "-debug"
resValue("string", "app_name", "NClientV3 Debug")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
lint {
abortOnError = false
checkReleaseBuilds = false
disable += "RestrictedApi"
}
bundle {
language {
// Specifies that the app bundle should not support
// configuration APKs for language resources. These
// resources are instead packaged with each base and
// dynamic feature APK.
@Suppress("UnstableApiUsage")
enableSplit = false
}
}
namespace = "com.maxwai.nclientv3"
buildFeatures {
buildConfig = true
}
androidResources {
@Suppress("UnstableApiUsage")
generateLocaleConfig = true
}
}
androidComponents {
onVariants() { variant ->
var renameTask = tasks.register<CreateRenamedApk>("createRenamedApk${variant.flavorName?.capitalized()}${variant.buildType?.capitalized()}") {
this.apkFolder.set(variant.artifacts.get(SingleArtifact.APK))
this.builtArtifactsLoader.set(variant.artifacts.getBuiltArtifactsLoader())
this.versionName.set(variant.outputs.single().versionName.get().substringBeforeLast("-"))
this.suffix.set((if (variant.flavorName == "pre28") "_pre28" else "") + (if (variant.buildType == "debug") "_debug" else ""))
}.get()
tasks.whenTaskAdded {
if (name == "assemble${variant.flavorName?.capitalized()}${variant.buildType?.capitalized()}") {
finalizedBy(renameTask)
}
}
}
}
dependencies {
// Android
implementation("androidx.appcompat:appcompat:1.7.1")
implementation("androidx.cardview:cardview:1.0.0")
implementation("androidx.constraintlayout:constraintlayout:2.2.1")
implementation("androidx.fragment:fragment:1.8.9")
implementation("androidx.preference:preference:1.2.1")
implementation("androidx.viewpager2:viewpager2:1.1.0")
implementation("androidx.recyclerview:recyclerview:1.4.0")
implementation("androidx.work:work-runtime:2.11.2")
implementation("androidx.core:core-splashscreen:1.2.0")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.2.0")
implementation("androidx.biometric:biometric:1.1.0")
implementation("com.google.android.material:material:1.13.0")
// Other
// image loading and caching
implementation("com.github.bumptech.glide:glide:5.0.5") {
exclude(group = "com.android.support")
}
implementation("com.github.bumptech.glide:okhttp3-integration:5.0.5@aar")
annotationProcessor("com.github.bumptech.glide:compiler:5.0.5")
// For Http Connection
implementation("com.squareup.okhttp3:okhttp-urlconnection:5.3.2")
// Used to store the cookies between runs
implementation("com.github.franmontiel:PersistentCookieJar:v1.0.1")
// To parse HTML
implementation("org.jsoup:jsoup:1.22.1")
// color picker
implementation("com.github.yukuku:ambilwarna:2.0.1")
// fast scroll
implementation("me.zhanghai.android.fastscroll:library:1.3.0")
}
abstract class CreateRenamedApk : DefaultTask() {
@get:InputFiles
abstract val apkFolder: DirectoryProperty
@get:Internal
abstract val builtArtifactsLoader: Property<BuiltArtifactsLoader>
@get:Input
abstract val versionName: Property<String>
@get:Input
abstract val suffix: Property<String>
@TaskAction
fun taskAction() {
val builtArtifacts = builtArtifactsLoader.get().load(apkFolder.get()) ?: throw RuntimeException("Cannot load APKs")
File(builtArtifacts.elements.single().outputFile).renameTo(
File(apkFolder.asFile.get(), "NClientV3_${versionName.get()}${suffix.get()}.apk")
)
}
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.kts.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-ignorewarnings
-keep class * {
public private *;
}
#glide proguard
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-assumenosideeffects class com.maxwai.nclientv3.utility.LogUtility {
public static void d(...);
public static void i(...);
public static void e(...);
}
-keep public class * implements com.bumptech.glide.module.GlideModule
-dontwarn com.bumptech.glide.load.resource.bitmap.VideoDecoder
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.REQUEST_INSTALL_PACKAGES"
tools:ignore="RequestInstallPackagesPolicy" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<uses-sdk tools:overrideLibrary="me.zhanghai.android.fastscroll" />
<application
android:name=".components.activities.CrashApplication"
android:allowBackup="true"
android:enableOnBackInvokedCallback="true"
android:fullBackupContent="@xml/backup_content"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="UnusedAttribute">
<activity android:name=".StatusManagerActivity" />
<activity
android:name=".PINActivity"
android:configChanges="orientation|screenSize"
android:exported="true">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity-alias
android:name=".components.launcher.LauncherReal"
android:enabled="true"
android:exported="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher"
android:targetActivity=".PINActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".components.launcher.LauncherCalculator"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_calculator"
android:label="@string/app_name_fake_calculator"
android:roundIcon="@mipmap/ic_launcher_calculator_round"
android:targetActivity=".PINActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity android:name=".StatusViewerActivity" />
<activity android:name=".HistoryActivity" />
<activity android:name=".BookmarkActivity" />
<activity android:name=".CommentActivity" />
<activity android:name=".SearchActivity" />
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:hardwareAccelerated="true"
android:parentActivityName=".PINActivity">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="nhentai.net" />
<data android:path="/" />
<data android:pathPrefix="/search/" />
<data android:pathPrefix="/parody/" />
<data android:pathPrefix="/character/" />
<data android:pathPrefix="/tag/" />
<data android:pathPrefix="/artist/" />
<data android:pathPrefix="/favorites/" />
<data android:pathPrefix="/group/" />
<data android:pathPrefix="/language/" />
<data android:pathPrefix="/category/" />
</intent-filter>
</activity>
<activity
android:name=".GalleryActivity"
android:exported="true"
android:label="@string/title_activity_gallery"
android:parentActivityName=".MainActivity">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="nhentai.net" />
<data android:pathPattern="/g/.*" />
</intent-filter>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.maxwai.nclientv3.MainActivity" />
</activity>
<activity
android:name=".ZoomActivity"
android:configChanges="orientation|screenSize"
android:label="@string/title_activity_zoom"
android:parentActivityName=".GalleryActivity" />
<activity
android:name=".LocalActivity"
android:configChanges="orientation|screenSize"
android:parentActivityName=".MainActivity" />
<activity
android:name=".TagFilterActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:label="@string/title_activity_tag_filter"
android:parentActivityName=".MainActivity">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="nhentai.net" />
<data android:pathPrefix="/tags" />
<data android:pathPrefix="/artists" />
<data android:pathPrefix="/characters" />
<data android:pathPrefix="/parodies" />
<data android:pathPrefix="/groups" />
</intent-filter>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.maxwai.nclientv3.MainActivity" />
</activity>
<activity android:name=".SettingsActivity" />
<activity
android:name=".RandomActivity"
android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:pathPrefix="/random" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="nhentai.net" />
</intent-filter>
</activity>
<activity
android:name=".FavoriteActivity"
android:configChanges="orientation|screenSize"
android:parentActivityName=".MainActivity" />
<activity
android:name=".CopyToClipboardActivity"
android:icon="@drawable/ic_content_copy"
android:label="@string/copyURL" />
<activity
android:name=".ApiKeyActivity"
android:label="@string/title_activity_api_key">
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
</application>
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:mimeType="application/pdf" />
</intent>
</queries>
</manifest>
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/ApiKeyActivity.java
================================================
package com.maxwai.nclientv3;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.button.MaterialButton;
import com.maxwai.nclientv3.components.activities.GeneralActivity;
import com.maxwai.nclientv3.settings.AuthStore;
import com.maxwai.nclientv3.settings.Global;
import com.maxwai.nclientv3.settings.Login;
import com.maxwai.nclientv3.utility.LogUtility;
import com.maxwai.nclientv3.utility.Utility;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.Response;
public class ApiKeyActivity extends GeneralActivity {
private TextView statusText;
private LinearLayout inputGroup;
private EditText apiKeyInput;
private ProgressBar progressBar;
private MaterialButton openApiKeyPage;
private MaterialButton clearApiKey;
private MaterialButton validateApiKey;
private boolean validationInFlight = false;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_api_key);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setTitle(R.string.title_activity_api_key);
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(true);
statusText = findViewById(R.id.api_key_status_text);
inputGroup = findViewById(R.id.api_key_input_group);
apiKeyInput = findViewById(R.id.api_key_input);
progressBar = findViewById(R.id.login_progress);
openApiKeyPage = findViewById(R.id.open_api_key_page);
clearApiKey = findViewById(R.id.clear_api_key);
validateApiKey = findViewById(R.id.validate_api_key);
setInputVisible(true);
openApiKeyPage.setOnClickListener(v -> openApiKeyPage());
clearApiKey.setOnClickListener(v -> clearSavedApiKey());
validateApiKey.setOnClickListener(v -> validateAndSaveApiKey());
loadSavedApiKey();
}
@Override
protected void onResume() {
super.onResume();
loadSavedApiKey();
}
private void openApiKeyPage() {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Utility.getBaseUrl() + "user/settings#apikeys")));
}
private void updateStatusMessage(@NonNull String message) {
statusText.setText(message);
}
private void setInputVisible(boolean visible) {
inputGroup.setVisibility(visible ? View.VISIBLE : View.GONE);
}
private void setLoading(boolean loading) {
validationInFlight = loading;
progressBar.setVisibility(loading ? View.VISIBLE : View.GONE);
apiKeyInput.setEnabled(!loading);
openApiKeyPage.setEnabled(!loading);
clearApiKey.setEnabled(!loading && AuthStore.hasApiKey(this));
validateApiKey.setEnabled(!loading);
updateStatusMessage(getStatusMessage());
}
private void loadSavedApiKey() {
String apiKey = AuthStore.getApiKey(this);
if (apiKey != null && !validationInFlight) {
apiKeyInput.setText(apiKey);
}
clearApiKey.setEnabled(!validationInFlight && AuthStore.hasApiKey(this));
updateStatusMessage(getStatusMessage());
}
@NonNull
private String getStatusMessage() {
if (AuthStore.hasValidApiKey(this)) return getString(R.string.login_status_api_key_saved);
if (AuthStore.hasApiKey(this)) return getString(R.string.login_status_api_key_invalid);
return getString(R.string.login_api_key_intro_message);
}
private void clearSavedApiKey() {
AuthStore.clear(this);
Login.updateUser(null);
apiKeyInput.setText("");
clearApiKey.setEnabled(false);
updateStatusMessage(getStatusMessage());
Toast.makeText(this, R.string.login_api_key_removed, Toast.LENGTH_SHORT).show();
}
private void validateAndSaveApiKey() {
String apiKey = apiKeyInput.getText().toString().trim();
if (apiKey.isEmpty()) {
Toast.makeText(this, R.string.login_api_key_empty, Toast.LENGTH_SHORT).show();
return;
}
setLoading(true);
Request request = new Request.Builder()
.url(Utility.getApiBaseUrl() + "favorites")
.header("Authorization", "Key " + apiKey)
.build();
Global.getClient(this).newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
LogUtility.e("API key validation failed", e);
runOnUiThread(() -> {
setLoading(false);
Toast.makeText(ApiKeyActivity.this, R.string.unable_to_connect_to_the_site, Toast.LENGTH_SHORT).show();
});
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
try (response) {
if (response.isSuccessful()) {
AuthStore.saveApiKey(ApiKeyActivity.this, apiKey, true);
Login.updateUser(null);
runOnUiThread(() -> {
setLoading(false);
Toast.makeText(ApiKeyActivity.this, R.string.login_api_key_saved, Toast.LENGTH_SHORT).show();
finish();
});
return;
}
LogUtility.w("API key validation rejected: " + response.code());
runOnUiThread(() -> {
setLoading(false);
Toast.makeText(ApiKeyActivity.this, R.string.login_api_key_invalid, Toast.LENGTH_SHORT).show();
});
}
}
});
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) finish();
return super.onOptionsItemSelected(item);
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/BookmarkActivity.java
================================================
package com.maxwai.nclientv3;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.RecyclerView;
import com.maxwai.nclientv3.adapters.BookmarkAdapter;
import com.maxwai.nclientv3.components.activities.GeneralActivity;
import com.maxwai.nclientv3.components.widgets.CustomLinearLayoutManager;
import java.util.Objects;
public class BookmarkActivity extends GeneralActivity {
BookmarkAdapter adapter;
RecyclerView recycler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Global.initActivity(this);
setContentView(R.layout.activity_bookmark);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = Objects.requireNonNull(getSupportActionBar());
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(R.string.manage_bookmarks);
recycler = findViewById(R.id.recycler);
adapter = new BookmarkAdapter(this);
recycler.setLayoutManager(new CustomLinearLayoutManager(this));
recycler.setAdapter(adapter);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/CommentActivity.java
================================================
package com.maxwai.nclientv3;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.JsonReader;
import android.util.JsonToken;
import android.util.JsonWriter;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DividerItemDecoration;
import com.maxwai.nclientv3.adapters.CommentAdapter;
import com.maxwai.nclientv3.api.comments.Comment;
import com.maxwai.nclientv3.api.comments.CommentsFetcher;
import com.maxwai.nclientv3.components.activities.BaseActivity;
import com.maxwai.nclientv3.settings.Global;
import com.maxwai.nclientv3.settings.Login;
import com.maxwai.nclientv3.utility.Utility;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Locale;
import java.util.Objects;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class CommentActivity extends BaseActivity {
private static final int MINIUM_MESSAGE_LENGHT = 10;
private CommentAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Global.initActivity(this);
setContentView(R.layout.activity_comment);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = Objects.requireNonNull(getSupportActionBar());
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(R.string.comments);
findViewById(R.id.page_switcher).setVisibility(View.GONE);
int id = getIntent().getIntExtra(getPackageName() + ".GALLERYID", -1);
if (id == -1) {
finish();
return;
}
recycler = findViewById(R.id.recycler);
refresher = findViewById(R.id.refresher);
refresher.setOnRefreshListener(() -> new CommentsFetcher(CommentActivity.this, id).start());
EditText commentText = findViewById(R.id.commentText);
findViewById(R.id.card).setVisibility(Login.isLogged() ? View.VISIBLE : View.GONE);
findViewById(R.id.sendButton).setOnClickListener(v -> {
if (commentText.getText().toString().length() < MINIUM_MESSAGE_LENGHT) {
Toast.makeText(this, getString(R.string.minimum_comment_length, MINIUM_MESSAGE_LENGHT), Toast.LENGTH_SHORT).show();
return;
}
String submitUrl = String.format(Locale.US, Utility.getApiBaseUrl() + "galleries/%d/comments", id);
String requestString = createRequestString(commentText.getText().toString());
commentText.setText("");
RequestBody body = RequestBody.create(requestString, MediaType.get("application/json"));
Global.getClient(this)
.newCall(new Request.Builder().url(submitUrl).post(body).build())
.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
try (JsonReader reader = new JsonReader(response.body().charStream())) {
Comment comment = new Comment(reader);
if (adapter != null)
adapter.addComment(comment);
}
}
});
});
// TODO: deactivated feature until fixed
findViewById(R.id.sendButton).setClickable(false);
findViewById(R.id.sendButton).setEnabled(false);
commentText.setEnabled(false);
commentText.setHint("Deactivated feature");
// TODO: end
changeLayout(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
recycler.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
refresher.setRefreshing(true);
new CommentsFetcher(CommentActivity.this, id).start();
}
public void setAdapter(CommentAdapter adapter) {
this.adapter = adapter;
}
private String createRequestString(String text) {
try (StringWriter writer = new StringWriter();
JsonWriter json = new JsonWriter(writer)) {
json.beginObject();
json.name("body").value(text);
// TODO: this now needs pow and captcha
json.endObject();
return writer.toString();
} catch (IOException ignore) {
}
return "";
}
@Override
protected int getPortraitColumnCount() {
return 1;
}
@Override
protected int getLandscapeColumnCount() {
return 2;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
getOnBackPressedDispatcher().onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/CopyToClipboardActivity.java
================================================
package com.maxwai.nclientv3;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.widget.Toast;
import com.maxwai.nclientv3.components.activities.GeneralActivity;
public class CopyToClipboardActivity extends GeneralActivity {
public static void copyTextToClipboard(Context context, String text) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("text", text);
if (clipboard != null)
clipboard.setPrimaryClip(clip);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Uri uri = getIntent().getData();
if (uri != null) {
copyTextToClipboard(this, uri.toString());
Toast.makeText(this, R.string.link_copied_to_clipboard, Toast.LENGTH_SHORT).show();
}
finish();
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/FavoriteActivity.java
================================================
package com.maxwai.nclientv3;
import android.content.Intent;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import com.maxwai.nclientv3.adapters.FavoriteAdapter;
import com.maxwai.nclientv3.api.components.Gallery;
import com.maxwai.nclientv3.async.database.Queries;
import com.maxwai.nclientv3.async.downloader.DownloadGalleryV2;
import com.maxwai.nclientv3.components.activities.BaseActivity;
import com.maxwai.nclientv3.components.views.PageSwitcher;
import com.maxwai.nclientv3.settings.Global;
import com.maxwai.nclientv3.utility.Utility;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.Objects;
public class FavoriteActivity extends BaseActivity {
private static final int ENTRY_PER_PAGE = 24;
private FavoriteAdapter adapter = null;
private boolean sortByTitle = false;
private PageSwitcher pageSwitcher;
private SearchView searchView;
public static int getEntryPerPage() {
return Global.isInfiniteScrollFavorite() ? Integer.MAX_VALUE : ENTRY_PER_PAGE;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Global.initActivity(this);
setContentView(R.layout.app_bar_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = Objects.requireNonNull(getSupportActionBar());
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(R.string.favorite_manga);
pageSwitcher = findViewById(R.id.page_switcher);
recycler = findViewById(R.id.recycler);
refresher = findViewById(R.id.refresher);
refresher.setRefreshing(true);
adapter = new FavoriteAdapter(this);
refresher.setOnRefreshListener(adapter::forceReload);
changeLayout(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
recycler.setAdapter(adapter);
pageSwitcher.setPages(1, 1);
pageSwitcher.setChanger(new PageSwitcher.DefaultPageChanger() {
@Override
public void pageChanged() {
if (adapter != null) adapter.changePage();
}
});
}
public int getActualPage() {
return pageSwitcher.getActualPage();
}
@Override
protected int getLandscapeColumnCount() {
return Global.getColLandFavorite();
}
@Override
protected int getPortraitColumnCount() {
return Global.getColPortFavorite();
}
private int calculatePages(@Nullable String text) {
int perPage = getEntryPerPage();
int totalEntries = Queries.FavoriteTable.countFavorite(text);
int div = totalEntries / perPage;
int mod = totalEntries % perPage;
return div + (mod == 0 ? 0 : 1);
}
@Override
protected void onResume() {
refresher.setEnabled(true);
refresher.setRefreshing(true);
String query = searchView == null ? null : searchView.getQuery().toString();
pageSwitcher.setTotalPage(calculatePages(query));
adapter.forceReload();
super.onResume();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
menu.findItem(R.id.download_page).setVisible(true);
menu.findItem(R.id.sort_by_name).setVisible(true);
menu.findItem(R.id.by_popular).setVisible(false);
menu.findItem(R.id.only_language).setVisible(false);
menu.findItem(R.id.add_bookmark).setVisible(false);
searchView = (androidx.appcompat.widget.SearchView) menu.findItem(R.id.search).getActionView();
Objects.requireNonNull(searchView).setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
pageSwitcher.setTotalPage(calculatePages(newText));
if (adapter != null)
adapter.getFilter().filter(newText);
return true;
}
});
Utility.tintMenu(this, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent i;
if (item.getItemId() == R.id.open_browser) {
i = new Intent(Intent.ACTION_VIEW, Uri.parse(Utility.getBaseUrl() + "favorites/"));
startActivity(i);
} else if (item.getItemId() == R.id.download_page) {
if (adapter != null) showDialogDownloadAll();
} else if (item.getItemId() == R.id.sort_by_name) {
sortByTitle = !sortByTitle;
adapter.setSortByTitle(sortByTitle);
item.setTitle(sortByTitle ? R.string.sort_by_latest : R.string.sort_by_title);
} else if (item.getItemId() == R.id.random_favorite) {
adapter.randomGallery();
}
return super.onOptionsItemSelected(item);
}
private void showDialogDownloadAll() {
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder
.setTitle(R.string.download_all_galleries_in_this_page)
.setIcon(R.drawable.ic_file)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok, (dialog, which) -> {
for (Gallery g : adapter.getAllGalleries())
DownloadGalleryV2.downloadGallery(this, g);
});
builder.show();
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/GalleryActivity.java
================================================
package com.maxwai.nclientv3;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckedTextView;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.snackbar.Snackbar;
import com.maxwai.nclientv3.adapters.GalleryAdapter;
import com.maxwai.nclientv3.api.InspectorV3;
import com.maxwai.nclientv3.api.components.Gallery;
import com.maxwai.nclientv3.api.components.GenericGallery;
import com.maxwai.nclientv3.async.database.Queries;
import com.maxwai.nclientv3.components.activities.BaseActivity;
import com.maxwai.nclientv3.components.status.Status;
import com.maxwai.nclientv3.components.status.StatusManager;
import com.maxwai.nclientv3.components.views.RangeSelector;
import com.maxwai.nclientv3.components.widgets.CustomGridLayoutManager;
import com.maxwai.nclientv3.settings.AuthStore;
import com.maxwai.nclientv3.settings.Favorites;
import com.maxwai.nclientv3.settings.Global;
import com.maxwai.nclientv3.utility.LogUtility;
import com.maxwai.nclientv3.utility.Utility;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import yuku.ambilwarna.AmbilWarnaDialog;
public class GalleryActivity extends BaseActivity {
@NonNull
private GenericGallery gallery = Gallery.emptyGallery();
private boolean isLocal;
private GalleryAdapter adapter;
private int zoom;
private boolean isLocalFavorite;
private Toolbar toolbar;
private MenuItem onlineFavoriteItem;
private String statusString;
private int newStatusColor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Global.initActivity(this);
setContentView(R.layout.activity_gallery);
if (Global.isLockScreen())
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = Objects.requireNonNull(getSupportActionBar());
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
recycler = findViewById(R.id.recycler);
refresher = findViewById(R.id.refresher);
masterLayout = findViewById(R.id.master_layout);
GenericGallery gal;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
gal = getIntent().getParcelableExtra(getPackageName() + ".GALLERY", GenericGallery.class);
} else {
gal = getIntent().getParcelableExtra(getPackageName() + ".GALLERY");
}
if (gal == null && !tryLoadFromURL()) {
finish();
return;
}
if (gal != null) this.gallery = gal;
if (gallery.getType() != GenericGallery.Type.LOCAL) {
Queries.HistoryTable.addGallery(((Gallery) gallery).toSimpleGallery());
}
LogUtility.d("" + gallery);
if (Global.useRtl()) recycler.setRotationY(180);
isLocal = getIntent().getBooleanExtra(getPackageName() + ".ISLOCAL", false);
zoom = getIntent().getIntExtra(getPackageName() + ".ZOOM", 0);
refresher.setEnabled(false);
recycler.setLayoutManager(new CustomGridLayoutManager(this, Global.getColumnCount()));
loadGallery(gallery, zoom);//if already has gallery
}
private boolean tryLoadFromURL() {
Uri data = getIntent().getData();
if (data != null && data.getPathSegments().size() >= 2) {//if using an URL
List<String> params = data.getPathSegments();
LogUtility.d(params.size() + ": " + params);
int id;
try {//if not an id return
id = Integer.parseInt(params.get(1));
} catch (NumberFormatException ignore) {
return false;
}
if (params.size() > 2) {//check if it has a specific page
try {
zoom = Integer.parseInt(params.get(2));
} catch (NumberFormatException e) {
LogUtility.e(e.getLocalizedMessage(), e);
zoom = 0;
}
}
InspectorV3.galleryInspector(this, id, new InspectorV3.DefaultInspectorResponse() {
@Override
public void onSuccess(List<GenericGallery> galleries) {
if (!galleries.isEmpty()) {
Intent intent = new Intent(GalleryActivity.this, GalleryActivity.class);
intent.putExtra(getPackageName() + ".GALLERY", galleries.get(0));
intent.putExtra(getPackageName() + ".ZOOM", zoom);
startActivity(intent);
}
finish();
}
}).start();
return true;
}
return false;
}
private void lookup() {
CustomGridLayoutManager manager = (CustomGridLayoutManager) recycler.getLayoutManager();
GalleryAdapter adapter = (GalleryAdapter) recycler.getAdapter();
Objects.requireNonNull(manager).setSpanSizeLookup(new CustomGridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return adapter == null ? 0 : (adapter.positionToType(position) == GalleryAdapter.Type.PAGE ? 1 : manager.getSpanCount());
}
});
}
private void loadGallery(GenericGallery gall, int zoom) {
this.gallery = gall;
if (getSupportActionBar() != null) {
applyTitle();
}
adapter = new GalleryAdapter(this, gallery, Global.getColumnCount());
recycler.setAdapter(adapter);
lookup();
if (zoom > 0 && Global.getDownloadPolicy() != Global.DataUsageType.NONE) {
Intent intent = new Intent(this, ZoomActivity.class);
intent.putExtra(getPackageName() + ".GALLERY", this.gallery);
intent.putExtra(getPackageName() + ".DIRECTORY", adapter.getDirectory());
intent.putExtra(getPackageName() + ".PAGE", zoom);
startActivity(intent);
}
checkBookmark();
}
private void checkBookmark() {
int page = Queries.ResumeTable.pageFromId(gallery.getId());
if (page < 0) return;
Snackbar snack = Snackbar.make(toolbar, getString(R.string.resume_from_page, page), Snackbar.LENGTH_LONG);
//Should be already compensated
snack.setAction(R.string.resume, v -> new Thread(() -> {
runOnUiThread(() -> recycler.scrollToPosition(page));
if (Global.getColumnCount() != 1) return;
Utility.threadSleep(500);
runOnUiThread(() -> recycler.scrollToPosition(page));
}).start());
snack.show();
}
private void applyTitle() {
CollapsingToolbarLayout collapsing = findViewById(R.id.collapsing);
ActionBar actionBar = getSupportActionBar();
final String title = gallery.getTitle();
if (collapsing == null || actionBar == null) return;
View.OnLongClickListener listener = v -> {
CopyToClipboardActivity.copyTextToClipboard(GalleryActivity.this, title);
GalleryActivity.this.runOnUiThread(
() -> Toast.makeText(GalleryActivity.this, R.string.title_copied_to_clipboard, Toast.LENGTH_SHORT).show()
);
return true;
};
collapsing.setOnLongClickListener(listener);
findViewById(R.id.toolbar).setOnLongClickListener(listener);
if (title.length() > 100) {
collapsing.setExpandedTitleTextAppearance(android.R.style.TextAppearance_DeviceDefault_Medium);
collapsing.setMaxLines(5);
} else {
collapsing.setExpandedTitleTextAppearance(android.R.style.TextAppearance_DeviceDefault_Large);
collapsing.setMaxLines(4);
}
actionBar.setTitle(title);
}
@Override
protected int getPortraitColumnCount() {
return 0;
}
@Override
protected int getLandscapeColumnCount() {
return 0;
}
public void initFavoriteIcon(Menu menu) {
boolean onlineFavorite = !isLocal && ((Gallery) gallery).isOnlineFavorite();
boolean unknown = getIntent().getBooleanExtra(getPackageName() + ".UNKNOWN", false);
MenuItem item = menu.findItem(R.id.add_online_gallery);
item.setIcon(onlineFavorite ? R.drawable.ic_star : R.drawable.ic_star_border);
if (unknown) item.setTitle(R.string.toggle_online_favorite);
else if (onlineFavorite) item.setTitle(R.string.remove_from_online_favorites);
else item.setTitle(R.string.add_to_online_favorite);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.gallery, menu);
isLocalFavorite = Favorites.isFavorite(gallery);
menu.findItem(R.id.favorite_manager).setIcon(isLocalFavorite ? R.drawable.ic_favorite : R.drawable.ic_favorite_border);
menuItemsVisible(menu);
initFavoriteIcon(menu);
Utility.tintMenu(this, menu);
updateColumnCount(false);
return true;
}
private void menuItemsVisible(Menu menu) {
boolean hasValidApiKey = AuthStore.hasValidApiKey(this);
boolean isValidOnline = gallery.isValid() && !isLocal;
onlineFavoriteItem = menu.findItem(R.id.add_online_gallery);
onlineFavoriteItem.setVisible(isValidOnline && hasValidApiKey);
menu.findItem(R.id.favorite_manager).setVisible(isValidOnline);
menu.findItem(R.id.download_gallery).setVisible(isValidOnline);
menu.findItem(R.id.related).setVisible(isValidOnline);
menu.findItem(R.id.comments).setVisible(isValidOnline);
menu.findItem(R.id.share).setVisible(gallery.isValid());
menu.findItem(R.id.load_internet).setVisible(isLocal && gallery.isValid());
}
@Override
protected void onResume() {
super.onResume();
updateColumnCount(false);
supportInvalidateOptionsMenu();
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
int id = item.getItemId();
if (id == R.id.download_gallery) {
if (Global.hasStoragePermission(this))
new RangeSelector(this, (Gallery) gallery).show();
else
requestStorage();
} else if (id == R.id.add_online_gallery) addToFavorite();
else if (id == R.id.change_view) updateColumnCount(true);
else if (id == R.id.load_internet) toInternet();
else if (id == R.id.manage_status) updateStatus();
else if (id == R.id.share) Global.shareGallery(this, gallery);
else if (id == R.id.comments) {
Intent i = new Intent(this, CommentActivity.class);
i.putExtra(getPackageName() + ".GALLERYID", gallery.getId());
startActivity(i);
} else if (id == R.id.related) {
if (recycler.getAdapter() != null)
recycler.smoothScrollToPosition(recycler.getAdapter().getItemCount());
} else if (id == R.id.favorite_manager) {
if (isLocalFavorite) {
Favorites.removeFavorite(gallery);
} else {
Favorites.addFavorite((Gallery) gallery);
}
isLocalFavorite = !isLocalFavorite;
item.setIcon(isLocalFavorite ? R.drawable.ic_favorite : R.drawable.ic_favorite_border);
Global.setTint(this, item.getIcon());
} else if (id == android.R.id.home) {
getOnBackPressedDispatcher().onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
private void updateStatus() {
List<String> statuses = StatusManager.getNames();
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
statusString = Queries.StatusMangaTable.getStatus(gallery.getId()).name;
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.select_dialog_singlechoice, statuses) {
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
CheckedTextView textView = (CheckedTextView) super.getView(position, convertView, parent);
textView.setTextColor(StatusManager.getByName(statuses.get(position)).opaqueColor());
return textView;
}
};
builder.setSingleChoiceItems(adapter, statuses.indexOf(statusString), (dialog, which) -> statusString = statuses.get(which));
builder
.setNeutralButton(R.string.add, (dialog, which) -> createNewStatusDialog())
.setNegativeButton(R.string.remove_status, (dialog, which) -> Queries.StatusMangaTable.remove(gallery.getId()))
.setPositiveButton(R.string.ok, (dialog, which) -> Queries.StatusMangaTable.insert(gallery, statusString))
.setTitle(R.string.change_status_title)
.show();
}
private void createNewStatusDialog() {
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
LinearLayout layout = (LinearLayout) View.inflate(this, R.layout.dialog_add_status, null);
EditText name = layout.findViewById(R.id.name);
Button btnColor = layout.findViewById(R.id.color);
do {
newStatusColor = Utility.RANDOM.nextInt() | 0xff000000;
} while (newStatusColor == Color.BLACK || newStatusColor == Color.WHITE);
btnColor.setBackgroundColor(newStatusColor);
btnColor.setOnClickListener(v -> new AmbilWarnaDialog(GalleryActivity.this, newStatusColor, false, new AmbilWarnaDialog.OnAmbilWarnaListener() {
@Override
public void onCancel(AmbilWarnaDialog dialog) {
}
@Override
public void onOk(AmbilWarnaDialog dialog, int color) {
if (color == Color.WHITE || color == Color.BLACK) {
Toast.makeText(GalleryActivity.this, R.string.invalid_color_selected, Toast.LENGTH_SHORT).show();
return;
}
newStatusColor = color;
btnColor.setBackgroundColor(color);
}
}).show());
builder.setView(layout);
builder.setTitle(R.string.create_new_status);
builder.setPositiveButton(R.string.ok, (dialog, which) -> {
String newName = name.getText().toString();
if (newName.length() < 2) {
Toast.makeText(this, R.string.name_too_short, Toast.LENGTH_SHORT).show();
return;
}
if (StatusManager.getByName(newName) != null) {
Toast.makeText(this, R.string.duplicated_name, Toast.LENGTH_SHORT).show();
return;
}
Status status = StatusManager.add(name.getText().toString(), newStatusColor);
Queries.StatusMangaTable.insert(gallery, status);
});
builder.setNegativeButton(R.string.cancel, (dialog, which) -> updateStatus());
builder.setOnCancelListener(dialog -> updateStatus());
builder.show();
}
private void updateIcon(boolean nowIsFavorite) {
GalleryActivity.this.runOnUiThread(() -> {
onlineFavoriteItem.setIcon(!nowIsFavorite ? R.drawable.ic_star_border : R.drawable.ic_star);
onlineFavoriteItem.setTitle(!nowIsFavorite ? R.string.add_to_online_favorite : R.string.remove_from_online_favorites);
});
}
private void addToFavorite() {
boolean wasFavorite = Objects.equals(onlineFavoriteItem.getTitle(), getString(R.string.remove_from_online_favorites));
String url = String.format(Locale.US, Utility.getApiBaseUrl() + "galleries/%d/favorite", gallery.getId());
LogUtility.d("Calling: " + url);
Global.getClient(this)
.newCall(new Request.Builder().url(url).method(wasFavorite ? "DELETE" : "POST", RequestBody.EMPTY).build())
.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
String responseString = response.body().string();
boolean nowIsFavorite = responseString.contains("true");
updateIcon(nowIsFavorite);
}
});
}
private void updateColumnCount(boolean increase) {
int x = Global.getColumnCount();
CustomGridLayoutManager manager = (CustomGridLayoutManager) recycler.getLayoutManager();
if (manager == null) return;
MenuItem item = ((Toolbar) findViewById(R.id.toolbar)).getMenu().findItem(R.id.change_view);
if (increase || manager.getSpanCount() != x) {
if (increase) x = x % 4 + 1;
int pos = manager.findFirstVisibleItemPosition();
Global.updateColumnCount(this, x);
recycler.setLayoutManager(new CustomGridLayoutManager(this, x));
LogUtility.d("Span count: " + manager.getSpanCount());
if (adapter != null) {
adapter.setColCount(Global.getColumnCount());
recycler.setAdapter(adapter);
lookup();
recycler.scrollToPosition(pos);
}
}
if (item != null) {
switch (x) {
case 1:
item.setIcon(R.drawable.ic_view_1);
break;
case 2:
item.setIcon(R.drawable.ic_view_2);
break;
case 3:
item.setIcon(R.drawable.ic_view_3);
break;
case 4:
item.setIcon(R.drawable.ic_view_4);
break;
}
Global.setTint(this, item.getIcon());
}
}
private void toInternet() {
refresher.setEnabled(true);
InspectorV3.galleryInspector(this, gallery.getId(), new InspectorV3.DefaultInspectorResponse() {
@Override
public void onSuccess(List<GenericGallery> galleries) {
if (galleries.isEmpty()) return;
Intent intent = new Intent(GalleryActivity.this, GalleryActivity.class);
LogUtility.d(galleries.get(0).toString());
intent.putExtra(getPackageName() + ".GALLERY", galleries.get(0));
runOnUiThread(() -> startActivity(intent));
}
}).start();
}
private void requestStorage() {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Global.initStorage(this);
if (requestCode == 1 && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
new RangeSelector(this, (Gallery) gallery).show();
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/HistoryActivity.java
================================================
package com.maxwai.nclientv3;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import com.maxwai.nclientv3.adapters.ListAdapter;
import com.maxwai.nclientv3.async.database.Queries;
import com.maxwai.nclientv3.components.activities.BaseActivity;
import com.maxwai.nclientv3.settings.Global;
import com.maxwai.nclientv3.utility.Utility;
import java.util.ArrayList;
import java.util.Objects;
public class HistoryActivity extends BaseActivity {
ListAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Global.initActivity(this);
setContentView(R.layout.activity_bookmark);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = Objects.requireNonNull(getSupportActionBar());
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(R.string.history);
recycler = findViewById(R.id.recycler);
masterLayout = findViewById(R.id.master_layout);
adapter = new ListAdapter(this);
adapter.addGalleries(new ArrayList<>(Queries.HistoryTable.getHistory()));
changeLayout(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
recycler.setAdapter(adapter);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
} else if (item.getItemId() == R.id.cancelAll) {
Queries.HistoryTable.emptyHistory();
adapter.restartDataset(new ArrayList<>(1));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected int getPortraitColumnCount() {
return Global.getColPortHistory();
}
@Override
protected int getLandscapeColumnCount() {
return Global.getColLandHistory();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.history, menu);
Utility.tintMenu(this, menu);
return true;
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/LocalActivity.java
================================================
package com.maxwai.nclientv3;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import androidx.activity.OnBackPressedCallback;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import com.maxwai.nclientv3.adapters.LocalAdapter;
import com.maxwai.nclientv3.api.local.FakeInspector;
import com.maxwai.nclientv3.api.local.LocalGallery;
import com.maxwai.nclientv3.api.local.LocalSortType;
import com.maxwai.nclientv3.async.converters.CreatePdfOrZip;
import com.maxwai.nclientv3.async.downloader.GalleryDownloaderV2;
import com.maxwai.nclientv3.components.activities.BaseActivity;
import com.maxwai.nclientv3.components.classes.MultichoiceAdapter;
import com.maxwai.nclientv3.settings.Global;
import com.maxwai.nclientv3.utility.Utility;
import com.google.android.material.chip.ChipGroup;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.switchmaterial.SwitchMaterial;
import java.io.File;
import java.util.List;
import java.util.Objects;
public class LocalActivity extends BaseActivity {
private Menu optionMenu;
private LocalAdapter adapter;
private final MultichoiceAdapter.MultichoiceListener listener = new MultichoiceAdapter.DefaultMultichoiceListener() {
@Override
public void choiceChanged() {
setMenuVisibility(optionMenu);
}
};
private Toolbar toolbar;
private int colCount;
private int idGalleryPosition = -1;
private File folder = Global.MAINFOLDER;
private androidx.appcompat.widget.SearchView searchView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Global.initActivity(this);
setContentView(R.layout.app_bar_main);
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = Objects.requireNonNull(getSupportActionBar());
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(R.string.downloaded_manga);
findViewById(R.id.page_switcher).setVisibility(View.GONE);
recycler = findViewById(R.id.recycler);
refresher = findViewById(R.id.refresher);
refresher.setOnRefreshListener(() -> new FakeInspector(this, folder).execute(this));
changeLayout(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
new FakeInspector(this, folder).execute(this);
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
if (adapter != null && adapter.getMode() == MultichoiceAdapter.Mode.SELECTING)
adapter.deselectAll();
else {
setEnabled(false);
getOnBackPressedDispatcher().onBackPressed();
setEnabled(true);
}
}
});
}
public void setAdapter(LocalAdapter adapter) {
this.adapter = adapter;
this.adapter.addListener(listener);
runOnUiThread(() -> recycler.setAdapter(adapter));
}
public void setIdGalleryPosition(int idGalleryPosition) {
this.idGalleryPosition = idGalleryPosition;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.download, menu);
getMenuInflater().inflate(R.menu.local_multichoice, menu);
this.optionMenu = menu;
setMenuVisibility(menu);
searchView = (androidx.appcompat.widget.SearchView) menu.findItem(R.id.search).getActionView();
Objects.requireNonNull(searchView).setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
if (recycler.getAdapter() != null)
((LocalAdapter) recycler.getAdapter()).getFilter().filter(newText);
return true;
}
});
Utility.tintMenu(this, menu);
return true;
}
private void setMenuVisibility(Menu menu) {
if (menu == null) return;
MultichoiceAdapter.Mode mode = adapter == null ? MultichoiceAdapter.Mode.NORMAL : adapter.getMode();
boolean hasGallery = false;
boolean hasDownloads = false;
if (mode == MultichoiceAdapter.Mode.SELECTING) {
hasGallery = adapter.hasSelectedClass(LocalGallery.class);
hasDownloads = adapter.hasSelectedClass(GalleryDownloaderV2.class);
}
menu.findItem(R.id.search).setVisible(mode == MultichoiceAdapter.Mode.NORMAL);
menu.findItem(R.id.sort_by_name).setVisible(mode == MultichoiceAdapter.Mode.NORMAL);
menu.findItem(R.id.folder_choose).setVisible(mode == MultichoiceAdapter.Mode.NORMAL && Global.getUsableFolders(this).size() > 1);
menu.findItem(R.id.random_favorite).setVisible(mode == MultichoiceAdapter.Mode.NORMAL);
menu.findItem(R.id.delete_all).setVisible(mode == MultichoiceAdapter.Mode.SELECTING);
menu.findItem(R.id.select_all).setVisible(mode == MultichoiceAdapter.Mode.SELECTING);
menu.findItem(R.id.pause_all).setVisible(mode == MultichoiceAdapter.Mode.SELECTING && !hasGallery && hasDownloads);
menu.findItem(R.id.start_all).setVisible(mode == MultichoiceAdapter.Mode.SELECTING && !hasGallery && hasDownloads);
menu.findItem(R.id.pdf_all).setVisible(mode == MultichoiceAdapter.Mode.SELECTING && hasGallery && !hasDownloads && CreatePdfOrZip.hasPDFCapabilities());
menu.findItem(R.id.zip_all).setVisible(mode == MultichoiceAdapter.Mode.SELECTING && hasGallery && !hasDownloads);
}
@Override
protected void onDestroy() {
if (adapter != null) adapter.removeObserver();
super.onDestroy();
}
@Override
protected void changeLayout(boolean landscape) {
colCount = (landscape ? getLandscapeColumnCount() : getPortraitColumnCount());
if (adapter != null) adapter.setColCount(colCount);
super.changeLayout(landscape);
}
public int getColCount() {
return colCount;
}
@Override
protected void onResume() {
super.onResume();
if (idGalleryPosition != -1) {
adapter.updateColor(idGalleryPosition);
idGalleryPosition = -1;
}
}
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
getOnBackPressedDispatcher().onBackPressed();
return true;
} else if (item.getItemId() == R.id.pause_all) {
adapter.pauseSelected();
} else if (item.getItemId() == R.id.start_all) {
adapter.startSelected();
} else if (item.getItemId() == R.id.delete_all) {
adapter.deleteSelected();
} else if (item.getItemId() == R.id.pdf_all) {
adapter.pdfSelected();
} else if (item.getItemId() == R.id.zip_all) {
adapter.zipSelected();
} else if (item.getItemId() == R.id.select_all) {
adapter.selectAll();
} else if (item.getItemId() == R.id.folder_choose) {
showDialogFolderChoose();
} else if (item.getItemId() == R.id.random_favorite) {
if (adapter != null) adapter.viewRandom();
} else if (item.getItemId() == R.id.sort_by_name) {
dialogSortType();
}
return super.onOptionsItemSelected(item);
}
private void showDialogFolderChoose() {
List<File> strings = Global.getUsableFolders(this);
ArrayAdapter<File> adapter = new ArrayAdapter<>(this, android.R.layout.select_dialog_singlechoice, strings);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.choose_directory).setIcon(R.drawable.ic_folder);
builder.setAdapter(adapter, (dialog, which) -> {
folder = new File(strings.get(which), "NClientV3");
new FakeInspector(this, folder).execute(this);
}).setNegativeButton(R.string.cancel, null).show();
}
private void dialogSortType() {
LocalSortType sortType = Global.getLocalSortType();
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
LinearLayout view = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.local_sort_type, toolbar, false);
ChipGroup group = view.findViewById(R.id.chip_group);
SwitchMaterial switchMaterial = view.findViewById(R.id.ascending);
group.check(group.getChildAt(sortType.type.ordinal()).getId());
switchMaterial.setChecked(sortType.descending);
builder.setView(view);
builder.setPositiveButton(R.string.ok, (dialog, which) -> {
int typeSelectedIndex = group.indexOfChild(group.findViewById(group.getCheckedChipId()));
LocalSortType.Type typeSelected = LocalSortType.Type.values()[typeSelectedIndex];
boolean descending = switchMaterial.isChecked();
LocalSortType newSortType = new LocalSortType(typeSelected, descending);
if (sortType.equals(newSortType)) return;
Global.setLocalSortType(LocalActivity.this, newSortType);
if (adapter != null) adapter.sortChanged();
})
.setNeutralButton(R.string.cancel, null)
.setTitle(R.string.sort_select_type)
.show();
/* boolean sortByName=Global.isLocalSortByName();
item.setIcon(sortByName?R.drawable.ic_sort_by_alpha:R.drawable.ic_access_time);
item.setTitle(sortByName?R.string.sort_by_title:R.string.sort_by_latest);
Global.setTint(item.getIcon());*/
}
@Override
protected int getPortraitColumnCount() {
return Global.getColPortDownload();
}
@Override
protected int getLandscapeColumnCount() {
return Global.getColLandDownload();
}
public String getQuery() {
if (searchView == null) return "";
CharSequence query = searchView.getQuery();
return query == null ? "" : query.toString();
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/MainActivity.java
================================================
package com.maxwai.nclientv3;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.core.os.LocaleListCompat;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.navigation.NavigationView;
import com.google.android.material.snackbar.Snackbar;
import com.maxwai.nclientv3.adapters.ListAdapter;
import com.maxwai.nclientv3.api.InspectorV3;
import com.maxwai.nclientv3.api.components.Gallery;
import com.maxwai.nclientv3.api.components.GenericGallery;
import com.maxwai.nclientv3.api.components.Ranges;
import com.maxwai.nclientv3.api.components.Tag;
import com.maxwai.nclientv3.api.enums.ApiRequestType;
import com.maxwai.nclientv3.api.enums.Language;
import com.maxwai.nclientv3.api.enums.SortType;
import com.maxwai.nclientv3.api.enums.SpecialTagIds;
import com.maxwai.nclientv3.api.enums.TagStatus;
import com.maxwai.nclientv3.api.enums.TagType;
import com.maxwai.nclientv3.async.ScrapeTags;
import com.maxwai.nclientv3.async.VersionChecker;
import com.maxwai.nclientv3.async.database.Queries;
import com.maxwai.nclientv3.async.downloader.DownloadGalleryV2;
import com.maxwai.nclientv3.components.activities.BaseActivity;
import com.maxwai.nclientv3.components.views.PageSwitcher;
import com.maxwai.nclientv3.components.widgets.CustomGridLayoutManager;
import com.maxwai.nclientv3.settings.AuthStore;
import com.maxwai.nclientv3.settings.Global;
import com.maxwai.nclientv3.settings.Login;
import com.maxwai.nclientv3.settings.TagV2;
import com.maxwai.nclientv3.utility.LogUtility;
import com.maxwai.nclientv3.utility.Utility;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
public class MainActivity extends BaseActivity
implements NavigationView.OnNavigationItemSelectedListener {
private static final int CHANGE_LANGUAGE_DELAY = 1000;
private static boolean firstTime = true;//true only when app starting
private final InspectorV3.InspectorResponse startGallery = new MainInspectorResponse() {
@Override
public void onSuccess(List<GenericGallery> galleries) {
Gallery g = galleries.size() == 1 ? (Gallery) galleries.get(0) : Gallery.emptyGallery();
Intent intent = new Intent(MainActivity.this, GalleryActivity.class);
LogUtility.d(g.toString());
intent.putExtra(getPackageName() + ".GALLERY", g);
runOnUiThread(() -> {
startActivity(intent);
finish();
});
LogUtility.d("STARTED");
}
};
private final Handler changeLanguageTimeHandler = new Handler(Objects.requireNonNull(Looper.myLooper()));
public ListAdapter adapter;
private final InspectorV3.InspectorResponse addDataset = new MainInspectorResponse() {
@Override
public void onSuccess(List<GenericGallery> galleries) {
adapter.addGalleries(galleries);
}
};
//views
public MenuItem onlineFavoriteManager;
private InspectorV3 inspector = null;
private NavigationView navigationView;
private ModeType modeType = ModeType.UNKNOWN;
private int idOpenedGallery = -1;//Position in the recycler of the opened gallery
private boolean inspecting = false, filteringTag = false;
private SortType temporaryType;
private Snackbar snackbar = null;
private PageSwitcher pageSwitcher;
private final InspectorV3.InspectorResponse
resetDataset = new MainInspectorResponse() {
@Override
public void onSuccess(List<GenericGallery> galleries) {
super.onSuccess(galleries);
adapter.restartDataset(galleries);
showPageSwitcher(inspector.getPage(), inspector.getPageCount());
runOnUiThread(() -> recycler.smoothScrollToPosition(0));
}
};
final Runnable changeLanguageRunnable = () -> {
useNormalMode();
inspector.start();
};
private DrawerLayout drawerLayout;
private Toolbar toolbar;
private boolean setting = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//load inspector
selectStartMode(getIntent(), getPackageName());
LogUtility.d("Main started with mode " + modeType);
//init views and actions
findUsefulViews();
initializeToolbar();
initializeNavigationView();
initializeRecyclerView();
initializePageSwitcherActions();
refresher.setOnRefreshListener(() -> {
inspector = inspector.cloneInspector(MainActivity.this, resetDataset);
if (Global.isInfiniteScrollMain()) inspector.setPage(1);
inspector.start();
});
manageDrawer();
setActivityTitle();
if (firstTime) checkUpdate();
if (inspector != null) {
inspector.start();
} else {
LogUtility.e(getIntent().getExtras());
}
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START))
drawerLayout.closeDrawer(GravityCompat.START);
else {
setEnabled(false);
getOnBackPressedDispatcher().onBackPressed();
setEnabled(true);
}
}
});
}
private void manageDrawer() {
if (modeType != ModeType.NORMAL) {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
} else {
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawerLayout.addDrawerListener(toggle);
toggle.syncState();
}
}
private void setActivityTitle() {
ActionBar actionBar = Objects.requireNonNull(getSupportActionBar());
switch (modeType) {
case FAVORITE:
actionBar.setTitle(R.string.favorite_online_manga);
break;
case SEARCH:
actionBar.setTitle(inspector.getSearchTitle());
break;
case TAG:
actionBar.setTitle(inspector.getTag().getName());
break;
case NORMAL:
actionBar.setTitle(R.string.app_name);
break;
default:
actionBar.setTitle("WTF");
break;
}
}
private void initializeToolbar() {
setSupportActionBar(toolbar);
ActionBar bar = getSupportActionBar();
assert bar != null;
bar.setDisplayShowTitleEnabled(true);
bar.setTitle(R.string.app_name);
}
private void initializePageSwitcherActions() {
pageSwitcher.setChanger(new PageSwitcher.DefaultPageChanger() {
@Override
public void pageChanged() {
inspector = inspector.cloneInspector(MainActivity.this, resetDataset);
inspector.setPage(pageSwitcher.getActualPage());
inspector.start();
}
});
}
private void initializeRecyclerView() {
adapter = new ListAdapter(this);
recycler.setAdapter(adapter);
recycler.setHasFixedSize(true);
//recycler.setItemViewCacheSize(24);
recycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
if (inspecting) return;
if (!Global.isInfiniteScrollMain()) return;
if (refresher.isRefreshing()) return;
CustomGridLayoutManager manager = (CustomGridLayoutManager) recycler.getLayoutManager();
assert manager != null;
if (!pageSwitcher.lastPageReached() && lastGalleryReached(manager)) {
inspecting = true;
inspector = inspector.cloneInspector(MainActivity.this, addDataset);
inspector.setPage(inspector.getPage() + 1);
inspector.start();
}
}
});
changeLayout(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
}
/**
* Check if the last gallery has been shown
**/
private boolean lastGalleryReached(CustomGridLayoutManager manager) {
return recycler.getAdapter() != null && manager.findLastVisibleItemPosition() >= (recycler.getAdapter().getItemCount() - 1 - manager.getSpanCount());
}
private void initializeNavigationView() {
toolbar.setNavigationIcon(R.drawable.ic_arrow_back);
toolbar.setNavigationOnClickListener(v -> finish());
navigationView.setNavigationItemSelectedListener(this);
onlineFavoriteManager.setVisible(AuthStore.hasValidApiKey(this));
}
public void setIdOpenedGallery(int idOpenedGallery) {
this.idOpenedGallery = idOpenedGallery;
}
private void findUsefulViews() {
masterLayout = findViewById(R.id.master_layout);
toolbar = findViewById(R.id.toolbar);
navigationView = findViewById(R.id.nav_view);
recycler = findViewById(R.id.recycler);
refresher = findViewById(R.id.refresher);
pageSwitcher = findViewById(R.id.page_switcher);
drawerLayout = findViewById(R.id.drawer_layout);
onlineFavoriteManager = navigationView.getMenu().findItem(R.id.online_favorite_manager);
}
private void hideError() {
//errorText.setVisibility(View.GONE);
runOnUiThread(() -> {
if (snackbar != null && snackbar.isShown()) {
snackbar.dismiss();
snackbar = null;
}
});
}
private void showError(@Nullable String text, @Nullable View.OnClickListener listener) {
if (text == null) {
hideError();
return;
}
if (listener == null) {
snackbar = Snackbar.make(masterLayout, text, Snackbar.LENGTH_SHORT);
} else {
snackbar = Snackbar.make(masterLayout, text, Snackbar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.retry, listener);
}
snackbar.show();
}
private void showError(@StringRes int text, View.OnClickListener listener) {
showError(getString(text), listener);
}
private void checkUpdate() {
if (Global.shouldCheckForUpdates(this))
new VersionChecker(this, true);
ScrapeTags.startWork(this);
firstTime = false;
}
private void selectStartMode(Intent intent, String packageName) {
Uri data = intent.getData();
if (intent.getBooleanExtra(packageName + ".ISBYTAG", false))
useTagMode(intent, packageName);
else if (intent.getBooleanExtra(packageName + ".SEARCHMODE", false))
useSearchMode(intent, packageName);
else if (intent.getBooleanExtra(packageName + ".FAVORITE", false)) useFavoriteMode(1);
else if (intent.getBooleanExtra(packageName + ".BYBOOKMARK", false))
useBookmarkMode(intent, packageName);
else if (data != null) manageDataStart(data);
else useNormalMode();
}
private void useNormalMode() {
inspector = InspectorV3.basicInspector(this, 1, resetDataset);
modeType = ModeType.NORMAL;
}
private void useBookmarkMode(Intent intent, String packageName) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
inspector = intent.getParcelableExtra(packageName + ".INSPECTOR", InspectorV3.class);
} else {
inspector = intent.getParcelableExtra(packageName + ".INSPECTOR");
}
assert inspector != null;
inspector.initialize(this, resetDataset);
modeType = ModeType.BOOKMARK;
ApiRequestType type = inspector.getRequestType();
if (type == ApiRequestType.BYTAG) modeType = ModeType.TAG;
else if (type == ApiRequestType.BYALL) modeType = ModeType.NORMAL;
else if (type == ApiRequestType.BYSEARCH) modeType = ModeType.SEARCH;
else if (type == ApiRequestType.FAVORITE) modeType = ModeType.FAVORITE;
}
private void useFavoriteMode(int page) {
//instantiateWebView();
inspector = InspectorV3.favoriteInspector(this, null, page, resetDataset);
modeType = ModeType.FAVORITE;
}
private void useSearchMode(Intent intent, String packageName) {
String query = intent.getStringExtra(packageName + ".QUERY");
boolean ok = tryOpenId(query);
if (!ok) createSearchInspector(intent, packageName, query);
}
private void createSearchInspector(Intent intent, String packageName, String query) {
boolean advanced = intent.getBooleanExtra(packageName + ".ADVANCED", false);
ArrayList<Tag> tagArrayList = intent.getParcelableArrayListExtra(packageName + ".TAGS");
Ranges ranges;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
ranges = intent.getParcelableExtra(getPackageName() + ".RANGES", Ranges.class);
} else {
ranges = intent.getParcelableExtra(getPackageName() + ".RANGES");
}
HashSet<Tag> tags = null;
query = query.trim();
if (advanced) {
assert tagArrayList != null;//tags is always not null when advanced is set
tags = new HashSet<>(tagArrayList);
}
inspector = InspectorV3.searchInspector(this, query, tags, 1, Global.getSortType(), ranges, resetDataset);
modeType = ModeType.SEARCH;
}
private boolean tryOpenId(String query) {
try {
int id = Integer.parseInt(query);
inspector = InspectorV3.galleryInspector(this, id, startGallery);
modeType = ModeType.ID;
return true;
} catch (NumberFormatException ignore) {
}
return false;
}
private void useTagMode(Intent intent, String packageName) {
Tag t;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
t = intent.getParcelableExtra(packageName + ".TAG", Tag.class);
} else {
t = intent.getParcelableExtra(packageName + ".TAG");
}
inspector = InspectorV3.tagInspector(this, t, 1, Global.getSortType(), resetDataset);
modeType = ModeType.TAG;
}
/**
* Load inspector from an URL, it can be either a tag or a search
*/
private void manageDataStart(Uri data) {
List<String> datas = data.getPathSegments();
TagType dataType;
LogUtility.d("Datas: " + datas);
if (datas.isEmpty()) {
useNormalMode();
return;
}
dataType = TagType.typeByName(datas.get(0));
if (dataType != TagType.UNKNOWN) useDataTagMode(datas, dataType);
else useDataSearchMode(data, datas);
}
private void useDataSearchMode(Uri data, List<String> datas) {
String query = data.getQueryParameter("q");
String pageParam = data.getQueryParameter("page");
boolean favorite = "favorites".equals(datas.get(0));
SortType type = SortType.findFromAddition(data.getQueryParameter("sort"));
int page = 1;
if (pageParam != null) page = Integer.parseInt(pageParam);
if (favorite) {
if (AuthStore.hasValidApiKey(this)) useFavoriteMode(page);
else {
Intent intent = new Intent(this, FavoriteActivity.class);
startActivity(intent);
finish();
}
return;
}
inspector = InspectorV3.searchInspector(this, query, null, page, type, null, resetDataset);
modeType = ModeType.SEARCH;
}
private void useDataTagMode(List<String> datas, TagType type) {
String query = datas.get(1);
Tag tag = Queries.TagTable.getTagFromTagName(query);
if (tag == null)
tag = new Tag(query, -1, SpecialTagIds.INVALID_ID, type, TagStatus.DEFAULT);
SortType sortType = SortType.RECENT_ALL_TIME;
if (datas.size() == 3) {
sortType = SortType.findFromAddition(datas.get(2));
}
inspector = InspectorV3.tagInspector(this, tag, 1, sortType, resetDataset);
modeType = ModeType.TAG;
}
public void hidePageSwitcher() {
runOnUiThread(() -> pageSwitcher.setVisibility(View.GONE));
}
public void showPageSwitcher(final int actualPage, final int totalPage) {
pageSwitcher.setPages(totalPage, actualPage);
if (Global.isInfiniteScrollMain()) {
hidePageSwitcher();
}
}
@SuppressLint("NotifyDataSetChanged")
@Override
protected void onResume() {
super.onResume();
Login.initLogin(this);
if (idOpenedGallery != -1) {
adapter.updateColor(idOpenedGallery);
idOpenedGallery = -1;
}
onlineFavoriteManager.setVisible(AuthStore.hasValidApiKey(this));
SharedPreferences settings = getSharedPreferences("Settings", 0);
LocaleListCompat setLocaleList = AppCompatDelegate.getApplicationLocales();
settings.edit().putString(getString(R.string.preference_key_language),
setLocaleList.isEmpty() ? getString(R.string.key_default_value) :
Objects.requireNonNull(setLocaleList.get(0)).toLanguageTag()).apply();
if (setting) {
Global.initFromShared(this);//restart all settings
inspector = inspector.cloneInspector(this, resetDataset);
inspector.start();//restart inspector
adapter.notifyDataSetChanged();//restart adapter
adapter.resetStatuses();
showPageSwitcher(inspector.getPage(), inspector.getPageCount());//restart page switcher
changeLayout(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
setting = false;
} else if (filteringTag) {
inspector = InspectorV3.basicInspector(this, 1, resetDataset);
inspector.start();
filteringTag = false;
}
invalidateOptionsMenu();
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
popularItemDispay(menu.findItem(R.id.by_popular));
showLanguageIcon(menu.findItem(R.id.only_language));
menu.findItem(R.id.only_language).setVisible(modeType == ModeType.NORMAL);
menu.findItem(R.id.random_favorite).setVisible(modeType == ModeType.FAVORITE);
initializeSearchItem(menu.findItem(R.id.search));
if (modeType == ModeType.TAG) {
MenuItem item = menu.findItem(R.id.tag_manager);
item.setVisible(inspector.getTag().getId() > 0);
TagStatus ts = inspector.getTag().getStatus();
updateTagStatus(item, ts);
}
Utility.tintMenu(this, menu);
return true;
}
private void initializeSearchItem(MenuItem item) {
if (modeType != ModeType.FAVORITE)
item.setActionView(null);
else {
((SearchView) Objects.requireNonNull(item.getActionView())).setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
inspector = InspectorV3.favoriteInspector(MainActivity.this, query, 1, resetDataset);
inspector.start();
Objects.requireNonNull(getSupportActionBar()).setTitle(query);
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
}
}
private void popularItemDispay(MenuItem item) {
item.setTitle(getString(R.string.sort_type_title_format, getString(Global.getSortType().getNameId())));
Global.setTint(this, item.getIcon());
}
private void showLanguageIcon(MenuItem item) {
switch (Global.getOnlyLanguage()) {
case JAPANESE:
item.setTitle(R.string.only_japanese);
item.setIcon(R.drawable.ic_jpbw);
break;
case CHINESE:
item.setTitle(R.string.only_chinese);
item.setIcon(R.drawable.ic_cnbw);
break;
case ENGLISH:
item.setTitle(R.string.only_english);
item.setIcon(R.drawable.ic_gbbw);
break;
case ALL:
item.setTitle(R.string.all_languages);
item.setIcon(R.drawable.ic_world);
break;
}
Global.setTint(this, item.getIcon());
}
@Override
protected int getPortraitColumnCount() {
return Global.getColPortMain();
}
@Override
protected int getLandscapeColumnCount() {
return Global.getColLandMain();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent i;
LogUtility.d("Pressed item: " + item.getItemId());
if (item.getItemId() == R.id.by_popular) {
updateSortType(item);
} else if (item.getItemId() == R.id.only_language) {
updateLanguageAndIcon(item);
} else if (item.getItemId() == R.id.search) {
if (modeType != ModeType.FAVORITE) {//show textbox or start search activity
i = new Intent(this, SearchActivity.class);
startActivity(i);
}
} else if (item.getItemId() == R.id.open_browser) {
if (inspector != null) {
i = new Intent(Intent.ACTION_VIEW, Uri.parse(inspector.getUrl()));
startActivity(i);
}
} else if (item.getItemId() == R.id.random_favorite) {
inspector = InspectorV3.randomInspector(this, startGallery, true);
inspector.start();
} else if (item.getItemId() == R.id.download_page) {
if (inspector.getGalleries() != null)
showDialogDownloadAll();
} else if (item.getItemId() == R.id.add_bookmark) {
Queries.BookmarkTable.addBookmark(inspector);
} else if (item.getItemId() == R.id.tag_manager) {
TagStatus ts = TagV2.updateStatus(inspector.getTag());
updateTagStatus(item, ts);
} else if (item.getItemId() == android.R.id.home) {
finish();
}
return super.onOptionsItemSelected(item);
}
private void updateSortType(MenuItem item) {
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.select_dialog_singlechoice);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
for (SortType type : SortType.values())
adapter.add(getString(type.getNameId()));
temporaryType = Global.getSortType();
builder.setIcon(R.drawable.ic_sort).setTitle(R.string.sort_select_type);
builder.setSingleChoiceItems(adapter, temporaryType.ordinal(), (dialog, which) -> temporaryType = SortType.values()[which]);
builder.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
temporaryType = SortType.values()[position];
parent.setSelection(position);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
builder.setPositiveButton(R.string.ok, (dialog, which) -> {
Global.updateSortType(MainActivity.this, temporaryType);
popularItemDispay(item);
inspector = inspector.cloneInspector(MainActivity.this, resetDataset);
inspector.setSortType(temporaryType);
inspector.start();
});
builder.setNegativeButton(R.string.cancel, null);
builder.show();
}
private void updateLanguageAndIcon(MenuItem item) {
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.select_dialog_singlechoice);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
adapter.addAll(Arrays.stream(Language.getFilteredValuesArray())
.map(lang -> getString(lang.getNameResId()))
.collect(Collectors.toList())
);
AtomicReference<Language> selectedLanguage = new AtomicReference<>(Global.getOnlyLanguage());
builder.setIcon(R.drawable.ic_world)
.setTitle(R.string.change_language)
.setSingleChoiceItems(adapter, selectedLanguage.get().ordinal(),
(dialog, which) -> selectedLanguage.set(Language.getFilteredValuesArray()[which]))
.setPositiveButton(R.string.ok, (dialog, which) -> {
Global.updateOnlyLanguage(MainActivity.this, Language.valueOf(selectedLanguage.get().name()));
// wait 250ms to reduce the requests
changeLanguageTimeHandler.removeCallbacks(changeLanguageRunnable);
changeLanguageTimeHandler.postDelayed(changeLanguageRunnable, CHANGE_LANGUAGE_DELAY);
showLanguageIcon(item);
})
.setNegativeButton(R.string.cancel, null)
.show();
}
private void showDialogDownloadAll() {
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder
.setTitle(R.string.download_all_galleries_in_this_page)
.setIcon(R.drawable.ic_file)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok, (dialog, which) -> {
for (GenericGallery g : inspector.getGalleries())
DownloadGalleryV2.downloadGallery(MainActivity.this, g);
});
builder.show();
}
private void updateTagStatus(MenuItem item, TagStatus ts) {
switch (ts) {
case DEFAULT:
item.setIcon(R.drawable.ic_help);
break;
case AVOIDED:
item.setIcon(R.drawable.ic_close);
break;
case ACCEPTED:
item.setIcon(R.drawable.ic_check);
break;
}
Global.setTint(this, item.getIcon());
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
Intent intent;
if (item.getItemId() == R.id.downloaded) {
if (Global.hasStoragePermission(this)) startLocalActivity();
else requestStorage();
} else if (item.getItemId() == R.id.bookmarks) {
intent = new Intent(this, BookmarkActivity.class);
startActivity(intent);
} else if (item.getItemId() == R.id.history) {
intent = new Intent(this, HistoryActivity.class);
startActivity(intent);
} else if (item.getItemId() == R.id.favorite_manager) {
intent = new Intent(this, FavoriteActivity.class);
startActivity(intent);
} else if (item.getItemId() == R.id.action_settings) {
setting = true;
intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
} else if (item.getItemId() == R.id.online_favorite_manager) {
intent = new Intent(this, MainActivity.class);
intent.putExtra(getPackageName() + ".FAVORITE", true);
startActivity(intent);
} else if (item.getItemId() == R.id.random) {
intent = new Intent(this, RandomActivity.class);
startActivity(intent);
} else if (item.getItemId() == R.id.tag_manager) {
intent = new Intent(this, TagFilterActivity.class);
filteringTag = true;
startActivity(intent);
} else if (item.getItemId() == R.id.status_manager) {
intent = new Intent(this, StatusViewerActivity.class);
startActivity(intent);
}
//drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
private void requestStorage() {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Global.initStorage(this);
if (requestCode == 1 && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
startLocalActivity();
if (requestCode == 2 && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
new VersionChecker(this, true);
}
private void startLocalActivity() {
Intent i = new Intent(this, LocalActivity.class);
startActivity(i);
}
/**
* UNKNOWN in case of error
* NORMAL when in main page
* TAG when searching for a specific tag
* FAVORITE when using online favorite button
* SEARCH when used SearchActivity
* BOOKMARK when loaded a bookmark
* ID when searched for an ID
*/
private enum ModeType {UNKNOWN, NORMAL, TAG, FAVORITE, SEARCH, BOOKMARK, ID}
abstract class MainInspectorResponse extends InspectorV3.DefaultInspectorResponse {
@Override
public void onSuccess(List<GenericGallery> galleries) {
super.onSuccess(galleries);
if (adapter != null) adapter.resetStatuses();
if (galleries.isEmpty())
showError(R.string.no_entry_found, null);
}
@Override
public void onStart() {
runOnUiThread(() -> refresher.setRefreshing(true));
hideError();
}
@Override
public void onEnd() {
runOnUiThread(() -> refresher.setRefreshing(false));
inspecting = false;
}
@Override
public void onFailure(Exception e) {
super.onFailure(e);
showError(R.string.unable_to_connect_to_the_site, v -> {
inspector = inspector.cloneInspector(MainActivity.this, inspector.getResponse());
inspector.start();
});
}
@Override
public boolean shouldStart(InspectorV3 inspector) {
return true;
//loadWebVewUrl(inspector.getUrl());
//return inspector.canParseDocument();
}
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/PINActivity.java
================================================
package com.maxwai.nclientv3;
import static androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK;
import static androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.biometric.BiometricPrompt;
import androidx.core.content.ContextCompat;
import com.maxwai.nclientv3.components.activities.GeneralActivity;
import java.util.concurrent.Executor;
public class PINActivity extends GeneralActivity {
private SharedPreferences preferences;
private boolean authSuccess = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Global.initActivity(this);
setContentView(R.layout.activity_pin);
preferences = getSharedPreferences("Settings", 0);
if (!hasPin()) {
finish();
return;
}
Executor executor = ContextCompat.getMainExecutor(this);
BiometricPrompt biometricPrompt = new BiometricPrompt(this,
executor, new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationError(int errorCode,
@NonNull CharSequence errString) {
super.onAuthenticationError(errorCode, errString);
Toast.makeText(getApplicationContext(),
getString(R.string.auth_error),
Toast.LENGTH_SHORT)
.show();
}
@Override
public void onAuthenticationSucceeded(
@NonNull BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
authSuccess = true;
finish();
}
@Override
public void onAuthenticationFailed() {
super.onAuthenticationFailed();
Toast.makeText(getApplicationContext(),
getString(R.string.auth_error),
Toast.LENGTH_SHORT)
.show();
}
});
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
.setTitle(getString(R.string.auth_title))
.setSubtitle(getString(R.string.auth_subtitle))
.setAllowedAuthenticators(BIOMETRIC_WEAK | DEVICE_CREDENTIAL)
.build();
Button unlockButton = findViewById(R.id.unlockButton);
unlockButton.setOnClickListener(view -> biometricPrompt.authenticate(promptInfo));
unlockButton.performClick();
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean hasPin() {
return preferences.getBoolean(getString(R.string.preference_key_has_credentials), false);
}
@Override
public void finish() {
Intent i = new Intent(this, MainActivity.class);
if (!hasPin() || authSuccess) startActivity(i);
authSuccess = false;
super.finish();
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/RandomActivity.java
================================================
package com.maxwai.nclientv3;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.activity.OnBackPressedCallback;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import androidx.core.widget.ImageViewCompat;
import com.maxwai.nclientv3.api.RandomLoader;
import com.maxwai.nclientv3.api.components.Gallery;
import com.maxwai.nclientv3.components.activities.GeneralActivity;
import com.maxwai.nclientv3.settings.Favorites;
import com.maxwai.nclientv3.settings.Global;
import com.maxwai.nclientv3.utility.ImageDownloadUtility;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.Objects;
public class RandomActivity extends GeneralActivity {
public static Gallery loadedGallery = null;
private TextView language;
private ImageButton thumbnail;
private ImageButton favorite;
private TextView title;
private TextView page;
private View censor;
private RandomLoader loader = null;
private boolean isFavorite;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Global.initActivity(this);
setContentView(R.layout.activity_random);
loader = new RandomLoader(this);
//init components id
Toolbar toolbar = findViewById(R.id.toolbar);
FloatingActionButton shuffle = findViewById(R.id.shuffle);
ImageButton share = findViewById(R.id.share);
censor = findViewById(R.id.censor);
language = findViewById(R.id.language);
thumbnail = findViewById(R.id.thumbnail);
favorite = findViewById(R.id.favorite);
title = findViewById(R.id.title);
page = findViewById(R.id.pages);
//init toolbar
setSupportActionBar(toolbar);
ActionBar actionBar = Objects.requireNonNull(getSupportActionBar());
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(R.string.random_manga);
if (loadedGallery != null) loadGallery(loadedGallery);
shuffle.setOnClickListener(v -> loader.requestGallery());
thumbnail.setOnClickListener(v -> {
if (loadedGallery != null) {
Intent intent = new Intent(RandomActivity.this, GalleryActivity.class);
intent.putExtra(RandomActivity.this.getPackageName() + ".GALLERY", loadedGallery);
RandomActivity.this.startActivity(intent);
}
});
share.setOnClickListener(v -> {
if (loadedGallery != null) Global.shareGallery(RandomActivity.this, loadedGallery);
});
censor.setOnClickListener(v -> censor.setVisibility(View.GONE));
favorite.setOnClickListener(v -> {
if (loadedGallery != null) {
if (isFavorite) {
Favorites.removeFavorite(loadedGallery);
isFavorite = false;
} else {
Favorites.addFavorite(loadedGallery);
isFavorite = true;
}
}
favoriteUpdateButton();
});
ColorStateList colorStateList = ColorStateList.valueOf(getColor(R.color.tint_light));
ImageViewCompat.setImageTintList(shuffle, colorStateList);
ImageViewCompat.setImageTintList(share, colorStateList);
ImageViewCompat.setImageTintList(favorite, colorStateList);
Global.setTint(this, shuffle.getContentBackground());
Global.setTint(this, share.getDrawable());
Global.setTint(this, favorite.getDrawable());
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
loadedGallery = null;
setEnabled(false);
getOnBackPressedDispatcher().onBackPressed();
setEnabled(true);
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
public void loadGallery(Gallery gallery) {
loadedGallery = gallery;
if (Global.isDestroyed(this)) return;
ImageDownloadUtility.loadImage(this, gallery.getCover(), thumbnail);
language.setText(Global.getLanguageFlag(gallery.getLanguage()));
isFavorite = Favorites.isFavorite(loadedGallery);
favoriteUpdateButton();
title.setText(gallery.getTitle());
page.setText(getString(R.string.page_count_format, gallery.getPageCount()));
censor.setVisibility(gallery.hasIgnoredTags() ? View.VISIBLE : View.GONE);
}
private void favoriteUpdateButton() {
runOnUiThread(() -> {
ImageDownloadUtility.loadImage(isFavorite ? R.drawable.ic_favorite : R.drawable.ic_favorite_border, favorite);
Global.setTint(this, favorite.getDrawable());
});
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/SearchActivity.java
================================================
package com.maxwai.nclientv3;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.AppCompatAutoCompleteTextView;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.RecyclerView;
import com.maxwai.nclientv3.adapters.HistoryAdapter;
import com.maxwai.nclientv3.api.components.Ranges;
import com.maxwai.nclientv3.api.components.Tag;
import com.maxwai.nclientv3.api.enums.Language;
import com.maxwai.nclientv3.api.enums.SpecialTagIds;
import com.maxwai.nclientv3.api.enums.TagStatus;
import com.maxwai.nclientv3.api.enums.TagType;
import com.maxwai.nclientv3.async.database.Queries;
import com.maxwai.nclientv3.components.activities.GeneralActivity;
import com.maxwai.nclientv3.components.widgets.ChipTag;
import com.maxwai.nclientv3.components.widgets.CustomLinearLayoutManager;
import com.maxwai.nclientv3.settings.DefaultDialogs;
import com.maxwai.nclientv3.settings.Global;
import com.maxwai.nclientv3.settings.Login;
import com.maxwai.nclientv3.utility.LogUtility;
import com.maxwai.nclientv3.utility.Utility;
import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class SearchActivity extends GeneralActivity {
public static final int CUSTOM_ID_START = 100000000;
private static int customId = CUSTOM_ID_START;
private final Ranges ranges = new Ranges();
private final ArrayList<ChipTag> tags = new ArrayList<>();
private final Chip[] addChip = new Chip[TagType.values.length];
private ChipGroup[] groups;
private SearchView searchView;
private AppCompatAutoCompleteTextView autoComplete;
private TagType loadedTag = null;
private HistoryAdapter adapter;
private boolean advanced = false;
private Ranges.TimeUnit temporaryUnit;
private InputMethodManager inputMethodManager;
private AlertDialog alertDialog;
public void setQuery(String str, boolean submit) {
runOnUiThread(() -> searchView.setQuery(str, submit));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Global.initActivity(this);
setContentView(R.layout.activity_search);
//init toolbar
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(false);
inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
//find IDs
searchView = findViewById(R.id.search);
RecyclerView recyclerView = findViewById(R.id.recycler);
groups = new ChipGroup[]{
null,
findViewById(R.id.parody_group),
findViewById(R.id.character_group),
findViewById(R.id.tag_group),
findViewById(R.id.artist_group),
findViewById(R.id.group_group),
findViewById(R.id.language_group),
findViewById(R.id.category_group),
};
initRanges();
adapter = new HistoryAdapter(this);
autoComplete = (AppCompatAutoCompleteTextView) getLayoutInflater().inflate(R.layout.autocomplete_entry, findViewById(R.id.appbar), false);
autoComplete.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_SEND) {
alertDialog.dismiss();
createChip();
return true;
}
return false;
});
//init recyclerview
recyclerView.setLayoutManager(new CustomLinearLayoutManager(this));
recyclerView.setAdapter(adapter);
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
query = query.trim();
if (query.isEmpty() && !advanced) return true;
if (!query.isEmpty()) adapter.addHistory(query);
final Intent i = new Intent(SearchActivity.this, MainActivity.class);
i.putExtra(getPackageName() + ".SEARCHMODE", true);
i.putExtra(getPackageName() + ".QUERY", query);
i.putExtra(getPackageName() + ".ADVANCED", advanced);
if (advanced) {
ArrayList<Tag> tt = new ArrayList<>(tags.size());
for (ChipTag t : tags)
if (t.getTag().getStatus() == TagStatus.ACCEPTED) tt.add(t.getTag());
i.putParcelableArrayListExtra(getPackageName() + ".TAGS", tt);
i.putExtra(getPackageName() + ".RANGES", ranges);
}
SearchActivity.this.runOnUiThread(() -> {
startActivity(i);
finish();
});
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
populateGroup();
searchView.requestFocus();
}
private void createPageBuilder(int title, int min, int max, int actual, DefaultDialogs.DialogResults results) {
min = Math.max(1, min);
actual = Math.max(actual, min);
DefaultDialogs.pageChangerDialog(new DefaultDialogs.Builder(this)
.setTitle(title)
.setMax(max)
.setMin(min)
.setDrawable(R.drawable.ic_search)
.setActual(actual)
.setYesbtn(R.string.ok)
.setNobtn(R.string.cancel)
.setMaybebtn(R.string.reset)
.setDialogs(results));
}
private void initRanges() {
LinearLayout pageRangeLayout = findViewById(R.id.page_range);
LinearLayout uploadRangeLayout = findViewById(R.id.upload_range);
((TextView) pageRangeLayout.findViewById(R.id.title)).setText(R.string.page_range);
((TextView) uploadRangeLayout.findViewById(R.id.title)).setText(R.string.upload_time);
Button fromPage = pageRangeLayout.findViewById(R.id.fromButton);
Button toPage = pageRangeLayout.findViewById(R.id.toButton);
Button fromDate = uploadRangeLayout.findViewById(R.id.fromButton);
Button toDate = uploadRangeLayout.findViewById(R.id.toButton);
fromPage.setOnClickListener(v -> createPageBuilder(R.string.from_page, 0, 2000, ranges.getFromPage(), new DefaultDialogs.CustomDialogResults() {
@Override
public void positive(int actual) {
ranges.setFromPage(actual);
fromPage.setText(String.format(Locale.US, "%d", actual));
if (ranges.getFromPage() > ranges.getToPage()) {
ranges.setToPage(Ranges.UNDEFINED);
toPage.setText("");
}
advanced = true;
}
@Override
public void neutral() {
ranges.setFromPage(Ranges.UNDEFINED);
fromPage.setText("");
}
}));
toPage.setOnClickListener(v -> createPageBuilder(R.string.to_page, ranges.getFromPage(), 2000, ranges.getToPage(), new DefaultDialogs.CustomDialogResults() {
@Override
public void positive(int actual) {
ranges.setToPage(actual);
toPage.setText(String.format(Locale.US, "%d", actual));
advanced = true;
}
@Override
public void neutral() {
ranges.setToPage(Ranges.UNDEFINED);
toPage.setText("");
}
}));
fromDate.setOnClickListener(v -> showUnitDialog(fromDate, true));
toDate.setOnClickListener(v -> showUnitDialog(toDate, false));
}
private void showUnitDialog(Button button, boolean from) {
int i = 0;
String[] strings = new String[Ranges.TimeUnit.values().length];
for (Ranges.TimeUnit unit : Ranges.TimeUnit.values())
strings[i++] = getString(unit.getString());
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.choose_unit);
builder.setIcon(R.drawable.ic_search);
builder.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, strings), (dialog, which) -> {
temporaryUnit = Ranges.TimeUnit.values()[which];
createPageBuilder(from ? R.string.from_time : R.string.to_time, 1, temporaryUnit == Ranges.TimeUnit.YEAR ? 10 : 100, 1, new DefaultDialogs.CustomDialogResults() {
@Override
public void positive(int actual) {
if (from) {
ranges.setFromDateUnit(temporaryUnit);
ranges.setFromDate(actual);
} else {
ranges.setToDateUnit(temporaryUnit);
ranges.setToDate(actual);
}
button.setText(String.format(Locale.US, "%d %c", actual, Character.toUpperCase(temporaryUnit.getVal())));
advanced = true;
}
@Override
public void neutral() {
if (from) {
ranges.setFromDateUnit(Ranges.UNDEFINED_DATE);
ranges.setFromDate(Ranges.UNDEFINED);
} else {
ranges.setToDateUnit(Ranges.UNDEFINED_DATE);
ranges.setToDate(Ranges.UNDEFINED);
}
button.setText("");
}
});
});
builder.setNeutralButton(R.string.reset, (dialog, which) -> {
if (from) {
ranges.setFromDateUnit(Ranges.UNDEFINED_DATE);
ranges.setFromDate(Ranges.UNDEFINED);
} else {
ranges.setToDateUnit(Ranges.UNDEFINED_DATE);
ranges.setToDate(Ranges.UNDEFINED);
}
button.setText("");
});
builder.show();
}
private void populateGroup() {
//add top tags
for (TagType type : new TagType[]{TagType.TAG, TagType.PARODY, TagType.CHARACTER, TagType.ARTIST, TagType.GROUP}) {
for (Tag t : Queries.TagTable.getTopTags(type, Global.getFavoriteLimit(this)))
addChipTag(t, true, true);
}
//add already filtered tags
for (Tag t : Queries.TagTable.getAllFiltered())
if (!tagAlreadyExist(t)) addChipTag(t, true, true);
//add categories
for (Tag t : Queries.TagTable.getTrueAllType(TagType.CATEGORY)) addChipTag(t, false, false);
//add languages
for (Tag t : Queries.TagTable.getTrueAllType(TagType.LANGUAGE)) {
if (t.getId() == SpecialTagIds.LANGUAGE_ENGLISH && Global.getOnlyLanguage() == Language.ENGLISH)
t.setStatus(TagStatus.ACCEPTED);
else if (t.getId() == SpecialTagIds.LANGUAGE_JAPANESE && Global.getOnlyLanguage() == Language.JAPANESE)
t.setStatus(TagStatus.ACCEPTED);
else if (t.getId() == SpecialTagIds.LANGUAGE_CHINESE && Global.getOnlyLanguage() == Language.CHINESE)
t.setStatus(TagStatus.ACCEPTED);
addChipTag(t, false, false);
}
//add online tags
if (Login.useAccountTag()) for (Tag t : Queries.TagTable.getAllOnlineBlacklisted())
if (!tagAlreadyExist(t))
addChipTag(t, true, true);
//add + button
for (TagType type : TagType.values) {
//ignore these tags
if (type == TagType.UNKNOWN || type == TagType.LANGUAGE || type == TagType.CATEGORY) {
addChip[type.getId()] = null;
continue;
}
ChipGroup cg = getGroup(type);
Chip add = createAddChip(type, cg);
addChip[type.getId()] = add;
cg.addView(add);
}
}
private Chip createAddChip(TagType type, ChipGroup group) {
Chip c = (Chip) getLayoutInflater().inflate(R.layout.chip_layout, group, false);
c.setCloseIconVisible(false);
c.setChipIconResource(R.drawable.ic_add);
c.setText(getString(R.string.add));
c.setOnClickListener(v -> loadTag(type));
Global.setTint(this, c.getChipIcon());
return c;
}
private boolean tagAlreadyExist(Tag tag) {
for (ChipTag t : tags) {
if (t.getTag().getName().equals(tag.getName())) return true;
}
return false;
}
private void addChipTag(Tag t, boolean close, boolean canBeAvoided) {
ChipGroup cg = getGroup(t.getType());
ChipTag c = (ChipTag) getLayoutInflater().inflate(R.layout.chip_layout_entry, cg, false);
c.init(t, close, canBeAvoided);
c.setOnCloseIconClickListener(v -> {
cg.removeView(c);
tags.remove(c);
advanced = true;
});
c.setOnClickListener(v -> {
c.updateStatus();
advanced = true;
});
cg.addView(c);
tags.add(c);
}
private void loadDropdown(TagType type) {
List<Tag> allTags = Queries.TagTable.getAllTagOfType(type);
String[] tagNames = new String[allTags.size()];
int i = 0;
for (Tag t : allTags) tagNames[i++] = t.getName();
autoComplete.setAdapter(new ArrayAdapter<>(SearchActivity.this, android.R.layout.simple_dropdown_item_1line, tagNames));
loadedTag = type;
}
private void loadTag(TagType type) {
if (type != loadedTag) loadDropdown(type);
addDialog();
autoComplete.requestFocus();
inputMethodManager.showSoftInput(autoComplete, InputMethodManager.SHOW_IMPLICIT);
}
private ChipGroup getGroup(TagType type) {
return groups[type.getId()];
}
private void addDialog() {
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setView(autoComplete);
autoComplete.setText("");
builder.setPositiveButton(R.string.ok, (dialog, which) -> createChip());
builder.setCancelable(true).setNegativeButton(R.string.cancel, null);
builder.setTitle(R.string.insert_tag_name);
try {
alertDialog = builder.show();
} catch (IllegalStateException e) {//the autoComplete is still attached to another View
((ViewGroup) autoComplete.getParent()).removeView(autoComplete);
alertDialog = builder.show();
}
}
private void createChip() {
String name = autoComplete.getText().toString().toLowerCase(Locale.US);
Tag tag = Queries.TagTable.searchTag(name, loadedTag);
if (tag == null) tag = new Tag(name, 0, customId++, loadedTag, TagStatus.ACCEPTED);
LogUtility.d("CREATED WITH ID: " + tag.getId());
if (tagAlreadyExist(tag)) return;
//remove add, insert new tag, reinsert add
if (getGroup(loadedTag) != null) getGroup(loadedTag).removeView(addChip[loadedTag.getId()]);
addChipTag(tag, true, true);
getGroup(loadedTag).addView(addChip[loadedTag.getId()]);
inputMethodManager.hideSoftInputFromWindow(searchView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
autoComplete.setText("");
advanced = true;
if (autoComplete.getParent() != null)
((ViewGroup) autoComplete.getParent()).removeView(autoComplete);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search, menu);
Utility.tintMenu(this, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
} else if (item.getItemId() == R.id.view_groups) {
View v = findViewById(R.id.groups);
boolean isVisible = v.getVisibility() == View.VISIBLE;
v.setVisibility(isVisible ? View.GONE : View.VISIBLE);
item.setIcon(isVisible ? R.drawable.ic_add : R.drawable.ic_close);
Global.setTint(this, item.getIcon());
}
return super.onOptionsItemSelected(item);
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/SettingsActivity.java
================================================
package com.maxwai.nclientv3;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.view.MenuItem;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.maxwai.nclientv3.async.database.export.Exporter;
import com.maxwai.nclientv3.async.database.export.Manager;
import com.maxwai.nclientv3.components.activities.GeneralActivity;
import com.maxwai.nclientv3.components.views.GeneralPreferenceFragment;
import com.maxwai.nclientv3.settings.Global;
import com.maxwai.nclientv3.utility.LogUtility;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;
import java.util.stream.Collectors;
public class SettingsActivity extends GeneralActivity {
GeneralPreferenceFragment fragment;
private ActivityResultLauncher<String> IMPORT_ZIP;
private ActivityResultLauncher<String> SAVE_SETTINGS;
private ActivityResultLauncher<Object> REQUEST_STORAGE_MANAGER;
private ActivityResultLauncher<String> COPY_LOGS;
private int selectedItem;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
registerActivities();
//Global.initActivity(this);
setContentView(R.layout.activity_settings);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = Objects.requireNonNull(getSupportActionBar());
actionBar.setTitle(R.string.settings);
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
fragment = Objects.requireNonNull((GeneralPreferenceFragment) getSupportFragmentManager().findFragmentById(R.id.fragment));
fragment.setAct(this);
fragment.setType(SettingsActivity.Type.values()[getIntent().getIntExtra(getPackageName() + ".TYPE", SettingsActivity.Type.MAIN.ordinal())]);
}
private void registerActivities() {
IMPORT_ZIP = registerForActivityResult(new ActivityResultContracts.GetContent(), selectedFile -> {
if (selectedFile == null) return;
importSettings(selectedFile);
});
SAVE_SETTINGS = registerForActivityResult(new ActivityResultContracts.CreateDocument("application/zip") {
@NonNull
@Override
public Intent createIntent(@NonNull Context context, @NonNull String input) {
Intent i = super.createIntent(context, input);
i.setType("application/zip");
return i;
}
}, selectedFile -> {
if (selectedFile == null) return;
exportSettings(selectedFile);
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
REQUEST_STORAGE_MANAGER = registerForActivityResult(new ActivityResultContract<>() {
@RequiresApi(api = Build.VERSION_CODES.R)
@NonNull
@Override
public Intent createIntent(@NonNull Context context, Object input) {
Intent i = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
i.setData(Uri.parse("package:" + getPackageName()));
return i;
}
@Override
public Object parseResult(int resultCode, @Nullable Intent intent) {
return null;
}
}, result -> {
if (Global.isExternalStorageManager()) {
fragment.manageCustomPath();
}
});
}
COPY_LOGS = registerForActivityResult(new ActivityResultContracts.CreateDocument("text/log") {
@NonNull
@Override
public Intent createIntent(@NonNull Context context, @NonNull String input) {
Intent i = super.createIntent(context, input);
i.setType("text/log");
return i;
}
}, selectedFile -> {
if (selectedFile == null) return;
try {
Process process = Runtime.getRuntime().exec(new String[]{"logcat", "-d"});
try (OutputStream outputStream = getContentResolver().openOutputStream(selectedFile);
Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream));
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String output = in.lines().collect(Collectors.joining("\n"));
writer.write(output);
}
Toast.makeText(this, getString(process.exitValue() != 0 ? R.string.copy_logs_fail : R.string.export_finished), Toast.LENGTH_SHORT).show();
} catch (IOException e) {
LogUtility.e("Error getting logcat", e);
Toast.makeText(this, getString(R.string.copy_logs_fail), Toast.LENGTH_SHORT).show();
}
});
}
private void importSettings(Uri selectedFile) {
new Manager(selectedFile, this, false, () -> {
Toast.makeText(this, R.string.import_finished, Toast.LENGTH_SHORT).show();
finish();
}).start();
}
private void exportSettings(Uri selectedFile) {
new Manager(selectedFile, this, true, () -> Toast.makeText(this, R.string.export_finished, Toast.LENGTH_SHORT).show()).start();
}
public void importSettings() {
if (IMPORT_ZIP != null) {
IMPORT_ZIP.launch("application/zip");
} else {
importOldVersion();
}
}
private void importOldVersion() {
String[] files = Global.BACKUPFOLDER.list();
if (files == null || files.length == 0) return;
selectedItem = 0;
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setSingleChoiceItems(files, 0, (dialog, which) -> {
LogUtility.d(which);
selectedItem = which;
});
builder.setPositiveButton(R.string.ok, (dialog, which) -> importSettings(Uri.fromFile(new File(Global.BACKUPFOLDER, files[selectedItem])))).setNegativeButton(R.string.cancel, null);
builder.show();
}
public void exportSettings() {
String name = Exporter.defaultExportName(this);
if (SAVE_SETTINGS != null)
SAVE_SETTINGS.launch(name);
else {
File f = new File(Global.BACKUPFOLDER, name);
exportSettings(Uri.fromFile(f));
}
}
public void exportLogs() {
if (COPY_LOGS == null) {
Toast.makeText(this, R.string.failed, Toast.LENGTH_SHORT).show();
return;
}
Date actualTime = new Date();
COPY_LOGS.launch(String.format("NClientv3_Log_%s.log", new SimpleDateFormat("yyMMdd_HHmmss", Locale.getDefault()).format(actualTime)));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
@RequiresApi(Build.VERSION_CODES.R)
public void requestStorageManager() {
if (REQUEST_STORAGE_MANAGER == null) {
Toast.makeText(this, R.string.failed, Toast.LENGTH_SHORT).show();
return;
}
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setIcon(R.drawable.ic_file);
builder.setTitle(R.string.requesting_storage_access);
builder.setMessage(R.string.request_storage_manager_summary);
builder.setPositiveButton(R.string.ok, (dialog, which) -> REQUEST_STORAGE_MANAGER.launch(null)).setNegativeButton(R.string.cancel, null).show();
}
public enum Type {MAIN, COLUMN, DATA}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/StatusManagerActivity.java
================================================
package com.maxwai.nclientv3;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.RecyclerView;
import com.maxwai.nclientv3.adapters.StatusManagerAdapter;
import com.maxwai.nclientv3.components.activities.GeneralActivity;
import com.maxwai.nclientv3.components.widgets.CustomLinearLayoutManager;
import java.util.Objects;
public class StatusManagerActivity extends GeneralActivity {
StatusManagerAdapter adapter;
RecyclerView recycler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Global.initActivity(this);
setContentView(R.layout.activity_bookmark);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = Objects.requireNonNull(getSupportActionBar());
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(R.string.manage_statuses);
recycler = findViewById(R.id.recycler);
adapter = new StatusManagerAdapter(this);
recycler.setLayoutManager(new CustomLinearLayoutManager(this));
recycler.setAdapter(adapter);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/StatusViewerActivity.java
================================================
package com.maxwai.nclientv3;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.viewpager2.widget.ViewPager2;
import com.maxwai.nclientv3.components.activities.GeneralActivity;
import com.maxwai.nclientv3.settings.Global;
import com.maxwai.nclientv3.ui.main.PlaceholderFragment;
import com.maxwai.nclientv3.ui.main.SectionsPagerAdapter;
import com.maxwai.nclientv3.utility.LogUtility;
import com.maxwai.nclientv3.utility.Utility;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import java.util.Objects;
public class StatusViewerActivity extends GeneralActivity {
private boolean sortByTitle = false;
private String query;
private ViewPager2 viewPager;
private SectionsPagerAdapter sectionsPagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_status_viewer);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = Objects.requireNonNull(getSupportActionBar());
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(R.string.manage_statuses);
viewPager = findViewById(R.id.view_pager);
sectionsPagerAdapter = new SectionsPagerAdapter(this);
viewPager.setAdapter(sectionsPagerAdapter);
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
PlaceholderFragment fragment = getPositionFragment(position);
if (fragment != null) fragment.reload(query, sortByTitle);
}
});
TabLayout tabs = findViewById(R.id.tabs);
new TabLayoutMediator(tabs, viewPager, true, (tab, position) -> tab.setText(sectionsPagerAdapter.getPageTitle(position))).attach();
}
@Override
protected void onResume() {
super.onResume();
TabLayout tabs = findViewById(R.id.tabs);
for (int i = 0; i < tabs.getTabCount(); i++) {
Objects.requireNonNull(tabs.getTabAt(i)).setText(sectionsPagerAdapter.getPageTitle(i));
}
PlaceholderFragment fragment = getActualFragment();
if (fragment != null) fragment.reload(query, sortByTitle);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
} else if (item.getItemId() == R.id.sort_by_name) {
sortByTitle = !sortByTitle;
PlaceholderFragment fragment = getActualFragment();
if (fragment != null) fragment.changeSort(sortByTitle);
item.setTitle(sortByTitle ? R.string.sort_by_latest : R.string.sort_by_title);
item.setIcon(sortByTitle ? R.drawable.ic_sort_by_alpha : R.drawable.ic_access_time);
Global.setTint(this, item.getIcon());
}
return super.onOptionsItemSelected(item);
}
@Nullable
private PlaceholderFragment getActualFragment() {
return getPositionFragment(viewPager.getCurrentItem());
}
@Nullable
private PlaceholderFragment getPositionFragment(int position) {
PlaceholderFragment f = (PlaceholderFragment) getSupportFragmentManager().findFragmentByTag("f" + position);
LogUtility.d(f);
return f;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.status_viewer, menu);
final SearchView searchView = (androidx.appcompat.widget.SearchView) menu.findItem(R.id.search).getActionView();
Objects.requireNonNull(searchView).setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
query = newText;
PlaceholderFragment fragment = getActualFragment();
if (fragment != null) fragment.changeQuery(query);
return true;
}
});
Utility.tintMenu(this, menu);
return super.onCreateOptionsMenu(menu);
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/TagFilterActivity.java
================================================
package com.maxwai.nclientv3;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.maxwai.nclientv3.adapters.TagsAdapter;
import com.maxwai.nclientv3.components.activities.GeneralActivity;
import com.maxwai.nclientv3.components.widgets.CustomGridLayoutManager;
import com.maxwai.nclientv3.components.widgets.TagTypePage;
import com.maxwai.nclientv3.settings.DefaultDialogs;
import com.maxwai.nclientv3.settings.Global;
import com.maxwai.nclientv3.settings.Login;
import com.maxwai.nclientv3.settings.TagV2;
import com.maxwai.nclientv3.utility.LogUtility;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import java.util.List;
import java.util.Objects;
public class TagFilterActivity extends GeneralActivity {
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
private SearchView searchView;
private ViewPager2 mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Global.initActivity(this);
setContentView(R.layout.activity_tag_filter);
//init toolbar
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = Objects.requireNonNull(getSupportActionBar());
actionBar.setDisplayHomeAsUpEnabled(true);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
TagTypePageAdapter mTagTypePageAdapter = new TagTypePageAdapter(this);
mViewPager = findViewById(R.id.container);
mViewPager.setAdapter(mTagTypePageAdapter);
mViewPager.setOffscreenPageLimit(1);
TabLayout tabLayout = findViewById(R.id.tabs);
mViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
TagTypePage page = getFragment(position);
if (page != null) {
((TagsAdapter) Objects.requireNonNull(page.getRecyclerView().getAdapter())).addItem();
}
}
});
new TabLayoutMediator(tabLayout, mViewPager, (tab, position) -> {
int id = 0;
switch (position) {
case 0:
id = R.string.applied_filters;
break;
case 1:
id = R.string.tags;
break;
case 2:
id = R.string.artists;
break;
case 3:
id = R.string.characters;
break;
case 4:
id = R.string.parodies;
break;
case 5:
id = R.string.groups;
break;
case 6:
id = R.string.online_tags;
break;
}
tab.setText(id);
}).attach();
mViewPager.setCurrentItem(getPage());
}
@Nullable
private TagTypePage getActualFragment() {
return getFragment(mViewPager.getCurrentItem());
}
@Nullable
private TagTypePage getFragment(int position) {
return (TagTypePage) getSupportFragmentManager().findFragmentByTag("f" + position);
}
private int getPage() {
Uri data = getIntent().getData();
if (data != null) {
List<String> params = data.getPathSegments();
for (String x : params) LogUtility.i(x);
if (!params.isEmpty()) {
switch (params.get(0)) {
case "tags":
return 1;
case "artists":
return 2;
case "characters":
return 3;
case "parodies":
return 4;
case "groups":
return 5;
}
}
}
return 0;
}
private void updateSortItem(MenuItem item) {
item.setIcon(TagV2.isSortedByName() ? R.drawable.ic_sort_by_alpha : R.drawable.ic_sort);
item.setTitle(TagV2.isSortedByName() ? R.string.sort_by_title : R.string.sort_by_popular);
Global.setTint(this, item.getIcon());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_tag_filter, menu);
updateSortItem(menu.findItem(R.id.sort_by_name));
searchView = (androidx.appcompat.widget.SearchView) menu.findItem(R.id.search).getActionView();
Objects.requireNonNull(searchView).setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
TagTypePage page = getActualFragment();
if (page != null) {
page.refilter(newText);
}
return true;
}
});
return true;
}
private void createDialog() {
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.are_you_sure).setMessage(getString(R.string.clear_this_list)).setIcon(R.drawable.ic_help);
builder.setPositiveButton(R.string.yes, (dialog, which) -> {
TagTypePage page = getActualFragment();
if (page != null) {
page.reset();
}
}).setNegativeButton(R.string.no, null).setCancelable(true);
builder.show();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
TagTypePage page = getActualFragment();
if (id == R.id.reset_tags) createDialog();
else if (id == R.id.set_min_count) minCountBuild();
else if (id == R.id.sort_by_name) {
TagV2.updateSortByName(this);
updateSortItem(item);
if (page != null)
page.refilter(searchView.getQuery().toString());
}
return super.onOptionsItemSelected(item);
}
private void minCountBuild() {
int min = TagV2.getMinCount();
DefaultDialogs.Builder builder = new DefaultDialogs.Builder(this);
builder.setActual(min).setMax(100).setMin(2);
builder.setYesbtn(R.string.ok).setNobtn(R.string.cancel);
builder.setTitle(R.string.set_minimum_count).setDialogs(new DefaultDialogs.CustomDialogResults() {
@Override
public void positive(int actual) {
LogUtility.d("ACTUAL: " + actual);
TagV2.updateMinCount(TagFilterActivity.this, actual);
TagTypePage page = getActualFragment();
if (page != null) {
page.changeSize();
}
}
});
DefaultDialogs.pageChangerDialog(builder);
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
changeLayout(true);
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
changeLayout(false);
}
}
private void changeLayout(boolean landscape) {
final int count = landscape ? 4 : 2;
TagTypePage page = getActualFragment();
if (page != null) {
RecyclerView recycler = page.getRecyclerView();
if (recycler != null) {
RecyclerView.Adapter<?> adapter = recycler.getAdapter();
CustomGridLayoutManager gridLayoutManager = new CustomGridLayoutManager(this, count);
recycler.setLayoutManager(gridLayoutManager);
recycler.setAdapter(adapter);
}
}
}
static class TagTypePageAdapter extends FragmentStateAdapter {
TagTypePageAdapter(TagFilterActivity activity) {
super(activity.getSupportFragmentManager(), activity.getLifecycle());
}
@NonNull
@Override
public Fragment createFragment(int position) {
return TagTypePage.newInstance(position);
}
@Override
public int getItemCount() {
return Login.isLogged() ? 7 : 6;
}
}
}
================================================
FILE: app/src/main/java/com/maxwai/nclientv3/ZoomActivity.java
================================================
package com.maxwai.nclientv3;
import android.Manifest;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.bumptech.glide.Priority;
import com.maxwai.nclientv3.api.components.GenericGallery;
import com.maxwai.nclientv3.async.database.Queries;
import com.maxwai.nclientv3.components.activities.GeneralActivity;
import com.maxwai.nclientv3.components.views.ZoomFragment;
import com.maxwai.nclientv3.files.GalleryFolder;
import com.maxwai.nclientv3.settings.DefaultDialogs;
import com.maxwai.nclientv3.settings.Global;
import com.maxwai.nclientv3.utility.LogUtility;
import com.maxwai.nclientv3.utility.Utility;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.io.File;
import java.util.Objects;
public class ZoomActivity extends GeneralActivity {
private final static int hideFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
private final static int showFlags = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
private static final String VOLUME_SIDE_KEY = "volumeSide";
private static final String SCROLL_TYPE_KEY = "zoomScrollType";
private GenericGallery gallery;
private int actualPage = 0;
private boolean isHidden = false;
private ViewPager2 mViewPager;
private TextView pageManagerLabel, cornerPageViewer;
private View pageSwitcher;
private SeekBar seekBar;
private Toolbar toolbar;
private View view;
private GalleryFolder directory;
@ViewPager2.Orientation
private int tmpScrollType;
private boolean up = false, down = false, side;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Global.initActivity(this);
SharedPreferences preferences = getSharedPreferences("Settings", 0);
side = preferences.getBoolean(VOLUME_SIDE_KEY, true);
setContentView(R.layout.activity_zoom);
//read arguments
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
gallery = getIntent().getParcelableExtra(getPackageName() + ".GALLERY", GenericGallery.class);
} else {
gallery = getIntent().getParcelableExtra(getPackageName() + ".GALLERY");
}
final int page = Objects.requireNonNull(getIntent().getExtras()).getInt(getPackageName() + ".PAGE", 1) - 1;
directory = gallery.getGalleryFolder();
//toolbar setup
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = Objects.requireNonNull(getSupportActionBar());
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
setTitle(gallery.getTitle());
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
if (Global.isLockScreen())
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//find views
SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(this);
mViewPager = findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setOrientation(preferences.getInt(SCROLL_TYPE_KEY, ScrollType.HORIZONTAL.ordinal()));
mViewPager.setOffscreenPageLimit(Global.getOffscreenLimit());
pageSwitcher = findViewById(R.id.page_switcher);
pageManagerLabel = findViewById(R.id.pages);
cornerPageViewer = findViewById(R.id.page_text);
seekBar = findViewById(R.id.seekBar);
view = findViewById(R.id.view);
//initial setup for views
changeLayout(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
mViewPager.setKeepScreenOn(Global.isLockScreen());
findViewById(R.id.prev).setOnClickListener(v -> changeClosePage(false));
findViewById(R.id.next).setOnClickListener(v -> changeClosePage(true));
seekBar.setMax(gallery.getPageCount() - 1);
if (Global.useRtl()) {
seekBar.setRotationY(180);
mViewPager.setLayoutDirection(ViewPager2.LAYOUT_DIRECTION_RTL);
}
//Adding listeners
mViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int newPage) {
int oldPage = actualPage;
actualPage = newPage;
LogUtility.d("Page selected: " + newPage + " from page " + oldPage);
setPageText(newPage + 1);
seekBar.setProgress(newPage);
clearFarRequests(oldPage, newPage);
makeNearRequests(newPage);
}
});
pageManagerLabel.setOnClickListener(v -> DefaultDialogs.pageChangerDialog(
new DefaultDialogs.Builder(this)
.setActual(actualPage + 1)
.setMin(1)
.setMax(gallery.getPageCount())
.setTitle(R.string.change_page)
.setDrawable(R.drawable.ic_find_in_page)
.setDialogs(new DefaultDialogs.CustomDialogResults() {
@Override
public void positive(int actual) {
changePage(actual - 1);
}
})
));
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
setPageText(progress + 1);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
changePage(seekBar.getProgress());
}
});
changePage(page);
setPageText(page + 1);
seekBar.setProgress(page);
}
private void setUserInput(boolean enabled) {
mViewPager.setUserInputEnabled(enabled);
}
private void setPageText(int page) {
pageManagerLabel.setText(getString(R.string.page_format, page, gallery.getPageCount()));
cornerPageViewer.setText(getString(R.string.page_format, page, gallery.getPageCount()));
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (Global.volumeOverride()) {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
up = false;
return true;
case KeyEvent.KEYCODE_VOLUME_DOWN:
down = false;
return true;
}
}
return super.onKeyUp(keyCode, event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (Global.volumeOverride()) {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
up = true;
changeClosePage(side);
if (up && down) changeSide();
return true;
case KeyEvent.KEYCODE_VOLUME_DOWN:
down = true;
changeClosePage(!side);
if (up && down) changeSide();
return true;
}
}
return super.onKeyDown(keyCode, event);
}
private void changeSide() {
getSharedPreferences("Settings", 0).edit().putBoolean(VOLUME_SIDE_KEY, side = !side).apply();
Toast.makeText(this, side ? R.string.next_page_volume_up : R.string.next_page_volume_down, Toast.LENGTH_SHORT).show();
}
public void changeClosePage(boolean next) {
if (Global.useRtl()) next = !next;
if (next && mViewPager.getCurrentItem() < (Objects.requireNonNull(mViewPager.getAdapter()).getItemCount() - 1))
changePage(mViewPager.getCurrentItem() + 1);
if (!next && mViewPager.getCurrentItem() > 0) changePage(mViewPager.getCurrentItem() - 1);
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
changeLayout(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE);
}
private boolean hardwareKeys() {
return ViewConfiguration.get(this).hasPermanentMenuKey();
}
private void applyMargin(boolean landscape, View view) {
ConstraintLayout.LayoutParams lp = (ConstraintLayout.LayoutParams) view.getLayoutParams();
lp.setMargins(0, 0, landscape && !hardwareKeys() ? Global.getNavigationBarHeight(this) : 0, 0);
view.setLayoutParams(lp);
}
private void changeLayout(boolean landscape) {
int statusBarHeight = Global.getStatusBarHeight(this);
applyMargin(landscape, findViewById(R.id.master_layout));
applyMargin(landscape, toolbar);
pageSwitcher.setPadding(0, 0, 0, landscape ? 0 : statusBarHeight);
}
private void changePage(int newPage) {
mViewPager.setCurrentItem(newPage);
}
private void changeScrollTypeDialog() {
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
int scrollType = mViewPager.getOrientation();
tmpScrollType = mViewPager.getOrientation();
builder.setTitle(getString(R.string.change_scroll_type) + ":");
builder.setSingleChoiceItems(R.array.scroll_type, scrollType, (dialog, which) -> tmpScrollType = which);
builder.setPositiveButton(R.string.ok, (dialog, which) -> {
if (tmpScrollType != scrollType) {
mViewPager.setOrientation(tmpScrollType);
getSharedPreferences("Settings", 0).edit().putInt(SCROLL_TYPE_KEY, tmpScrollType).apply();
int page = actualPage;
changePage(page + 1);
changePage(page);
}
}).setNegativeButton(R.string.cancel, null);
builder.show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_zoom, menu);
Utility.tintMenu(this, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.rotate) {
getActualFragment().rotate();
} else if (id == R.id.save_page) {
if (Global.hasStoragePermission(this)) {
downloadPage();
} else requestStorage();
} else if (id == R.id.share) {
if (gallery.getId() <= 0) sendImage(false);
else openSendImageDialog();
} else if (id == android.R.id.home) {
finish();
return true;
} else if (id == R.id.bookmark) {
Queries.ResumeTable.insert(gallery.getId(), actualPage + 1);
} else if (id == R.id.scrollType) {
changeScrollTypeDialog();
}
return super.onOptionsItemSelected(item);
}
private void openSendImageDialog() {
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setPositiveButton(R.string.yes, (dialog, which) -> sendImage(true))
.setNegativeButton(R.string.no, (dialog, which) -> sendImage(false))
.setCancelable(true).setTitle(R.string.send_with_title)
.setMessage(R.string.caption_send_with_title)
.show();
}
private void requestStorage() {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResul
gitextract_atw2n2is/ ├── .editorconfig ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.yaml │ │ ├── config.yml │ │ └── feature_request.yaml │ ├── PULL_REQUEST_TEMPLATE.md │ ├── dependabot.yml │ └── workflows/ │ ├── android.yml │ ├── dependencies.yml │ └── update_data.yml ├── .gitignore ├── DCO ├── LICENSE ├── README.md ├── SECURITY.md ├── app/ │ ├── .gitignore │ ├── build.gradle.kts │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── com/ │ │ └── maxwai/ │ │ └── nclientv3/ │ │ ├── ApiKeyActivity.java │ │ ├── BookmarkActivity.java │ │ ├── CommentActivity.java │ │ ├── CopyToClipboardActivity.java │ │ ├── FavoriteActivity.java │ │ ├── GalleryActivity.java │ │ ├── HistoryActivity.java │ │ ├── LocalActivity.java │ │ ├── MainActivity.java │ │ ├── PINActivity.java │ │ ├── RandomActivity.java │ │ ├── SearchActivity.java │ │ ├── SettingsActivity.java │ │ ├── StatusManagerActivity.java │ │ ├── StatusViewerActivity.java │ │ ├── TagFilterActivity.java │ │ ├── ZoomActivity.java │ │ ├── adapters/ │ │ │ ├── BookmarkAdapter.java │ │ │ ├── CommentAdapter.java │ │ │ ├── FavoriteAdapter.java │ │ │ ├── GalleryAdapter.java │ │ │ ├── GenericAdapter.java │ │ │ ├── HistoryAdapter.java │ │ │ ├── ListAdapter.java │ │ │ ├── LocalAdapter.java │ │ │ ├── StatusManagerAdapter.java │ │ │ ├── StatusViewerAdapter.java │ │ │ └── TagsAdapter.java │ │ ├── api/ │ │ │ ├── InspectorV3.java │ │ │ ├── RandomLoader.java │ │ │ ├── SimpleGallery.java │ │ │ ├── comments/ │ │ │ │ ├── Comment.java │ │ │ │ ├── CommentsFetcher.java │ │ │ │ └── User.java │ │ │ ├── components/ │ │ │ │ ├── Gallery.java │ │ │ │ ├── GalleryData.java │ │ │ │ ├── GenericGallery.java │ │ │ │ ├── Page.java │ │ │ │ ├── Ranges.java │ │ │ │ ├── Tag.java │ │ │ │ └── TagList.java │ │ │ ├── enums/ │ │ │ │ ├── ApiRequestType.java │ │ │ │ ├── ImageType.java │ │ │ │ ├── Language.java │ │ │ │ ├── SortType.java │ │ │ │ ├── SpecialTagIds.java │ │ │ │ ├── TagStatus.java │ │ │ │ ├── TagType.java │ │ │ │ └── TitleType.java │ │ │ └── local/ │ │ │ ├── FakeInspector.java │ │ │ ├── LocalGallery.java │ │ │ └── LocalSortType.java │ │ ├── async/ │ │ │ ├── MetadataFetcher.java │ │ │ ├── ScrapeTags.java │ │ │ ├── VersionChecker.java │ │ │ ├── converters/ │ │ │ │ └── CreatePdfOrZip.java │ │ │ ├── database/ │ │ │ │ ├── DatabaseHelper.java │ │ │ │ ├── Queries.java │ │ │ │ └── export/ │ │ │ │ ├── Exporter.java │ │ │ │ ├── Importer.java │ │ │ │ └── Manager.java │ │ │ └── downloader/ │ │ │ ├── DownloadGalleryV2.java │ │ │ ├── DownloadObserver.java │ │ │ ├── DownloadQueue.java │ │ │ ├── GalleryDownloaderManager.java │ │ │ ├── GalleryDownloaderV2.java │ │ │ └── PageChecker.java │ │ ├── components/ │ │ │ ├── CookieInterceptor.java │ │ │ ├── CustomCookieJar.java │ │ │ ├── GlideX.java │ │ │ ├── ThreadAsyncTask.java │ │ │ ├── activities/ │ │ │ │ ├── BaseActivity.java │ │ │ │ ├── CrashApplication.java │ │ │ │ └── GeneralActivity.java │ │ │ ├── classes/ │ │ │ │ ├── Bookmark.java │ │ │ │ ├── History.java │ │ │ │ ├── MultichoiceAdapter.java │ │ │ │ └── Size.java │ │ │ ├── launcher/ │ │ │ │ ├── LauncherCalculator.java │ │ │ │ └── LauncherReal.java │ │ │ ├── status/ │ │ │ │ ├── Status.java │ │ │ │ └── StatusManager.java │ │ │ ├── views/ │ │ │ │ ├── CFTokenView.java │ │ │ │ ├── GeneralPreferenceFragment.java │ │ │ │ ├── PageSwitcher.java │ │ │ │ ├── RangeSelector.java │ │ │ │ └── ZoomFragment.java │ │ │ └── widgets/ │ │ │ ├── ChipTag.java │ │ │ ├── CustomGridLayoutManager.java │ │ │ ├── CustomImageView.java │ │ │ ├── CustomLinearLayoutManager.java │ │ │ ├── CustomSearchView.java │ │ │ ├── CustomSwipe.java │ │ │ └── TagTypePage.java │ │ ├── files/ │ │ │ ├── GalleryFolder.java │ │ │ └── PageFile.java │ │ ├── github/ │ │ │ └── chrisbanes/ │ │ │ └── photoview/ │ │ │ ├── Compat.java │ │ │ ├── CustomGestureDetector.java │ │ │ ├── OnGestureListener.java │ │ │ ├── OnMatrixChangedListener.java │ │ │ ├── OnOutsidePhotoTapListener.java │ │ │ ├── OnPhotoTapListener.java │ │ │ ├── OnScaleChangedListener.java │ │ │ ├── OnSingleFlingListener.java │ │ │ ├── OnViewDragListener.java │ │ │ ├── OnViewTapListener.java │ │ │ ├── PhotoView.java │ │ │ ├── PhotoViewAttacher.java │ │ │ └── Util.java │ │ ├── loginapi/ │ │ │ ├── LoadTags.java │ │ │ └── User.java │ │ ├── settings/ │ │ │ ├── ApiAuthInterceptor.java │ │ │ ├── AuthCredentials.java │ │ │ ├── AuthStore.java │ │ │ ├── Database.java │ │ │ ├── DefaultDialogs.java │ │ │ ├── Favorites.java │ │ │ ├── Global.java │ │ │ ├── Login.java │ │ │ ├── NotificationSettings.java │ │ │ └── TagV2.java │ │ ├── ui/ │ │ │ └── main/ │ │ │ ├── PlaceholderFragment.java │ │ │ └── SectionsPagerAdapter.java │ │ └── utility/ │ │ ├── CSRFGet.java │ │ ├── ImageDownloadUtility.java │ │ ├── IntentUtility.java │ │ ├── LogUtility.java │ │ ├── Utility.java │ │ └── network/ │ │ └── NetworkUtil.java │ └── res/ │ ├── drawable/ │ │ ├── ic_access_time.xml │ │ ├── ic_add.xml │ │ ├── ic_archive.xml │ │ ├── ic_arrow_back.xml │ │ ├── ic_arrow_forward.xml │ │ ├── ic_backspace.xml │ │ ├── ic_bookmark.xml │ │ ├── ic_bookmark_border.xml │ │ ├── ic_burst_mode.xml │ │ ├── ic_chat_bubble.xml │ │ ├── ic_check.xml │ │ ├── ic_check_circle.xml │ │ ├── ic_close.xml │ │ ├── ic_cnbw.xml │ │ ├── ic_content_copy.xml │ │ ├── ic_delete.xml │ │ ├── ic_exit_to_app.xml │ │ ├── ic_favorite.xml │ │ ├── ic_favorite_border.xml │ │ ├── ic_filter_list.xml │ │ ├── ic_find_in_page.xml │ │ ├── ic_folder.xml │ │ ├── ic_gbbw.xml │ │ ├── ic_hashtag.xml │ │ ├── ic_help.xml │ │ ├── ic_jpbw.xml │ │ ├── ic_keyboard_arrow_left.xml │ │ ├── ic_keyboard_arrow_right.xml │ │ ├── ic_launcher_calculator_foreground.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── ic_logo.xml │ │ ├── ic_mode_edit.xml │ │ ├── ic_pause.xml │ │ ├── ic_pdf.xml │ │ ├── ic_person.xml │ │ ├── ic_play.xml │ │ ├── ic_refresh.xml │ │ ├── ic_rotate_90_degrees.xml │ │ ├── ic_save.xml │ │ ├── ic_search.xml │ │ ├── ic_select_all.xml │ │ ├── ic_settings.xml │ │ ├── ic_share.xml │ │ ├── ic_shuffle.xml │ │ ├── ic_sort.xml │ │ ├── ic_sort_by_alpha.xml │ │ ├── ic_star.xml │ │ ├── ic_star_border.xml │ │ ├── ic_view_1.xml │ │ ├── ic_view_2.xml │ │ ├── ic_view_3.xml │ │ ├── ic_view_4.xml │ │ ├── ic_void.xml │ │ ├── ic_world.xml │ │ ├── side_nav_bar.xml │ │ └── thumb.xml │ ├── drawable-anydpi/ │ │ ├── ic_archive.xml │ │ ├── ic_check.xml │ │ ├── ic_close.xml │ │ ├── ic_file.xml │ │ ├── ic_pause.xml │ │ └── ic_play.xml │ ├── drawable-night/ │ │ ├── ic_logo.xml │ │ └── side_nav_bar.xml │ ├── layout/ │ │ ├── activity_api_key.xml │ │ ├── activity_bookmark.xml │ │ ├── activity_comment.xml │ │ ├── activity_gallery.xml │ │ ├── activity_main.xml │ │ ├── activity_pin.xml │ │ ├── activity_random.xml │ │ ├── activity_search.xml │ │ ├── activity_settings.xml │ │ ├── activity_status_viewer.xml │ │ ├── activity_tag_filter.xml │ │ ├── activity_zoom.xml │ │ ├── app_bar_gallery.xml │ │ ├── app_bar_main.xml │ │ ├── autocomplete_entry.xml │ │ ├── bookmark_layout.xml │ │ ├── cftoken_layout.xml │ │ ├── chip_layout.xml │ │ ├── chip_layout_entry.xml │ │ ├── comment_layout.xml │ │ ├── content_gallery.xml │ │ ├── content_main.xml │ │ ├── dialog_add_status.xml │ │ ├── entry_download_layout.xml │ │ ├── entry_download_layout_compact.xml │ │ ├── entry_history.xml │ │ ├── entry_layout.xml │ │ ├── entry_layout_single.xml │ │ ├── entry_status.xml │ │ ├── entry_tag_layout.xml │ │ ├── fragment_status_viewer.xml │ │ ├── fragment_tag_filter.xml │ │ ├── fragment_zoom.xml │ │ ├── image_void_full.xml │ │ ├── image_void_static.xml │ │ ├── info_layout.xml │ │ ├── local_sort_type.xml │ │ ├── multichoice_adapter.xml │ │ ├── nav_header_main.xml │ │ ├── page_changer.xml │ │ ├── page_switcher.xml │ │ ├── range_selector.xml │ │ ├── related_recycler.xml │ │ ├── search_options.xml │ │ ├── search_range.xml │ │ ├── sub_tag_layout.xml │ │ ├── tags_layout.xml │ │ └── zoom_manager.xml │ ├── layout-land/ │ │ └── activity_random.xml │ ├── menu/ │ │ ├── activity_main_drawer.xml │ │ ├── download.xml │ │ ├── gallery.xml │ │ ├── history.xml │ │ ├── local_multichoice.xml │ │ ├── main.xml │ │ ├── menu_tag_filter.xml │ │ ├── menu_zoom.xml │ │ ├── search.xml │ │ └── status_viewer.xml │ ├── mipmap-anydpi/ │ │ ├── ic_launcher.xml │ │ ├── ic_launcher_calculator.xml │ │ └── ic_launcher_calculator_round.xml │ ├── resources.properties │ ├── values/ │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_launcher_calculator_background.xml │ │ ├── strings.xml │ │ └── styles.xml │ ├── values-ar-rSA/ │ │ └── strings.xml │ ├── values-de-rDE/ │ │ └── strings.xml │ ├── values-es-rES/ │ │ └── strings.xml │ ├── values-fr-rFR/ │ │ └── strings.xml │ ├── values-it-rIT/ │ │ └── strings.xml │ ├── values-ja-rJP/ │ │ └── strings.xml │ ├── values-night/ │ │ └── colors.xml │ ├── values-pt-rBR/ │ │ └── strings.xml │ ├── values-ru-rRU/ │ │ └── strings.xml │ ├── values-tr-rTR/ │ │ └── strings.xml │ ├── values-uk-rUA/ │ │ └── strings.xml │ ├── values-w820dp/ │ │ └── dimens.xml │ ├── values-zh-rCN/ │ │ └── strings.xml │ ├── values-zh-rTW/ │ │ └── strings.xml │ └── xml/ │ ├── backup_content.xml │ ├── provider_paths.xml │ ├── settings.xml │ ├── settings_column.xml │ └── settings_data.xml ├── build.gradle.kts ├── crowdin.yml ├── data/ │ ├── tags.json │ ├── tagsPretty.json │ └── tagsVersion ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── scripts/ │ ├── requirements.txt │ └── update_tags.py └── settings.gradle.kts
SYMBOL INDEX (1690 symbols across 130 files)
FILE: app/src/main/java/com/maxwai/nclientv3/ApiKeyActivity.java
class ApiKeyActivity (line 33) | public class ApiKeyActivity extends GeneralActivity {
method onCreate (line 44) | @Override
method onResume (line 70) | @Override
method openApiKeyPage (line 76) | private void openApiKeyPage() {
method updateStatusMessage (line 80) | private void updateStatusMessage(@NonNull String message) {
method setInputVisible (line 84) | private void setInputVisible(boolean visible) {
method setLoading (line 88) | private void setLoading(boolean loading) {
method loadSavedApiKey (line 98) | private void loadSavedApiKey() {
method getStatusMessage (line 107) | @NonNull
method clearSavedApiKey (line 114) | private void clearSavedApiKey() {
method validateAndSaveApiKey (line 123) | private void validateAndSaveApiKey() {
method onOptionsItemSelected (line 169) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/BookmarkActivity.java
class BookmarkActivity (line 16) | public class BookmarkActivity extends GeneralActivity {
method onCreate (line 20) | @Override
method onOptionsItemSelected (line 38) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/CommentActivity.java
class CommentActivity (line 39) | public class CommentActivity extends BaseActivity {
method onCreate (line 43) | @Override
method setAdapter (line 103) | public void setAdapter(CommentAdapter adapter) {
method createRequestString (line 107) | private String createRequestString(String text) {
method getPortraitColumnCount (line 120) | @Override
method getLandscapeColumnCount (line 125) | @Override
method onOptionsItemSelected (line 130) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/CopyToClipboardActivity.java
class CopyToClipboardActivity (line 12) | public class CopyToClipboardActivity extends GeneralActivity {
method copyTextToClipboard (line 13) | public static void copyTextToClipboard(Context context, String text) {
method onCreate (line 20) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/FavoriteActivity.java
class FavoriteActivity (line 28) | public class FavoriteActivity extends BaseActivity {
method getEntryPerPage (line 35) | public static int getEntryPerPage() {
method onCreate (line 39) | @Override
method getActualPage (line 71) | public int getActualPage() {
method getLandscapeColumnCount (line 75) | @Override
method getPortraitColumnCount (line 80) | @Override
method calculatePages (line 85) | private int calculatePages(@Nullable String text) {
method onResume (line 93) | @Override
method onCreateOptionsMenu (line 103) | @Override
method onOptionsItemSelected (line 132) | @Override
method showDialogDownloadAll (line 150) | private void showDialogDownloadAll() {
FILE: app/src/main/java/com/maxwai/nclientv3/GalleryActivity.java
class GalleryActivity (line 58) | public class GalleryActivity extends BaseActivity {
method onCreate (line 71) | @Override
method tryLoadFromURL (line 110) | private boolean tryLoadFromURL() {
method lookup (line 146) | private void lookup() {
method loadGallery (line 157) | private void loadGallery(GenericGallery gall, int zoom) {
method checkBookmark (line 175) | private void checkBookmark() {
method applyTitle (line 189) | private void applyTitle() {
method getPortraitColumnCount (line 215) | @Override
method getLandscapeColumnCount (line 220) | @Override
method initFavoriteIcon (line 226) | public void initFavoriteIcon(Menu menu) {
method onCreateOptionsMenu (line 238) | @Override
method menuItemsVisible (line 251) | private void menuItemsVisible(Menu menu) {
method onResume (line 265) | @Override
method onOptionsItemSelected (line 272) | @Override
method updateStatus (line 309) | private void updateStatus() {
method createNewStatusDialog (line 331) | private void createNewStatusDialog() {
method updateIcon (line 375) | private void updateIcon(boolean nowIsFavorite) {
method addToFavorite (line 382) | private void addToFavorite() {
method updateColumnCount (line 402) | private void updateColumnCount(boolean increase) {
method toInternet (line 443) | private void toInternet() {
method requestStorage (line 457) | private void requestStorage() {
method onRequestPermissionsResult (line 461) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/HistoryActivity.java
class HistoryActivity (line 20) | public class HistoryActivity extends BaseActivity {
method onCreate (line 23) | @Override
method onOptionsItemSelected (line 42) | @Override
method getPortraitColumnCount (line 56) | @Override
method getLandscapeColumnCount (line 61) | @Override
method onCreateOptionsMenu (line 66) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/LocalActivity.java
class LocalActivity (line 34) | public class LocalActivity extends BaseActivity {
method choiceChanged (line 39) | @Override
method onCreate (line 50) | @Override
method setAdapter (line 81) | public void setAdapter(LocalAdapter adapter) {
method setIdGalleryPosition (line 87) | public void setIdGalleryPosition(int idGalleryPosition) {
method onCreateOptionsMenu (line 91) | @Override
method setMenuVisibility (line 118) | private void setMenuVisibility(Menu menu) {
method onDestroy (line 141) | @Override
method changeLayout (line 147) | @Override
method getColCount (line 154) | public int getColCount() {
method onResume (line 158) | @Override
method onOptionsItemSelected (line 167) | public boolean onOptionsItemSelected(MenuItem item) {
method showDialogFolderChoose (line 193) | private void showDialogFolderChoose() {
method dialogSortType (line 204) | private void dialogSortType() {
method getPortraitColumnCount (line 233) | @Override
method getLandscapeColumnCount (line 238) | @Override
method getQuery (line 243) | public String getQuery() {
FILE: app/src/main/java/com/maxwai/nclientv3/MainActivity.java
class MainActivity (line 71) | public class MainActivity extends BaseActivity
method onSuccess (line 77) | @Override
method onSuccess (line 93) | @Override
method onSuccess (line 110) | @Override
method onCreate (line 126) | @Override
method manageDrawer (line 168) | private void manageDrawer() {
method setActivityTitle (line 178) | private void setActivityTitle() {
method initializeToolbar (line 199) | private void initializeToolbar() {
method initializePageSwitcherActions (line 207) | private void initializePageSwitcherActions() {
method initializeRecyclerView (line 218) | private void initializeRecyclerView() {
method lastGalleryReached (line 246) | private boolean lastGalleryReached(CustomGridLayoutManager manager) {
method initializeNavigationView (line 250) | private void initializeNavigationView() {
method setIdOpenedGallery (line 257) | public void setIdOpenedGallery(int idOpenedGallery) {
method findUsefulViews (line 261) | private void findUsefulViews() {
method hideError (line 272) | private void hideError() {
method showError (line 282) | private void showError(@Nullable String text, @Nullable View.OnClickLi...
method showError (line 296) | private void showError(@StringRes int text, View.OnClickListener liste...
method checkUpdate (line 300) | private void checkUpdate() {
method selectStartMode (line 307) | private void selectStartMode(Intent intent, String packageName) {
method useNormalMode (line 320) | private void useNormalMode() {
method useBookmarkMode (line 325) | private void useBookmarkMode(Intent intent, String packageName) {
method useFavoriteMode (line 342) | private void useFavoriteMode(int page) {
method useSearchMode (line 348) | private void useSearchMode(Intent intent, String packageName) {
method createSearchInspector (line 354) | private void createSearchInspector(Intent intent, String packageName, ...
method tryOpenId (line 373) | private boolean tryOpenId(String query) {
method useTagMode (line 384) | private void useTagMode(Intent intent, String packageName) {
method manageDataStart (line 398) | private void manageDataStart(Uri data) {
method useDataSearchMode (line 412) | private void useDataSearchMode(Uri data, List<String> datas) {
method useDataTagMode (line 435) | private void useDataTagMode(List<String> datas, TagType type) {
method hidePageSwitcher (line 448) | public void hidePageSwitcher() {
method showPageSwitcher (line 452) | public void showPageSwitcher(final int actualPage, final int totalPage) {
method onResume (line 461) | @SuppressLint("NotifyDataSetChanged")
method onConfigurationChanged (line 493) | @Override
method onCreateOptionsMenu (line 498) | @Override
method initializeSearchItem (line 521) | private void initializeSearchItem(MenuItem item) {
method popularItemDispay (line 542) | private void popularItemDispay(MenuItem item) {
method showLanguageIcon (line 547) | private void showLanguageIcon(MenuItem item) {
method getPortraitColumnCount (line 569) | @Override
method getLandscapeColumnCount (line 574) | @Override
method onOptionsItemSelected (line 579) | @Override
method updateSortType (line 614) | private void updateSortType(MenuItem item) {
method updateLanguageAndIcon (line 644) | private void updateLanguageAndIcon(MenuItem item) {
method showDialogDownloadAll (line 669) | private void showDialogDownloadAll() {
method updateTagStatus (line 682) | private void updateTagStatus(MenuItem item, TagStatus ts) {
method onNavigationItemSelected (line 697) | @Override
method requestStorage (line 736) | private void requestStorage() {
method onRequestPermissionsResult (line 740) | @Override
method startLocalActivity (line 750) | private void startLocalActivity() {
type ModeType (line 764) | private enum ModeType {UNKNOWN, NORMAL, TAG, FAVORITE, SEARCH, BOOKMAR...
class MainInspectorResponse (line 766) | abstract class MainInspectorResponse extends InspectorV3.DefaultInspec...
method onSuccess (line 767) | @Override
method onStart (line 775) | @Override
method onEnd (line 781) | @Override
method onFailure (line 787) | @Override
method shouldStart (line 796) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/PINActivity.java
class PINActivity (line 20) | public class PINActivity extends GeneralActivity {
method onCreate (line 24) | @Override
method hasPin (line 76) | @SuppressWarnings("BooleanMethodIsAlwaysInverted")
method finish (line 81) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/RandomActivity.java
class RandomActivity (line 26) | public class RandomActivity extends GeneralActivity {
method onCreate (line 37) | @Override
method onOptionsItemSelected (line 114) | @Override
method loadGallery (line 124) | public void loadGallery(Gallery gallery) {
method favoriteUpdateButton (line 136) | private void favoriteUpdateButton() {
FILE: app/src/main/java/com/maxwai/nclientv3/SearchActivity.java
class SearchActivity (line 48) | public class SearchActivity extends GeneralActivity {
method setQuery (line 64) | public void setQuery(String str, boolean submit) {
method onCreate (line 68) | @Override
method createPageBuilder (line 148) | private void createPageBuilder(int title, int min, int max, int actual...
method initRanges (line 163) | private void initRanges() {
method showUnitDialog (line 208) | private void showUnitDialog(Button button, boolean from) {
method populateGroup (line 259) | private void populateGroup() {
method createAddChip (line 298) | private Chip createAddChip(TagType type, ChipGroup group) {
method tagAlreadyExist (line 308) | private boolean tagAlreadyExist(Tag tag) {
method addChipTag (line 315) | private void addChipTag(Tag t, boolean close, boolean canBeAvoided) {
method loadDropdown (line 332) | private void loadDropdown(TagType type) {
method loadTag (line 341) | private void loadTag(TagType type) {
method getGroup (line 348) | private ChipGroup getGroup(TagType type) {
method addDialog (line 352) | private void addDialog() {
method createChip (line 368) | private void createChip() {
method onCreateOptionsMenu (line 386) | @Override
method onOptionsItemSelected (line 394) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/SettingsActivity.java
class SettingsActivity (line 43) | public class SettingsActivity extends GeneralActivity {
method onCreate (line 51) | @Override
method registerActivities (line 70) | private void registerActivities() {
method importSettings (line 137) | private void importSettings(Uri selectedFile) {
method exportSettings (line 144) | private void exportSettings(Uri selectedFile) {
method importSettings (line 148) | public void importSettings() {
method importOldVersion (line 156) | private void importOldVersion() {
method exportSettings (line 170) | public void exportSettings() {
method exportLogs (line 180) | public void exportLogs() {
method onOptionsItemSelected (line 189) | @Override
method requestStorageManager (line 198) | @RequiresApi(Build.VERSION_CODES.R)
type Type (line 211) | public enum Type {MAIN, COLUMN, DATA}
FILE: app/src/main/java/com/maxwai/nclientv3/StatusManagerActivity.java
class StatusManagerActivity (line 16) | public class StatusManagerActivity extends GeneralActivity {
method onCreate (line 21) | @Override
method onOptionsItemSelected (line 39) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/StatusViewerActivity.java
class StatusViewerActivity (line 24) | public class StatusViewerActivity extends GeneralActivity {
method onCreate (line 30) | @Override
method onResume (line 58) | @Override
method onOptionsItemSelected (line 69) | @Override
method getActualFragment (line 85) | @Nullable
method getPositionFragment (line 90) | @Nullable
method onCreateOptionsMenu (line 97) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/TagFilterActivity.java
class TagFilterActivity (line 36) | public class TagFilterActivity extends GeneralActivity {
method onCreate (line 44) | @Override
method getActualFragment (line 106) | @Nullable
method getFragment (line 111) | @Nullable
method getPage (line 116) | private int getPage() {
method updateSortItem (line 139) | private void updateSortItem(MenuItem item) {
method onCreateOptionsMenu (line 145) | @Override
method createDialog (line 169) | private void createDialog() {
method onOptionsItemSelected (line 182) | @Override
method minCountBuild (line 201) | private void minCountBuild() {
method onConfigurationChanged (line 221) | @Override
method changeLayout (line 231) | private void changeLayout(boolean landscape) {
class TagTypePageAdapter (line 246) | static class TagTypePageAdapter extends FragmentStateAdapter {
method TagTypePageAdapter (line 248) | TagTypePageAdapter(TagFilterActivity activity) {
method createFragment (line 252) | @NonNull
method getItemCount (line 258) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/ZoomActivity.java
class ZoomActivity (line 44) | public class ZoomActivity extends GeneralActivity {
method onCreate (line 68) | @Override
method setUserInput (line 175) | private void setUserInput(boolean enabled) {
method setPageText (line 179) | private void setPageText(int page) {
method onKeyUp (line 185) | @Override
method onKeyDown (line 200) | @Override
method changeSide (line 219) | private void changeSide() {
method changeClosePage (line 224) | public void changeClosePage(boolean next) {
method onConfigurationChanged (line 231) | @Override
method hardwareKeys (line 237) | private boolean hardwareKeys() {
method applyMargin (line 241) | private void applyMargin(boolean landscape, View view) {
method changeLayout (line 247) | private void changeLayout(boolean landscape) {
method changePage (line 254) | private void changePage(int newPage) {
method changeScrollTypeDialog (line 258) | private void changeScrollTypeDialog() {
method onCreateOptionsMenu (line 276) | @Override
method onOptionsItemSelected (line 284) | @Override
method openSendImageDialog (line 311) | private void openSendImageDialog() {
method requestStorage (line 320) | private void requestStorage() {
method onRequestPermissionsResult (line 324) | @Override
method getActualFragment (line 333) | private ZoomFragment getActualFragment() {
method makeNearRequests (line 337) | private void makeNearRequests(int newPage) {
method clearFarRequests (line 348) | private void clearFarRequests(int oldPage, int newPage) {
method getActualFragment (line 360) | private ZoomFragment getActualFragment(int position) {
method sendImage (line 364) | private void sendImage(boolean withText) {
method downloadPage (line 369) | private void downloadPage() {
method animateLayout (line 374) | private void animateLayout() {
method applyVisibilityFlag (line 398) | private void applyVisibilityFlag() {
type ScrollType (line 402) | private enum ScrollType {HORIZONTAL}
class SectionsPagerAdapter (line 404) | public class SectionsPagerAdapter extends FragmentStateAdapter {
method SectionsPagerAdapter (line 405) | public SectionsPagerAdapter(ZoomActivity activity) {
method createFragment (line 412) | @NonNull
method getItemCount (line 437) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/adapters/BookmarkAdapter.java
class BookmarkAdapter (line 23) | public class BookmarkAdapter extends RecyclerView.Adapter<BookmarkAdapte...
method BookmarkAdapter (line 29) | public BookmarkAdapter(BookmarkActivity bookmarkActivity) {
method onCreateViewHolder (line 35) | @NonNull
method onBindViewHolder (line 42) | @Override
method loadBookmark (line 60) | private void loadBookmark(Bookmark bookmark) {
method removeBookmarkAtPosition (line 72) | private void removeBookmarkAtPosition(int position) {
method getItemCount (line 80) | @Override
class ViewHolder (line 85) | public static class ViewHolder extends RecyclerView.ViewHolder {
method ViewHolder (line 91) | ViewHolder(@NonNull View itemView) {
FILE: app/src/main/java/com/maxwai/nclientv3/adapters/CommentAdapter.java
class CommentAdapter (line 32) | public class CommentAdapter extends RecyclerView.Adapter<CommentAdapter....
method CommentAdapter (line 38) | public CommentAdapter(AppCompatActivity context, List<Comment> comment...
method onCreateViewHolder (line 47) | @NonNull
method onBindViewHolder (line 53) | @Override
method getItemCount (line 87) | @Override
method addComment (line 92) | public void addComment(Comment c) {
class ViewHolder (line 97) | public static class ViewHolder extends RecyclerView.ViewHolder {
method ViewHolder (line 105) | public ViewHolder(@NonNull View v) {
FILE: app/src/main/java/com/maxwai/nclientv3/adapters/FavoriteAdapter.java
class FavoriteAdapter (line 32) | public class FavoriteAdapter extends RecyclerView.Adapter<GenericAdapter...
method FavoriteAdapter (line 42) | public FavoriteAdapter(FavoriteActivity activity) {
method getItemId (line 48) | @SuppressLint("Range")
method onCreateViewHolder (line 55) | @NonNull
method galleryFromPosition (line 61) | @Nullable
method onBindViewHolder (line 78) | @Override
method startGallery (line 111) | private void startGallery(Gallery ent) {
method changePage (line 119) | public void changePage() {
method getItemCount (line 123) | @Override
method getFilter (line 128) | @Override
method setSortByTitle (line 166) | public void setSortByTitle(boolean sortByTitle) {
method forceReload (line 171) | public void forceReload() {
method setRefresh (line 176) | public void setRefresh(boolean refresh) {
method updateCursor (line 180) | private void updateCursor(@Nullable Cursor c) {
method getAllGalleries (line 187) | public Collection<Gallery> getAllGalleries() {
method randomGallery (line 195) | public void randomGallery() {
FILE: app/src/main/java/com/maxwai/nclientv3/adapters/GalleryAdapter.java
class GalleryAdapter (line 45) | public class GalleryAdapter extends RecyclerView.Adapter<GalleryAdapter....
method GalleryAdapter (line 63) | public GalleryAdapter(GalleryActivity cont, GenericGallery gallery, in...
method positionToType (line 84) | public Type positionToType(int pos) {
method setColCount (line 90) | public void setColCount(int colCount) {
method applyProportionPolicy (line 95) | private void applyProportionPolicy() {
method getDirectory (line 101) | public GalleryFolder getDirectory() {
method onCreateViewHolder (line 105) | @NonNull
method onBindViewHolder (line 130) | @Override
method loadRelatedLayout (line 146) | private void loadRelatedLayout(ViewHolder holder) {
method loadTagLayout (line 166) | private void loadTagLayout(ViewHolder holder) {
method initializeIdContainer (line 211) | private void initializeIdContainer(TextView idContainer) {
method addInfoLayout (line 227) | private void addInfoLayout(ViewHolder holder, GalleryData gallery) {
method loadPageLayout (line 241) | private void loadPageLayout(ViewHolder holder) {
method optionDialog (line 273) | private void optionDialog(ImageView imgView, final int pos) {
method openSendImageDialog (line 301) | private void openSendImageDialog(ImageView img, int pos) {
method sendImage (line 310) | private void sendImage(ImageView img, int pos, boolean text) {
method rotate (line 314) | private void rotate(int pos) {
method startGallery (line 319) | private void startGallery(int page) {
method loadImageOnPolicy (line 333) | private void loadImageOnPolicy(ImageView imgView, int pos) {
method hasTags (line 355) | private boolean hasTags() {
method getItemViewType (line 359) | @Override
method getItemCount (line 364) | @Override
type Type (line 369) | public enum Type {TAG, PAGE, RELATED}
type Policy (line 371) | public enum Policy {PROPORTION, FULL}
class ViewHolder (line 373) | public static class ViewHolder extends RecyclerView.ViewHolder {
method ViewHolder (line 377) | ViewHolder(View v, Type type) {
FILE: app/src/main/java/com/maxwai/nclientv3/adapters/GenericAdapter.java
class GenericAdapter (line 22) | public abstract class GenericAdapter<T extends GenericGallery> extends R...
method GenericAdapter (line 27) | GenericAdapter(List<T> dataset) {
method onCreateViewHolder (line 33) | @NonNull
method getItemCount (line 39) | @Override
method getFilter (line 44) | @Override
class ViewHolder (line 86) | public static class ViewHolder extends RecyclerView.ViewHolder {
method ViewHolder (line 92) | ViewHolder(View v) {
FILE: app/src/main/java/com/maxwai/nclientv3/adapters/HistoryAdapter.java
class HistoryAdapter (line 22) | public class HistoryAdapter extends RecyclerView.Adapter<HistoryAdapter....
method HistoryAdapter (line 27) | public HistoryAdapter(SearchActivity context) {
method onCreateViewHolder (line 34) | @NonNull
method onBindViewHolder (line 40) | @Override
method getItemCount (line 73) | @Override
method addHistory (line 78) | public void addHistory(String value) {
method removeHistory (line 87) | public void removeHistory(int pos) {
class ViewHolder (line 94) | public static class ViewHolder extends RecyclerView.ViewHolder {
method ViewHolder (line 99) | public ViewHolder(@NonNull View itemView) {
FILE: app/src/main/java/com/maxwai/nclientv3/adapters/ListAdapter.java
class ListAdapter (line 34) | public class ListAdapter extends RecyclerView.Adapter<GenericAdapter.Vie...
method ListAdapter (line 40) | public ListAdapter(BaseActivity cont) {
method onCreateViewHolder (line 55) | @NonNull
method loadGallery (line 61) | private void loadGallery(final GenericAdapter.ViewHolder holder, Simpl...
method onBindViewHolder (line 71) | @Override
method updateColor (line 130) | public void updateColor(int id) {
method downloadGallery (line 144) | private void downloadGallery(final SimpleGallery ent) {
method getItemCount (line 181) | @Override
method addGalleries (line 186) | public void addGalleries(List<GenericGallery> galleries) {
method restartDataset (line 197) | public void restartDataset(List<GenericGallery> galleries) {
method resetStatuses (line 213) | public void resetStatuses() {
FILE: app/src/main/java/com/maxwai/nclientv3/adapters/LocalAdapter.java
class LocalAdapter (line 51) | public class LocalAdapter extends MultichoiceAdapter<Object, LocalAdapte...
method updatePosition (line 124) | private void updatePosition(GalleryDownloaderV2 downloader) {
method triggerStartDownload (line 129) | @Override
method triggerUpdateProgress (line 134) | @Override
method triggerEndDownload (line 139) | @Override
method triggerCancelDownload (line 152) | @Override
method triggerPauseDownload (line 157) | @Override
method LocalAdapter (line 164) | public LocalAdapter(LocalActivity cont, ArrayList<LocalGallery> myData...
method startGallery (line 177) | static void startGallery(Activity context, File directory) {
method addGalleries (line 189) | public void addGalleries(@Nullable List<LocalGallery> gallery) {
method getMaster (line 198) | @Override
method getItemAt (line 203) | @Override
method createHash (line 208) | private CopyOnWriteArrayList<Object> createHash(List<GalleryDownloader...
method sortItems (line 227) | private void sortItems(ArrayList<Object> arr) {
method getComparator (line 240) | private Comparator<Object> getComparator(LocalSortType.Type type) {
method setColCount (line 257) | public void setColCount(int colCount) {
method sortElements (line 261) | private void sortElements() {
method onCreateMultichoiceViewHolder (line 265) | @NonNull
method getItemViewType (line 280) | @Override
method bindGallery (line 285) | private void bindGallery(@NonNull final ViewHolder holder, LocalGaller...
method updateColor (line 313) | public void updateColor(int id) {
method defaultMasterAction (line 324) | @Override
method bindDownload (line 333) | private void bindDownload(@NonNull final ViewHolder holder, int positi...
method removeDownloader (line 368) | private void removeDownloader(GalleryDownloaderV2 downloader) {
method getItemId (line 378) | @Override
method onBindMultichoiceViewHolder (line 384) | @Override
method showDialogDelete (line 392) | private void showDialogDelete() {
method getAllGalleries (line 411) | private String getAllGalleries() {
method showDialogPDF (line 421) | private void showDialogPDF() {
method showDialogZip (line 434) | private void showDialogZip() {
method hasSelectedClass (line 447) | public boolean hasSelectedClass(Class<?> c) {
method getItemCount (line 452) | @Override
method getFilter (line 457) | @Override
method removeObserver (line 482) | public void removeObserver() {
method viewRandom (line 486) | public void viewRandom() {
method sortChanged (line 492) | public void sortChanged() {
method startSelected (line 497) | public void startSelected() {
method pauseSelected (line 508) | public void pauseSelected() {
method deleteSelected (line 517) | public void deleteSelected() {
method zipSelected (line 521) | public void zipSelected() {
method pdfSelected (line 525) | public void pdfSelected() {
class ViewHolder (line 529) | public static class ViewHolder extends RecyclerView.ViewHolder {
method ViewHolder (line 537) | ViewHolder(View v) {
FILE: app/src/main/java/com/maxwai/nclientv3/adapters/StatusManagerAdapter.java
class StatusManagerAdapter (line 30) | public class StatusManagerAdapter extends RecyclerView.Adapter<StatusMan...
method StatusManagerAdapter (line 35) | public StatusManagerAdapter(Activity activity) {
method onCreateViewHolder (line 40) | @NonNull
method onBindViewHolder (line 48) | @Override
method getItemCount (line 74) | @Override
method getItemViewType (line 79) | @Override
method updateStatus (line 84) | private void updateStatus(@Nullable Status status) {
class ViewHolder (line 141) | public static class ViewHolder extends RecyclerView.ViewHolder {
method ViewHolder (line 147) | public ViewHolder(@NonNull View itemView) {
FILE: app/src/main/java/com/maxwai/nclientv3/adapters/StatusViewerAdapter.java
class StatusViewerAdapter (line 28) | public class StatusViewerAdapter extends RecyclerView.Adapter<GenericAda...
method StatusViewerAdapter (line 37) | public StatusViewerAdapter(Activity context, String statusName) {
method onCreateViewHolder (line 43) | @NonNull
method onBindViewHolder (line 50) | @Override
method positionToGallery (line 80) | @Nullable
method getItemCount (line 88) | @Override
method setGalleries (line 93) | public void setGalleries(@Nullable Cursor galleries) {
method reloadGalleries (line 99) | public void reloadGalleries() {
method setQuery (line 103) | public void setQuery(@Nullable String newQuery) {
method updateSort (line 108) | public void updateSort(boolean byTitle) {
method update (line 113) | public void update(String newQuery, boolean byTitle) {
FILE: app/src/main/java/com/maxwai/nclientv3/adapters/TagsAdapter.java
class TagsAdapter (line 43) | public class TagsAdapter extends RecyclerView.Adapter<TagsAdapter.ViewHo...
method TagsAdapter (line 52) | public TagsAdapter(@NonNull TagFilterActivity cont, String query, bool...
method TagsAdapter (line 59) | public TagsAdapter(@NonNull TagFilterActivity cont, String query, TagT...
method getFilter (line 66) | @Override
method onCreateViewHolder (line 97) | @NonNull
method onBindViewHolder (line 103) | @Override
method getItemCount (line 139) | @Override
method showBlacklistDialog (line 144) | private void showBlacklistDialog(final Tag tag, final ImageView imgVie...
method onlineTagUpdate (line 157) | private void onlineTagUpdate(final Tag tag, final boolean add, final I...
method updateLogo (line 188) | private void updateLogo(ImageView img, TagStatus s) {
method addItem (line 207) | public void addItem() {
type TagMode (line 211) | private enum TagMode {ONLINE, OFFLINE, TYPE}
class ViewHolder (line 213) | public static class ViewHolder extends RecyclerView.ViewHolder {
method ViewHolder (line 218) | ViewHolder(View v) {
FILE: app/src/main/java/com/maxwai/nclientv3/api/InspectorV3.java
class InspectorV3 (line 48) | public class InspectorV3 extends Thread implements Parcelable {
method createFromParcel (line 50) | @Override
method newArray (line 55) | @Override
method InspectorV3 (line 72) | protected InspectorV3(Parcel in) {
method InspectorV3 (line 106) | private InspectorV3(Context context, InspectorResponse response) {
method favoriteInspector (line 113) | public static InspectorV3 favoriteInspector(Context context, String qu...
method randomInspector (line 127) | public static InspectorV3 randomInspector(Context context, InspectorRe...
method galleryInspector (line 134) | public static InspectorV3 galleryInspector(Context context, int id, In...
method basicInspector (line 142) | public static InspectorV3 basicInspector(Context context, int page, In...
method tagInspector (line 146) | public static InspectorV3 tagInspector(Context context, Tag tag, int p...
method searchInspector (line 157) | public static InspectorV3 searchInspector(Context context, String quer...
method getDefaultTags (line 187) | @NonNull
method getLanguageTags (line 197) | private static Set<Tag> getLanguageTags(Language onlyLanguage) {
method describeContents (line 214) | @Override
method writeToParcel (line 219) | @Override
method getSearchTitle (line 237) | public String getSearchTitle() {
method initialize (line 243) | public void initialize(Context context, InspectorResponse response) {
method getResponse (line 248) | public InspectorResponse getResponse() {
method cloneInspector (line 252) | public InspectorV3 cloneInspector(Context context, InspectorResponse r...
method tryByAllPopular (line 267) | private void tryByAllPopular() {
method createUrl (line 274) | private void createUrl() {
method getBookmarkURL (line 322) | private String getBookmarkURL() {
method createDocument (line 327) | public boolean createDocument() throws IOException {
method parseDocument (line 335) | public void parseDocument() throws IOException, InvalidResponseExcepti...
method start (line 346) | @Override
method run (line 353) | @Override
method filterDocumentTags (line 370) | private void filterDocumentTags() {
method doSingleV2 (line 388) | private void doSingleV2() throws IOException, JSONException {
method doSearchV2 (line 423) | private void doSearchV2() throws InvalidResponseException, JSONExcepti...
method setSortType (line 437) | public void setSortType(SortType sortType) {
method getPage (line 444) | public int getPage() {
method setPage (line 448) | public void setPage(int page) {
method getGalleries (line 453) | public List<GenericGallery> getGalleries() {
method getUrl (line 457) | public String getUrl() {
method getRequestType (line 461) | public ApiRequestType getRequestType() {
method getPageCount (line 465) | public int getPageCount() {
method getTag (line 469) | public Tag getTag() {
class InvalidResponseException (line 480) | public static class InvalidResponseException extends Exception {
method InvalidResponseException (line 481) | public InvalidResponseException() {
type InspectorResponse (line 486) | public interface InspectorResponse {
method shouldStart (line 487) | boolean shouldStart(InspectorV3 inspector);
method onSuccess (line 489) | void onSuccess(List<GenericGallery> galleries);
method onFailure (line 491) | void onFailure(Exception e);
method onStart (line 493) | void onStart();
method onEnd (line 495) | void onEnd();
class DefaultInspectorResponse (line 498) | public static abstract class DefaultInspectorResponse implements Inspe...
method shouldStart (line 499) | @Override
method onStart (line 504) | @Override
method onEnd (line 508) | @Override
method onSuccess (line 512) | @Override
method onFailure (line 516) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/api/RandomLoader.java
class RandomLoader (line 11) | public class RandomLoader {
method onFailure (line 18) | @Override
method onSuccess (line 23) | @Override
method RandomLoader (line 38) | public RandomLoader(RandomActivity activity) {
method loadRandomGallery (line 45) | private void loadRandomGallery() {
method requestGallery (line 50) | public void requestGallery() {
FILE: app/src/main/java/com/maxwai/nclientv3/api/SimpleGallery.java
class SimpleGallery (line 32) | public class SimpleGallery extends GenericGallery {
method createFromParcel (line 34) | @Override
method newArray (line 39) | @Override
method SimpleGallery (line 50) | public SimpleGallery(Parcel in) {
method SimpleGallery (line 58) | @SuppressLint("Range")
method SimpleGallery (line 66) | private SimpleGallery(String title, int id, int mediaId, Uri thumbnail...
method SimpleGallery (line 75) | public SimpleGallery(Gallery gallery) {
method fromV2ListItem (line 87) | public static SimpleGallery fromV2ListItem(Context context, JSONObject...
method hasTags (line 150) | public boolean hasTags(Collection<Tag> tags) {
method getLanguage (line 154) | public Language getLanguage() {
method hasIgnoredTags (line 158) | public boolean hasIgnoredTags(String s) {
method getId (line 168) | @Override
method getType (line 173) | @Override
method getPageCount (line 178) | @Override
method isValid (line 183) | @Override
method getTitle (line 188) | @Override
method getMaxSize (line 194) | @Override
method getMinSize (line 199) | @Override
method describeContents (line 204) | @Override
method writeToParcel (line 209) | @Override
method getThumbnail (line 219) | public Uri getThumbnail() {
method getMediaId (line 223) | public int getMediaId() {
method getGalleryFolder (line 227) | @Override
method toString (line 232) | @NonNull
method hasGalleryData (line 244) | @Override
method getGalleryData (line 249) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/api/comments/Comment.java
class Comment (line 13) | public class Comment implements Parcelable {
method createFromParcel (line 15) | @Override
method newArray (line 20) | @Override
method Comment (line 30) | public Comment(JsonReader reader) throws IOException {
method Comment (line 54) | protected Comment(Parcel in) {
method describeContents (line 65) | @Override
method writeToParcel (line 70) | @Override
method getId (line 78) | public int getId() {
method getPostDate (line 82) | public Date getPostDate() {
method getComment (line 86) | public String getComment() {
method getPosterId (line 90) | public int getPosterId() {
method getUsername (line 94) | public String getUsername() {
method getAvatarUrl (line 98) | public Uri getAvatarUrl() {
FILE: app/src/main/java/com/maxwai/nclientv3/api/comments/CommentsFetcher.java
class CommentsFetcher (line 23) | public class CommentsFetcher extends Thread {
method CommentsFetcher (line 29) | public CommentsFetcher(CommentActivity commentActivity, int id) {
method run (line 34) | @Override
method postResult (line 40) | private void postResult() {
method populateComments (line 49) | private void populateComments() {
FILE: app/src/main/java/com/maxwai/nclientv3/api/comments/User.java
class User (line 14) | public class User implements Parcelable {
method createFromParcel (line 16) | @Override
method newArray (line 21) | @Override
method User (line 29) | public User(JsonReader reader) throws IOException {
method User (line 50) | protected User(Parcel in) {
method describeContents (line 56) | @Override
method writeToParcel (line 61) | @Override
method getId (line 68) | public int getId() {
method getAvatarUrl (line 72) | public Uri getAvatarUrl() {
method getUsername (line 76) | public String getUsername() {
FILE: app/src/main/java/com/maxwai/nclientv3/api/components/Gallery.java
class Gallery (line 37) | public class Gallery extends GenericGallery {
method createFromParcel (line 39) | @Override
method newArray (line 45) | @Override
method Gallery (line 59) | public Gallery(Context context, String json, List<SimpleGallery> relat...
method Gallery (line 70) | public Gallery(Context context, Cursor cursor, TagList tags) {
method Gallery (line 82) | private Gallery() {
method Gallery (line 88) | public Gallery(Parcel in) {
method getPathTitle (line 105) | public static String getPathTitle(@Nullable String title, @NonNull Str...
method getPathTitle (line 113) | public static String getPathTitle(@Nullable String title) {
method loadLanguage (line 117) | public static Language loadLanguage(TagList tags) {
method emptyGallery (line 131) | public static Gallery emptyGallery() {
method calculateSizes (line 135) | private void calculateSizes(GalleryData galleryData) {
method isOnlineFavorite (line 148) | public boolean isOnlineFavorite() {
method getPathTitle (line 152) | @NonNull
method getCover (line 157) | public Uri getCover() {
method getThumbnail (line 162) | public Uri getThumbnail() {
method getFileUri (line 166) | private @Nullable
method getPageUrl (line 174) | public Uri getPageUrl(int page) {
method getHighPage (line 181) | public Uri getHighPage(int page) {
method getLowPage (line 185) | public Uri getLowPage(int page) {
method getPage (line 191) | private Page getPage(int index) {
method toSimpleGallery (line 195) | public SimpleGallery toSimpleGallery() {
method isRelatedLoaded (line 199) | public boolean isRelatedLoaded() {
method getRelated (line 203) | public List<SimpleGallery> getRelated() {
method isValid (line 207) | @Override
method getMaxSize (line 212) | @Override
method getMinSize (line 217) | @Override
method getGalleryFolder (line 222) | @Override
method getTitle (line 227) | @NonNull
method getTitle (line 238) | public String getTitle(TitleType x) {
method getLanguage (line 242) | public Language getLanguage() {
method getUploadDate (line 246) | public Date getUploadDate() {
method getFavoriteCount (line 250) | public int getFavoriteCount() {
method getId (line 254) | @Override
method getTags (line 259) | public TagList getTags() {
method getPageCount (line 263) | @Override
method getType (line 268) | @Override
method getMediaId (line 273) | public int getMediaId() {
method hasIgnoredTags (line 277) | public boolean hasIgnoredTags(Set<Tag> s) {
method hasIgnoredTags (line 286) | public boolean hasIgnoredTags() {
method hasGalleryData (line 293) | @Override
method getGalleryData (line 298) | @NonNull
method jsonWrite (line 304) | public void jsonWrite(Writer ww) throws IOException {
method toJsonTags (line 319) | private void toJsonTags(JsonWriter writer) throws IOException {
method toJsonTitle (line 327) | private void toJsonTitle(JsonWriter writer) throws IOException {
method describeContents (line 340) | @Override
method writeToParcel (line 345) | @Override
method toString (line 355) | @NonNull
FILE: app/src/main/java/com/maxwai/nclientv3/api/components/GalleryData.java
class GalleryData (line 38) | public class GalleryData implements Parcelable {
method createFromParcel (line 40) | @Override
method newArray (line 45) | @Override
method GalleryData (line 68) | private GalleryData(@Nullable Context context) {
method GalleryData (line 72) | public GalleryData(JsonReader jr) throws IOException {
method GalleryData (line 77) | public GalleryData(@NonNull Context context, Cursor cursor, @NonNull T...
method GalleryData (line 93) | protected GalleryData(Parcel in) {
method fakeData (line 115) | public static GalleryData fakeData() {
method hasUpdatedInfo (line 126) | public boolean hasUpdatedInfo() {
method isDeleted (line 131) | public boolean isDeleted() {
method parseJSON (line 135) | private void parseJSON(JsonReader jr) throws IOException {
method setTitle (line 190) | private void setTitle(TitleType type, String title) {
method readTitles (line 194) | private void readTitles(JsonReader jr) throws IOException {
method readTags (line 216) | private void readTags(JsonReader jr) throws IOException {
method getUploadDate (line 227) | @NonNull
method getFavoriteCount (line 232) | public int getFavoriteCount() {
method getId (line 236) | public int getId() {
method setId (line 240) | public void setId(int id) {
method getPageCount (line 244) | public int getPageCount() {
method setPageInfo (line 248) | public void setPageInfo(GalleryFolder folder) {
method setCheckedExt (line 257) | public void setCheckedExt() {
method getMediaId (line 261) | public int getMediaId() {
method getTitle (line 265) | public String getTitle(TitleType type) {
method getTags (line 269) | @NonNull
method getCover (line 274) | @NonNull
method getThumbnail (line 279) | @NonNull
method getPage (line 284) | public Page getPage(int index) {
method getPages (line 288) | @NonNull
method isValid (line 293) | public boolean isValid() {
method describeContents (line 297) | @Override
method getCheckedExt (line 302) | public boolean getCheckedExt() {
method writeToParcel (line 306) | @Override
method truncateUrl (line 325) | private String truncateUrl(Uri uri) {
method createPagePath (line 330) | public String createPagePath() {
method readPagePathNew (line 346) | private void readPagePathNew(String path) {
method readPagePath (line 367) | private void readPagePath(String path) {
method toString (line 406) | @NonNull
FILE: app/src/main/java/com/maxwai/nclientv3/api/components/GenericGallery.java
class GenericGallery (line 13) | public abstract class GenericGallery implements Parcelable {
method getId (line 15) | public abstract int getId();
method getType (line 17) | public abstract Type getType();
method getPageCount (line 19) | public abstract int getPageCount();
method isValid (line 21) | public abstract boolean isValid();
method getTitle (line 23) | @NonNull
method getMaxSize (line 26) | public abstract Size getMaxSize();
method getMinSize (line 28) | public abstract Size getMinSize();
method getGalleryFolder (line 30) | public abstract GalleryFolder getGalleryFolder();
method sharePageUrl (line 32) | public String sharePageUrl(int i) {
method isLocal (line 36) | public boolean isLocal() {
method hasGalleryData (line 40) | public abstract boolean hasGalleryData();
method getGalleryData (line 42) | public abstract GalleryData getGalleryData();
type Type (line 44) | public enum Type {COMPLETE, LOCAL, SIMPLE}
FILE: app/src/main/java/com/maxwai/nclientv3/api/components/Page.java
class Page (line 20) | public class Page implements Parcelable {
method createFromParcel (line 22) | @Override
method newArray (line 27) | @Override
method Page (line 39) | Page() {
method Page (line 44) | public Page(ImageType type, JsonReader reader) throws IOException {
method Page (line 48) | public Page(ImageType type, Uri path) {
method Page (line 52) | public Page(ImageType type, Uri path, @Nullable Uri thumbPath, int pag...
method Page (line 59) | public Page(ImageType type, JsonReader reader, int page) throws IOExce...
method Page (line 86) | protected Page(Parcel in) {
method describeContents (line 99) | @Override
method writeToParcel (line 104) | @Override
method getImagePath (line 113) | public Uri getImagePath() {
method setImagePath (line 117) | public void setImagePath(Uri path) {
method getThumbnailPath (line 121) | @NonNull
method getSize (line 126) | public Size getSize() {
method toString (line 130) | @NonNull
FILE: app/src/main/java/com/maxwai/nclientv3/api/components/Ranges.java
class Ranges (line 10) | public class Ranges implements Parcelable {
method createFromParcel (line 16) | @Override
method newArray (line 21) | @Override
method Ranges (line 30) | public Ranges() {
method Ranges (line 33) | protected Ranges(Parcel in) {
method isDefault (line 45) | public boolean isDefault() {
method getFromPage (line 50) | public int getFromPage() {
method setFromPage (line 54) | public void setFromPage(int fromPage) {
method getToPage (line 58) | public int getToPage() {
method setToPage (line 62) | public void setToPage(int toPage) {
method setFromDate (line 66) | public void setFromDate(int fromDate) {
method setToDate (line 70) | public void setToDate(int toDate) {
method setFromDateUnit (line 74) | public void setFromDateUnit(TimeUnit fromDateUnit) {
method setToDateUnit (line 78) | public void setToDateUnit(TimeUnit toDateUnit) {
method toQuery (line 82) | public String toQuery() {
method writeToParcel (line 102) | @Override
method describeContents (line 112) | @Override
type TimeUnit (line 117) | public enum TimeUnit {
method TimeUnit (line 127) | TimeUnit(int string, char val) {
method getString (line 132) | public int getString() {
method getVal (line 136) | public char getVal() {
FILE: app/src/main/java/com/maxwai/nclientv3/api/components/Tag.java
class Tag (line 20) | @SuppressWarnings("unused")
method createFromParcel (line 23) | @Override
method newArray (line 28) | @Override
method Tag (line 38) | public Tag(String text) {
method Tag (line 47) | public Tag(String name, int count, int id, TagType type, TagStatus sta...
method Tag (line 55) | public Tag(JsonReader jr) throws IOException {
method Tag (line 82) | private Tag(Parcel in) {
method toQueryTag (line 94) | public String toQueryTag(TagStatus status) {
method toQueryTag (line 107) | public String toQueryTag() {
method getName (line 111) | public String getName() {
method getCount (line 115) | public int getCount() {
method getStatus (line 119) | public TagStatus getStatus() {
method setStatus (line 123) | public void setStatus(TagStatus status) {
method getId (line 127) | public int getId() {
method updateStatus (line 131) | public TagStatus updateStatus() {
method writeJson (line 143) | void writeJson(JsonWriter writer) throws IOException {
method getType (line 152) | public TagType getType() {
method getTypeSingleName (line 156) | public String getTypeSingleName() {
method toString (line 161) | @NonNull
method toScrapedString (line 173) | public String toScrapedString() {
method equals (line 177) | @Override
method hashCode (line 187) | @Override
method describeContents (line 192) | @Override
method writeToParcel (line 197) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/api/components/TagList.java
class TagList (line 15) | public class TagList implements Parcelable {
method createFromParcel (line 18) | @Override
method newArray (line 23) | @Override
method TagList (line 30) | protected TagList(Parcel in) {
method TagList (line 37) | public TagList() {
method describeContents (line 41) | @Override
method writeToParcel (line 46) | @Override
method getAllTagsSet (line 51) | public Set<Tag> getAllTagsSet() {
method getAllTagsList (line 57) | public List<Tag> getAllTagsList() {
method getCount (line 63) | public int getCount(TagType type) {
method getTag (line 67) | public Tag getTag(TagType type, int index) {
method addTag (line 71) | public void addTag(Tag tag) {
method addTags (line 75) | public void addTags(Collection<? extends Tag> tags) {
method retrieveForType (line 79) | public List<Tag> retrieveForType(TagType type) {
method sort (line 83) | public void sort(Comparator<Tag> comparator) {
method hasTag (line 87) | public boolean hasTag(Tag tag) {
method hasTags (line 91) | public boolean hasTags(Collection<Tag> tags) {
class Tags (line 100) | public static class Tags extends ArrayList<Tag> {
method Tags (line 102) | public Tags() {
FILE: app/src/main/java/com/maxwai/nclientv3/api/enums/ApiRequestType.java
class ApiRequestType (line 3) | public class ApiRequestType {
method ApiRequestType (line 18) | private ApiRequestType(int id, boolean single) {
method ordinal (line 23) | public byte ordinal() {
method isSingle (line 27) | public boolean isSingle() {
method equals (line 31) | @Override
method hashCode (line 41) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/api/enums/ImageType.java
type ImageType (line 3) | public enum ImageType {
FILE: app/src/main/java/com/maxwai/nclientv3/api/enums/Language.java
type Language (line 7) | public enum Language {
method Language (line 17) | Language(int nameResId) {
method getNameResId (line 21) | public int getNameResId() {
method getFilteredValuesArray (line 29) | public static Language[] getFilteredValuesArray() {
FILE: app/src/main/java/com/maxwai/nclientv3/api/enums/SortType.java
type SortType (line 7) | public enum SortType {
method SortType (line 19) | SortType(int nameId, @Nullable String urlAddition) {
method findFromAddition (line 25) | public static SortType findFromAddition(@Nullable String addition) {
method getNameId (line 39) | public int getNameId() {
method getUrlAddition (line 43) | @Nullable
FILE: app/src/main/java/com/maxwai/nclientv3/api/enums/SpecialTagIds.java
class SpecialTagIds (line 3) | public class SpecialTagIds {
FILE: app/src/main/java/com/maxwai/nclientv3/api/enums/TagStatus.java
type TagStatus (line 3) | public enum TagStatus {
FILE: app/src/main/java/com/maxwai/nclientv3/api/enums/TagType.java
class TagType (line 8) | public class TagType implements Parcelable {
method createFromParcel (line 19) | @Override
method newArray (line 24) | @Override
method TagType (line 32) | private TagType(int id, String single, String plural) {
method TagType (line 38) | protected TagType(Parcel in) {
method typeByName (line 44) | public static TagType typeByName(String name) {
method getId (line 49) | public byte getId() {
method getSingle (line 53) | public String getSingle() {
method equals (line 57) | @Override
method hashCode (line 65) | @Override
method toString (line 70) | @NonNull
method describeContents (line 77) | @Override
method writeToParcel (line 82) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/api/enums/TitleType.java
type TitleType (line 3) | public enum TitleType {
FILE: app/src/main/java/com/maxwai/nclientv3/api/local/FakeInspector.java
class FakeInspector (line 11) | public class FakeInspector extends ThreadAsyncTask<LocalActivity, LocalA...
method FakeInspector (line 17) | public FakeInspector(LocalActivity activity, File folder) {
method doInBackground (line 25) | @Override
method onProgressUpdate (line 43) | @Override
method onPostExecute (line 48) | @Override
method createGallery (line 53) | private void createGallery(final File file) {
FILE: app/src/main/java/com/maxwai/nclientv3/api/local/LocalGallery.java
class LocalGallery (line 25) | public class LocalGallery extends GenericGallery {
method createFromParcel (line 27) | @Override
method newArray (line 32) | @Override
method LocalGallery (line 47) | public LocalGallery(@NonNull File file, boolean jumpDataRetrieve) {
method LocalGallery (line 72) | public LocalGallery(@NonNull File file) {
method LocalGallery (line 76) | private LocalGallery(Parcel in) {
method createTitle (line 97) | private static String createTitle(File file) {
method getGalleryFolder (line 105) | @Override
method readGalleryData (line 110) | @NonNull
method calculateSizes (line 122) | public void calculateSizes() {
method checkSize (line 127) | private void checkSize(File f) {
method getMaxSize (line 138) | @NonNull
method getMinSize (line 144) | @NonNull
method getTrueTitle (line 150) | public String getTrueTitle() {
method hasGalleryData (line 154) | @Override
method getGalleryData (line 159) | @Override
method getType (line 165) | @Override
method isValid (line 170) | @Override
method getId (line 175) | @Override
method getPageCount (line 180) | @Override
method getTitle (line 185) | @Override
method getMin (line 191) | public int getMin() {
method getDirectory (line 195) | @NonNull
method getPage (line 200) | @Nullable
method describeContents (line 205) | @Override
method writeToParcel (line 210) | @Override
method equals (line 221) | @Override
method hashCode (line 231) | @Override
method toString (line 236) | @NonNull
FILE: app/src/main/java/com/maxwai/nclientv3/api/local/LocalSortType.java
class LocalSortType (line 5) | public class LocalSortType {
method LocalSortType (line 12) | public LocalSortType(@NonNull Type type, boolean ascending) {
method LocalSortType (line 17) | public LocalSortType(int hash) {
method equals (line 22) | @Override
method hashCode (line 32) | @Override
method toString (line 39) | @NonNull
type Type (line 49) | public enum Type {TITLE, DATE, PAGE_COUNT, ARTIST, GROUP, RANDOM}
FILE: app/src/main/java/com/maxwai/nclientv3/async/MetadataFetcher.java
class MetadataFetcher (line 16) | public class MetadataFetcher implements Runnable {
method MetadataFetcher (line 19) | public MetadataFetcher(Context context) {
method run (line 23) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/async/ScrapeTags.java
class ScrapeTags (line 33) | public class ScrapeTags extends Worker {
method ScrapeTags (line 39) | public ScrapeTags(@NonNull Context context, @NonNull WorkerParameters ...
method startWork (line 43) | public static void startWork(Context context) {
method getNewVersionCode (line 48) | private int getNewVersionCode() throws IOException {
method doWork (line 62) | @NonNull
method fetchTags (line 90) | private void fetchTags() throws IOException, JSONException {
method readTag (line 114) | private Tag readTag(JSONArray reader) throws JSONException {
method enoughDayPassed (line 122) | private boolean enoughDayPassed(Date nowTime, Date lastTime) {
FILE: app/src/main/java/com/maxwai/nclientv3/async/VersionChecker.java
class VersionChecker (line 34) | public class VersionChecker {
method VersionChecker (line 41) | public VersionChecker(AppCompatActivity context, final boolean silent) {
method parseVersionJson (line 92) | private static GitHubRelease parseVersionJson(JsonReader jr, boolean w...
method parseVersion (line 106) | private static GitHubRelease parseVersion(JsonReader jr, boolean withP...
method getDownloadUrl (line 149) | private static String getDownloadUrl(JsonReader jr) throws IOException {
method createDialog (line 161) | private void createDialog(String versionName, GitHubRelease release) {
method downloadVersion (line 192) | private void downloadVersion(String latestVersion) {
method installApp (line 235) | private void installApp(File f) {
class GitHubRelease (line 249) | public static class GitHubRelease {
method isNewerThenVersion (line 255) | public boolean isNewerThenVersion(String currentVersion) throws Ille...
FILE: app/src/main/java/com/maxwai/nclientv3/async/converters/CreatePdfOrZip.java
class CreatePdfOrZip (line 42) | public class CreatePdfOrZip extends Worker {
method CreatePdfOrZip (line 50) | public CreatePdfOrZip(@NonNull Context context, @NonNull WorkerParamet...
method startWork (line 54) | public static void startWork(Context context, LocalGallery gallery, bo...
method hasPDFCapabilities (line 69) | public static boolean hasPDFCapabilities() {
method doWork (line 78) | @NonNull
method postExecutePdf (line 185) | private void postExecutePdf(boolean success, LocalGallery gallery, Str...
method createIntentOpen (line 198) | private void createIntentOpen(File finalPath, boolean pdf) {
method preExecute (line 219) | private void preExecute(File file, boolean pdf) {
FILE: app/src/main/java/com/maxwai/nclientv3/async/database/DatabaseHelper.java
class DatabaseHelper (line 26) | public class DatabaseHelper extends SQLiteOpenHelper {
method DatabaseHelper (line 31) | public DatabaseHelper(Context context1) {
method onCreate (line 36) | @Override
method createAllTables (line 46) | private void createAllTables(SQLiteDatabase db) {
method insertCategoryTags (line 61) | private void insertCategoryTags() {
method insertLanguageTags (line 73) | private void insertLanguageTags() {
method onUpgrade (line 82) | @Override
method addStatusTables (line 99) | private void addStatusTables(SQLiteDatabase db) {
method insertDefaultStatus (line 105) | private void insertDefaultStatus() {
method updateFavoriteTable (line 114) | private void updateFavoriteTable(SQLiteDatabase db) {
method addRangeColumn (line 118) | private void addRangeColumn(SQLiteDatabase db) {
method getAllFavoriteIndex (line 126) | @SuppressLint("Range")
method insertFavorite (line 149) | private void insertFavorite(Context context, SQLiteDatabase db) {
method updateGalleryWithSizes (line 163) | private void updateGalleryWithSizes(SQLiteDatabase db) {
method onDowngrade (line 170) | @Override
method onOpen (line 176) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/async/database/Queries.java
class Queries (line 42) | @SuppressLint("Range")
method setDb (line 47) | public static void setDb(SQLiteDatabase database) {
method getColumnFromName (line 51) | public static int getColumnFromName(Cursor cursor, String name) {
class DebugDatabase (line 58) | public static class DebugDatabase {
method dumpTable (line 59) | private static void dumpTable(String name, FileWriter sb) throws IOE...
class GalleryTable (line 81) | public static class GalleryTable {
method clearGalleries (line 112) | static void clearGalleries() {
method galleryFromId (line 140) | public static Gallery galleryFromId(Context context, int id) {
method getAllFavoriteCursorDeprecated (line 155) | @Deprecated
method getAllGalleries (line 175) | public static List<Gallery> getAllGalleries(Context context) {
method insert (line 188) | public static void insert(GenericGallery gallery) {
method cursorToList (line 214) | static List<Gallery> cursorToList(Context context, Cursor cursor) {
method delete (line 225) | public static void delete(int id) {
method cursorToGallery (line 234) | public static Gallery cursorToGallery(Context context, Cursor cursor) {
method updateSizes (line 241) | public static void updateSizes(@Nullable Gallery gallery) {
class TagTable (line 254) | public static class TagTable {
method cursorToTag (line 278) | public static Tag cursorToTag(Cursor cursor) {
method getTagsFromCursor (line 292) | private static List<Tag> getTagsFromCursor(Cursor cursor) {
method getFilterCursor (line 313) | public static Cursor getFilterCursor(@NonNull String query, TagType ...
method getAllTagOfType (line 345) | public static List<Tag> getAllTagOfType(TagType type) {
method getTrueAllType (line 355) | public static List<Tag> getTrueAllType(TagType type) {
method getAllStatus (line 365) | public static List<Tag> getAllStatus(TagStatus status) {
method getAllFiltered (line 373) | public static List<Tag> getAllFiltered() {
method getAllFilteredByType (line 381) | public static List<Tag> getAllFilteredByType(TagType type) {
method getAllOnlineBlacklisted (line 389) | public static List<Tag> getAllOnlineBlacklisted() {
method isBlackListed (line 399) | public static boolean isBlackListed(Tag tag) {
method getTagById (line 409) | @Nullable
method updateStatus (line 419) | public static void updateStatus(int id, TagStatus status) {
method updateTag (line 428) | public static int updateTag(Tag tag) {
method insert (line 436) | public static void insert(Tag tag, boolean replace) {
method insert (line 448) | public static void insert(Tag tag) {
method updateBlacklistedTag (line 452) | public static void updateBlacklistedTag(Tag tag, boolean online) {
method removeAllBlacklisted (line 458) | public static void removeAllBlacklisted() {
method resetAllStatus (line 464) | public static void resetAllStatus() {
method getTopTags (line 473) | public static List<Tag> getTopTags(TagType type, int count) {
method getStatus (line 484) | @Nullable
method getTagFromTagName (line 498) | public static Tag getTagFromTagName(String name) {
method getTagsFromListOfInt (line 510) | public static TagList getTagsFromListOfInt(String tagString) {
method search (line 526) | public static List<Tag> search(String name, TagType type) {
method searchTag (line 538) | public static Tag searchTag(String name, TagType type) {
method insertTagsForGallery (line 551) | public static void insertTagsForGallery(GalleryData gallery) {
method insertScrape (line 566) | public static void insertScrape(List<Tag> tags, boolean b) {
class DownloadTable (line 581) | public static class DownloadTable {
method addGallery (line 597) | public static void addGallery(GalleryDownloaderV2 downloader) {
method removeGallery (line 607) | public static void removeGallery(int id) {
method getAllDownloads (line 613) | public static List<GalleryDownloaderManager> getAllDownloads(Context...
class HistoryTable (line 633) | public static class HistoryTable {
method addGallery (line 652) | public static void addGallery(SimpleGallery gallery) {
method getHistory (line 664) | public static List<SimpleGallery> getHistory() {
method emptyHistory (line 677) | public static void emptyHistory() {
method cleanHistory (line 681) | private static void cleanHistory() {
class BookmarkTable (line 688) | public static class BookmarkTable {
method deleteBookmark (line 705) | public static void deleteBookmark(String url) {
method addBookmark (line 709) | public static void addBookmark(InspectorV3 inspector) {
method getBookmarks (line 720) | public static List<Bookmark> getBookmarks() {
class GalleryBridgeTable (line 742) | public static class GalleryBridgeTable {
method insert (line 758) | static void insert(int galleryId, int tagId) {
method deleteGallery (line 765) | public static void deleteGallery(int id) {
method getTagCursorForGallery (line 769) | static Cursor getTagCursorForGallery(int id) {
method getTagsForGallery (line 781) | public static TagList getTagsForGallery(int id) {
class FavoriteTable (line 790) | public static class FavoriteTable {
method addFavorite (line 817) | public static void addFavorite(Gallery gallery) {
method titleTypeToColumn (line 823) | static String titleTypeToColumn(TitleType type) {
method getAllFavoriteGalleriesCursor (line 841) | public static Cursor getAllFavoriteGalleriesCursor(CharSequence quer...
method getAllFavoriteGalleriesCursor (line 853) | public static Cursor getAllFavoriteGalleriesCursor() {
method getAllFavoriteGalleries (line 866) | static List<Gallery> getAllFavoriteGalleries(Context context) {
method insert (line 872) | static void insert(int galleryId) {
method removeFavorite (line 879) | public static void removeFavorite(int id) {
method countFavorite (line 883) | public static int countFavorite(@Nullable String text) {
method countFavorite (line 895) | public static int countFavorite() {
method isFavorite (line 906) | public static boolean isFavorite(int id) {
method removeAllFavorite (line 913) | public static void removeAllFavorite() {
class ResumeTable (line 918) | public static class ResumeTable {
method insert (line 931) | public static void insert(int id, int page) {
method pageFromId (line 940) | public static int pageFromId(int id) {
method remove (line 950) | public static void remove(int id) {
class StatusMangaTable (line 956) | public static class StatusMangaTable {
method insert (line 973) | public static void insert(GenericGallery gallery, Status status) {
method remove (line 983) | public static void remove(int id) {
method getStatus (line 987) | @NonNull
method insert (line 999) | public static void insert(GenericGallery gallery, String s) {
method update (line 1003) | public static void update(Status oldStatus, Status newStatus) {
method getGalleryOfStatus (line 1010) | public static Cursor getGalleryOfStatus(String name, String filter, ...
method getCountPerStatus (line 1023) | public static int getCountPerStatus(String name) {
method removeStatus (line 1037) | public static void removeStatus(String name) {
class StatusTable (line 1042) | public static class StatusTable {
method insert (line 1055) | public static void insert(Status status) {
method remove (line 1062) | public static void remove(String name) {
method initStatuses (line 1067) | public static void initStatuses() {
method update (line 1080) | public static void update(Status oldStatus, Status newStatus) {
FILE: app/src/main/java/com/maxwai/nclientv3/async/database/export/Exporter.java
class Exporter (line 26) | public class Exporter {
method dumpDB (line 45) | private static void dumpDB(OutputStream stream) throws IOException {
method defaultExportName (line 89) | public static String defaultExportName(SettingsActivity context) {
method exportData (line 96) | public static void exportData(SettingsActivity context, Uri selectedFi...
method exportSharedPreferences (line 115) | private static void exportSharedPreferences(Context context, String sh...
type SharedType (line 156) | enum SharedType {
FILE: app/src/main/java/com/maxwai/nclientv3/async/database/export/Importer.java
class Importer (line 23) | class Importer {
method importSharedPreferences (line 24) | private static void importSharedPreferences(Context context, String sh...
method importDB (line 66) | private static void importDB(InputStream stream) throws IOException {
method importData (line 109) | public static void importData(@NonNull Context context, Uri selectedFi...
FILE: app/src/main/java/com/maxwai/nclientv3/async/database/export/Manager.java
class Manager (line 12) | public class Manager extends Thread {
method Manager (line 20) | public Manager(@NonNull Uri file, @NonNull SettingsActivity context, b...
method run (line 28) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/async/downloader/DownloadGalleryV2.java
class DownloadGalleryV2 (line 27) | public class DownloadGalleryV2 extends Worker {
method DownloadGalleryV2 (line 30) | public DownloadGalleryV2(@NonNull Context context, @NonNull WorkerPara...
method downloadGallery (line 34) | public static void downloadGallery(Context context, GenericGallery gal...
method downloadGallery (line 45) | private static void downloadGallery(Context context, String title, Uri...
method downloadGallery (line 51) | private static void downloadGallery(Context context, Gallery gallery) {
method downloadGallery (line 55) | private static void downloadGallery(Context context, Gallery gallery, ...
method loadDownloads (line 60) | public static void loadDownloads(Context context) {
method downloadRange (line 70) | public static void downloadRange(Context context, Gallery gallery, int...
method startWork (line 74) | public static void startWork(@Nullable Context context) {
method doWork (line 81) | @NonNull
method obtainData (line 100) | private void obtainData() {
FILE: app/src/main/java/com/maxwai/nclientv3/async/downloader/DownloadObserver.java
type DownloadObserver (line 3) | public interface DownloadObserver {
method triggerStartDownload (line 4) | void triggerStartDownload(GalleryDownloaderV2 downloader);
method triggerUpdateProgress (line 6) | void triggerUpdateProgress(GalleryDownloaderV2 downloader, int reach, ...
method triggerEndDownload (line 8) | void triggerEndDownload(GalleryDownloaderV2 downloader);
method triggerCancelDownload (line 10) | void triggerCancelDownload(GalleryDownloaderV2 downloader);
method triggerPauseDownload (line 12) | void triggerPauseDownload(GalleryDownloaderV2 downloader);
FILE: app/src/main/java/com/maxwai/nclientv3/async/downloader/DownloadQueue.java
class DownloadQueue (line 6) | public class DownloadQueue {
method add (line 9) | public static void add(GalleryDownloaderManager x) {
method fetchForData (line 19) | public static GalleryDownloaderV2 fetchForData() {
method fetch (line 25) | public static GalleryDownloaderManager fetch() {
method getDownloaders (line 31) | public static CopyOnWriteArrayList<GalleryDownloaderV2> getDownloaders...
method addObserver (line 38) | public static void addObserver(DownloadObserver observer) {
method removeObserver (line 43) | public static void removeObserver(DownloadObserver observer) {
method findManagerFromDownloader (line 48) | private static GalleryDownloaderManager findManagerFromDownloader(Gall...
method remove (line 55) | public static void remove(GalleryDownloaderV2 downloader, boolean canc...
method givePriority (line 63) | public static void givePriority(GalleryDownloaderV2 downloader) {
FILE: app/src/main/java/com/maxwai/nclientv3/async/downloader/GalleryDownloaderManager.java
class GalleryDownloaderManager (line 19) | public class GalleryDownloaderManager {
method triggerStartDownload (line 27) | @Override
method triggerUpdateProgress (line 34) | @Override
method triggerEndDownload (line 40) | @Override
method triggerCancelDownload (line 48) | @Override
method triggerPauseDownload (line 54) | @Override
method GalleryDownloaderManager (line 60) | public GalleryDownloaderManager(Context context, Gallery gallery, int ...
method GalleryDownloaderManager (line 67) | public GalleryDownloaderManager(Context context, String title, Uri thu...
method cancelNotification (line 73) | private void cancelNotification() {
method addClickListener (line 77) | private void addClickListener() {
method downloader (line 96) | public GalleryDownloaderV2 downloader() {
method endNotification (line 100) | private void endNotification() {
method hidePercentage (line 113) | private void hidePercentage() {
method setPercentage (line 117) | private void setPercentage(int reach, int total) {
method prepareNotification (line 121) | private void prepareNotification() {
method notificationUpdate (line 132) | private synchronized void notificationUpdate() {
FILE: app/src/main/java/com/maxwai/nclientv3/async/downloader/GalleryDownloaderV2.java
class GalleryDownloaderV2 (line 33) | public class GalleryDownloaderV2 {
method GalleryDownloaderV2 (line 48) | public GalleryDownloaderV2(Context context, @Nullable String title, @N...
method GalleryDownloaderV2 (line 55) | public GalleryDownloaderV2(Context context, Gallery gallery, int start...
method findFolder (line 62) | private static File findFolder(File downloadfolder, String pathTitle, ...
method usableFolder (line 72) | private static boolean usableFolder(File file, int id) {
method hasData (line 81) | public boolean hasData() {
method removeObserver (line 85) | public void removeObserver(DownloadObserver observer) {
method getFolder (line 89) | public File getFolder() {
method getGallery (line 93) | public Gallery getGallery() {
method setGallery (line 97) | private void setGallery(Gallery gallery) {
method getTotalPage (line 106) | private int getTotalPage() {
method getPercentage (line 110) | public int getPercentage() {
method onStart (line 115) | private void onStart() {
method onEnd (line 120) | private void onEnd() {
method onUpdate (line 127) | private void onUpdate() {
method onCancel (line 134) | private void onCancel() {
method onPause (line 138) | private void onPause() {
method localGallery (line 142) | public LocalGallery localGallery() {
method getTitle (line 147) | public String getTitle() {
method addObserver (line 151) | public void addObserver(DownloadObserver observer) {
method getId (line 156) | public int getId() {
method getStart (line 160) | public int getStart() {
method getEnd (line 164) | public int getEnd() {
method getPathTitle (line 168) | @NonNull
method getTruePathTitle (line 173) | @NonNull
method downloadGalleryData (line 181) | public boolean downloadGalleryData() {
method getThumbnail (line 199) | public Uri getThumbnail() {
method canBeFetched (line 203) | public boolean canBeFetched() {
method getStatus (line 207) | public Status getStatus() {
method setStatus (line 211) | public void setStatus(Status status) {
method download (line 222) | public void download() {
method downloadPage (line 240) | private void downloadPage(PageContainer page) {
method isCorrupted (line 247) | private boolean isCorrupted(File file) {
method savePage (line 260) | private boolean savePage(PageContainer page) {
method initDownload (line 289) | public void initDownload() {
method checkPages (line 297) | private void checkPages() {
method createPages (line 310) | private void createPages() {
method createFolder (line 315) | private void createFolder() {
method createIdFile (line 328) | private void createIdFile() throws IOException {
method writeNoMedia (line 334) | private void writeNoMedia() throws IOException {
method equals (line 342) | @Override
method hashCode (line 353) | @Override
type Status (line 360) | public enum Status {NOT_STARTED, DOWNLOADING, PAUSED, FINISHED, CANCELED}
class PageContainer (line 362) | public static class PageContainer {
method PageContainer (line 366) | public PageContainer(int page, Uri url) {
method getPageName (line 371) | public String getPageName() {
FILE: app/src/main/java/com/maxwai/nclientv3/async/downloader/PageChecker.java
class PageChecker (line 3) | public class PageChecker extends Thread {
method run (line 4) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/components/CookieInterceptor.java
class CookieInterceptor (line 15) | public class CookieInterceptor {
method hideWebView (line 19) | public static void hideWebView() {
method CookieInterceptor (line 32) | public CookieInterceptor(@NonNull Manager manager) {
method setupWebView (line 36) | private CFTokenView setupWebView() {
method getWebView (line 46) | @NonNull
method interceptInternal (line 55) | private void interceptInternal() {
method intercept (line 80) | public void intercept() {
type Manager (line 96) | public interface Manager {
method applyCookie (line 97) | void applyCookie(String key, String value);
method endInterceptor (line 99) | boolean endInterceptor();
method onFinish (line 101) | void onFinish();
FILE: app/src/main/java/com/maxwai/nclientv3/components/CustomCookieJar.java
class CustomCookieJar (line 17) | public class CustomCookieJar implements ClearableCookieJar {
method CustomCookieJar (line 21) | public CustomCookieJar(CookieCache cache, CookiePersistor persistor) {
method filterPersistentCookies (line 28) | private static List<Cookie> filterPersistentCookies(List<Cookie> cooki...
method isCookieExpired (line 39) | private static boolean isCookieExpired(Cookie cookie) {
method saveFromResponse (line 43) | @Override
method loadForRequest (line 49) | @NonNull
method clearSession (line 71) | @Override
method clear (line 77) | @Override
method removeCookie (line 83) | public void removeCookie(String name) {
FILE: app/src/main/java/com/maxwai/nclientv3/components/GlideX.java
class GlideX (line 11) | public class GlideX {
method with (line 13) | @Nullable
method with (line 22) | @Nullable
FILE: app/src/main/java/com/maxwai/nclientv3/components/ThreadAsyncTask.java
class ThreadAsyncTask (line 7) | public abstract class ThreadAsyncTask<Param, Progress, Result> {
method ThreadAsyncTask (line 12) | public ThreadAsyncTask(AppCompatActivity activity) {
method execute (line 16) | public final void execute(Param params) {
method onPreExecute (line 21) | protected void onPreExecute() {
method onPostExecute (line 24) | protected void onPostExecute(Result result) {
method onProgressUpdate (line 27) | protected void onProgressUpdate(Progress value) {
method doInBackground (line 30) | protected abstract Result doInBackground(Param param);
method publishProgress (line 32) | protected final void publishProgress(Progress value) {
class AsyncThread (line 37) | class AsyncThread extends Thread {
method AsyncThread (line 41) | AsyncThread(Param param) {
method run (line 45) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/components/activities/BaseActivity.java
class BaseActivity (line 12) | public abstract class BaseActivity extends GeneralActivity {
method getPortraitColumnCount (line 17) | protected abstract int getPortraitColumnCount();
method getLandscapeColumnCount (line 19) | protected abstract int getLandscapeColumnCount();
method getRefresher (line 22) | public SwipeRefreshLayout getRefresher() {
method getRecycler (line 26) | public RecyclerView getRecycler() {
method getMasterLayout (line 30) | public ViewGroup getMasterLayout() {
method onConfigurationChanged (line 34) | @Override
method changeLayout (line 44) | protected void changeLayout(boolean landscape) {
FILE: app/src/main/java/com/maxwai/nclientv3/components/activities/CrashApplication.java
class CrashApplication (line 28) | public class CrashApplication extends Application {
method setDarkLightTheme (line 33) | @DeprecatedSinceApi(api = Build.VERSION_CODES.S)
method onCreate (line 42) | @Override
method afterUpdateChecks (line 67) | private void afterUpdateChecks(SharedPreferences preferences, String o...
method removeOldUpdates (line 77) | private void removeOldUpdates() {
class CustomActivityLifecycleCallback (line 84) | private static class CustomActivityLifecycleCallback implements Activi...
method onActivityCreated (line 86) | @Override
method onActivityDestroyed (line 101) | @Override
method onActivityPaused (line 106) | @Override
method onActivityResumed (line 111) | @Override
method onActivitySaveInstanceState (line 116) | @Override
method onActivityStarted (line 121) | @Override
method onActivityStopped (line 126) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/components/activities/GeneralActivity.java
class GeneralActivity (line 21) | public abstract class GeneralActivity extends AppCompatActivity {
method getLastCFView (line 26) | public static @Nullable
method inflateWebView (line 37) | private void inflateWebView() {
method onPause (line 49) | @Override
method onCreate (line 54) | @Override
method onResume (line 62) | @Override
method getTheme (line 72) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/components/classes/Bookmark.java
class Bookmark (line 19) | public class Bookmark {
method Bookmark (line 26) | public Bookmark(String url, int page, ApiRequestType requestType, int ...
method createInspector (line 39) | public InspectorV3 createInspector(Context context, InspectorV3.Inspec...
method deleteBookmark (line 53) | public void deleteBookmark() {
method toString (line 57) | @NonNull
FILE: app/src/main/java/com/maxwai/nclientv3/components/classes/History.java
class History (line 9) | public class History {
method History (line 13) | public History(String value, boolean set) {
method setToList (line 24) | public static List<History> setToList(Set<String> set) {
method listToSet (line 36) | public static Set<String> listToSet(List<History> list) {
method getValue (line 42) | public String getValue() {
method equals (line 46) | @Override
method hashCode (line 54) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/components/classes/MultichoiceAdapter.java
class MultichoiceAdapter (line 21) | public abstract class MultichoiceAdapter<D, T extends RecyclerView.ViewH...
method put (line 25) | @Nullable
method remove (line 34) | @Nullable
method clear (line 43) | @Override
method MultichoiceAdapter (line 51) | public MultichoiceAdapter() {
method changeSelecting (line 55) | private void changeSelecting() {
method getItemAt (line 63) | protected abstract D getItemAt(int position);
method getMaster (line 65) | protected abstract ViewGroup getMaster(T holder);
method defaultMasterAction (line 67) | protected abstract void defaultMasterAction(int position);
method onBindMultichoiceViewHolder (line 69) | protected abstract void onBindMultichoiceViewHolder(T holder, int posi...
method onCreateMultichoiceViewHolder (line 71) | @NonNull
method getItemId (line 74) | @Override
method startSelecting (line 77) | private void startSelecting() {
method endSelecting (line 83) | private void endSelecting() {
method addListener (line 89) | public void addListener(MultichoiceListener listener) {
method onCreateViewHolder (line 93) | @NonNull
method onBindViewHolder (line 102) | @Override
method updateLayoutParams (line 130) | private void updateLayoutParams(View master, View multichoiceHolder, b...
method toggleSelection (line 148) | private void toggleSelection(int position) {
method getMode (line 157) | public Mode getMode() {
method setMode (line 161) | private void setMode(Mode mode) {
method selectAll (line 165) | public void selectAll() {
method getSelected (line 172) | public Collection<D> getSelected() {
method deselectAll (line 176) | public void deselectAll() {
type Mode (line 181) | public enum Mode {NORMAL, SELECTING}
type MultichoiceListener (line 183) | public interface MultichoiceListener {
method firstChoice (line 184) | void firstChoice();
method noMoreChoices (line 186) | void noMoreChoices();
method choiceChanged (line 188) | void choiceChanged();
class DefaultMultichoiceListener (line 191) | public static class DefaultMultichoiceListener implements MultichoiceL...
method firstChoice (line 193) | @Override
method noMoreChoices (line 198) | @Override
method choiceChanged (line 203) | @Override
class MultichoiceViewHolder (line 209) | public static class MultichoiceViewHolder<T extends RecyclerView.ViewH...
method MultichoiceViewHolder (line 214) | public MultichoiceViewHolder(@NonNull ConstraintLayout multichoiceHo...
FILE: app/src/main/java/com/maxwai/nclientv3/components/classes/Size.java
class Size (line 8) | public class Size implements Parcelable {
method createFromParcel (line 10) | @Override
method newArray (line 15) | @Override
method Size (line 22) | public Size(int width, int height) {
method Size (line 27) | protected Size(Parcel in) {
method getWidth (line 32) | public int getWidth() {
method setWidth (line 36) | public void setWidth(int width) {
method getHeight (line 40) | public int getHeight() {
method setHeight (line 44) | public void setHeight(int height) {
method describeContents (line 48) | @Override
method writeToParcel (line 53) | @Override
method toString (line 59) | @NonNull
FILE: app/src/main/java/com/maxwai/nclientv3/components/launcher/LauncherCalculator.java
class LauncherCalculator (line 3) | public class LauncherCalculator {
FILE: app/src/main/java/com/maxwai/nclientv3/components/launcher/LauncherReal.java
class LauncherReal (line 3) | public class LauncherReal {
FILE: app/src/main/java/com/maxwai/nclientv3/components/status/Status.java
class Status (line 5) | public class Status {
method Status (line 9) | Status(int color, String name) {
method opaqueColor (line 14) | public int opaqueColor() {
FILE: app/src/main/java/com/maxwai/nclientv3/components/status/StatusManager.java
class StatusManager (line 11) | public class StatusManager {
method getByName (line 15) | public static Status getByName(String name) {
method add (line 19) | public static Status add(String name, int color) {
method add (line 23) | static Status add(Status status) {
method remove (line 29) | public static void remove(Status status) {
method getNames (line 34) | public static List<String> getNames() {
method toList (line 42) | public static List<Status> toList() {
method updateStatus (line 49) | public static Status updateStatus(@Nullable Status oldStatus, String n...
FILE: app/src/main/java/com/maxwai/nclientv3/components/views/CFTokenView.java
class CFTokenView (line 20) | public class CFTokenView {
method CFTokenView (line 25) | public CFTokenView(ViewGroup masterLayout) {
method getWebView (line 32) | public CFTokenWebView getWebView() {
method setVisibility (line 36) | public void setVisibility(int visible) {
method post (line 40) | public void post(Runnable o) {
class CFTokenWebView (line 45) | public static class CFTokenWebView extends WebView{
method CFTokenWebView (line 46) | public CFTokenWebView(@NonNull Context context) {
method CFTokenWebView (line 51) | public CFTokenWebView(@NonNull Context context, @Nullable @org.jetbr...
method CFTokenWebView (line 56) | public CFTokenWebView(@NonNull Context context, @Nullable @org.jetbr...
method init (line 61) | private void init() {
method forceAcceptCookies (line 66) | private void forceAcceptCookies() {
method applyWebViewSettings (line 71) | @SuppressLint("SetJavaScriptEnabled")
FILE: app/src/main/java/com/maxwai/nclientv3/components/views/GeneralPreferenceFragment.java
class GeneralPreferenceFragment (line 63) | public class GeneralPreferenceFragment extends PreferenceFragmentCompat {
method setAct (line 66) | public void setAct(SettingsActivity act) {
method setType (line 70) | public void setType(SettingsActivity.Type type) {
method dataMenu (line 84) | private void dataMenu() {
method getDataUsageString (line 102) | private int getDataUsageString(int val) {
method getLocaleListFromXml (line 114) | private LocaleListCompat getLocaleListFromXml() {
method fillRoba (line 140) | private void fillRoba() {
method mainMenu (line 166) | @SuppressLint("ApplySharedPref")
method onResume (line 422) | @Override
method updateApiKeySummary (line 430) | private void updateApiKeySummary(@NonNull Preference preference) {
method manageCustomPath (line 441) | public void manageCustomPath() {
method changeLauncher (line 459) | private void changeLauncher(PackageManager pm, ComponentName name, boo...
method initStoragePaths (line 465) | private void initStoragePaths(ListPreference storagePreference) {
method getDataSettings (line 489) | private String getDataSettings(Context context) throws IOException {
method processSharedFromName (line 507) | private void processSharedFromName(JsonWriter writer, Context context,...
method writeEntry (line 517) | private void writeEntry(JsonWriter writer, Map.Entry<String, ?> entry)...
method onCreatePreferences (line 525) | @Override
method columnMenu (line 530) | private void columnMenu() {
FILE: app/src/main/java/com/maxwai/nclientv3/components/views/PageSwitcher.java
class PageSwitcher (line 21) | public class PageSwitcher extends CardView {
method PageSwitcher (line 30) | public PageSwitcher(@NonNull Context context) {
method PageSwitcher (line 36) | public PageSwitcher(@NonNull Context context, @Nullable AttributeSet a...
method PageSwitcher (line 42) | public PageSwitcher(@NonNull Context context, @Nullable AttributeSet a...
method setChanger (line 47) | public void setChanger(@Nullable PageChanger changer) {
method setPages (line 51) | public void setPages(int totalPage, int actualPage) {
method setTotalPage (line 61) | public void setTotalPage(int totalPage) {
method updateViews (line 65) | private void updateViews() {
method init (line 76) | private void init(Context context) {
method addViewListeners (line 84) | private void addViewListeners() {
method getActualPage (line 94) | public int getActualPage() {
method setActualPage (line 98) | public void setActualPage(int actualPage) {
method lastPageReached (line 102) | public boolean lastPageReached() {
method loadDialog (line 106) | private void loadDialog() {
type PageChanger (line 124) | public interface PageChanger {
method pageChanged (line 125) | void pageChanged();
method onPrevClicked (line 127) | void onPrevClicked(PageSwitcher switcher);
method onNextClicked (line 129) | void onNextClicked(PageSwitcher switcher);
class DefaultPageChanger (line 132) | public static class DefaultPageChanger implements PageChanger {
method pageChanged (line 134) | @Override
method onPrevClicked (line 138) | @Override
method onNextClicked (line 143) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/components/views/RangeSelector.java
class RangeSelector (line 18) | public class RangeSelector extends MaterialAlertDialogBuilder {
method RangeSelector (line 22) | public RangeSelector(@NonNull Context context, Gallery gallery) {
method getPrevListener (line 40) | private View.OnClickListener getPrevListener(SeekBar s) {
method getNextListener (line 44) | private View.OnClickListener getNextListener(SeekBar s) {
method getSeekBarListener (line 48) | private SeekBar.OnSeekBarChangeListener getSeekBarListener(TextView t) {
method applyLogic (line 65) | private void applyLogic(LinearLayout layout, boolean start) {
FILE: app/src/main/java/com/maxwai/nclientv3/components/views/ZoomFragment.java
class ZoomFragment (line 44) | public class ZoomFragment extends Fragment {
type OnZoomChangeListener (line 46) | public interface OnZoomChangeListener {
method onZoomChange (line 47) | void onZoomChange(View v, float zoomLevel);
method ZoomFragment (line 63) | public ZoomFragment() {
method newInstance (line 66) | public static ZoomFragment newInstance(GenericGallery gallery, int pag...
method setClickListener (line 75) | public void setClickListener(View.OnClickListener clickListener) {
method setZoomChangeListener (line 80) | public void setZoomChangeListener(OnZoomChangeListener zoomChangeListe...
method calculateScaleFactor (line 84) | private float calculateScaleFactor(int width, int height) {
method onCreateView (line 96) | @Nullable
method createTarget (line 139) | private void createTarget() {
method scalePhoto (line 182) | private void scalePhoto(Drawable drawable) {
method loadImage (line 189) | public void loadImage() {
method loadImage (line 193) | public void loadImage(Priority priority) {
method loadPage (line 219) | @Nullable
method getDrawable (line 237) | public Drawable getDrawable() {
method cancelRequest (line 241) | public void cancelRequest() {
method updateDegree (line 249) | private void updateDegree() {
method rotate (line 254) | public void rotate() {
FILE: app/src/main/java/com/maxwai/nclientv3/components/widgets/ChipTag.java
class ChipTag (line 15) | public class ChipTag extends Chip {
method ChipTag (line 19) | public ChipTag(Context context) {
method ChipTag (line 23) | public ChipTag(Context context, AttributeSet attrs) {
method ChipTag (line 27) | public ChipTag(Context context, AttributeSet attrs, int defStyleAttr) {
method init (line 31) | public void init(Tag t, boolean close, boolean canBeAvoided) {
method setCanBeAvoided (line 37) | private void setCanBeAvoided(boolean canBeAvoided) {
method getTag (line 41) | @Override
method setTag (line 46) | private void setTag(Tag tag) {
method changeStatus (line 52) | public void changeStatus(TagStatus status) {
method updateStatus (line 57) | public void updateStatus() {
method loadStatusIcon (line 71) | private void loadStatusIcon() {
FILE: app/src/main/java/com/maxwai/nclientv3/components/widgets/CustomGridLayoutManager.java
class CustomGridLayoutManager (line 7) | public class CustomGridLayoutManager extends GridLayoutManager {
method CustomGridLayoutManager (line 9) | public CustomGridLayoutManager(Context context, int spanCount) {
method CustomGridLayoutManager (line 13) | public CustomGridLayoutManager(Context context, int spanCount, int ori...
method supportsPredictiveItemAnimations (line 17) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/components/widgets/CustomImageView.java
class CustomImageView (line 11) | public class CustomImageView extends AppCompatImageView {
method CustomImageView (line 13) | public CustomImageView(Context context) {
method CustomImageView (line 17) | public CustomImageView(Context context, AttributeSet attrs) {
method CustomImageView (line 21) | public CustomImageView(Context context, AttributeSet attrs, int defSty...
method setImageDrawable (line 25) | @Override
method setFrame (line 32) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/components/widgets/CustomLinearLayoutManager.java
class CustomLinearLayoutManager (line 8) | public class CustomLinearLayoutManager extends LinearLayoutManager {
method CustomLinearLayoutManager (line 9) | public CustomLinearLayoutManager(Context context) {
method supportsPredictiveItemAnimations (line 14) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/components/widgets/CustomSearchView.java
class CustomSearchView (line 8) | public class CustomSearchView extends SearchView {
method CustomSearchView (line 10) | public CustomSearchView(Context context) {
method CustomSearchView (line 14) | public CustomSearchView(Context context, AttributeSet attrs) {
method CustomSearchView (line 18) | public CustomSearchView(Context context, AttributeSet attrs, int defSt...
method setOnQueryTextListener (line 22) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/components/widgets/CustomSwipe.java
class CustomSwipe (line 12) | public class CustomSwipe extends SwipeRefreshLayout {
method CustomSwipe (line 13) | public CustomSwipe(@NonNull Context context) {
method CustomSwipe (line 17) | public CustomSwipe(@NonNull Context context, @Nullable AttributeSet at...
method setEnabled (line 21) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/components/widgets/TagTypePage.java
class TagTypePage (line 22) | public class TagTypePage extends Fragment {
method TagTypePage (line 29) | public TagTypePage() {
method getTag (line 32) | private static int getTag(int page) {
method newInstance (line 52) | public static TagTypePage newInstance(int page) {
method getRecyclerView (line 60) | public RecyclerView getRecyclerView() {
method onCreateView (line 64) | @Override
method loadTags (line 77) | public void loadTags() {
method refilter (line 85) | public void refilter(String newText) {
method reset (line 89) | public void reset() {
method changeSize (line 100) | public void changeSize() {
FILE: app/src/main/java/com/maxwai/nclientv3/files/GalleryFolder.java
class GalleryFolder (line 21) | public class GalleryFolder implements Parcelable, Iterable<PageFile> {
method createFromParcel (line 24) | @Override
method newArray (line 29) | @Override
method GalleryFolder (line 44) | public GalleryFolder(@NonNull String child) {
method GalleryFolder (line 48) | public GalleryFolder(@Nullable File parent, @NonNull String child) {
method GalleryFolder (line 53) | public GalleryFolder(File file) {
method GalleryFolder (line 61) | protected GalleryFolder(Parcel in) {
method fromId (line 79) | public static @Nullable
method parseFiles (line 86) | private void parseFiles() {
method elaborateFile (line 94) | private void elaborateFile(File f) {
method elaborateId (line 108) | private int elaborateId(Matcher matcher) {
method getPageCount (line 112) | public int getPageCount() {
method getGalleryDataFile (line 116) | public File getGalleryDataFile() {
method getFolder (line 120) | public File getFolder() {
method getMax (line 124) | public int getMax() {
method getMin (line 128) | public int getMin() {
method elaboratePage (line 132) | private void elaboratePage(File f, Matcher matcher) {
method getPage (line 139) | public PageFile getPage(int page) {
method getFirstPage (line 143) | public PageFile getFirstPage() {
method getId (line 153) | public int getId() {
method describeContents (line 157) | @Override
method writeToParcel (line 162) | @Override
method iterator (line 175) | @NonNull
method equals (line 181) | @Override
method hashCode (line 191) | @Override
method toString (line 196) | @NonNull
class PageFileIterator (line 209) | public static class PageFileIterator implements Iterator<PageFile> {
method PageFileIterator (line 213) | public PageFileIterator(SparseArrayCompat<PageFile> files) {
method hasNext (line 218) | @Override
method next (line 223) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/files/PageFile.java
class PageFile (line 10) | public class PageFile extends File implements Parcelable {
method createFromParcel (line 12) | @Override
method newArray (line 17) | @Override
method PageFile (line 24) | public PageFile(File file, int page) {
method PageFile (line 29) | protected PageFile(Parcel in) {
method toUri (line 34) | public Uri toUri() {
method describeContents (line 38) | @Override
method writeToParcel (line 43) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/Compat.java
class Compat (line 20) | class Compat {
method postOnAnimation (line 22) | public static void postOnAnimation(View view, Runnable runnable) {
method postOnAnimationJellyBean (line 26) | private static void postOnAnimationJellyBean(View view, Runnable runna...
FILE: app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/CustomGestureDetector.java
class CustomGestureDetector (line 29) | class CustomGestureDetector {
method CustomGestureDetector (line 43) | CustomGestureDetector(Context context, OnGestureListener listener) {
method getActiveX (line 88) | private float getActiveX(MotionEvent ev) {
method getActiveY (line 96) | private float getActiveY(MotionEvent ev) {
method isScaling (line 104) | public boolean isScaling() {
method isDragging (line 108) | public boolean isDragging() {
method onTouchEvent (line 112) | public boolean onTouchEvent(MotionEvent ev) {
method processTouchEvent (line 122) | private boolean processTouchEvent(MotionEvent ev) {
FILE: app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnGestureListener.java
type OnGestureListener (line 18) | interface OnGestureListener {
method onDrag (line 20) | void onDrag(float dx, float dy);
method onFling (line 22) | void onFling(float startX, float startY, float velocityX,
method onScale (line 25) | void onScale(float scaleFactor, float focusX, float focusY);
method onScale (line 27) | void onScale(float scaleFactor, float focusX, float focusY, float dx, ...
FILE: app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnMatrixChangedListener.java
type OnMatrixChangedListener (line 9) | public interface OnMatrixChangedListener {
method onMatrixChanged (line 17) | void onMatrixChanged(RectF rect);
FILE: app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnOutsidePhotoTapListener.java
type OnOutsidePhotoTapListener (line 8) | public interface OnOutsidePhotoTapListener {
method onOutsidePhotoTap (line 13) | void onOutsidePhotoTap(ImageView imageView);
FILE: app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnPhotoTapListener.java
type OnPhotoTapListener (line 9) | public interface OnPhotoTapListener {
method onPhotoTap (line 21) | void onPhotoTap(ImageView view, float x, float y);
FILE: app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnScaleChangedListener.java
type OnScaleChangedListener (line 7) | public interface OnScaleChangedListener {
method onScaleChange (line 16) | void onScaleChange(float scaleFactor, float focusX, float focusY);
FILE: app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnSingleFlingListener.java
type OnSingleFlingListener (line 9) | public interface OnSingleFlingListener {
method onFling (line 20) | boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float...
FILE: app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnViewDragListener.java
type OnViewDragListener (line 6) | public interface OnViewDragListener {
method onDrag (line 15) | void onDrag(float dx, float dy);
FILE: app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnViewTapListener.java
type OnViewTapListener (line 5) | public interface OnViewTapListener {
method onViewTap (line 15) | void onViewTap(View view, float x, float y);
FILE: app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/PhotoView.java
class PhotoView (line 32) | @SuppressWarnings("unused")
method PhotoView (line 38) | public PhotoView(Context context) {
method PhotoView (line 42) | public PhotoView(Context context, AttributeSet attr) {
method PhotoView (line 46) | public PhotoView(Context context, AttributeSet attr, int defStyle) {
method init (line 51) | private void init() {
method getAttacher (line 70) | public PhotoViewAttacher getAttacher() {
method getScaleType (line 74) | @Override
method setScaleType (line 79) | @Override
method getImageMatrix (line 88) | @Override
method setOnLongClickListener (line 93) | @Override
method setOnClickListener (line 98) | @Override
method setImageDrawable (line 103) | @Override
method setImageResource (line 112) | @Override
method setImageURI (line 120) | @Override
method setFrame (line 128) | @Override
method setRotationTo (line 137) | public void setRotationTo(float rotationDegree) {
method setRotationBy (line 141) | public void setRotationBy(float rotationDegree) {
method isZoomable (line 145) | public boolean isZoomable() {
method setZoomable (line 149) | public void setZoomable(boolean zoomable) {
method getDisplayRect (line 153) | public RectF getDisplayRect() {
method getDisplayMatrix (line 157) | public void getDisplayMatrix(Matrix matrix) {
method setDisplayMatrix (line 161) | @SuppressWarnings("UnusedReturnValue")
method getSuppMatrix (line 166) | public void getSuppMatrix(Matrix matrix) {
method setSuppMatrix (line 170) | public boolean setSuppMatrix(Matrix matrix) {
method getMinimumScale (line 174) | public float getMinimumScale() {
method setMinimumScale (line 178) | public void setMinimumScale(float minimumScale) {
method getMediumScale (line 182) | public float getMediumScale() {
method setMediumScale (line 186) | public void setMediumScale(float mediumScale) {
method getMaximumScale (line 190) | public float getMaximumScale() {
method setMaximumScale (line 194) | public void setMaximumScale(float maximumScale) {
method getScale (line 198) | public float getScale() {
method setScale (line 202) | public void setScale(float scale) {
method setAllowParentInterceptOnEdge (line 206) | public void setAllowParentInterceptOnEdge(boolean allow) {
method setScaleLevels (line 210) | public void setScaleLevels(float minimumScale, float mediumScale, floa...
method setOnMatrixChangeListener (line 214) | public void setOnMatrixChangeListener(OnMatrixChangedListener listener) {
method setOnPhotoTapListener (line 218) | public void setOnPhotoTapListener(OnPhotoTapListener listener) {
method setOnOutsidePhotoTapListener (line 222) | public void setOnOutsidePhotoTapListener(OnOutsidePhotoTapListener lis...
method setOnViewTapListener (line 226) | public void setOnViewTapListener(OnViewTapListener listener) {
method setOnViewDragListener (line 230) | public void setOnViewDragListener(OnViewDragListener listener) {
method setScale (line 234) | public void setScale(float scale, boolean animate) {
method setScale (line 238) | public void setScale(float scale, float focalX, float focalY, boolean ...
method setZoomTransitionDuration (line 242) | public void setZoomTransitionDuration(int milliseconds) {
method setOnDoubleTapListener (line 246) | public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener...
method setOnScaleChangeListener (line 250) | public void setOnScaleChangeListener(OnScaleChangedListener onScaleCha...
method setOnSingleFlingListener (line 254) | public void setOnSingleFlingListener(OnSingleFlingListener onSingleFli...
FILE: app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/PhotoViewAttacher.java
class PhotoViewAttacher (line 41) | public class PhotoViewAttacher implements View.OnTouchListener,
method onDrag (line 95) | @Override
method onFling (line 133) | @Override
method onScale (line 141) | @Override
method onScale (line 146) | @Override
method PhotoViewAttacher (line 159) | public PhotoViewAttacher(ImageView imageView) {
method setOnDoubleTapListener (line 253) | public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener...
method setOnScaleChangeListener (line 257) | public void setOnScaleChangeListener(OnScaleChangedListener onScaleCha...
method setOnSingleFlingListener (line 261) | public void setOnSingleFlingListener(OnSingleFlingListener onSingleFli...
method isZoomEnabled (line 265) | @Deprecated
method getDisplayRect (line 270) | public RectF getDisplayRect() {
method setDisplayMatrix (line 275) | public boolean setDisplayMatrix(Matrix finalMatrix) {
method setRotationTo (line 287) | public void setRotationTo(float degrees) {
method setRotationBy (line 292) | public void setRotationBy(float degrees) {
method getMinimumScale (line 297) | public float getMinimumScale() {
method setMinimumScale (line 301) | public void setMinimumScale(float minimumScale) {
method getMediumScale (line 306) | public float getMediumScale() {
method setMediumScale (line 310) | public void setMediumScale(float mediumScale) {
method getMaximumScale (line 315) | public float getMaximumScale() {
method setMaximumScale (line 319) | public void setMaximumScale(float maximumScale) {
method getScale (line 324) | public float getScale() {
method setScale (line 329) | public void setScale(float scale) {
method getScaleType (line 333) | public ScaleType getScaleType() {
method setScaleType (line 337) | public void setScaleType(ScaleType scaleType) {
method onLayoutChange (line 344) | @Override
method onTouch (line 353) | @Override
method setAllowParentInterceptOnEdge (line 408) | public void setAllowParentInterceptOnEdge(boolean allow) {
method setScaleLevels (line 412) | public void setScaleLevels(float minimumScale, float mediumScale, floa...
method setOnLongClickListener (line 419) | public void setOnLongClickListener(OnLongClickListener listener) {
method setOnClickListener (line 423) | public void setOnClickListener(View.OnClickListener listener) {
method setOnMatrixChangeListener (line 427) | public void setOnMatrixChangeListener(OnMatrixChangedListener listener) {
method setOnPhotoTapListener (line 431) | public void setOnPhotoTapListener(OnPhotoTapListener listener) {
method setOnOutsidePhotoTapListener (line 435) | public void setOnOutsidePhotoTapListener(OnOutsidePhotoTapListener mOu...
method setOnViewTapListener (line 439) | public void setOnViewTapListener(OnViewTapListener listener) {
method setOnViewDragListener (line 443) | public void setOnViewDragListener(OnViewDragListener listener) {
method setScale (line 447) | public void setScale(float scale, boolean animate) {
method setScale (line 454) | public void setScale(float scale, float focalX, float focalY,
method isZoomable (line 469) | public boolean isZoomable() {
method setZoomable (line 473) | public void setZoomable(boolean zoomable) {
method update (line 478) | public void update() {
method getDisplayMatrix (line 493) | public void getDisplayMatrix(Matrix matrix) {
method getSuppMatrix (line 500) | public void getSuppMatrix(Matrix matrix) {
method getDrawMatrix (line 504) | private Matrix getDrawMatrix() {
method getImageMatrix (line 510) | public Matrix getImageMatrix() {
method setZoomTransitionDuration (line 514) | public void setZoomTransitionDuration(int milliseconds) {
method getValue (line 525) | private float getValue(Matrix matrix, int whichValue) {
method resetMatrix (line 533) | private void resetMatrix() {
method setImageViewMatrix (line 540) | private void setImageViewMatrix(Matrix matrix) {
method checkAndDisplayMatrix (line 554) | private void checkAndDisplayMatrix() {
method getDisplayRect (line 566) | private RectF getDisplayRect(Matrix matrix) {
method updateBaseMatrix (line 582) | private void updateBaseMatrix(Drawable drawable) {
method checkMatrixBounds (line 636) | private boolean checkMatrixBounds() {
method getImageViewWidth (line 694) | private int getImageViewWidth(ImageView imageView) {
method getImageViewHeight (line 698) | private int getImageViewHeight(ImageView imageView) {
method cancelFling (line 702) | private void cancelFling() {
class AnimatedZoomRunnable (line 709) | private class AnimatedZoomRunnable implements Runnable {
method AnimatedZoomRunnable (line 715) | public AnimatedZoomRunnable(final float currentZoom, final float tar...
method run (line 724) | @Override
method interpolate (line 736) | private float interpolate() {
class FlingRunnable (line 744) | private class FlingRunnable implements Runnable {
method FlingRunnable (line 749) | public FlingRunnable(Context context) {
method cancelFling (line 753) | public void cancelFling() {
method fling (line 757) | public void fling(int viewWidth, int viewHeight, int velocityX,
method run (line 787) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/Util.java
class Util (line 6) | class Util {
method checkZoomLevels (line 8) | static void checkZoomLevels(float minZoom, float midZoom,
method hasDrawable (line 19) | static boolean hasDrawable(ImageView imageView) {
method isSupportedScaleType (line 23) | static boolean isSupportedScaleType(final ImageView.ScaleType scaleTyp...
method getPointerIndex (line 33) | static int getPointerIndex(int action) {
FILE: app/src/main/java/com/maxwai/nclientv3/loginapi/LoadTags.java
class LoadTags (line 21) | public class LoadTags extends Thread {
method LoadTags (line 25) | public LoadTags(@NonNull Context context) {
method readTags (line 29) | private void readTags(JsonReader jr) throws IOException {
method run (line 49) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/loginapi/User.java
class User (line 20) | public class User {
method User (line 24) | private User(JsonReader jr) throws IOException {
method createUser (line 49) | public static void createUser(@NonNull Context context, final CreateUs...
method toString (line 67) | @NonNull
method getUsername (line 73) | public String getUsername() {
method getId (line 77) | public int getId() {
type CreateUser (line 81) | public interface CreateUser {
method onCreateUser (line 82) | void onCreateUser(User user);
FILE: app/src/main/java/com/maxwai/nclientv3/settings/ApiAuthInterceptor.java
class ApiAuthInterceptor (line 19) | public class ApiAuthInterceptor implements Interceptor {
method ApiAuthInterceptor (line 24) | public ApiAuthInterceptor(@NonNull Context context, boolean logRequest...
method intercept (line 29) | @NonNull
FILE: app/src/main/java/com/maxwai/nclientv3/settings/AuthCredentials.java
class AuthCredentials (line 5) | public final class AuthCredentials {
type Type (line 6) | public enum Type {
method AuthCredentials (line 15) | public AuthCredentials(@NonNull Type type, @NonNull String secret) {
method getType (line 20) | @NonNull
method getSecret (line 25) | @NonNull
method toAuthorizationHeader (line 30) | @NonNull
FILE: app/src/main/java/com/maxwai/nclientv3/settings/AuthStore.java
class AuthStore (line 9) | public final class AuthStore {
method AuthStore (line 15) | private AuthStore() {
method getPreferences (line 18) | @NonNull
method saveApiKey (line 23) | public static void saveApiKey(@NonNull Context context, @NonNull Strin...
method clear (line 32) | public static void clear(@NonNull Context context) {
method getCredentials (line 36) | @Nullable
method hasCredentials (line 50) | public static boolean hasCredentials(@NonNull Context context) {
method hasApiKey (line 54) | public static boolean hasApiKey(@NonNull Context context) {
method hasValidApiKey (line 59) | public static boolean hasValidApiKey(@NonNull Context context) {
method setApiKeyValidation (line 68) | public static void setApiKeyValidation(@NonNull Context context, boole...
method getApiKey (line 73) | @Nullable
method getAuthorizationHeader (line 80) | @Nullable
FILE: app/src/main/java/com/maxwai/nclientv3/settings/Database.java
class Database (line 10) | public class Database {
method getDatabase (line 13) | @Nullable
method setDatabase (line 18) | public static void setDatabase(SQLiteDatabase database) {
method setDBForTables (line 25) | private static void setDBForTables(SQLiteDatabase database) {
FILE: app/src/main/java/com/maxwai/nclientv3/settings/DefaultDialogs.java
class DefaultDialogs (line 20) | public class DefaultDialogs {
method pageChangerDialog (line 21) | public static void pageChangerDialog(final Builder builder) {
type DialogResults (line 93) | public interface DialogResults {
method positive (line 94) | void positive(int actual);
method negative (line 96) | void negative();
method neutral (line 98) | void neutral();
class CustomDialogResults (line 101) | public static class CustomDialogResults implements DialogResults {
method positive (line 102) | @Override
method negative (line 106) | @Override
method neutral (line 110) | @Override
class Builder (line 115) | @SuppressWarnings("UnusedReturnValue")
method Builder (line 125) | public Builder(Context context) {
method setMin (line 136) | public Builder setMin(int min) {
method setTitle (line 141) | public Builder setTitle(int title) {
method setYesbtn (line 146) | public Builder setYesbtn(int yesbtn) {
method setNobtn (line 151) | public Builder setNobtn(int nobtn) {
method setDrawable (line 156) | public Builder setDrawable(int drawable) {
method setMax (line 161) | public Builder setMax(int max) {
method setMaybebtn (line 166) | public Builder setMaybebtn(int maybebtn) {
method setActual (line 171) | public Builder setActual(int actual) {
method setDialogs (line 176) | public Builder setDialogs(DialogResults dialogs) {
FILE: app/src/main/java/com/maxwai/nclientv3/settings/Favorites.java
class Favorites (line 7) | public class Favorites {
method addFavorite (line 10) | public static void addFavorite(Gallery gallery) {
method removeFavorite (line 14) | public static void removeFavorite(GenericGallery gallery) {
method isFavorite (line 18) | public static boolean isFavorite(GenericGallery gallery) {
FILE: app/src/main/java/com/maxwai/nclientv3/settings/Global.java
class Global (line 54) | public class Global {
method recursiveSize (line 85) | public static long recursiveSize(File path) {
method isExactTagMatch (line 96) | public static boolean isExactTagMatch() {
method getFavoriteLimit (line 100) | public static int getFavoriteLimit(Context context) {
method getLastVersion (line 104) | public static String getLastVersion(Context context) {
method isEnableBeta (line 110) | public static boolean isEnableBeta() {
method setEnableBeta (line 114) | public static void setEnableBeta(boolean enableBeta) {
method setLastVersion (line 118) | public static void setLastVersion(Context context) {
method getColLandHistory (line 124) | public static int getColLandHistory() {
method getColPortHistory (line 128) | public static int getColPortHistory() {
method getColLandStatus (line 132) | public static int getColLandStatus() {
method getColPortStatus (line 136) | public static int getColPortStatus() {
method isDestroyed (line 140) | public static boolean isDestroyed(Activity activity) {
method getDefaultFileParent (line 144) | @Nullable
method initFilesTree (line 155) | private static void initFilesTree(@NonNull Context context) {
method getClient (line 172) | @Nullable
method getClient (line 177) | @NonNull
method getGalleryWidth (line 183) | public static int getGalleryWidth() {
method initScreenSize (line 187) | public static void initScreenSize(AppCompatActivity activity) {
method initGallerySize (line 194) | private static void initGallerySize() {
method getGalleryHeight (line 199) | public static int getGalleryHeight() {
method getMaxHistory (line 203) | public static int getMaxHistory() {
method isInfiniteScrollMain (line 207) | public static boolean isInfiniteScrollMain() {
method isInfiniteScrollFavorite (line 211) | public static boolean isInfiniteScrollFavorite() {
method initTitleType (line 216) | private static void initTitleType(@NonNull Context context) {
method getDeviceWidth (line 231) | public static int getDeviceWidth(@Nullable Activity activity) {
method getDeviceHeight (line 236) | public static int getDeviceHeight(@Nullable Activity activity) {
method getDeviceMetrics (line 241) | private static void getDeviceMetrics(Activity activity) {
method initFromShared (line 246) | public static void initFromShared(@NonNull Context context) {
method isButtonChangePage (line 298) | public static boolean isButtonChangePage() {
method hideMultitask (line 302) | public static boolean hideMultitask() {
method getLocalSortType (line 306) | public static LocalSortType getLocalSortType() {
method setLocalSortType (line 310) | public static void setLocalSortType(Context context, LocalSortType loc...
method getMirror (line 316) | public static String getMirror() {
method getDownloadPolicy (line 320) | public static DataUsageType getDownloadPolicy() {
method volumeOverride (line 330) | public static boolean volumeOverride() {
method isZoomOneColumn (line 334) | public static boolean isZoomOneColumn() {
method reloadHttpClient (line 338) | public static void reloadHttpClient(@NonNull Context context) {
method initHttpClient (line 357) | private static void initHttpClient(@NonNull Context context) {
method getOffscreenLimit (line 362) | public static int getOffscreenLimit() {
method shouldCheckForUpdates (line 366) | public static boolean shouldCheckForUpdates(Context context) {
method getLogo (line 370) | public static Drawable getLogo(Resources resources) {
method getDefaultZoom (line 374) | public static float getDefaultZoom() {
method getTitleType (line 378) | public static TitleType getTitleType() {
method removeAvoidedGalleries (line 382) | public static boolean removeAvoidedGalleries() {
method getOnlyLanguage (line 386) | @NonNull
method isOnlyTag (line 391) | public static boolean isOnlyTag() {
method isLockScreen (line 395) | public static boolean isLockScreen() {
method getColLandDownload (line 399) | public static int getColLandDownload() {
method getColPortMain (line 403) | public static int getColPortMain() {
method getColLandMain (line 407) | public static int getColLandMain() {
method getColPortDownload (line 411) | public static int getColPortDownload() {
method getColLandFavorite (line 415) | public static int getColLandFavorite() {
method getColPortFavorite (line 419) | public static int getColPortFavorite() {
method isKeepHistory (line 423) | public static boolean isKeepHistory() {
method useRtl (line 427) | public static boolean useRtl() {
method showTitles (line 431) | public static boolean showTitles() {
method getSortType (line 435) | public static SortType getSortType() {
method getColumnCount (line 440) | public static int getColumnCount() {
method getMaxId (line 444) | public static int getMaxId() {
method initStorage (line 448) | public static void initStorage(Context context) {
method updateOnlyLanguage (line 479) | public static void updateOnlyLanguage(@NonNull Context context, @NonNu...
method updateSortType (line 484) | public static void updateSortType(@NonNull Context context, @NonNull S...
method updateColumnCount (line 489) | public static void updateColumnCount(@NonNull Context context, int cou...
method updateMaxId (line 494) | public static void updateMaxId(@NonNull Context context, int id) {
method getStatusBarHeight (line 499) | public static int getStatusBarHeight(Context context) {
method getNavigationBarHeight (line 503) | public static int getNavigationBarHeight(Context context) {
method shareURL (line 507) | public static void shareURL(Context context, String title, String url) {
method shareGallery (line 519) | public static void shareGallery(Context context, GenericGallery galler...
method setTint (line 523) | public static void setTint(Context context, Drawable drawable) {
method loadNotificationChannel (line 528) | private static void loadNotificationChannel(@NonNull Context context) {
method getUsableFolders (line 543) | public static List<File> getUsableFolders(Context context) {
method hasStoragePermission (line 553) | public static boolean hasStoragePermission(Context context) {
method isJPEGCorrupted (line 561) | public static boolean isJPEGCorrupted(String path) {
method findGalleryFolder (line 578) | private static File findGalleryFolder(File directory, int id) {
method findGalleryFolder (line 591) | @Nullable
method findGalleryFolder (line 596) | @Nullable
method initActivity (line 609) | public static void initActivity(AppCompatActivity context) {
method recursiveDelete (line 614) | public static void recursiveDelete(File file) {
method getVersionName (line 625) | @NonNull
method isExternalStorageManager (line 636) | public static boolean isExternalStorageManager() {
method applyFastScroller (line 640) | public static void applyFastScroller(RecyclerView recycler) {
method getLanguageFlag (line 647) | @NonNull
type DataUsageType (line 662) | public enum DataUsageType {NONE, THUMBNAIL, FULL}
FILE: app/src/main/java/com/maxwai/nclientv3/settings/Login.java
class Login (line 18) | public class Login {
method initLogin (line 24) | public static void initLogin(@NonNull Context context) {
method useAccountTag (line 31) | public static boolean useAccountTag() {
method clearOnlineTags (line 35) | public static void clearOnlineTags() {
method addOnlineTag (line 39) | public static void addOnlineTag(Tag tag) {
method removeOnlineTag (line 44) | public static void removeOnlineTag(Tag tag) {
method isLogged (line 48) | public static boolean isLogged(@Nullable Context context) {
method isLogged (line 63) | public static boolean isLogged() {
method getUser (line 68) | public static User getUser() {
method updateUser (line 72) | public static void updateUser(User user) {
method isOnlineTags (line 77) | public static boolean isOnlineTags(Tag tag) {
FILE: app/src/main/java/com/maxwai/nclientv3/settings/NotificationSettings.java
class NotificationSettings (line 17) | public class NotificationSettings {
method NotificationSettings (line 24) | private NotificationSettings(NotificationManagerCompat notificationMan...
method getNotificationId (line 28) | public static int getNotificationId() {
method initializeNotificationManager (line 32) | public static void initializeNotificationManager(Context context) {
method notify (line 38) | public static void notify(Context context, int notificationId, Notific...
method cancel (line 57) | public static void cancel(int notificationId) {
method trimArray (line 62) | private static void trimArray() {
FILE: app/src/main/java/com/maxwai/nclientv3/settings/TagV2.java
class TagV2 (line 15) | @SuppressWarnings({"unused", "UnusedReturnValue"})
method getTagSet (line 21) | public static List<Tag> getTagSet(TagType type) {
method getTagStatus (line 25) | public static List<Tag> getTagStatus(TagStatus status) {
method getQueryString (line 29) | public static String getQueryString(String query, @NonNull Set<Tag> al...
method getListPrefer (line 36) | public static List<Tag> getListPrefer(boolean removeIgnoredGalleries) {
method updateStatus (line 41) | public static TagStatus updateStatus(Tag t) {
method resetAllStatus (line 59) | public static void resetAllStatus() {
method containTag (line 63) | public static boolean containTag(Tag[] tags, Tag t) {
method getStatus (line 69) | public static TagStatus getStatus(Tag tag) {
method maxTagReached (line 74) | public static boolean maxTagReached() {
method updateMinCount (line 78) | public static void updateMinCount(Context context, int min) {
method initMinCount (line 82) | public static void initMinCount(Context context) {
method initSortByName (line 86) | public static void initSortByName(Context context) {
method updateSortByName (line 90) | public static boolean updateSortByName(Context context) {
method isSortedByName (line 95) | public static boolean isSortedByName() {
method getMinCount (line 99) | public static int getMinCount() {
method getAvoidedTags (line 103) | public static String getAvoidedTags() {
FILE: app/src/main/java/com/maxwai/nclientv3/ui/main/PlaceholderFragment.java
class PlaceholderFragment (line 22) | public class PlaceholderFragment extends Fragment {
method newInstance (line 28) | public static PlaceholderFragment newInstance(String statusName) {
method updateColumnCount (line 36) | private void updateColumnCount(boolean landscape) {
method getColumnCount (line 41) | private int getColumnCount(boolean landscape) {
method onConfigurationChanged (line 45) | @Override
method onCreateView (line 55) | @Override
method changeQuery (line 72) | public void changeQuery(String newQuery) {
method changeSort (line 77) | public void changeSort(boolean byTitle) {
method reload (line 81) | public void reload(String query, boolean sortByTitle) {
FILE: app/src/main/java/com/maxwai/nclientv3/ui/main/SectionsPagerAdapter.java
class SectionsPagerAdapter (line 19) | public class SectionsPagerAdapter extends FragmentStateAdapter {
method SectionsPagerAdapter (line 22) | public SectionsPagerAdapter(StatusViewerActivity context) {
method getPageTitle (line 27) | @Nullable
method createFragment (line 34) | @NonNull
method getItemCount (line 40) | @Override
FILE: app/src/main/java/com/maxwai/nclientv3/utility/CSRFGet.java
class CSRFGet (line 11) | public class CSRFGet extends Thread {
method CSRFGet (line 16) | public CSRFGet(@Nullable Response response, String url) {
method run (line 21) | @Override
type Response (line 38) | public interface Response {
method onResponse (line 39) | void onResponse(String token) throws IOException;
method onError (line 41) | default void onError(Exception e) {
FILE: app/src/main/java/com/maxwai/nclientv3/utility/ImageDownloadUtility.java
class ImageDownloadUtility (line 34) | public class ImageDownloadUtility {
method preloadImage (line 38) | public static void preloadImage(Context context, Uri url) {
method loadImageOp (line 45) | public static void loadImageOp(Context context, ImageView view, File f...
method loadImageOp (line 53) | public static void loadImageOp(Context context, ImageView view, Galler...
method downloadPage (line 57) | public static void downloadPage(Activity activity, ImageView imageView...
method loadImageOp (line 62) | public static void loadImageOp(Context context, ImageView imageView, G...
method loadImageOp (line 66) | private static void loadImageOp(Context context, ImageView view, @Null...
method getUrlForGallery (line 128) | private static Uri getUrlForGallery(Gallery gallery, int page, boolean...
method loadLogo (line 132) | private static void loadLogo(ImageView imageView) {
method loadImage (line 136) | public static void loadImage(Activity activity, Uri url, ImageView ima...
method loadImage (line 140) | public static void loadImage(Activity activity, File file, ImageView i...
method loadImage (line 147) | public static void loadImage(@DrawableRes int resource, ImageView imag...
FILE: app/src/main/java/com/maxwai/nclientv3/utility/IntentUtility.java
class IntentUtility (line 6) | public class IntentUtility extends Intent {
method startAnotherActivity (line 8) | public static void startAnotherActivity(Activity activity, Intent inte...
FILE: app/src/main/java/com/maxwai/nclientv3/utility/LogUtility.java
class LogUtility (line 8) | public class LogUtility {
method d (line 12) | public static void d(Object... message) {
method d (line 16) | public static void d(Object message, Throwable throwable) {
method i (line 20) | public static void i(Object... message) {
method i (line 24) | public static void i(Object message, Throwable throwable) {
method w (line 28) | public static void w(Object... message) {
method w (line 32) | public static void w(Object message, Throwable throwable) {
method e (line 36) | public static void e(Object... message) {
method e (line 40) | public static void e(Object message, Throwable throwable) {
method wtf (line 44) | public static void wtf(Object... message) {
method wtf (line 48) | public static void wtf(Object message, Throwable throwable) {
method common (line 52) | private static void common(BiConsumer<String, String> logCall, Object....
method common (line 58) | private static void common(TriConsumer logCall, Object message, Throwa...
type TriConsumer (line 63) | @FunctionalInterface
method accept (line 65) | void accept(String tag, String msg, Throwable tr);
FILE: app/src/main/java/com/maxwai/nclientv3/utility/Utility.java
class Utility (line 33) | public class Utility {
method getBaseUrl (line 37) | public static String getBaseUrl() {
method getApiBaseUrl (line 41) | public static String getApiBaseUrl() {
method getHost (line 45) | public static String getHost() {
method parseEscapedCharacter (line 49) | private static void parseEscapedCharacter(Reader reader, Writer writer...
method unescapeUnicodeString (line 73) | @NonNull
method threadSleep (line 90) | public static void threadSleep(long millis) {
method tintMenu (line 98) | public static void tintMenu(Context context, Menu menu) {
method drawableToBitmap (line 106) | @Nullable
method saveImage (line 112) | public static void saveImage(Drawable drawable, File output) {
method saveImage (line 117) | private static void saveImage(@NonNull Bitmap bitmap, @NonNull File ou...
method writeStreamToFile (line 131) | public static long writeStreamToFile(InputStream inputStream, File fil...
method sendImage (line 146) | public static void sendImage(Context context, Drawable drawable, Strin...
FILE: app/src/main/java/com/maxwai/nclientv3/utility/network/NetworkUtil.java
class NetworkUtil (line 13) | public class NetworkUtil {
method getType (line 16) | public static ConnectionType getType() {
method setType (line 20) | public static void setType(ConnectionType x) {
method getConnectivityPostLollipop (line 25) | private static ConnectionType getConnectivityPostLollipop(Connectivity...
method initConnectivity (line 35) | public static void initConnectivity(@NonNull Context context) {
type ConnectionType (line 63) | public enum ConnectionType {WIFI, CELLULAR}
FILE: scripts/update_tags.py
class TagInfo (line 37) | class TagInfo:
method to_list (line 43) | def to_list(self) -> list[str | int]:
method __eq__ (line 46) | def __eq__(self, other):
method __hash__ (line 51) | def __hash__(self):
method __lt__ (line 54) | def __lt__(self, other):
function make_api_request (line 64) | def make_api_request(url_path: str) -> dict:
function get_tags (line 78) | def get_tags(name, category) -> Generator[TagInfo]:
function main (line 90) | def main():
Copy disabled (too large)
Download .json
Condensed preview — 313 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (10,513K chars).
[
{
"path": ".editorconfig",
"chars": 166,
"preview": "# editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 4\nend_of_line = lf\ninsert_final_n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yaml",
"chars": 1951,
"preview": "name: Bug Report\ndescription: Create a report to help us improve\nlabels: [ \"bug\" ]\nbody:\n - type: checkboxes\n attrib"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 28,
"preview": "blank_issues_enabled: false\n"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.yaml",
"chars": 1213,
"preview": "name: Feature request\ndescription: Suggest an idea for this project\nlabels: [ \"enhancement\" ]\nbody:\n - type: checkboxes"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 1160,
"preview": "A similar PR may already be submitted!\nPlease search among the [Pull request](../) before creating one.\n\nThanks for subm"
},
{
"path": ".github/dependabot.yml",
"chars": 911,
"preview": "version: 2\nupdates:\n # Enable version updates for Gradle\n - package-ecosystem: \"gradle\"\n # Look for a `bu"
},
{
"path": ".github/workflows/android.yml",
"chars": 1357,
"preview": "name: Android CI\n\non:\n push:\n branches:\n - 'main'\n pull_request:\n branches:\n -"
},
{
"path": ".github/workflows/dependencies.yml",
"chars": 1190,
"preview": "name: Dependency Submission\n\non:\n push:\n branches:\n - 'main'\n\npermissions:\n contents: write\n\njob"
},
{
"path": ".github/workflows/update_data.yml",
"chars": 842,
"preview": "name: Update Data\n\non:\n schedule:\n - cron: \"42 1 * * 0\"\n workflow_dispatch:\n\njobs:\n update:\n runs-on: ubuntu-la"
},
{
"path": ".gitignore",
"chars": 195,
"preview": "*.iml\n*.apk\n.gradle\n/local.properties\n.idea/\noutput.json\n.DS_Store\n/build\n/captures\n/svgs\n/app/release\n/app/debug\n/app/s"
},
{
"path": "DCO",
"chars": 1366,
"preview": "Developer Certificate of Origin\nVersion 1.1\n\nCopyright (C) 2004, 2006 The Linux Foundation and its contributors.\n\nEveryo"
},
{
"path": "LICENSE",
"chars": 11336,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 6149,
"preview": "# NClientV3\n\n[](https://github.com/ma"
},
{
"path": "SECURITY.md",
"chars": 1015,
"preview": "# Security Policy\n\n## Supported Versions\n\nOnly the latest version is supported. The `pre28` versions are also not suppor"
},
{
"path": "app/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "app/build.gradle.kts",
"chars": 6115,
"preview": "import com.android.build.api.artifact.SingleArtifact\nimport java.io.FileInputStream\nimport java.util.Properties\nimport c"
},
{
"path": "app/proguard-rules.pro",
"chars": 1361,
"preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
},
{
"path": "app/src/main/AndroidManifest.xml",
"chars": 9182,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:to"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/ApiKeyActivity.java",
"chars": 6551,
"preview": "package com.maxwai.nclientv3;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport a"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/BookmarkActivity.java",
"chars": 1540,
"preview": "package com.maxwai.nclientv3;\n\nimport android.os.Bundle;\nimport android.view.MenuItem;\n\nimport androidx.appcompat.app.Ac"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/CommentActivity.java",
"chars": 5330,
"preview": "package com.maxwai.nclientv3;\n\nimport android.content.res.Configuration;\nimport android.os.Bundle;\nimport android.util.J"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/CopyToClipboardActivity.java",
"chars": 1045,
"preview": "package com.maxwai.nclientv3;\n\nimport android.content.ClipData;\nimport android.content.ClipboardManager;\nimport android."
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/FavoriteActivity.java",
"chars": 5968,
"preview": "package com.maxwai.nclientv3;\n\nimport android.content.Intent;\nimport android.content.res.Configuration;\nimport android.n"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/GalleryActivity.java",
"chars": 20214,
"preview": "package com.maxwai.nclientv3;\n\nimport android.Manifest;\nimport android.content.Intent;\nimport android.content.pm.Package"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/HistoryActivity.java",
"chars": 2410,
"preview": "package com.maxwai.nclientv3;\n\nimport android.content.res.Configuration;\nimport android.os.Bundle;\nimport android.view.M"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/LocalActivity.java",
"chars": 10668,
"preview": "package com.maxwai.nclientv3;\n\nimport android.content.res.Configuration;\nimport android.os.Bundle;\nimport android.view.L"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/MainActivity.java",
"chars": 32188,
"preview": "package com.maxwai.nclientv3;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.content.I"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/PINActivity.java",
"chars": 3207,
"preview": "package com.maxwai.nclientv3;\n\nimport static androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK;\nimport s"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/RandomActivity.java",
"chars": 5280,
"preview": "package com.maxwai.nclientv3;\n\nimport android.content.Intent;\nimport android.content.res.ColorStateList;\nimport android."
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/SearchActivity.java",
"chars": 17221,
"preview": "package com.maxwai.nclientv3;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\n"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/SettingsActivity.java",
"chars": 8619,
"preview": "package com.maxwai.nclientv3;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nim"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/StatusManagerActivity.java",
"chars": 1560,
"preview": "package com.maxwai.nclientv3;\n\nimport android.os.Bundle;\nimport android.view.MenuItem;\n\nimport androidx.appcompat.app.Ac"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/StatusViewerActivity.java",
"chars": 4638,
"preview": "package com.maxwai.nclientv3;\n\nimport android.os.Bundle;\nimport android.view.Menu;\nimport android.view.MenuItem;\n\nimport"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/TagFilterActivity.java",
"chars": 9533,
"preview": "package com.maxwai.nclientv3;\n\nimport android.content.res.Configuration;\nimport android.net.Uri;\nimport android.os.Bundl"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/ZoomActivity.java",
"chars": 17634,
"preview": "package com.maxwai.nclientv3;\n\nimport android.Manifest;\nimport android.animation.Animator;\nimport android.animation.Anim"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/adapters/BookmarkAdapter.java",
"chars": 3540,
"preview": "package com.maxwai.nclientv3.adapters;\n\nimport android.content.Intent;\nimport android.view.LayoutInflater;\nimport androi"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/adapters/CommentAdapter.java",
"chars": 4435,
"preview": "package com.maxwai.nclientv3.adapters;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.vie"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/adapters/FavoriteAdapter.java",
"chars": 7912,
"preview": "package com.maxwai.nclientv3.adapters;\n\nimport android.annotation.SuppressLint;\nimport android.content.Intent;\nimport an"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/adapters/GalleryAdapter.java",
"chars": 15658,
"preview": "package com.maxwai.nclientv3.adapters;\n\nimport android.content.Intent;\nimport android.util.SparseIntArray;\nimport androi"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/adapters/GenericAdapter.java",
"chars": 3762,
"preview": "package com.maxwai.nclientv3.adapters;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.vie"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/adapters/HistoryAdapter.java",
"chars": 4159,
"preview": "package com.maxwai.nclientv3.adapters;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.vie"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/adapters/ListAdapter.java",
"chars": 8980,
"preview": "package com.maxwai.nclientv3.adapters;\n\nimport android.content.Intent;\nimport android.text.Layout;\nimport android.util.S"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/adapters/LocalAdapter.java",
"chars": 22225,
"preview": "package com.maxwai.nclientv3.adapters;\n\nimport android.annotation.SuppressLint;\nimport android.app.Activity;\nimport andr"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/adapters/StatusManagerAdapter.java",
"chars": 6206,
"preview": "package com.maxwai.nclientv3.adapters;\n\nimport android.app.Activity;\nimport android.graphics.Color;\nimport android.view."
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/adapters/StatusViewerAdapter.java",
"chars": 4384,
"preview": "package com.maxwai.nclientv3.adapters;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.datab"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/adapters/TagsAdapter.java",
"chars": 9060,
"preview": "package com.maxwai.nclientv3.adapters;\n\nimport android.database.Cursor;\nimport android.util.JsonWriter;\nimport android.v"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/InspectorV3.java",
"chars": 19010,
"preview": "package com.maxwai.nclientv3.api;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.Parcel;\nim"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/RandomLoader.java",
"chars": 2212,
"preview": "package com.maxwai.nclientv3.api;\n\nimport com.maxwai.nclientv3.RandomActivity;\nimport com.maxwai.nclientv3.api.component"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/SimpleGallery.java",
"chars": 8094,
"preview": "package com.maxwai.nclientv3.api;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport androi"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/comments/Comment.java",
"chars": 2577,
"preview": "package com.maxwai.nclientv3.api.comments;\n\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Parcel;\ni"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/comments/CommentsFetcher.java",
"chars": 2247,
"preview": "package com.maxwai.nclientv3.api.comments;\n\nimport android.util.JsonReader;\nimport android.util.JsonToken;\n\nimport com.m"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/comments/User.java",
"chars": 1990,
"preview": "package com.maxwai.nclientv3.api.comments;\n\nimport android.net.Uri;\nimport android.os.Parcel;\nimport android.os.Parcelab"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/components/Gallery.java",
"chars": 11783,
"preview": "package com.maxwai.nclientv3.api.components;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport and"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/components/GalleryData.java",
"chars": 14615,
"preview": "package com.maxwai.nclientv3.api.components;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport and"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/components/GenericGallery.java",
"chars": 1066,
"preview": "package com.maxwai.nclientv3.api.components;\n\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\n\nimport"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/components/Page.java",
"chars": 4109,
"preview": "package com.maxwai.nclientv3.api.components;\n\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Parcel;"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/components/Ranges.java",
"chars": 3986,
"preview": "package com.maxwai.nclientv3.api.components;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.a"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/components/Tag.java",
"chars": 5456,
"preview": "package com.maxwai.nclientv3.api.components;\n\n\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parc"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/components/TagList.java",
"chars": 2527,
"preview": "package com.maxwai.nclientv3.api.components;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport com.maxwai"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/enums/ApiRequestType.java",
"chars": 1460,
"preview": "package com.maxwai.nclientv3.api.enums;\n\npublic class ApiRequestType {\n public static final ApiRequestType BYALL = ne"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/enums/ImageType.java",
"chars": 94,
"preview": "package com.maxwai.nclientv3.api.enums;\n\npublic enum ImageType {\n PAGE, COVER, THUMBNAIL\n}\n"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/enums/Language.java",
"chars": 748,
"preview": "package com.maxwai.nclientv3.api.enums;\n\nimport com.maxwai.nclientv3.R;\n\nimport java.util.Arrays;\n\npublic enum Language "
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/enums/SortType.java",
"chars": 1204,
"preview": "package com.maxwai.nclientv3.api.enums;\n\nimport androidx.annotation.Nullable;\n\nimport com.maxwai.nclientv3.R;\n\npublic en"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/enums/SpecialTagIds.java",
"chars": 287,
"preview": "package com.maxwai.nclientv3.api.enums;\n\npublic class SpecialTagIds {\n public static final short LANGUAGE_JAPANESE = "
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/enums/TagStatus.java",
"chars": 98,
"preview": "package com.maxwai.nclientv3.api.enums;\n\npublic enum TagStatus {\n DEFAULT, AVOIDED, ACCEPTED\n}\n"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/enums/TagType.java",
"chars": 2533,
"preview": "package com.maxwai.nclientv3.api.enums;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annota"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/enums/TitleType.java",
"chars": 97,
"preview": "package com.maxwai.nclientv3.api.enums;\n\npublic enum TitleType {\n JAPANESE, PRETTY, ENGLISH\n}\n"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/local/FakeInspector.java",
"chars": 2213,
"preview": "package com.maxwai.nclientv3.api.local;\n\nimport com.maxwai.nclientv3.LocalActivity;\nimport com.maxwai.nclientv3.adapters"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/local/LocalGallery.java",
"chars": 7416,
"preview": "package com.maxwai.nclientv3.api.local;\n\nimport android.graphics.BitmapFactory;\nimport android.os.Build;\nimport android."
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/api/local/LocalSortType.java",
"chars": 1408,
"preview": "package com.maxwai.nclientv3.api.local;\n\nimport androidx.annotation.NonNull;\n\npublic class LocalSortType {\n public st"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/MetadataFetcher.java",
"chars": 1597,
"preview": "package com.maxwai.nclientv3.async;\n\nimport android.content.Context;\n\nimport com.maxwai.nclientv3.api.InspectorV3;\nimpor"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/ScrapeTags.java",
"chars": 5314,
"preview": "package com.maxwai.nclientv3.async;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\nimport a"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/VersionChecker.java",
"chars": 14868,
"preview": "package com.maxwai.nclientv3.async;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.con"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/converters/CreatePdfOrZip.java",
"chars": 10885,
"preview": "package com.maxwai.nclientv3.async.converters;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/database/DatabaseHelper.java",
"chars": 7406,
"preview": "package com.maxwai.nclientv3.async.database;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nim"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/database/Queries.java",
"chars": 46462,
"preview": "package com.maxwai.nclientv3.async.database;\n\nimport android.annotation.SuppressLint;\nimport android.content.ContentValu"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/database/export/Exporter.java",
"chars": 6811,
"preview": "package com.maxwai.nclientv3.async.database.export;\n\nimport android.content.Context;\nimport android.content.SharedPrefer"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/database/export/Importer.java",
"chars": 4879,
"preview": "package com.maxwai.nclientv3.async.database.export;\n\nimport android.content.ContentValues;\nimport android.content.Contex"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/database/export/Manager.java",
"chars": 956,
"preview": "package com.maxwai.nclientv3.async.database.export;\n\nimport android.net.Uri;\n\nimport androidx.annotation.NonNull;\n\nimpor"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/downloader/DownloadGalleryV2.java",
"chars": 3890,
"preview": "package com.maxwai.nclientv3.async.downloader;\n\nimport android.content.Context;\nimport android.net.Uri;\n\nimport androidx"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/downloader/DownloadObserver.java",
"chars": 427,
"preview": "package com.maxwai.nclientv3.async.downloader;\n\npublic interface DownloadObserver {\n void triggerStartDownload(Galler"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/downloader/DownloadQueue.java",
"chars": 2663,
"preview": "package com.maxwai.nclientv3.async.downloader;\n\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/downloader/GalleryDownloaderManager.java",
"chars": 5202,
"preview": "package com.maxwai.nclientv3.async.downloader;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/downloader/GalleryDownloaderV2.java",
"chars": 11629,
"preview": "package com.maxwai.nclientv3.async.downloader;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport a"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/async/downloader/PageChecker.java",
"chars": 252,
"preview": "package com.maxwai.nclientv3.async.downloader;\n\npublic class PageChecker extends Thread {\n @Override\n public void "
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/CookieInterceptor.java",
"chars": 3218,
"preview": "package com.maxwai.nclientv3.components;\n\nimport android.view.View;\nimport android.webkit.CookieManager;\n\nimport android"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/CustomCookieJar.java",
"chars": 2654,
"preview": "package com.maxwai.nclientv3.components;\n\nimport androidx.annotation.NonNull;\n\nimport com.franmontiel.persistentcookieja"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/GlideX.java",
"chars": 691,
"preview": "package com.maxwai.nclientv3.components;\n\nimport android.content.Context;\nimport android.view.View;\n\nimport androidx.ann"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/ThreadAsyncTask.java",
"chars": 1432,
"preview": "package com.maxwai.nclientv3.components;\n\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.maxwai.nclientv3."
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/activities/BaseActivity.java",
"chars": 1916,
"preview": "package com.maxwai.nclientv3.components.activities;\n\nimport android.content.res.Configuration;\nimport android.view.ViewG"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/activities/CrashApplication.java",
"chars": 4616,
"preview": "package com.maxwai.nclientv3.components.activities;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/activities/GeneralActivity.java",
"chars": 2824,
"preview": "package com.maxwai.nclientv3.components.activities;\n\nimport android.content.SharedPreferences;\nimport android.content.re"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/classes/Bookmark.java",
"chars": 2768,
"preview": "package com.maxwai.nclientv3.components.classes;\n\nimport android.content.Context;\nimport android.net.Uri;\n\nimport androi"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/classes/History.java",
"chars": 1556,
"preview": "package com.maxwai.nclientv3.components.classes;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.Ha"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/classes/MultichoiceAdapter.java",
"chars": 7142,
"preview": "package com.maxwai.nclientv3.components.classes;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport a"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/classes/Size.java",
"chars": 1368,
"preview": "package com.maxwai.nclientv3.components.classes;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androi"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/launcher/LauncherCalculator.java",
"chars": 87,
"preview": "package com.maxwai.nclientv3.components.launcher;\n\npublic class LauncherCalculator {\n}\n"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/launcher/LauncherReal.java",
"chars": 81,
"preview": "package com.maxwai.nclientv3.components.launcher;\n\npublic class LauncherReal {\n}\n"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/status/Status.java",
"chars": 402,
"preview": "package com.maxwai.nclientv3.components.status;\n\nimport android.graphics.Color;\n\npublic class Status {\n public final "
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/status/StatusManager.java",
"chars": 1818,
"preview": "package com.maxwai.nclientv3.components.status;\n\nimport androidx.annotation.Nullable;\n\nimport com.maxwai.nclientv3.async"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/views/CFTokenView.java",
"chars": 2857,
"preview": "package com.maxwai.nclientv3.components.views;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\n"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/views/GeneralPreferenceFragment.java",
"chars": 24141,
"preview": "package com.maxwai.nclientv3.components.views;\n\nimport static androidx.biometric.BiometricManager.Authenticators.BIOMETR"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/views/PageSwitcher.java",
"chars": 4499,
"preview": "package com.maxwai.nclientv3.components.views;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport andr"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/views/RangeSelector.java",
"chars": 3018,
"preview": "package com.maxwai.nclientv3.components.views;\n\nimport android.content.Context;\nimport android.view.View;\nimport android"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/views/ZoomFragment.java",
"chars": 9593,
"preview": "package com.maxwai.nclientv3.components.views;\n\nimport static com.bumptech.glide.request.target.Target.SIZE_ORIGINAL;\n\ni"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/widgets/ChipTag.java",
"chars": 2389,
"preview": "package com.maxwai.nclientv3.components.widgets;\n\nimport android.content.Context;\nimport android.graphics.drawable.Drawa"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/widgets/CustomGridLayoutManager.java",
"chars": 621,
"preview": "package com.maxwai.nclientv3.components.widgets;\n\nimport android.content.Context;\n\nimport androidx.recyclerview.widget.G"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/widgets/CustomImageView.java",
"chars": 1608,
"preview": "package com.maxwai.nclientv3.components.widgets;\n\nimport android.content.Context;\nimport android.graphics.Matrix;\nimport"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/widgets/CustomLinearLayoutManager.java",
"chars": 399,
"preview": "package com.maxwai.nclientv3.components.widgets;\n\nimport android.content.Context;\n\nimport androidx.recyclerview.widget.L"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/widgets/CustomSearchView.java",
"chars": 1020,
"preview": "package com.maxwai.nclientv3.components.widgets;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\n\nimp"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/widgets/CustomSwipe.java",
"chars": 850,
"preview": "package com.maxwai.nclientv3.components.widgets;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\n\nimp"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/components/widgets/TagTypePage.java",
"chars": 3487,
"preview": "package com.maxwai.nclientv3.components.widgets;\n\nimport android.app.Activity;\nimport android.content.res.Configuration;"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/files/GalleryFolder.java",
"chars": 6334,
"preview": "package com.maxwai.nclientv3.files;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.Parcel;\n"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/files/PageFile.java",
"chars": 1109,
"preview": "package com.maxwai.nclientv3.files;\n\nimport android.net.Uri;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nim"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/Compat.java",
"chars": 931,
"preview": "/*\n Copyright 2011, 2012 Chris Banes.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/CustomGestureDetector.java",
"chars": 7798,
"preview": "/*\n Copyright 2011, 2012 Chris Banes.\n <p/>\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may no"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnGestureListener.java",
"chars": 951,
"preview": "/*\n Copyright 2011, 2012 Chris Banes.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnMatrixChangedListener.java",
"chars": 541,
"preview": "package com.maxwai.nclientv3.github.chrisbanes.photoview;\n\nimport android.graphics.RectF;\n\n/**\n * Interface definition f"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnOutsidePhotoTapListener.java",
"chars": 316,
"preview": "package com.maxwai.nclientv3.github.chrisbanes.photoview;\n\nimport android.widget.ImageView;\n\n/**\n * Callback when the us"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnPhotoTapListener.java",
"chars": 772,
"preview": "package com.maxwai.nclientv3.github.chrisbanes.photoview;\n\nimport android.widget.ImageView;\n\n/**\n * A callback to be inv"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnScaleChangedListener.java",
"chars": 535,
"preview": "package com.maxwai.nclientv3.github.chrisbanes.photoview;\n\n\n/**\n * Interface definition for callback to be invoked when "
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnSingleFlingListener.java",
"chars": 712,
"preview": "package com.maxwai.nclientv3.github.chrisbanes.photoview;\n\nimport android.view.MotionEvent;\n\n/**\n * A callback to be inv"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnViewDragListener.java",
"chars": 518,
"preview": "package com.maxwai.nclientv3.github.chrisbanes.photoview;\n\n/**\n * Interface definition for a callback to be invoked when"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/OnViewTapListener.java",
"chars": 564,
"preview": "package com.maxwai.nclientv3.github.chrisbanes.photoview;\n\nimport android.view.View;\n\npublic interface OnViewTapListener"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/PhotoView.java",
"chars": 7324,
"preview": "/*\n Copyright 2011, 2012 Chris Banes.\n <p>\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/PhotoViewAttacher.java",
"chars": 29919,
"preview": "/*\n Copyright 2011, 2012 Chris Banes.\n <p>\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/github/chrisbanes/photoview/Util.java",
"chars": 1268,
"preview": "package com.maxwai.nclientv3.github.chrisbanes.photoview;\n\nimport android.view.MotionEvent;\nimport android.widget.ImageV"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/loginapi/LoadTags.java",
"chars": 1966,
"preview": "package com.maxwai.nclientv3.loginapi;\n\nimport android.content.Context;\nimport android.util.JsonReader;\nimport android.u"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/loginapi/User.java",
"chars": 2384,
"preview": "package com.maxwai.nclientv3.loginapi;\n\nimport android.content.Context;\nimport android.util.JsonReader;\nimport android.u"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/settings/ApiAuthInterceptor.java",
"chars": 1968,
"preview": "package com.maxwai.nclientv3.settings;\n\nimport android.content.Context;\nimport android.webkit.CookieManager;\n\nimport and"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/settings/AuthCredentials.java",
"chars": 626,
"preview": "package com.maxwai.nclientv3.settings;\n\nimport androidx.annotation.NonNull;\n\npublic final class AuthCredentials {\n pu"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/settings/AuthStore.java",
"chars": 3272,
"preview": "package com.maxwai.nclientv3.settings;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\nimpor"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/settings/Database.java",
"chars": 736,
"preview": "package com.maxwai.nclientv3.settings;\n\nimport android.database.sqlite.SQLiteDatabase;\n\nimport androidx.annotation.Nulla"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/settings/DefaultDialogs.java",
"chars": 6039,
"preview": "package com.maxwai.nclientv3.settings;\n\nimport android.content.Context;\nimport android.text.Editable;\nimport android.tex"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/settings/Favorites.java",
"chars": 682,
"preview": "package com.maxwai.nclientv3.settings;\n\nimport com.maxwai.nclientv3.api.components.Gallery;\nimport com.maxwai.nclientv3."
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/settings/Global.java",
"chars": 26203,
"preview": "package com.maxwai.nclientv3.settings;\n\nimport android.Manifest;\nimport android.app.Activity;\nimport android.app.Notific"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/settings/Login.java",
"chars": 2358,
"preview": "package com.maxwai.nclientv3.settings;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\nimpor"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/settings/NotificationSettings.java",
"chars": 2896,
"preview": "package com.maxwai.nclientv3.settings;\n\nimport android.Manifest;\nimport android.app.Notification;\nimport android.content"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/settings/TagV2.java",
"chars": 3504,
"preview": "package com.maxwai.nclientv3.settings;\n\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\n\nimport com"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/ui/main/PlaceholderFragment.java",
"chars": 3008,
"preview": "package com.maxwai.nclientv3.ui.main;\n\nimport android.content.res.Configuration;\nimport android.os.Bundle;\nimport androi"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/ui/main/SectionsPagerAdapter.java",
"chars": 1329,
"preview": "package com.maxwai.nclientv3.ui.main;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport a"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/utility/CSRFGet.java",
"chars": 1317,
"preview": "package com.maxwai.nclientv3.utility;\n\nimport androidx.annotation.Nullable;\n\nimport com.maxwai.nclientv3.settings.Global"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/utility/ImageDownloadUtility.java",
"chars": 6641,
"preview": "package com.maxwai.nclientv3.utility;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.graph"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/utility/IntentUtility.java",
"chars": 304,
"preview": "package com.maxwai.nclientv3.utility;\n\nimport android.app.Activity;\nimport android.content.Intent;\n\npublic class IntentU"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/utility/LogUtility.java",
"chars": 1858,
"preview": "package com.maxwai.nclientv3.utility;\n\nimport android.util.Log;\n\nimport java.util.Arrays;\nimport java.util.function.BiCo"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/utility/Utility.java",
"chars": 6193,
"preview": "package com.maxwai.nclientv3.utility;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.con"
},
{
"path": "app/src/main/java/com/maxwai/nclientv3/utility/network/NetworkUtil.java",
"chars": 2397,
"preview": "package com.maxwai.nclientv3.utility.network;\n\nimport android.content.Context;\nimport android.net.ConnectivityManager;\ni"
},
{
"path": "app/src/main/res/drawable/ic_access_time.xml",
"chars": 600,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_add.xml",
"chars": 349,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_archive.xml",
"chars": 572,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_arrow_back.xml",
"chars": 376,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_arrow_forward.xml",
"chars": 372,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_backspace.xml",
"chars": 557,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_bookmark.xml",
"chars": 384,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_bookmark_border.xml",
"chars": 420,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_burst_mode.xml",
"chars": 496,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_chat_bubble.xml",
"chars": 393,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_check.xml",
"chars": 364,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_check_circle.xml",
"chars": 480,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_close.xml",
"chars": 415,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_cnbw.xml",
"chars": 2679,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"200dp\"\n android:height=\"133.13d"
},
{
"path": "app/src/main/res/drawable/ic_content_copy.xml",
"chars": 477,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_delete.xml",
"chars": 441,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_exit_to_app.xml",
"chars": 496,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_favorite.xml",
"chars": 493,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_favorite_border.xml",
"chars": 673,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_filter_list.xml",
"chars": 369,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_find_in_page.xml",
"chars": 609,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_folder.xml",
"chars": 421,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_gbbw.xml",
"chars": 5049,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_hashtag.xml",
"chars": 515,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_help.xml",
"chars": 625,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_jpbw.xml",
"chars": 570,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"200dp\"\n android:height=\"100dp\"\n"
},
{
"path": "app/src/main/res/drawable/ic_keyboard_arrow_left.xml",
"chars": 372,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_keyboard_arrow_right.xml",
"chars": 371,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_launcher_calculator_foreground.xml",
"chars": 819,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"108dp\"\n android:height=\"108dp\"\n"
},
{
"path": "app/src/main/res/drawable/ic_launcher_foreground.xml",
"chars": 2411,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/src/main/res/drawable/ic_logo.xml",
"chars": 2237,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/src/main/res/drawable/ic_mode_edit.xml",
"chars": 448,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_pause.xml",
"chars": 353,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_pdf.xml",
"chars": 759,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_person.xml",
"chars": 439,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_play.xml",
"chars": 328,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_refresh.xml",
"chars": 532,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_rotate_90_degrees.xml",
"chars": 692,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_save.xml",
"chars": 482,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_search.xml",
"chars": 562,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_select_all.xml",
"chars": 728,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_settings.xml",
"chars": 1218,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_share.xml",
"chars": 745,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_shuffle.xml",
"chars": 499,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_sort.xml",
"chars": 370,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_sort_by_alpha.xml",
"chars": 567,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_star.xml",
"chars": 405,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_star_border.xml",
"chars": 517,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_view_1.xml",
"chars": 344,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_view_2.xml",
"chars": 920,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_view_3.xml",
"chars": 421,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_view_4.xml",
"chars": 525,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/src/main/res/drawable/ic_void.xml",
"chars": 367,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
}
]
// ... and 113 more files (download for full content)
About this extraction
This page contains the full source code of the maxwai/NClientV3 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 313 files (9.1 MB), approximately 2.4M tokens, and a symbol index with 1690 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.