├── .github ├── CODEOWNERS ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── --bug-report.yml │ └── --feature-request.yml ├── PULL_REQUEST_TEMPLATE │ ├── general_template.md │ └── translations_template.md ├── pull_request_template.md └── workflows │ ├── android.yml │ └── release.yml ├── .gitignore ├── .idea ├── .gitignore ├── AndroidProjectSystem.xml ├── appInsightsSettings.xml ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── compiler.xml ├── deploymentTargetDropDown.xml ├── deploymentTargetSelector.xml ├── gradle.xml ├── inspectionProfiles │ └── Project_Default.xml ├── jarRepositories.xml ├── kotlinc.xml ├── migrations.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── schemas │ └── com.starry.myne.database.MyneDatabase │ │ ├── 1.json │ │ ├── 2.json │ │ ├── 3.json │ │ ├── 4.json │ │ └── 5.json └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── starry │ │ └── myne │ │ └── ExampleInstrumentedTest.kt │ ├── debug │ ├── ic_launcher-playstore.png │ └── res │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── resources.properties │ │ └── values │ │ └── ic_launcher_background.xml │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-playstore.png │ ├── java │ │ └── com │ │ │ └── starry │ │ │ └── myne │ │ │ ├── MainActivity.kt │ │ │ ├── MainViewModel.kt │ │ │ ├── MyneApp.kt │ │ │ ├── api │ │ │ ├── BookAPI.kt │ │ │ ├── CacheInterceptor.kt │ │ │ └── models │ │ │ │ ├── Author.kt │ │ │ │ ├── Book.kt │ │ │ │ ├── BookSet.kt │ │ │ │ ├── ExtraInfo.kt │ │ │ │ ├── Formats.kt │ │ │ │ └── Translator.kt │ │ │ ├── database │ │ │ ├── MyneDatabase.kt │ │ │ ├── library │ │ │ │ ├── LibraryDao.kt │ │ │ │ └── LibraryItem.kt │ │ │ └── progress │ │ │ │ ├── ProgressDao.kt │ │ │ │ └── ProgressData.kt │ │ │ ├── di │ │ │ └── MainModule.kt │ │ │ ├── epub │ │ │ ├── BookTextMapper.kt │ │ │ ├── EpubParser.kt │ │ │ ├── EpubParserException.kt │ │ │ ├── EpubUtils.kt │ │ │ ├── EpubXMLFileParser.kt │ │ │ ├── cache │ │ │ │ ├── BitmapSerializer.kt │ │ │ │ ├── EpubCache.kt │ │ │ │ └── epub_cache.proto │ │ │ └── models │ │ │ │ ├── EpubBook.kt │ │ │ │ ├── EpubChapter.kt │ │ │ │ └── EpubImage.kt │ │ │ ├── helpers │ │ │ ├── Constants.kt │ │ │ ├── Extensions.kt │ │ │ ├── NetworkObserver.kt │ │ │ ├── Paginator.kt │ │ │ ├── Preferencesutils.kt │ │ │ ├── Utils.kt │ │ │ └── book │ │ │ │ ├── BookDownloader.kt │ │ │ │ ├── BookLanguage.kt │ │ │ │ └── BookUtils.kt │ │ │ └── ui │ │ │ ├── common │ │ │ ├── BookDetailTopUI.kt │ │ │ ├── BookItemCard.kt │ │ │ ├── BookLanguageSheeet.kt │ │ │ ├── MyneTextSelectionContainer.kt │ │ │ ├── NetworkError.kt │ │ │ ├── NoBooksAvailable.kt │ │ │ ├── ProgressDots.kt │ │ │ ├── SlideInContainer.kt │ │ │ ├── TopAppBars.kt │ │ │ ├── VerticalScrollbar.kt │ │ │ └── placeholder │ │ │ │ ├── PlaceHolder.kt │ │ │ │ └── PlaceholderHighlight.kt │ │ │ ├── navigation │ │ │ ├── BottomBarScreen.kt │ │ │ ├── NavAnimation.kt │ │ │ ├── NavGraph.kt │ │ │ └── Screens.kt │ │ │ ├── screens │ │ │ ├── categories │ │ │ │ ├── composables │ │ │ │ │ ├── BookCategories.kt │ │ │ │ │ ├── CategoriesScreen.kt │ │ │ │ │ └── CategoryDetailScreen.kt │ │ │ │ └── viewmodels │ │ │ │ │ └── CategoryViewModel.kt │ │ │ ├── detail │ │ │ │ ├── composables │ │ │ │ │ └── BookDetailScreen.kt │ │ │ │ └── viewmodels │ │ │ │ │ └── BookDetailViewModel.kt │ │ │ ├── home │ │ │ │ ├── composables │ │ │ │ │ └── HomeScreen.kt │ │ │ │ └── viewmodels │ │ │ │ │ └── HomeViewModel.kt │ │ │ ├── library │ │ │ │ ├── composables │ │ │ │ │ └── LibraryScreen.kt │ │ │ │ └── viewmodels │ │ │ │ │ └── LibraryViewModel.kt │ │ │ ├── main │ │ │ │ └── MainScreen.kt │ │ │ ├── reader │ │ │ │ ├── detail │ │ │ │ │ ├── ReaderDetailScreen.kt │ │ │ │ │ └── ReaderDetailViewModel.kt │ │ │ │ └── main │ │ │ │ │ ├── activities │ │ │ │ │ └── ReaderActivity.kt │ │ │ │ │ ├── composables │ │ │ │ │ ├── ChaptersContent.kt │ │ │ │ │ ├── ChaptersDrawer.kt │ │ │ │ │ ├── ReaderBottomBar.kt │ │ │ │ │ └── ReaderScreen.kt │ │ │ │ │ └── viewmodel │ │ │ │ │ ├── ReaderFont.kt │ │ │ │ │ └── ReaderViewModel.kt │ │ │ ├── settings │ │ │ │ ├── composables │ │ │ │ │ ├── AboutScreen.kt │ │ │ │ │ ├── OSLScreen.kt │ │ │ │ │ ├── SettingsItems.kt │ │ │ │ │ └── SettingsScreen.kt │ │ │ │ └── viewmodels │ │ │ │ │ └── SettingsViewModel.kt │ │ │ └── welcome │ │ │ │ ├── composables │ │ │ │ └── WelcomeScreen.kt │ │ │ │ └── viewmodels │ │ │ │ ├── WelcomeDataStore.kt │ │ │ │ └── WelcomeViewModel.kt │ │ │ └── theme │ │ │ ├── Color.kt │ │ │ ├── Theme.kt │ │ │ └── Type.kt │ └── res │ │ ├── drawable │ │ ├── about_screen_bg.jpg │ │ ├── book_details_bg.jpg │ │ ├── book_reader_bg.jpg │ │ ├── github_pfp.jpg │ │ ├── ic_book_downloads.xml │ │ ├── ic_book_language.xml │ │ ├── ic_book_pages.xml │ │ ├── ic_github_logo.xml │ │ ├── ic_info.xml │ │ ├── ic_info_white.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── ic_launcher_monochrome.xml │ │ ├── ic_library_external_item.xml │ │ ├── ic_library_item.xml │ │ ├── ic_library_read.xml │ │ ├── ic_nav_categories.xml │ │ ├── ic_nav_home.xml │ │ ├── ic_nav_library.xml │ │ ├── ic_nav_settings.xml │ │ ├── ic_no_internet.xml │ │ ├── ic_osi_logo.xml │ │ ├── ic_reader_cat.xml │ │ ├── ic_reader_error.xml │ │ ├── ic_reader_fab_button.xml │ │ ├── ic_reader_font.xml │ │ ├── ic_reader_text_minus.xml │ │ ├── ic_reader_text_plus.xml │ │ ├── ic_reader_text_size.xml │ │ ├── ic_right_arrow.xml │ │ ├── ic_search.xml │ │ ├── ic_settings_google_api.xml │ │ ├── ic_settings_reader.xml │ │ ├── ic_share.xml │ │ ├── ic_share_white.xml │ │ ├── ic_splash_screen.xml │ │ ├── ic_telegram_logo.xml │ │ └── placeholder_cat.jpeg │ │ ├── font │ │ ├── opendyslexic_regular.otf │ │ ├── pacifico_regular.ttf │ │ ├── poppins_black.ttf │ │ ├── poppins_bold.ttf │ │ ├── poppins_extrabold.ttf │ │ ├── poppins_extralight.ttf │ │ ├── poppins_light.ttf │ │ ├── poppins_medium.ttf │ │ ├── poppins_regular.ttf │ │ ├── poppins_semibold.ttf │ │ ├── poppins_thin.ttf │ │ └── reader_inter_font.ttf │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── raw │ │ ├── no_internet_lottie.json │ │ ├── no_library_items_lottie.json │ │ ├── synopis_not_found_lottie.json │ │ └── welcome_lottie.json │ │ ├── resources.properties │ │ ├── values-ar │ │ └── strings.xml │ │ ├── values-bn │ │ └── strings.xml │ │ ├── values-cs │ │ └── strings.xml │ │ ├── values-de │ │ └── strings.xml │ │ ├── values-es │ │ └── strings.xml │ │ ├── values-hi │ │ └── strings.xml │ │ ├── values-it │ │ └── strings.xml │ │ ├── values-night │ │ ├── splash.xml │ │ └── themes.xml │ │ ├── values-pt-rBR │ │ └── strings.xml │ │ ├── values-ro │ │ └── strings.xml │ │ ├── values-ru │ │ └── strings.xml │ │ ├── values-tr │ │ └── strings.xml │ │ ├── values-zh-rCN │ │ └── strings.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── ic_launcher_background.xml │ │ ├── splash.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ ├── data_extraction_rules.xml │ │ └── provider_paths.xml │ └── test │ ├── java │ └── com │ │ └── starry │ │ └── myne │ │ ├── BookTextMapperTest.kt │ │ ├── BookUtilsTest.kt │ │ ├── EpubParserTest.kt │ │ ├── EpubXMLFileParserTest.kt │ │ ├── PaginatorTest.kt │ │ └── UtilsTest.kt │ └── resources │ └── The+Idiot.epub ├── build.gradle ├── fastlane └── metadata │ └── android │ ├── cs-CZ │ ├── full_description.txt │ ├── short_description.txt │ └── title.txt │ ├── en-US │ ├── changelogs │ │ ├── 1.txt │ │ ├── 11.txt │ │ ├── 12.txt │ │ ├── 13.txt │ │ ├── 14.txt │ │ ├── 15.txt │ │ ├── 16.txt │ │ ├── 17.txt │ │ ├── 18.txt │ │ ├── 19.txt │ │ ├── 2.txt │ │ ├── 20.txt │ │ ├── 21.txt │ │ ├── 22.txt │ │ ├── 23.txt │ │ ├── 290.txt │ │ ├── 3.txt │ │ ├── 300.txt │ │ ├── 310.txt │ │ ├── 320.txt │ │ ├── 325.txt │ │ ├── 330.txt │ │ ├── 340.txt │ │ ├── 350.txt │ │ ├── 351.txt │ │ ├── 360.txt │ │ ├── 370.txt │ │ ├── 380.txt │ │ ├── 390.txt │ │ ├── 391.txt │ │ ├── 4.txt │ │ ├── 400.txt │ │ ├── 410.txt │ │ ├── 420.txt │ │ ├── 421.txt │ │ ├── 430.txt │ │ ├── 440.txt │ │ ├── 450.txt │ │ ├── 5.txt │ │ ├── 7.txt │ │ ├── 8.txt │ │ └── 9.txt │ ├── full_description.txt │ ├── images │ │ ├── icon.png │ │ └── phoneScreenshots │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ └── 6.png │ ├── short_description.txt │ └── title.txt │ └── ro │ ├── full_description.txt │ ├── short_description.txt │ └── title.txt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── legal └── PRIVACY-POLICY.md └── settings.gradle /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in Myne 2 | * @starry-shivam 3 | 4 | # Dot-files are handled by the lead dev (.gitignore and co) 5 | .* @starry-shivam -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [starry-shivam] 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--bug-report.yml: -------------------------------------------------------------------------------- 1 | # TODO: Change info of issue guide. 2 | name: "\U0001F41E Bug report" 3 | description: Create a bug report to help us improve. 4 | title: "[Bug]: " 5 | labels: ["\U0001F41E bug"] 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Please do your best to search for duplicate issues before filing a new issue so we can keep our issue board clean. 11 | - type: textarea 12 | attributes: 13 | label: Steps to reproduce 14 | description: Steps to reproduce the behaviour. 15 | placeholder: | 16 | 1. Click on... 17 | 2. Go to... 18 | 3. Go back... 19 | 4. Observe... 20 | validations: 21 | required: true 22 | - type: textarea 23 | attributes: 24 | label: Expected behaviour 25 | placeholder: Files successfully downloads... 26 | validations: 27 | required: true 28 | - type: textarea 29 | attributes: 30 | label: Actual behaviour 31 | placeholder: The app closes unexpectedly... 32 | validations: 33 | required: true 34 | - type: markdown 35 | attributes: 36 | value: | 37 | # Device information 38 | - type: input 39 | attributes: 40 | label: Device name 41 | description: The name of the device model and manufacturer. 42 | placeholder: Google Pixel 6 43 | validations: 44 | required: false 45 | - type: input 46 | attributes: 47 | label: Android version 48 | description: You can find the Android version information in the About section of your device's system settings. 49 | placeholder: Android 13 50 | validations: 51 | required: true 52 | - type: input 53 | attributes: 54 | label: Myne version 55 | description: You can find this information in Settings -> About -> Version. 56 | placeholder: 1.0.0 57 | validations: 58 | required: true 59 | - type: textarea 60 | attributes: 61 | label: Device logs 62 | description: | 63 | Device logs or crash information can greatly aid in debugging. You can find some details here on how to [retrieve device logs or crash IDs][log]. 64 | 65 | [log]: https://github.com/mozilla-mobile/fenix/wiki/Logging-Crash-Information 66 | validations: 67 | required: false 68 | - type: textarea 69 | attributes: 70 | label: Additional information 71 | description: | 72 | If you have any additional information for us, use the field below. 73 | Please note, you can attach screenshots or screen recordings here, by 74 | dragging and dropping files in the field below. 75 | validations: 76 | required: false 77 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--feature-request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Suggest a new feature or UI/UX enhancements. 3 | title: "[Feature Request]" 4 | labels: [enhancement] 5 | body: 6 | - type: checkboxes 7 | id: checklist 8 | attributes: 9 | label: Checklist 10 | description: | 11 | Even if you're not sure about the answer, feel free to leave it blank and provide us with more information about this request. 12 | options: 13 | - label: This issue contains only one feature request. I will open one issue for every feature I want to request. 14 | required: true 15 | - label: I checked, but didn't find any duplicates (open OR closed) of this issue in the repo. 16 | required: true 17 | - label: This feature is merely an UI/UX update. 18 | required: false 19 | - label: This feature is not going to conflict with many of the existing features/options. 20 | required: true 21 | - type: textarea 22 | id: description_1 23 | attributes: 24 | label: Is your feature request related to a problem? Please describe. 25 | description: 26 | placeholder: A clear and concise description of what the problem is. E.g. I'm always frustrated when [...] 27 | validations: 28 | required: true 29 | - type: textarea 30 | id: description_2 31 | attributes: 32 | label: Describe the solution you'd like 33 | description: 34 | placeholder: A clear and concise description of what you want to happen. 35 | validations: 36 | required: true 37 | - type: textarea 38 | id: description_3 39 | attributes: 40 | label: How will you/everyone benefit from this feature? 41 | description: 42 | placeholder: 43 | validations: 44 | required: true 45 | - type: textarea 46 | id: description_4 47 | attributes: 48 | label: Additional context 49 | description: 50 | placeholder: Add any other context or screenshots about the feature request here. 51 | validations: 52 | required: false 53 | render: shell 54 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/general_template.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | 4 | ### Related Issue 5 | 6 | 7 | 8 | 9 | 10 | ## Type of change 11 | 12 | 13 | ### Pull Request checklist 14 | 15 | - [ ] The commit message uses the [conventional commiting method][conv-commits]. 16 | - [ ] Made sure that your PR is not duplicate 17 | - [ ] **Tests**: This PR includes thorough tests or an explanation of why it does not (for bug fixes/features). Your PR should pass all CI checks in our Gtihub Actions [Workflow](https://github.com/Pool-Of-Tears/Myne/actions) 18 | - [ ] **Screenshots**: This PR includes screenshots or GIFs of the changes made or an explanation of why it does not (*optional*) 19 | 20 | [conv-commits]:https://kapeli.com/cheat_sheets/Conventional_Commits.docset/Contents/Resources/Documents/index -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/translations_template.md: -------------------------------------------------------------------------------- 1 | ### Tanslation language 2 | 3 | 4 | ### Translation checklist 5 | 6 | 13 | 14 | - [ ] Provide the translated strings inside strings.xml under the appropriate folder. 15 | - [ ] Used the correct locale code (en-US, en-GB, de, es, fr...) 16 | - [ ] Named the folder correctly (values-[locale-code]) 17 | 18 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Please go the the `Preview` tab and select the appropriate sub-template: 2 | - [General PR](?expand=1&template=general_template.md): for all other PRs, including bug fixes, adding features etc. 3 | - [Translation PR](?expand=1&template=translations_template.md): specifically to be used for translation PRs -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Android CI 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: set up JDK 17 17 | uses: actions/setup-java@v3 18 | with: 19 | java-version: '17' 20 | distribution: 'temurin' 21 | cache: gradle 22 | 23 | - name: Grant execute permission for gradlew 24 | run: chmod +x gradlew 25 | - name: Build with Gradle 26 | run: ./gradlew build 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | .kotlin 4 | /local.properties 5 | /.idea/caches 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | /.idea/navEditor.xml 10 | /.idea/assetWizardSettings.xml 11 | .DS_Store 12 | /build 13 | /captures 14 | .externalNativeBuild 15 | .cxx 16 | local.properties 17 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # GitHub Copilot persisted chat sessions 5 | /copilot/chatSessions 6 | -------------------------------------------------------------------------------- /.idea/AndroidProjectSystem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/appInsightsSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 45 | 46 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deploymentTargetDropDown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/deploymentTargetSelector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | For bug reports and feature requests, please search in issues first (including the closed ones). If there are no duplicates, feel free to [submit an issue][issues] with an issue template. 4 | 5 | **We'll probably ignore and close your issue if it's not using the existing templates or doesn't contain sufficient description.** 6 | 7 | ## Bug Report 8 | 9 | When submitting a bug report, please make sure your issue contains **enough** information for reproducing the problem, including the options or the custom command being used, the link to the video, and other fields in the issue template. 10 | 11 | ## Feature Request 12 | 13 | **Myne** is an ebook library client designed to give users easy access to the Gutenberg Project’s extensive collection of free assets. Our goal is to make exploring and enjoying literature straightforward and enjoyable. We focus on feature requests that fit our core mission and the essential principles of ebook accessibility and management. 14 | 15 | Our library already includes a variety of features to enhance your reading experience, such as robust search capabilities, customizable reading settings, and efficient download options. While we're open to suggestions for improvements, we may not be able to accommodate requests that stray too far from our primary purpose or go beyond the scope of ebook management and accessibility. We kindly ask users to consider the library's intended functionality and limitations when submitting feature requests. 16 | 17 | We appreciate the feedback and input from our users, and we are committed to continually improving **Myne** to meet the evolving needs of our user base. However, please understand that not all feature requests may be feasible or aligned with our app's mission and vision. 18 | 19 | If you'd like to request a feature you deem necessary and useful, open a new Github issue with the Feature-Request template [here][feature-req]. 20 | 21 | ## Pull Request 22 | 23 | If you wish to contribute to the project by submitting code directly, please first leave a comment under the relevant issue or file a new issue, describe the changes you are about to make. 24 | 25 | As per our project's guidelines, we adhere to [conventional commits][conv-commits]. Therefore, it's expected that all PRs align with this convention. Should a PR not meet these standards, we'll kindly request a review and revision. 26 | 27 | Please use the provided Pull Request templates according to your needs. Currently, there are two to choose from: 28 | - [General PR](.github/PULL_REQUEST_TEMPLATE/general_template.md): for all other PRs, including bug fixes, adding features etc. 29 | - [Translation PR](.github/PULL_REQUEST_TEMPLATE/translations_template.md): specifically to be used for translation PRs 30 | 31 | > [!TIP] 32 | > 33 | > To avoid multiple pull requests resolving the same issue, let others know you are working on it by saying so in a comment, or ask the issue to be assigned to yourself. 34 | 35 | ## Building From Source 36 | 37 | Fork this project, import and compile it with the latest version of [Android Studio](https://developer.android.com/studio/). 38 | 39 | [issues]: https://github.com/Pool-Of-Tears/Myne/issues/new/choose 40 | [feature-req]: https://github.com/Pool-Of-Tears/Myne/issues/new?assignees=&labels=enhancement&projects=&template=--feature-request.yml&title=%5BFeature+Request%5D 41 | [conv-commits]:https://kapeli.com/cheat_sheets/Conventional_Commits.docset/Contents/Resources/Documents/index -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /release -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | # remove Log statements in release builds 24 | -assumenosideeffects class android.util.Log { 25 | public static *** d(...); 26 | public static *** v(...); 27 | public static *** i(...); 28 | public static *** w(...); 29 | public static *** e(...); 30 | } -------------------------------------------------------------------------------- /app/schemas/com.starry.myne.database.MyneDatabase/1.json: -------------------------------------------------------------------------------- 1 | { 2 | "formatVersion": 1, 3 | "database": { 4 | "version": 1, 5 | "identityHash": "ae01aba71e1661869cd52028bf95e902", 6 | "entities": [ 7 | { 8 | "tableName": "book_library", 9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`book_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `authors` TEXT NOT NULL, `file_path` TEXT NOT NULL, `created_at` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", 10 | "fields": [ 11 | { 12 | "fieldPath": "bookId", 13 | "columnName": "book_id", 14 | "affinity": "INTEGER", 15 | "notNull": true 16 | }, 17 | { 18 | "fieldPath": "title", 19 | "columnName": "title", 20 | "affinity": "TEXT", 21 | "notNull": true 22 | }, 23 | { 24 | "fieldPath": "authors", 25 | "columnName": "authors", 26 | "affinity": "TEXT", 27 | "notNull": true 28 | }, 29 | { 30 | "fieldPath": "filePath", 31 | "columnName": "file_path", 32 | "affinity": "TEXT", 33 | "notNull": true 34 | }, 35 | { 36 | "fieldPath": "createdAt", 37 | "columnName": "created_at", 38 | "affinity": "INTEGER", 39 | "notNull": true 40 | }, 41 | { 42 | "fieldPath": "id", 43 | "columnName": "id", 44 | "affinity": "INTEGER", 45 | "notNull": true 46 | } 47 | ], 48 | "primaryKey": { 49 | "columnNames": [ 50 | "id" 51 | ], 52 | "autoGenerate": true 53 | }, 54 | "indices": [], 55 | "foreignKeys": [] 56 | } 57 | ], 58 | "views": [], 59 | "setupQueries": [ 60 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", 61 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ae01aba71e1661869cd52028bf95e902')" 62 | ] 63 | } 64 | } -------------------------------------------------------------------------------- /app/schemas/com.starry.myne.database.MyneDatabase/2.json: -------------------------------------------------------------------------------- 1 | { 2 | "formatVersion": 1, 3 | "database": { 4 | "version": 2, 5 | "identityHash": "928feed3e5c5e84e97e276a4ce4e4095", 6 | "entities": [ 7 | { 8 | "tableName": "book_library", 9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`book_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `authors` TEXT NOT NULL, `file_path` TEXT NOT NULL, `created_at` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", 10 | "fields": [ 11 | { 12 | "fieldPath": "bookId", 13 | "columnName": "book_id", 14 | "affinity": "INTEGER", 15 | "notNull": true 16 | }, 17 | { 18 | "fieldPath": "title", 19 | "columnName": "title", 20 | "affinity": "TEXT", 21 | "notNull": true 22 | }, 23 | { 24 | "fieldPath": "authors", 25 | "columnName": "authors", 26 | "affinity": "TEXT", 27 | "notNull": true 28 | }, 29 | { 30 | "fieldPath": "filePath", 31 | "columnName": "file_path", 32 | "affinity": "TEXT", 33 | "notNull": true 34 | }, 35 | { 36 | "fieldPath": "createdAt", 37 | "columnName": "created_at", 38 | "affinity": "INTEGER", 39 | "notNull": true 40 | }, 41 | { 42 | "fieldPath": "id", 43 | "columnName": "id", 44 | "affinity": "INTEGER", 45 | "notNull": true 46 | } 47 | ], 48 | "primaryKey": { 49 | "autoGenerate": true, 50 | "columnNames": [ 51 | "id" 52 | ] 53 | }, 54 | "indices": [], 55 | "foreignKeys": [] 56 | }, 57 | { 58 | "tableName": "reader_table", 59 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`book_id` INTEGER NOT NULL, `last_chapter_index` INTEGER NOT NULL, `last_chapter_offset` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", 60 | "fields": [ 61 | { 62 | "fieldPath": "bookId", 63 | "columnName": "book_id", 64 | "affinity": "INTEGER", 65 | "notNull": true 66 | }, 67 | { 68 | "fieldPath": "lastChapterIndex", 69 | "columnName": "last_chapter_index", 70 | "affinity": "INTEGER", 71 | "notNull": true 72 | }, 73 | { 74 | "fieldPath": "lastChapterOffset", 75 | "columnName": "last_chapter_offset", 76 | "affinity": "INTEGER", 77 | "notNull": true 78 | }, 79 | { 80 | "fieldPath": "id", 81 | "columnName": "id", 82 | "affinity": "INTEGER", 83 | "notNull": true 84 | } 85 | ], 86 | "primaryKey": { 87 | "autoGenerate": true, 88 | "columnNames": [ 89 | "id" 90 | ] 91 | }, 92 | "indices": [], 93 | "foreignKeys": [] 94 | } 95 | ], 96 | "views": [], 97 | "setupQueries": [ 98 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", 99 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '928feed3e5c5e84e97e276a4ce4e4095')" 100 | ] 101 | } 102 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/starry/myne/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.starry.myne 2 | 3 | import androidx.test.ext.junit.runners.AndroidJUnit4 4 | import androidx.test.platform.app.InstrumentationRegistry 5 | import org.junit.Assert.assertEquals 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | /** 10 | * Instrumented test, which will execute on an Android device. 11 | * 12 | * See [testing documentation](http://d.android.com/tools/testing). 13 | */ 14 | @RunWith(AndroidJUnit4::class) 15 | class ExampleInstrumentedTest { 16 | @Test 17 | fun useAppContext() { 18 | // Context of the app under test. 19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 20 | assertEquals("com.starry.myne", appContext.packageName) 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/debug/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/debug/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/debug/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/debug/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/debug/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/debug/res/resources.properties: -------------------------------------------------------------------------------- 1 | unqualifiedResLocale=en-US -------------------------------------------------------------------------------- /app/src/debug/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 18 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 59 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/MyneApp.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.starry.myne 19 | 20 | import android.app.Application 21 | import cat.ereza.customactivityoncrash.config.CaocConfig 22 | import coil.ImageLoader 23 | import coil.ImageLoaderFactory 24 | import coil.disk.DiskCache 25 | import coil.memory.MemoryCache 26 | import coil.request.CachePolicy 27 | import coil.util.DebugLogger 28 | import dagger.hilt.android.HiltAndroidApp 29 | import okhttp3.OkHttpClient 30 | import java.util.concurrent.TimeUnit 31 | 32 | 33 | @HiltAndroidApp 34 | class MyneApp : Application(), ImageLoaderFactory { 35 | override fun onCreate() { 36 | super.onCreate() 37 | CaocConfig.Builder.create().restartActivity(MainActivity::class.java).apply() 38 | } 39 | 40 | override fun newImageLoader(): ImageLoader { 41 | val coilOkhttpClient = OkHttpClient.Builder() 42 | .connectTimeout(60, TimeUnit.SECONDS) 43 | .writeTimeout(60, TimeUnit.SECONDS) 44 | .readTimeout(100, TimeUnit.SECONDS) 45 | .build() 46 | 47 | return ImageLoader(this).newBuilder() 48 | .memoryCachePolicy(CachePolicy.ENABLED) 49 | .memoryCache { 50 | MemoryCache.Builder(this) 51 | .maxSizePercent(0.25) 52 | .strongReferencesEnabled(true) 53 | .build() 54 | } 55 | .diskCachePolicy(CachePolicy.ENABLED) 56 | .diskCache { 57 | DiskCache.Builder() 58 | .maxSizePercent(0.05) 59 | .directory(cacheDir) 60 | .build() 61 | } 62 | .okHttpClient(coilOkhttpClient) 63 | .logger(DebugLogger()) 64 | .build() 65 | } 66 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/api/CacheInterceptor.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.starry.myne.api 19 | 20 | import com.starry.myne.api.CacheInterceptor.Companion.CACHE_MAX_AGE 21 | import com.starry.myne.api.CacheInterceptor.Companion.CACHE_SIZE 22 | import okhttp3.CacheControl 23 | import okhttp3.Interceptor 24 | import okhttp3.Response 25 | import java.util.concurrent.TimeUnit 26 | 27 | /** 28 | * Interceptor to cache the response for a week to 29 | * reduce the number of network calls. 30 | * 31 | * @property CACHE_SIZE 32 MiB 32 | * @property CACHE_MAX_AGE 1 week 33 | */ 34 | class CacheInterceptor : Interceptor { 35 | 36 | companion object { 37 | const val CACHE_SIZE = 32L * 1024L * 1024L // 32 MiB 38 | const val CACHE_MAX_AGE = 7 // 1 week 39 | } 40 | 41 | override fun intercept(chain: Interceptor.Chain): Response { 42 | val response: Response = chain.proceed(chain.request()) 43 | val cacheControl = CacheControl.Builder() 44 | .maxAge(CACHE_MAX_AGE, TimeUnit.DAYS) 45 | .build() 46 | return response.newBuilder() 47 | .header("Cache-Control", cacheControl.toString()) 48 | .build() 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/api/models/Author.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.api.models 18 | 19 | import androidx.annotation.Keep 20 | import kotlinx.serialization.SerialName 21 | import kotlinx.serialization.Serializable 22 | 23 | @Keep 24 | @Serializable 25 | data class Author( 26 | @SerialName("birth_year") 27 | val birthYear: Int? = null, 28 | @SerialName("death_year") 29 | val deathYear: Int? = null, 30 | @SerialName("name") 31 | val name: String = "N/A", 32 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/api/models/Book.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.api.models 18 | 19 | import androidx.annotation.Keep 20 | import kotlinx.serialization.SerialName 21 | import kotlinx.serialization.Serializable 22 | 23 | @Keep 24 | @Serializable 25 | data class Book( 26 | @SerialName("authors") 27 | val authors: List, 28 | @SerialName("bookshelves") 29 | val bookshelves: List, 30 | @SerialName("copyright") 31 | val copyright: Boolean, 32 | @SerialName("download_count") 33 | val downloadCount: Int, 34 | @SerialName("formats") 35 | val formats: Formats, 36 | @SerialName("id") 37 | val id: Int, 38 | @SerialName("languages") 39 | val languages: List, 40 | @SerialName("media_type") 41 | val mediaType: String, 42 | @SerialName("subjects") 43 | val subjects: List, 44 | @SerialName("title") 45 | val title: String, 46 | @SerialName("translators") 47 | val translators: List 48 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/api/models/BookSet.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.api.models 18 | 19 | import androidx.annotation.Keep 20 | import kotlinx.serialization.SerialName 21 | import kotlinx.serialization.Serializable 22 | 23 | @Keep 24 | @Serializable 25 | data class BookSet( 26 | @SerialName("count") 27 | val count: Int = 0, 28 | @SerialName("next") 29 | val next: String? = null, 30 | @SerialName("previous") 31 | val previous: String? = null, 32 | @SerialName("results") 33 | val books: List = listOf(), 34 | // For checking if the book is cached or not 35 | // Not part of the API response. 36 | val isCached: Boolean = false 37 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/api/models/ExtraInfo.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.api.models 18 | 19 | import androidx.annotation.Keep 20 | 21 | /** Extra info from google books API */ 22 | @Keep 23 | data class ExtraInfo( 24 | val coverImage: String = "", 25 | val pageCount: Int = 0, 26 | val description: String = "", 27 | // Not part of the API response. 28 | // Used to check if extra info is cached. 29 | val isCached: Boolean = false 30 | ) 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/api/models/Formats.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.api.models 18 | 19 | import androidx.annotation.Keep 20 | import kotlinx.serialization.SerialName 21 | import kotlinx.serialization.Serializable 22 | 23 | @Keep 24 | @Serializable 25 | data class Formats( 26 | @SerialName("application/epub+zip") 27 | val applicationepubzip: String? = null, 28 | @SerialName("application/octet-stream") 29 | val applicationoctetStream: String? = null, 30 | @SerialName("application/rdf+xml") 31 | val applicationrdfxml: String? = null, 32 | @SerialName("application/x-mobipocket-ebook") 33 | val applicationxMobipocketEbook: String? = null, 34 | @SerialName("image/jpeg") 35 | val imagejpeg: String? = null, 36 | @SerialName("text/html") 37 | val texthtml: String? = null, 38 | @SerialName("text/html; charset=iso-8859-1") 39 | val texthtmlCharsetiso88591: String? = null, 40 | @SerialName("text/html; charset=utf-8") 41 | val texthtmlCharsetutf8: String? = null, 42 | @SerialName("text/plain; charset=iso-8859-1") 43 | val textplainCharsetiso88591: String? = null, 44 | @SerialName("text/plain; charset=us-ascii") 45 | val textplainCharsetusAscii: String? = null, 46 | @SerialName("text/plain; charset=utf-8") 47 | val textplainCharsetutf8: String? = null, 48 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/api/models/Translator.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.api.models 18 | 19 | import androidx.annotation.Keep 20 | import kotlinx.serialization.SerialName 21 | import kotlinx.serialization.Serializable 22 | 23 | @Keep 24 | @Serializable 25 | data class Translator( 26 | @SerialName("birth_year") 27 | val birthYear: Int? = null, 28 | @SerialName("death_year") 29 | val deathYear: Int? = null, 30 | @SerialName("name") 31 | val name: String = "N/A", 32 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/database/MyneDatabase.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.database 18 | 19 | import android.content.Context 20 | import androidx.room.AutoMigration 21 | import androidx.room.Database 22 | import androidx.room.Room 23 | import androidx.room.RoomDatabase 24 | import androidx.room.migration.Migration 25 | import com.starry.myne.database.library.LibraryDao 26 | import com.starry.myne.database.library.LibraryItem 27 | import com.starry.myne.database.progress.ProgressDao 28 | import com.starry.myne.database.progress.ProgressData 29 | import com.starry.myne.helpers.Constants 30 | 31 | @Database( 32 | entities = [LibraryItem::class, ProgressData::class], 33 | version = 5, 34 | exportSchema = true, 35 | autoMigrations = [ 36 | AutoMigration(from = 1, to = 2), 37 | AutoMigration(from = 2, to = 3), 38 | AutoMigration(from = 4, to = 5), 39 | ] 40 | ) 41 | abstract class MyneDatabase : RoomDatabase() { 42 | 43 | abstract fun getLibraryDao(): LibraryDao 44 | abstract fun getReaderDao(): ProgressDao 45 | 46 | companion object { 47 | 48 | private val migration3to4 = Migration(3, 4) { database -> 49 | database.execSQL("ALTER TABLE reader_table RENAME COLUMN book_id TO library_item_id") 50 | } 51 | 52 | @Volatile 53 | private var INSTANCE: MyneDatabase? = null 54 | 55 | fun getInstance(context: Context): MyneDatabase { 56 | /* 57 | if the INSTANCE is not null, then return it, 58 | if it is, then create the database and save 59 | in instance variable then return it. 60 | */ 61 | return INSTANCE ?: synchronized(this) { 62 | val instance = Room.databaseBuilder( 63 | context.applicationContext, 64 | MyneDatabase::class.java, 65 | Constants.DATABASE_NAME 66 | ).addMigrations(migration3to4).build() 67 | INSTANCE = instance 68 | // return instance 69 | instance 70 | } 71 | } 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/database/library/LibraryDao.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.database.library 18 | 19 | import androidx.lifecycle.LiveData 20 | import androidx.room.Dao 21 | import androidx.room.Delete 22 | import androidx.room.Insert 23 | import androidx.room.OnConflictStrategy 24 | import androidx.room.Query 25 | 26 | @Dao 27 | interface LibraryDao { 28 | 29 | @Insert(onConflict = OnConflictStrategy.REPLACE) 30 | fun insert(libraryItem: LibraryItem) 31 | 32 | @Delete 33 | fun delete(libraryItem: LibraryItem) 34 | 35 | @Query("SELECT * FROM book_library ORDER BY created_at DESC") 36 | fun getAllItems(): LiveData> 37 | 38 | @Query("SELECT * FROM book_library WHERE id = :id") 39 | fun getItemById(id: Int): LibraryItem? 40 | 41 | @Query("SELECT * FROM book_library WHERE book_id = :bookId") 42 | fun getItemByBookId(bookId: Int): LibraryItem? 43 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/database/library/LibraryItem.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.database.library 18 | 19 | import androidx.room.ColumnInfo 20 | import androidx.room.Entity 21 | import androidx.room.PrimaryKey 22 | import java.io.File 23 | import java.io.IOException 24 | import java.text.CharacterIterator 25 | import java.text.DateFormat 26 | import java.text.StringCharacterIterator 27 | import java.util.Date 28 | import java.util.Locale 29 | 30 | /** 31 | * Data class for storing the library items (books). 32 | * 33 | * @param bookId The ID of the book. 34 | * @param title The title of the book. 35 | * @param authors The authors of the book. 36 | * @param filePath The path to the book file. 37 | * @param createdAt The time when the book was added to the library. 38 | */ 39 | @Entity(tableName = "book_library") 40 | data class LibraryItem( 41 | @ColumnInfo(name = "book_id") 42 | val bookId: Int, 43 | @ColumnInfo(name = "title") 44 | val title: String, 45 | @ColumnInfo(name = "authors") 46 | val authors: String, 47 | @ColumnInfo(name = "file_path") 48 | val filePath: String, 49 | @ColumnInfo(name = "created_at") 50 | val createdAt: Long, 51 | // Added in database schema version 3 52 | @ColumnInfo(name = "is_external_book", defaultValue = "false") 53 | val isExternalBook: Boolean = false 54 | ) { 55 | @PrimaryKey(autoGenerate = true) 56 | var id: Int = 0 57 | 58 | fun fileExist(): Boolean { 59 | val file = File(filePath) 60 | return file.exists() 61 | } 62 | 63 | fun getFileSize(): String { 64 | val file = File(filePath) 65 | var bytes = file.length() 66 | if (-1000 < bytes && bytes < 1000) { 67 | return "$bytes B" 68 | } 69 | val ci: CharacterIterator = StringCharacterIterator("kMGTPE") 70 | while (bytes <= -999950 || bytes >= 999950) { 71 | bytes /= 1000 72 | ci.next() 73 | } 74 | return java.lang.String.format(Locale.US, "%.1f %cB", bytes / 1000.0, ci.current()) 75 | } 76 | 77 | fun getDownloadDate(): String { 78 | val date = Date(createdAt) 79 | return DateFormat.getDateInstance().format(date) 80 | } 81 | 82 | fun deleteFile(): Boolean { 83 | val file = File(filePath) 84 | return try { 85 | file.delete() 86 | } catch (exc: IOException) { 87 | false 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/database/progress/ProgressDao.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.starry.myne.database.progress 19 | 20 | import androidx.room.Dao 21 | import androidx.room.Insert 22 | import androidx.room.OnConflictStrategy 23 | import androidx.room.Query 24 | import androidx.room.Update 25 | import kotlinx.coroutines.flow.Flow 26 | 27 | 28 | @Dao 29 | interface ProgressDao { 30 | 31 | @Insert(onConflict = OnConflictStrategy.REPLACE) 32 | fun insert(progressData: ProgressData) 33 | 34 | @Query("DELETE FROM reader_table WHERE library_item_id = :libraryItemId") 35 | fun delete(libraryItemId: Int) 36 | 37 | @Update 38 | fun update(progressData: ProgressData) 39 | 40 | @Query("SELECT * FROM reader_table WHERE library_item_id = :libraryItemId") 41 | fun getReaderData(libraryItemId: Int): ProgressData? 42 | 43 | @Query("SELECT * FROM reader_table") 44 | fun getAllReaderItems(): List 45 | 46 | @Query("SELECT * FROM reader_table WHERE library_item_id = :libraryItemId") 47 | fun getReaderDataAsFlow(libraryItemId: Int): Flow 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/database/progress/ProgressData.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.starry.myne.database.progress 19 | 20 | import androidx.room.ColumnInfo 21 | import androidx.room.Entity 22 | import androidx.room.PrimaryKey 23 | import java.util.Locale 24 | 25 | /** 26 | * Data class for storing the reading progress of a library item (book). 27 | * 28 | * @param libraryItemId The ID of the library item. 29 | * @param lastChapterIndex The index of the last chapter read. 30 | * @param lastChapterOffset The offset of the last chapter read. 31 | * @param lastReadTime The time when the last chapter was read. 32 | */ 33 | @Entity(tableName = "reader_table") 34 | data class ProgressData( 35 | @ColumnInfo(name = "library_item_id") val libraryItemId: Int, 36 | @ColumnInfo(name = "last_chapter_index") val lastChapterIndex: Int, 37 | @ColumnInfo(name = "last_chapter_offset") val lastChapterOffset: Int, 38 | // Added in database schema version 5 39 | @ColumnInfo( 40 | name = "last_read_time", 41 | defaultValue = "0" 42 | ) val lastReadTime: Long = System.currentTimeMillis() 43 | ) { 44 | @PrimaryKey(autoGenerate = true) 45 | var id: Int = 0 46 | 47 | fun getProgressPercent(totalChapters: Int) = 48 | String.format( 49 | locale = Locale.US, 50 | format = "%.2f", 51 | ((lastChapterIndex + 1).toFloat() / totalChapters.toFloat()) * 100f 52 | ) 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/di/MainModule.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.starry.myne.di 19 | 20 | import android.content.Context 21 | import com.starry.myne.api.BookAPI 22 | import com.starry.myne.database.MyneDatabase 23 | import com.starry.myne.epub.EpubParser 24 | import com.starry.myne.helpers.PreferenceUtil 25 | import com.starry.myne.helpers.book.BookDownloader 26 | import com.starry.myne.ui.screens.welcome.viewmodels.WelcomeDataStore 27 | import dagger.Module 28 | import dagger.Provides 29 | import dagger.hilt.InstallIn 30 | import dagger.hilt.android.qualifiers.ApplicationContext 31 | import dagger.hilt.components.SingletonComponent 32 | import javax.inject.Singleton 33 | 34 | 35 | @InstallIn(SingletonComponent::class) 36 | @Module 37 | class MainModule { 38 | 39 | // Core application related. ========================================================== 40 | 41 | @Provides 42 | fun provideAppContext(@ApplicationContext context: Context) = context 43 | 44 | @Singleton 45 | @Provides 46 | fun provideMyneDatabase(@ApplicationContext context: Context) = 47 | MyneDatabase.getInstance(context) 48 | 49 | @Provides 50 | fun provideLibraryDao(myneDatabase: MyneDatabase) = myneDatabase.getLibraryDao() 51 | 52 | @Provides 53 | fun provideReaderDao(myneDatabase: MyneDatabase) = myneDatabase.getReaderDao() 54 | 55 | @Singleton 56 | @Provides 57 | fun providePreferenceUtil(@ApplicationContext context: Context) = PreferenceUtil(context) 58 | 59 | // Network & Books related. ========================================================== 60 | 61 | @Singleton 62 | @Provides 63 | fun provideBooksApi( 64 | @ApplicationContext context: Context, 65 | preferenceUtil: PreferenceUtil 66 | ) = BookAPI(context, preferenceUtil) 67 | 68 | @Singleton 69 | @Provides 70 | fun provideBookDownloader(@ApplicationContext context: Context) = BookDownloader(context) 71 | 72 | @Singleton 73 | @Provides 74 | fun provideEpubParser(@ApplicationContext context: Context) = EpubParser(context) 75 | 76 | @Provides 77 | @Singleton 78 | fun provideDataStoreRepository( 79 | @ApplicationContext context: Context 80 | ) = WelcomeDataStore(context = context) 81 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/epub/BookTextMapper.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.starry.myne.epub 19 | 20 | import org.jsoup.Jsoup 21 | import java.util.Locale 22 | 23 | object BookTextMapper { 24 | 25 | // {uri} 26 | data class ImgEntry(val path: String, val yrel: Float) { 27 | 28 | /** 29 | * Deprecated versions: v0 30 | * Current versions: v1 31 | */ 32 | companion object { 33 | 34 | fun fromXMLString(text: String): ImgEntry? { 35 | return fromXMLStringV0(text) ?: fromXMLStringV1(text) 36 | } 37 | 38 | private fun fromXMLStringV1(text: String): ImgEntry? { 39 | return Jsoup.parse(text).selectFirst("img")?.let { 40 | ImgEntry( 41 | path = it.attr("src") ?: return null, 42 | yrel = it.attr("yrel").toFloatOrNull() ?: return null 43 | ) 44 | } 45 | } 46 | 47 | private val XMLForm_v0 = """^\W*.+\W*$""".toRegex() 48 | 49 | private fun fromXMLStringV0(text: String): ImgEntry? { 50 | // Fast discard filter 51 | if (!text.matches(XMLForm_v0)) 52 | return null 53 | return parseXMLText(text)?.selectFirstTag("img")?.let { 54 | ImgEntry( 55 | path = it.textContent ?: return null, 56 | yrel = it.getAttributeValue("yrel")?.toFloatOrNull() ?: return null 57 | ) 58 | } 59 | } 60 | } 61 | 62 | fun toXMLString(): String { 63 | return toXMLStringV1() 64 | } 65 | 66 | private fun toXMLStringV1(): String { 67 | return """""" 68 | } 69 | 70 | /* 71 | private fun toXMLStringV0(): String { 72 | return """$path""" 73 | } 74 | */ 75 | } 76 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/epub/EpubParserException.kt: -------------------------------------------------------------------------------- 1 | package com.starry.myne.epub 2 | 3 | /** 4 | * Exception thrown when an error occurs while parsing an EPUB file. 5 | * 6 | * @param message The error message. 7 | */ 8 | class EpubParserException(message: String) : Exception(message) -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/epub/EpubUtils.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.starry.myne.epub 19 | 20 | import org.w3c.dom.Document 21 | import org.w3c.dom.Element 22 | import org.w3c.dom.Node 23 | import org.w3c.dom.NodeList 24 | import org.xml.sax.InputSource 25 | import java.io.File 26 | import java.io.InputStream 27 | import java.net.URLDecoder 28 | import java.util.zip.ZipInputStream 29 | import javax.xml.parsers.DocumentBuilderFactory 30 | import kotlin.io.path.invariantSeparatorsPathString 31 | import org.jsoup.nodes.Node as JsoupNode 32 | 33 | fun parseXMLText(text: String): Document? = text.reader().runCatching { 34 | DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(InputSource(this)) 35 | }.getOrNull() 36 | 37 | fun parseXMLFile(inputSteam: InputStream): Document? = 38 | DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputSteam) 39 | 40 | fun parseXMLFile(byteArray: ByteArray): Document? = parseXMLFile(byteArray.inputStream()) 41 | 42 | val String.decodedURL: String get() = URLDecoder.decode(this, "UTF-8") 43 | fun String.asFileName(): String = this.replace("/", "_") 44 | 45 | fun String.hrefAbsolutePath(hrefRootPath: File): String { 46 | return File(hrefRootPath, this).canonicalFile 47 | .toPath() 48 | .invariantSeparatorsPathString 49 | .removePrefix("/") 50 | } 51 | 52 | fun ZipInputStream.entries() = generateSequence { nextEntry } 53 | 54 | fun Document.selectFirstTag(tag: String): Node? = getElementsByTagName(tag).item(0) 55 | fun Node.selectFirstChildTag(tag: String) = childElements.find { it.tagName == tag } 56 | fun Node.selectChildTag(tag: String) = childElements.filter { it.tagName == tag } 57 | fun Node.getAttributeValue(attribute: String): String? = 58 | attributes?.getNamedItem(attribute)?.textContent 59 | 60 | val NodeList.elements get() = (0..length).asSequence().mapNotNull { item(it) as? Element } 61 | val Node.childElements get() = childNodes.elements 62 | 63 | fun JsoupNode.nextSiblingNodes(): List { 64 | val siblings = mutableListOf() 65 | var nextSibling = nextSibling() 66 | while (nextSibling != null) { 67 | siblings.add(nextSibling) 68 | nextSibling = nextSibling.nextSibling() 69 | } 70 | return siblings 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/epub/cache/BitmapSerializer.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.epub.cache 18 | 19 | import android.graphics.Bitmap 20 | import android.graphics.BitmapFactory 21 | import kotlinx.serialization.KSerializer 22 | import kotlinx.serialization.builtins.ByteArraySerializer 23 | import kotlinx.serialization.descriptors.SerialDescriptor 24 | import kotlinx.serialization.descriptors.buildClassSerialDescriptor 25 | import kotlinx.serialization.descriptors.element 26 | import kotlinx.serialization.encoding.Decoder 27 | import kotlinx.serialization.encoding.Encoder 28 | import java.io.ByteArrayOutputStream 29 | 30 | /** 31 | * A [KSerializer] for [Bitmap] objects. 32 | * It serializes the bitmap to a byte array and deserializes it back to a bitmap. 33 | */ 34 | object BitmapSerializer : KSerializer { 35 | override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Bitmap") { 36 | element("bytes") 37 | } 38 | 39 | override fun serialize(encoder: Encoder, value: Bitmap) { 40 | val stream = ByteArrayOutputStream() 41 | value.compress(Bitmap.CompressFormat.PNG, 100, stream) 42 | val byteArray = stream.toByteArray() 43 | encoder.encodeSerializableValue(ByteArraySerializer(), byteArray) 44 | } 45 | 46 | override fun deserialize(decoder: Decoder): Bitmap { 47 | val byteArray = decoder.decodeSerializableValue(ByteArraySerializer()) 48 | return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size) 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/epub/cache/epub_cache.proto: -------------------------------------------------------------------------------- 1 | // Generated schema file for 'com.starry.myne.epub.models.EpubBook' 2 | // For reference only, not actually used to generate protobuf code 3 | 4 | syntax = "proto2"; 5 | 6 | // serial name 'com.starry.myne.epub.models.EpubBook' 7 | message EpubBook { 8 | required string fileName = 1; 9 | required string title = 2; 10 | required string author = 3; 11 | required string language = 4; 12 | optional Bitmap coverImage = 5; 13 | // WARNING: a default value decoded when value is missing 14 | repeated EpubChapter chapters = 6; 15 | // WARNING: a default value decoded when value is missing 16 | repeated EpubImage images = 7; 17 | } 18 | 19 | // serial name 'Bitmap?' 20 | message Bitmap { 21 | required bytes bytes = 1; 22 | } 23 | 24 | // serial name 'com.starry.myne.epub.models.EpubChapter' 25 | message EpubChapter { 26 | required string chapterId = 1; 27 | required string absPath = 2; 28 | required string title = 3; 29 | required string body = 4; 30 | } 31 | 32 | // serial name 'com.starry.myne.epub.models.EpubImage' 33 | message EpubImage { 34 | required string absPath = 1; 35 | required bytes image = 2; 36 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/epub/models/EpubBook.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.starry.myne.epub.models 19 | 20 | import android.graphics.Bitmap 21 | import com.starry.myne.epub.cache.BitmapSerializer 22 | import kotlinx.serialization.ExperimentalSerializationApi 23 | import kotlinx.serialization.Serializable 24 | import kotlinx.serialization.protobuf.ProtoNumber 25 | 26 | /** 27 | * Represents an epub book. 28 | * 29 | * @param fileName The name of the epub file. 30 | * @param title The title of the book. 31 | * @param author The author of the book. 32 | * @param language The language code of the book. 33 | * @param coverImage The cover image of the book. 34 | * @param chapters The list of chapters in the book. 35 | * @param images The list of images in the book. 36 | */ 37 | @OptIn(ExperimentalSerializationApi::class) 38 | @Serializable 39 | data class EpubBook @OptIn(ExperimentalSerializationApi::class) constructor( 40 | @ProtoNumber(1) val fileName: String, 41 | @ProtoNumber(2) val title: String, 42 | @ProtoNumber(3) val author: String, 43 | @ProtoNumber(4) val language: String, 44 | @ProtoNumber(5) @Serializable(with = BitmapSerializer::class) val coverImage: Bitmap?, 45 | @ProtoNumber(6) val chapters: List = emptyList(), 46 | @ProtoNumber(7) val images: List = emptyList() 47 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/epub/models/EpubChapter.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.starry.myne.epub.models 19 | 20 | import kotlinx.serialization.ExperimentalSerializationApi 21 | import kotlinx.serialization.Serializable 22 | import kotlinx.serialization.protobuf.ProtoNumber 23 | 24 | /** 25 | * Represents a chapter in an epub book. 26 | * 27 | * @param absPath The absolute path of the chapter. 28 | * @param title The title of the chapter. 29 | * @param body The body of the chapter. 30 | */ 31 | @OptIn(ExperimentalSerializationApi::class) 32 | @Serializable 33 | data class EpubChapter @OptIn(ExperimentalSerializationApi::class) constructor( 34 | @ProtoNumber(1) val chapterId: String, 35 | @ProtoNumber(2) val absPath: String, 36 | @ProtoNumber(3) val title: String, 37 | @ProtoNumber(4) val body: String 38 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/epub/models/EpubImage.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.starry.myne.epub.models 19 | 20 | import kotlinx.serialization.ExperimentalSerializationApi 21 | import kotlinx.serialization.Serializable 22 | import kotlinx.serialization.protobuf.ProtoNumber 23 | 24 | /** 25 | * Represents an image in an epub book. 26 | * 27 | * @param absPath The absolute path of the image. 28 | * @param image The image data. 29 | */ 30 | @OptIn(ExperimentalSerializationApi::class) 31 | @Serializable 32 | data class EpubImage @OptIn(ExperimentalSerializationApi::class) constructor( 33 | @ProtoNumber(1) val absPath: String, 34 | @ProtoNumber(2) val image: ByteArray 35 | ) { 36 | override fun equals(other: Any?): Boolean { 37 | if (this === other) return true 38 | if (javaClass != other?.javaClass) return false 39 | 40 | other as EpubImage 41 | 42 | if (absPath != other.absPath) return false 43 | if (!image.contentEquals(other.image)) return false 44 | 45 | return true 46 | } 47 | 48 | override fun hashCode(): Int { 49 | var result = absPath.hashCode() 50 | result = 31 * result + image.contentHashCode() 51 | return result 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/helpers/Constants.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.helpers 18 | 19 | object Constants { 20 | /** Name of database file. */ 21 | const val DATABASE_NAME = "myne.db" 22 | 23 | /** Epub Mime Type. */ 24 | const val EPUB_MIME_TYPE = "application/epub+zip" 25 | 26 | /** Placeholder for unknown error. */ 27 | const val UNKNOWN_ERR = "unknown-error" 28 | 29 | // URLs 30 | const val DEV_EMAIL = "starry@krsh.dev" 31 | const val DEV_GITHUB_URL = "https://github.com/starry-shivam" 32 | const val DEV_TELEGRAM_URL = "https://t.me/starryboi" 33 | const val PROJECT_CONTRIBUTORS = "https://github.com/Pool-Of-Tears/Myne/graphs/contributors" 34 | const val GITHUB_REPO = "https://github.com/Pool-Of-Tears/Myne" 35 | const val WEBSITE = "https://pool-of-tears.github.io" 36 | const val PRIVACY_POLICY = 37 | "https://github.com/Pool-Of-Tears/Myne/blob/main/legal/PRIVACY-POLICY.md" 38 | const val GITHUB_ISSUE = "https://github.com/Pool-Of-Tears/Myne/issues/new/choose" 39 | const val TELEGRAM_GROUP = "https://t.me/PotApps" 40 | const val SUPPORT = "https://github.com/sponsors/starry-shivam" 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/helpers/Extensions.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.helpers 18 | 19 | import android.content.Context 20 | import android.content.ContextWrapper 21 | import android.view.HapticFeedbackConstants 22 | import android.view.View 23 | import android.widget.Toast 24 | import androidx.appcompat.app.AppCompatActivity 25 | import androidx.compose.foundation.clickable 26 | import androidx.compose.foundation.interaction.MutableInteractionSource 27 | import androidx.compose.foundation.lazy.LazyListState 28 | import androidx.compose.runtime.Composable 29 | import androidx.compose.runtime.derivedStateOf 30 | import androidx.compose.runtime.getValue 31 | import androidx.compose.runtime.mutableIntStateOf 32 | import androidx.compose.runtime.remember 33 | import androidx.compose.runtime.setValue 34 | import androidx.compose.ui.Modifier 35 | 36 | fun Context.getActivity(): AppCompatActivity? = when (this) { 37 | is AppCompatActivity -> this 38 | is ContextWrapper -> baseContext.getActivity() 39 | else -> null 40 | } 41 | 42 | fun String.toToast(context: Context, length: Int = Toast.LENGTH_SHORT) { 43 | Toast.makeText(context, this, length).show() 44 | } 45 | 46 | @Composable 47 | fun Modifier.noRippleClickable(onClick: () -> Unit): Modifier = 48 | this.clickable( 49 | indication = null, 50 | interactionSource = remember { MutableInteractionSource() } 51 | ) { 52 | onClick() 53 | } 54 | 55 | @Composable 56 | fun LazyListState.isScrollingUp(): Boolean { 57 | var previousIndex by remember(this) { mutableIntStateOf(firstVisibleItemIndex) } 58 | var previousScrollOffset by remember(this) { mutableIntStateOf(firstVisibleItemScrollOffset) } 59 | return remember(this) { 60 | derivedStateOf { 61 | if (previousIndex != firstVisibleItemIndex) { 62 | previousIndex > firstVisibleItemIndex 63 | } else { 64 | previousScrollOffset >= firstVisibleItemScrollOffset 65 | }.also { 66 | previousIndex = firstVisibleItemIndex 67 | previousScrollOffset = firstVisibleItemScrollOffset 68 | } 69 | } 70 | }.value 71 | } 72 | 73 | fun View.weakHapticFeedback() { 74 | this.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK) 75 | } 76 | 77 | fun View.strongHapticFeedback() { 78 | this.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) 79 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/helpers/NetworkObserver.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.helpers 18 | 19 | import android.content.Context 20 | import android.net.ConnectivityManager 21 | import android.net.Network 22 | import kotlinx.coroutines.channels.awaitClose 23 | import kotlinx.coroutines.flow.Flow 24 | import kotlinx.coroutines.flow.callbackFlow 25 | import kotlinx.coroutines.flow.distinctUntilChanged 26 | import kotlinx.coroutines.launch 27 | 28 | class NetworkObserver(context: Context) { 29 | 30 | enum class Status { 31 | Available, Unavailable, Loosing, Lost 32 | } 33 | 34 | private val connectivityManager = 35 | context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager 36 | 37 | fun observe(): Flow { 38 | return callbackFlow { 39 | val callback = object : ConnectivityManager.NetworkCallback() { 40 | 41 | override fun onAvailable(network: Network) { 42 | super.onAvailable(network) 43 | launch { send(Status.Available) } 44 | } 45 | 46 | override fun onLosing(network: Network, maxMsToLive: Int) { 47 | super.onLosing(network, maxMsToLive) 48 | launch { send(Status.Loosing) } 49 | 50 | } 51 | 52 | override fun onLost(network: Network) { 53 | super.onLost(network) 54 | launch { send(Status.Lost) } 55 | } 56 | 57 | override fun onUnavailable() { 58 | super.onUnavailable() 59 | launch { send(Status.Unavailable) } 60 | } 61 | } 62 | 63 | connectivityManager.registerDefaultNetworkCallback(callback) 64 | awaitClose { 65 | connectivityManager.unregisterNetworkCallback(callback) 66 | } 67 | 68 | }.distinctUntilChanged() 69 | } 70 | 71 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/helpers/Paginator.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.helpers 18 | 19 | /** 20 | * A class that helps in paginating data from a remote source. 21 | * 22 | * @param Page The type of the page. 23 | * @param BookSet The type of the data set. 24 | * @property initialPage The initial page to start from. 25 | * @property onLoadUpdated A lambda that is called when the loading state is updated. 26 | * @property onRequest A suspend function that is called to request data from the remote source. 27 | * @property getNextPage A suspend function that is called to get the next page. 28 | * @property onError A suspend function that is called when an error occurs. 29 | * @property onSuccess A suspend function that is called when the data is successfully loaded. 30 | */ 31 | class Paginator( 32 | private val initialPage: Page, 33 | private val onLoadUpdated: (Boolean) -> Unit, 34 | private val onRequest: suspend (nextPage: Page) -> Result, 35 | private val getNextPage: suspend (BookSet) -> Page, 36 | private val onError: suspend (Throwable?) -> Unit, 37 | private val onSuccess: suspend (item: BookSet, newPage: Page) -> Unit 38 | ) { 39 | 40 | private var currentPage = initialPage 41 | private var isMakingRequest = false 42 | 43 | /** 44 | * Loads the next items from the remote source. 45 | */ 46 | suspend fun loadNextItems() { 47 | if (isMakingRequest) { 48 | return 49 | } 50 | isMakingRequest = true 51 | onLoadUpdated(true) 52 | val result = onRequest(currentPage) 53 | isMakingRequest = false 54 | val bookSet = result.getOrElse { 55 | onError(it) 56 | onLoadUpdated(false) 57 | return 58 | } 59 | currentPage = getNextPage(bookSet) 60 | onSuccess(bookSet, currentPage) 61 | onLoadUpdated(false) 62 | } 63 | 64 | /** 65 | * Resets the paginator to the initial state. 66 | */ 67 | fun reset() { 68 | currentPage = initialPage 69 | } 70 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/helpers/book/BookLanguage.kt: -------------------------------------------------------------------------------- 1 | package com.starry.myne.helpers.book 2 | 3 | import androidx.annotation.Keep 4 | 5 | @Keep 6 | sealed class BookLanguage(val name: String, val isoCode: String) { 7 | 8 | companion object { 9 | fun getAllLanguages() = 10 | BookLanguage::class.sealedSubclasses.mapNotNull { it.objectInstance } 11 | } 12 | 13 | @Keep 14 | data object AllBooks : BookLanguage("All Books", "all") 15 | 16 | @Keep 17 | data object Chinese : BookLanguage("Chinese", "zh") 18 | 19 | @Keep 20 | data object Danish : BookLanguage("Danish", "da") 21 | 22 | @Keep 23 | data object Dutch : BookLanguage("Dutch", "nl") 24 | 25 | @Keep 26 | data object English : BookLanguage("English", "en") 27 | 28 | @Keep 29 | data object Esperanto : BookLanguage("Esperanto", "eo") 30 | 31 | @Keep 32 | data object Finnish : BookLanguage("Finnish", "fi") 33 | 34 | @Keep 35 | data object French : BookLanguage("French", "fr") 36 | 37 | @Keep 38 | data object German : BookLanguage("German", "de") 39 | 40 | @Keep 41 | data object Greek : BookLanguage("Greek", "el") 42 | 43 | @Keep 44 | data object Hungarian : BookLanguage("Hungarian", "hu") 45 | 46 | @Keep 47 | data object Italian : BookLanguage("Italian", "it") 48 | 49 | @Keep 50 | data object Latin : BookLanguage("Latin", "la") 51 | 52 | @Keep 53 | data object Portuguese : BookLanguage("Portuguese", "pt") 54 | 55 | @Keep 56 | data object Russian : BookLanguage("Russian", "ru") 57 | 58 | @Keep 59 | data object Spanish : BookLanguage("Spanish", "es") 60 | 61 | @Keep 62 | data object Swedish : BookLanguage("Swedish", "sv") 63 | 64 | @Keep 65 | data object Tagalog : BookLanguage("Tagalog", "tl") 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/ui/common/NoBooksAvailable.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.ui.common 18 | 19 | import androidx.compose.foundation.layout.Column 20 | import androidx.compose.foundation.layout.Spacer 21 | import androidx.compose.foundation.layout.fillMaxSize 22 | import androidx.compose.foundation.layout.fillMaxWidth 23 | import androidx.compose.foundation.layout.padding 24 | import androidx.compose.foundation.layout.size 25 | import androidx.compose.material3.Text 26 | import androidx.compose.runtime.Composable 27 | import androidx.compose.runtime.getValue 28 | import androidx.compose.ui.Alignment 29 | import androidx.compose.ui.Modifier 30 | import androidx.compose.ui.text.font.FontWeight 31 | import androidx.compose.ui.text.style.TextAlign 32 | import androidx.compose.ui.unit.dp 33 | import androidx.compose.ui.unit.sp 34 | import com.airbnb.lottie.compose.LottieAnimation 35 | import com.airbnb.lottie.compose.LottieCompositionResult 36 | import com.airbnb.lottie.compose.LottieCompositionSpec 37 | import com.airbnb.lottie.compose.LottieConstants 38 | import com.airbnb.lottie.compose.animateLottieCompositionAsState 39 | import com.airbnb.lottie.compose.rememberLottieComposition 40 | import com.starry.myne.R 41 | 42 | @Composable 43 | fun NoBooksAvailable(text: String) { 44 | Column( 45 | modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally 46 | ) { 47 | val compositionResult: LottieCompositionResult = rememberLottieComposition( 48 | spec = LottieCompositionSpec.RawRes(R.raw.no_library_items_lottie) 49 | ) 50 | val progressAnimation by animateLottieCompositionAsState( 51 | compositionResult.value, 52 | isPlaying = true, 53 | iterations = LottieConstants.IterateForever, 54 | speed = 1f 55 | ) 56 | 57 | Spacer(modifier = Modifier.weight(1f)) 58 | LottieAnimation( 59 | composition = compositionResult.value, 60 | progress = { progressAnimation }, 61 | modifier = Modifier.size(300.dp), 62 | enableMergePaths = true 63 | ) 64 | 65 | Text( 66 | text = text, 67 | fontWeight = FontWeight.Medium, 68 | fontSize = 18.sp, 69 | textAlign = TextAlign.Center, 70 | modifier = Modifier 71 | .fillMaxWidth() 72 | .padding(horizontal = 24.dp) 73 | ) 74 | Spacer(modifier = Modifier.weight(1.4f)) 75 | } 76 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/ui/common/SlideInContainer.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.ui.common 18 | 19 | import androidx.compose.animation.AnimatedVisibility 20 | import androidx.compose.animation.expandVertically 21 | import androidx.compose.animation.fadeIn 22 | import androidx.compose.animation.fadeOut 23 | import androidx.compose.animation.shrinkVertically 24 | import androidx.compose.animation.slideInVertically 25 | import androidx.compose.animation.slideOutVertically 26 | import androidx.compose.runtime.Composable 27 | import androidx.compose.runtime.LaunchedEffect 28 | import androidx.compose.runtime.mutableStateOf 29 | import androidx.compose.runtime.remember 30 | import androidx.compose.ui.Alignment 31 | import kotlinx.coroutines.delay 32 | 33 | @Composable 34 | fun SlideInAnimatedContainer( 35 | initialDelay: Long, content: 36 | @Composable () -> Unit 37 | ) { 38 | val showContent = remember { mutableStateOf(false) } 39 | LaunchedEffect(key1 = true) { 40 | delay(initialDelay) 41 | showContent.value = true 42 | } 43 | 44 | AnimatedVisibility( 45 | visible = showContent.value, 46 | enter = slideInVertically { it / 2 } + expandVertically(expandFrom = Alignment.Top) + fadeIn( 47 | initialAlpha = 0.3f 48 | ), 49 | exit = slideOutVertically() + shrinkVertically() + fadeOut(), 50 | ) { 51 | content() 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/ui/common/VerticalScrollbar.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.starry.myne.ui.common 19 | 20 | import androidx.compose.animation.core.animateFloatAsState 21 | import androidx.compose.animation.core.tween 22 | import androidx.compose.foundation.lazy.LazyListState 23 | import androidx.compose.runtime.getValue 24 | import androidx.compose.ui.Modifier 25 | import androidx.compose.ui.composed 26 | import androidx.compose.ui.draw.drawWithContent 27 | import androidx.compose.ui.geometry.Offset 28 | import androidx.compose.ui.geometry.Size 29 | import androidx.compose.ui.graphics.Color 30 | import androidx.compose.ui.unit.Dp 31 | import androidx.compose.ui.unit.dp 32 | 33 | 34 | /** 35 | * Shows a simple vertical scrollbar when using 36 | * LazyColumn, LazyList etc... 37 | */ 38 | fun Modifier.simpleVerticalScrollbar( 39 | state: LazyListState, 40 | color: Color, 41 | width: Dp = 8.dp 42 | ): Modifier = composed { 43 | val targetAlpha = if (state.isScrollInProgress) 1f else 0f 44 | val duration = if (state.isScrollInProgress) 150 else 500 45 | 46 | val alpha by animateFloatAsState( 47 | targetValue = targetAlpha, 48 | animationSpec = tween(durationMillis = duration), label = "scrollbarAlpha" 49 | ) 50 | 51 | drawWithContent { 52 | drawContent() 53 | 54 | val firstVisibleElementIndex = state.layoutInfo.visibleItemsInfo.firstOrNull()?.index 55 | val needDrawScrollbar = state.isScrollInProgress || alpha > 0.0f 56 | 57 | // Draw scrollbar if scrolling or if the animation is still running and lazy column has content 58 | if (needDrawScrollbar && firstVisibleElementIndex != null) { 59 | val elementHeight = this.size.height / state.layoutInfo.totalItemsCount 60 | val scrollbarOffsetY = firstVisibleElementIndex * elementHeight 61 | val scrollbarHeight = state.layoutInfo.visibleItemsInfo.size * elementHeight 62 | 63 | drawRect( 64 | color = color, 65 | topLeft = Offset(this.size.width - width.toPx(), scrollbarOffsetY), 66 | size = Size(width.toPx(), scrollbarHeight), 67 | alpha = alpha 68 | ) 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/ui/navigation/BottomBarScreen.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.ui.navigation 18 | 19 | import com.starry.myne.R 20 | 21 | sealed class BottomBarScreen( 22 | val route: String, 23 | val title: Int, 24 | val icon: Int 25 | ) { 26 | data object Home : BottomBarScreen( 27 | route = "home", 28 | title = R.string.navigation_home, 29 | icon = R.drawable.ic_nav_home 30 | ) 31 | 32 | data object Categories : BottomBarScreen( 33 | route = "categories", 34 | title = R.string.navigation_categories, 35 | icon = R.drawable.ic_nav_categories 36 | ) 37 | 38 | data object Library : BottomBarScreen( 39 | route = "library", 40 | title = R.string.navigation_library, 41 | icon = R.drawable.ic_nav_library 42 | ) 43 | 44 | data object Settings : BottomBarScreen( 45 | route = "settings", 46 | title = R.string.navigation_settings, 47 | icon = R.drawable.ic_nav_settings 48 | ) 49 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/ui/navigation/Screens.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.ui.navigation 18 | 19 | const val BOOK_ID_ARG_KEY = "bookId" 20 | const val LIBRARY_ITEM_ID_ARG_KEY = "libraryItemId" 21 | const val CATEGORY_DETAIL_ARG_KEY = "category" 22 | 23 | sealed class Screens(val route: String) { 24 | 25 | data object BookDetailScreen : Screens("book_detail_screen/{$BOOK_ID_ARG_KEY}") { 26 | fun withBookId(id: String): String { 27 | return this.route.replace("{$BOOK_ID_ARG_KEY}", id) 28 | } 29 | } 30 | 31 | data object CategoryDetailScreen : 32 | Screens("category_detail_screen/{$CATEGORY_DETAIL_ARG_KEY}") { 33 | fun withCategory(category: String): String { 34 | return this.route.replace("{$CATEGORY_DETAIL_ARG_KEY}", category) 35 | } 36 | } 37 | 38 | data object ReaderDetailScreen : Screens("reader_detail_screen/{$LIBRARY_ITEM_ID_ARG_KEY}") { 39 | fun withLibraryItemId(id: String): String { 40 | return this.route.replace("{$LIBRARY_ITEM_ID_ARG_KEY}", id) 41 | } 42 | } 43 | 44 | data object WelcomeScreen : Screens("welcome_screen") 45 | 46 | data object OSLScreen : Screens("osl_screen") 47 | 48 | data object AboutScreen : Screens("about_screen") 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/ui/screens/reader/main/composables/ChaptersDrawer.kt: -------------------------------------------------------------------------------- 1 | package com.starry.myne.ui.screens.reader.main.composables 2 | 3 | import androidx.compose.foundation.layout.Spacer 4 | import androidx.compose.foundation.layout.fillMaxWidth 5 | import androidx.compose.foundation.layout.height 6 | import androidx.compose.foundation.layout.padding 7 | import androidx.compose.foundation.layout.systemBarsPadding 8 | import androidx.compose.foundation.lazy.LazyColumn 9 | import androidx.compose.material3.DrawerState 10 | import androidx.compose.material3.HorizontalDivider 11 | import androidx.compose.material3.MaterialTheme 12 | import androidx.compose.material3.ModalDrawerSheet 13 | import androidx.compose.material3.ModalNavigationDrawer 14 | import androidx.compose.material3.NavigationDrawerItem 15 | import androidx.compose.material3.Text 16 | import androidx.compose.runtime.Composable 17 | import androidx.compose.runtime.rememberCoroutineScope 18 | import androidx.compose.ui.Modifier 19 | import androidx.compose.ui.res.stringResource 20 | import androidx.compose.ui.text.font.FontWeight 21 | import androidx.compose.ui.text.style.TextOverflow 22 | import androidx.compose.ui.unit.dp 23 | import androidx.compose.ui.unit.sp 24 | import com.starry.myne.R 25 | import com.starry.myne.epub.models.EpubChapter 26 | import com.starry.myne.ui.theme.poppinsFont 27 | import kotlinx.coroutines.launch 28 | 29 | @Composable 30 | fun ChaptersDrawer( 31 | drawerState: DrawerState, 32 | chapters: List, 33 | currentChapterIndex: Int, 34 | onScrollToChapter: (Int) -> Unit, 35 | content: @Composable () -> Unit 36 | ) { 37 | val coroutineScope = rememberCoroutineScope() 38 | 39 | ModalNavigationDrawer( 40 | modifier = Modifier.systemBarsPadding(), 41 | drawerState = drawerState, 42 | gesturesEnabled = drawerState.isOpen, 43 | drawerContent = { 44 | ModalDrawerSheet { 45 | Spacer(Modifier.height(14.dp)) 46 | 47 | Text( 48 | text = stringResource(id = R.string.reader_chapter_list_title), 49 | modifier = Modifier.padding(start = 16.dp, top = 12.dp), 50 | fontSize = 24.sp, 51 | fontWeight = FontWeight.SemiBold, 52 | fontFamily = poppinsFont, 53 | color = MaterialTheme.colorScheme.onSurface 54 | ) 55 | 56 | HorizontalDivider( 57 | modifier = Modifier 58 | .fillMaxWidth() 59 | .padding(top = 16.dp, bottom = 16.dp), 60 | thickness = 0.5.dp, 61 | color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.2f) 62 | ) 63 | LazyColumn { 64 | items(chapters.size) { idx -> 65 | NavigationDrawerItem( 66 | label = { 67 | Text( 68 | text = chapters[idx].title, 69 | maxLines = 2, 70 | overflow = TextOverflow.Ellipsis 71 | ) 72 | }, 73 | selected = idx == currentChapterIndex, 74 | onClick = { 75 | coroutineScope.launch { 76 | drawerState.close() 77 | onScrollToChapter(idx) 78 | } 79 | } 80 | ) 81 | } 82 | } 83 | } 84 | }, content = content 85 | ) 86 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/ui/screens/reader/main/viewmodel/ReaderFont.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.ui.screens.reader.main.viewmodel 18 | 19 | import androidx.annotation.Keep 20 | import androidx.compose.ui.text.font.Font 21 | import androidx.compose.ui.text.font.FontFamily 22 | import com.starry.myne.R 23 | import com.starry.myne.ui.theme.poppinsFont 24 | 25 | @Keep 26 | sealed class ReaderFont(val id: String, val name: String, val fontFamily: FontFamily) { 27 | 28 | companion object { 29 | private val fontMap by lazy { 30 | ReaderFont::class.sealedSubclasses 31 | .mapNotNull { it.objectInstance } 32 | .associateBy { it.id } 33 | } 34 | 35 | fun getAllFonts() = fontMap.values.toList() 36 | fun getFontById(id: String) = fontMap[id]!! 37 | fun getFontByName(name: String) = getAllFonts().find { it.name == name }!! 38 | } 39 | 40 | @Keep 41 | data object System : ReaderFont("system", "System Default", FontFamily.Default) 42 | 43 | @Keep 44 | data object Serif : ReaderFont("serif", "Serif", FontFamily.Serif) 45 | 46 | @Keep 47 | data object Cursive : ReaderFont("cursive", "Cursive", FontFamily.Cursive) 48 | 49 | @Keep 50 | data object SansSerif : ReaderFont("sans-serif", "SansSerif", FontFamily.SansSerif) 51 | 52 | @Keep 53 | data object Inter : ReaderFont("inter", "Inter", FontFamily(Font(R.font.reader_inter_font))) 54 | 55 | @Keep 56 | data object Dyslexic : 57 | ReaderFont("dyslexic", "OpenDyslexic", FontFamily(Font(R.font.reader_inter_font))) 58 | 59 | @Keep 60 | data object Lora : ReaderFont("poppins", "Poppins", poppinsFont) 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/ui/screens/settings/composables/OSLScreen.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.ui.screens.settings.composables 18 | 19 | import androidx.compose.foundation.background 20 | import androidx.compose.foundation.layout.Column 21 | import androidx.compose.foundation.layout.fillMaxSize 22 | import androidx.compose.foundation.layout.padding 23 | import androidx.compose.material3.MaterialTheme 24 | import androidx.compose.material3.Scaffold 25 | import androidx.compose.runtime.Composable 26 | import androidx.compose.ui.Modifier 27 | import androidx.compose.ui.res.stringResource 28 | import androidx.navigation.NavController 29 | import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer 30 | import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults 31 | import com.starry.myne.R 32 | import com.starry.myne.ui.common.CustomTopAppBar 33 | 34 | 35 | @Composable 36 | fun OSLScreen(navController: NavController) { 37 | 38 | Scaffold( 39 | modifier = Modifier 40 | .fillMaxSize() 41 | .background(MaterialTheme.colorScheme.background), 42 | topBar = { 43 | CustomTopAppBar(headerText = stringResource(id = R.string.open_source_licenses_header)) { 44 | navController.navigateUp() 45 | } 46 | } 47 | ) { paddingValues -> 48 | Column( 49 | modifier = Modifier 50 | .fillMaxSize() 51 | .background(MaterialTheme.colorScheme.background) 52 | .padding(paddingValues) 53 | ) { 54 | LibrariesContainer( 55 | modifier = Modifier.fillMaxSize(), 56 | showAuthor = true, 57 | showVersion = true, 58 | showLicenseBadges = true, 59 | colors = LibraryDefaults.libraryColors( 60 | backgroundColor = MaterialTheme.colorScheme.background, 61 | contentColor = MaterialTheme.colorScheme.onBackground, 62 | badgeBackgroundColor = MaterialTheme.colorScheme.primary, 63 | badgeContentColor = MaterialTheme.colorScheme.onPrimary 64 | ) 65 | ) 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/ui/screens/welcome/viewmodels/WelcomeDataStore.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.starry.myne.ui.screens.welcome.viewmodels 19 | 20 | import android.content.Context 21 | import androidx.datastore.core.DataStore 22 | import androidx.datastore.preferences.core.Preferences 23 | import androidx.datastore.preferences.core.booleanPreferencesKey 24 | import androidx.datastore.preferences.core.edit 25 | import androidx.datastore.preferences.core.emptyPreferences 26 | import androidx.datastore.preferences.preferencesDataStore 27 | import kotlinx.coroutines.flow.Flow 28 | import kotlinx.coroutines.flow.catch 29 | import kotlinx.coroutines.flow.map 30 | import java.io.IOException 31 | 32 | val Context.dataStore: DataStore by preferencesDataStore(name = "on_boarding_pref") 33 | 34 | class WelcomeDataStore(context: Context) { 35 | private val dataStore = context.dataStore 36 | 37 | private object PreferencesKey { 38 | val onBoardingKey = booleanPreferencesKey(name = "on_boarding_completed") 39 | } 40 | 41 | suspend fun saveOnBoardingState(completed: Boolean) { 42 | dataStore.edit { preferences -> 43 | preferences[PreferencesKey.onBoardingKey] = completed 44 | } 45 | } 46 | 47 | fun readOnBoardingState(): Flow { 48 | return dataStore.data 49 | .catch { exception -> 50 | if (exception is IOException) { 51 | emit(emptyPreferences()) 52 | } else { 53 | throw exception 54 | } 55 | } 56 | .map { preferences -> 57 | val onBoardingState = preferences[PreferencesKey.onBoardingKey] ?: false 58 | onBoardingState 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/ui/screens/welcome/viewmodels/WelcomeViewModel.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.starry.myne.ui.screens.welcome.viewmodels 19 | 20 | import androidx.lifecycle.ViewModel 21 | import androidx.lifecycle.viewModelScope 22 | import com.starry.myne.helpers.PreferenceUtil 23 | import dagger.hilt.android.lifecycle.HiltViewModel 24 | import kotlinx.coroutines.Dispatchers 25 | import kotlinx.coroutines.launch 26 | import javax.inject.Inject 27 | 28 | @HiltViewModel 29 | class WelcomeViewModel @Inject constructor( 30 | private val welcomeDataStore: WelcomeDataStore, 31 | private val preferenceUtil: PreferenceUtil 32 | ) : ViewModel() { 33 | 34 | fun saveOnBoardingState(completed: Boolean) { 35 | viewModelScope.launch(Dispatchers.IO) { 36 | welcomeDataStore.saveOnBoardingState(completed = completed) 37 | } 38 | } 39 | 40 | 41 | fun setInternalReaderSetting(newValue: Boolean) { 42 | preferenceUtil.putBoolean(PreferenceUtil.INTERNAL_READER_BOOL, newValue) 43 | } 44 | 45 | fun getInternalReaderSetting() = preferenceUtil.getBoolean( 46 | PreferenceUtil.INTERNAL_READER_BOOL, true 47 | ) 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/starry/myne/ui/theme/Type.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne.ui.theme 18 | 19 | import androidx.compose.material3.Typography 20 | import androidx.compose.ui.text.PlatformTextStyle 21 | import androidx.compose.ui.text.TextStyle 22 | import androidx.compose.ui.text.font.Font 23 | import androidx.compose.ui.text.font.FontFamily 24 | import androidx.compose.ui.text.font.FontStyle 25 | import androidx.compose.ui.text.font.FontWeight 26 | import androidx.compose.ui.text.style.LineHeightStyle 27 | import androidx.compose.ui.unit.sp 28 | import com.starry.myne.R 29 | 30 | 31 | val poppinsFont = FontFamily( 32 | fonts = listOf( 33 | Font( 34 | resId = R.font.poppins_black, 35 | weight = FontWeight.Black, 36 | style = FontStyle.Normal 37 | ), 38 | Font( 39 | resId = R.font.poppins_bold, 40 | weight = FontWeight.Bold, 41 | style = FontStyle.Normal 42 | ), 43 | Font( 44 | resId = R.font.poppins_extrabold, 45 | weight = FontWeight.ExtraBold, 46 | style = FontStyle.Normal 47 | ), 48 | Font( 49 | resId = R.font.poppins_extralight, 50 | weight = FontWeight.ExtraLight, 51 | style = FontStyle.Normal 52 | ), 53 | Font( 54 | resId = R.font.poppins_light, 55 | weight = FontWeight.Light, 56 | style = FontStyle.Normal 57 | ), 58 | Font( 59 | resId = R.font.poppins_medium, 60 | weight = FontWeight.Medium, 61 | style = FontStyle.Normal 62 | ), 63 | Font( 64 | resId = R.font.poppins_regular, 65 | weight = FontWeight.Normal, 66 | style = FontStyle.Normal 67 | ), 68 | Font( 69 | resId = R.font.poppins_semibold, 70 | weight = FontWeight.SemiBold, 71 | style = FontStyle.Normal 72 | ), 73 | Font( 74 | resId = R.font.poppins_thin, 75 | weight = FontWeight.Thin, 76 | style = FontStyle.Normal 77 | ), 78 | ) 79 | ) 80 | 81 | val pacificoFont = FontFamily(Font(R.font.pacifico_regular)) 82 | 83 | // Set of Material typography styles to start with 84 | val Typography = Typography( 85 | bodyLarge = TextStyle( 86 | fontFamily = poppinsFont, 87 | fontWeight = FontWeight.Normal, 88 | fontSize = 16.sp, 89 | lineHeight = 24.sp, 90 | letterSpacing = 0.5.sp, 91 | lineHeightStyle = LineHeightStyle( 92 | alignment = LineHeightStyle.Alignment.Proportional, 93 | trim = LineHeightStyle.Trim.Both 94 | ), 95 | platformStyle = PlatformTextStyle(includeFontPadding = true) 96 | ) 97 | ) 98 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/about_screen_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/drawable/about_screen_bg.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/book_details_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/drawable/book_details_bg.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/book_reader_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/drawable/book_reader_bg.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/github_pfp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/drawable/github_pfp.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_book_downloads.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_book_language.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_book_pages.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_github_logo.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info_white.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 17 | 20 | 23 | 26 | 29 | 32 | 35 | 38 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_monochrome.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 15 | 18 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_library_external_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 13 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_library_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 13 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_library_read.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_nav_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_nav_library.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_nav_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_no_internet.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 14 | 17 | 20 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_osi_logo.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reader_cat.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reader_error.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reader_fab_button.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 27 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reader_font.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reader_text_minus.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reader_text_plus.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reader_text_size.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_right_arrow.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings_google_api.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings_reader.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_share.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_share_white.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_splash_screen.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 17 | 20 | 23 | 26 | 29 | 32 | 35 | 38 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_telegram_logo.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 14 | 17 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/placeholder_cat.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/drawable/placeholder_cat.jpeg -------------------------------------------------------------------------------- /app/src/main/res/font/opendyslexic_regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/font/opendyslexic_regular.otf -------------------------------------------------------------------------------- /app/src/main/res/font/pacifico_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/font/pacifico_regular.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/poppins_black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/font/poppins_black.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/poppins_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/font/poppins_bold.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/poppins_extrabold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/font/poppins_extrabold.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/poppins_extralight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/font/poppins_extralight.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/poppins_light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/font/poppins_light.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/poppins_medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/font/poppins_medium.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/poppins_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/font/poppins_regular.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/poppins_semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/font/poppins_semibold.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/poppins_thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/font/poppins_thin.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/reader_inter_font.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/font/reader_inter_font.ttf -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/resources.properties: -------------------------------------------------------------------------------- 1 | unqualifiedResLocale=en-US -------------------------------------------------------------------------------- /app/src/main/res/values-night/splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/xml/provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/test/java/com/starry/myne/BookTextMapperTest.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne 18 | 19 | import com.google.common.truth.Truth.assertThat 20 | import com.starry.myne.epub.BookTextMapper 21 | import org.junit.Test 22 | 23 | 24 | class BookTextMapperTest { 25 | 26 | @Test 27 | fun testImgEntryFromXMLStringV1() { 28 | val xmlString = """""" 29 | val imgEntry = BookTextMapper.ImgEntry.fromXMLString(xmlString) 30 | 31 | assertThat(imgEntry).isNotNull() 32 | assertThat(imgEntry?.path).isEqualTo("image.jpg") 33 | assertThat(imgEntry?.yrel).isEqualTo(1.23f) 34 | } 35 | 36 | @Test 37 | fun testImgEntryFromXMLStringV0() { 38 | val xmlString = """image.jpg""" 39 | val imgEntry = BookTextMapper.ImgEntry.fromXMLString(xmlString) 40 | 41 | assertThat(imgEntry).isNotNull() 42 | assertThat(imgEntry?.path).isEqualTo("image.jpg") 43 | assertThat(imgEntry?.yrel).isEqualTo(1.45f) 44 | } 45 | 46 | @Test 47 | fun testImgEntryFromInvalidXMLString() { 48 | val invalidXmlString = """image.jpg""" 49 | val imgEntry = BookTextMapper.ImgEntry.fromXMLString(invalidXmlString) 50 | 51 | assertThat(imgEntry).isNull() 52 | } 53 | 54 | @Test 55 | fun testImgEntryToXMLStringV1() { 56 | val imgEntry = BookTextMapper.ImgEntry("image.jpg", 1.23f) 57 | val expectedXmlString = """""" 58 | 59 | assertThat(imgEntry.toXMLString()).isEqualTo(expectedXmlString) 60 | } 61 | 62 | // Commented out since the v0 version is deprecated 63 | /* 64 | @Test 65 | fun testImgEntryToXMLStringV0() { 66 | val imgEntry = BookTextMapper.ImgEntry("image.jpg", 1.45f) 67 | val expectedXmlString = """image.jpg""" 68 | 69 | assertThat(imgEntry.toXMLString()).isEqualTo(expectedXmlString) 70 | } 71 | */ 72 | } -------------------------------------------------------------------------------- /app/src/test/java/com/starry/myne/BookUtilsTest.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) [2022 - Present] Stɑrry Shivɑm 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.starry.myne 18 | 19 | import com.google.common.truth.Truth.assertThat 20 | import com.starry.myne.api.models.Author 21 | import com.starry.myne.helpers.book.BookUtils 22 | import kotlinx.coroutines.test.runTest 23 | import org.junit.Test 24 | 25 | 26 | class BookUtilsTest { 27 | @Test 28 | fun `getAuthorsAsString returns expected string with one author`() = runTest { 29 | val author = Author(name = "Dostoyevsky, Fyodor", birthYear = 0, deathYear = 0) 30 | assertThat(BookUtils.getAuthorsAsString(listOf(author))).isEqualTo("Fyodor Dostoyevsky") 31 | } 32 | 33 | @Test 34 | fun `getAuthorsAsString returns expected string with multiple authors`() = runTest { 35 | val author1 = Author(name = "Dostoyevsky, Fyodor", birthYear = 0, deathYear = 0) 36 | val author2 = Author(name = "Orwell, George", birthYear = 0, deathYear = 0) 37 | assertThat( 38 | BookUtils.getAuthorsAsString( 39 | listOf( 40 | author1, 41 | author2 42 | ) 43 | ) 44 | ).isEqualTo("Fyodor Dostoyevsky, George Orwell") 45 | } 46 | 47 | @Test 48 | fun `getAuthorsAsString returns 'Unknown Author' when the list is empty`() = runTest { 49 | assertThat(BookUtils.getAuthorsAsString(emptyList())).isEqualTo("Unknown Author") 50 | } 51 | 52 | @Test 53 | fun `getLanguagesAsString returns expected string with one language`() = runTest { 54 | assertThat(BookUtils.getLanguagesAsString(listOf("en"))).isEqualTo("English") 55 | } 56 | 57 | @Test 58 | fun `getLanguagesAsString returns expected string with multiple languages`() = runTest { 59 | assertThat(BookUtils.getLanguagesAsString(listOf("en", "fr"))).isEqualTo("English, French") 60 | } 61 | 62 | @Test 63 | fun `getSubjectsAsString returns expected string with less than limit subjects`() = runTest { 64 | val subjects = listOf("Historical fiction", "Robinsonades") 65 | assertThat( 66 | BookUtils.getSubjectsAsString( 67 | subjects, 68 | 3 69 | ) 70 | ).isEqualTo("Historical fiction, Robinsonades") 71 | } 72 | 73 | @Test 74 | fun `getSubjectsAsString returns expected string with more than limit subjects`() = runTest { 75 | val subjects = 76 | listOf( 77 | "Adventure stories", 78 | "Russia -- Social conditions -- 1801-1917 -- Fiction", 79 | "Pirates", 80 | "Shipwrecks", 81 | "Survival" 82 | ) 83 | assertThat( 84 | BookUtils.getSubjectsAsString( 85 | subjects, 86 | 3 87 | ) 88 | ).isEqualTo("Adventure stories, Russia, Social conditions") 89 | } 90 | 91 | } -------------------------------------------------------------------------------- /app/src/test/java/com/starry/myne/UtilsTest.kt: -------------------------------------------------------------------------------- 1 | package com.starry.myne 2 | 3 | import com.starry.myne.helpers.Utils.prettyCount 4 | import junit.framework.TestCase.assertEquals 5 | import kotlinx.coroutines.test.runTest 6 | import org.junit.Test 7 | 8 | class UtilsTest { 9 | @Test 10 | fun `prettyCount with a small number`() = runTest { 11 | assertEquals("100", prettyCount(100)) 12 | } 13 | 14 | @Test 15 | fun `prettyCount with a large number`() = runTest { 16 | assertEquals("1.0k", prettyCount(1000)) 17 | assertEquals("1.5k", prettyCount(1500)) 18 | assertEquals("10.0k", prettyCount(10000)) 19 | assertEquals("999.0k", prettyCount(999000)) 20 | assertEquals("1.0M", prettyCount(1000000)) 21 | assertEquals("1.5M", prettyCount(1500000)) 22 | assertEquals("10.0M", prettyCount(10000000)) 23 | assertEquals("999.0M", prettyCount(999000000)) 24 | assertEquals("1.0B", prettyCount(1000000000)) 25 | assertEquals("1.5B", prettyCount(1500000000)) 26 | assertEquals("10.0B", prettyCount(10000000000)) 27 | assertEquals("999.0B", prettyCount(999000000000)) 28 | assertEquals("1.0T", prettyCount(1000000000000)) 29 | assertEquals("1.5T", prettyCount(1500000000000)) 30 | assertEquals("10.0T", prettyCount(10000000000000)) 31 | assertEquals("999.0T", prettyCount(999000000000000)) 32 | assertEquals("1.0P", prettyCount(1000000000000000)) 33 | assertEquals("1.5P", prettyCount(1500000000000000)) 34 | assertEquals("10.0P", prettyCount(10000000000000000)) 35 | assertEquals("999.0P", prettyCount(999000000000000000)) 36 | assertEquals("1.0E", prettyCount(1000000000000000000)) 37 | } 38 | } -------------------------------------------------------------------------------- /app/src/test/resources/The+Idiot.epub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/app/src/test/resources/The+Idiot.epub -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | kotlin_version = '2.1.20' 4 | gradle_version = '8.9.2' 5 | hilt_version = '2.56.2' 6 | room_version = '2.7.1' 7 | } 8 | 9 | repositories { 10 | google() 11 | mavenCentral() 12 | } 13 | 14 | dependencies { 15 | classpath "com.android.tools.build:gradle:$gradle_version" 16 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 17 | classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" 18 | // NOTE: Do not place your application dependencies here; they belong 19 | // in the individual module build.gradle files 20 | } 21 | } 22 | 23 | plugins { 24 | id 'com.android.application' version "$gradle_version" apply false 25 | id 'com.android.library' version "$gradle_version" apply false 26 | id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false 27 | id 'org.jetbrains.kotlin.plugin.compose' version "$kotlin_version" apply false 28 | id 'com.google.devtools.ksp' version '2.1.20-1.0.32' apply false 29 | id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlin_version" apply false 30 | } -------------------------------------------------------------------------------- /fastlane/metadata/android/cs-CZ/full_description.txt: -------------------------------------------------------------------------------- 1 | Myne je bezplatná open-source aplikace pro Android ke stahování elektronických knih z Projektu GutenBerg, která v backendu využívá GutenDex API k načítání metadat elektronických knih. 2 | 3 | Funkce: 4 | 5 | - Čisté a krásné uživatelské rozhraní založené na zásadách Material Design 3 společnosti Google. 6 | - Prohlížení a stahování více než 70 tisíc bezplatných elektronických knih dostupných v několika jazycích a denně aktualizovaných. 7 | - Obsahuje vestavěnou čtečku elektronických knih a zároveň možnost používat čtečky elektronických knih třetích stran. 8 | - Kompatibilní se systémem Android 7.0 a novějším (API 24+) 9 | - Podporuje motivy Material You v zařízeních se systémem Android 12+ 10 | - Obsahuje světlý i tmavý režim. 11 | - MAD: uživatelské rozhraní a logika napsané v čistém jazyce Kotlin. Jedna aktivita, žádné fragmenty, pouze složitelné cíle. 12 | 13 | PS: *Název aplikace je inspirován hlavním hrdinou anime s názvem Ascendance of a Bookworm (Honzuki no gekokudžó).* 14 | -------------------------------------------------------------------------------- /fastlane/metadata/android/cs-CZ/short_description.txt: -------------------------------------------------------------------------------- 1 | Android aplikace pro stahování e-knih z Projektu GutenBerg. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/cs-CZ/title.txt: -------------------------------------------------------------------------------- 1 | Myne: stahování e-knih 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/1.txt: -------------------------------------------------------------------------------- 1 | - Initial Release. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/11.txt: -------------------------------------------------------------------------------- 1 | - Refactored networking related stuff and improved handling of connection errors. 2 | - Added a setup/welcome screen which allows user to pick their preferred reader when they launch app for the first time. 3 | And more! visit https://github.com/Pool-Of-Tears/Myne/releases/tag/v1.7.0 for full changelog. 4 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/12.txt: -------------------------------------------------------------------------------- 1 | - Added ability to filter/browse books by multiple languages. 2 | - Improved some animations, app should feel bit more snappier than before. 3 | - Fixed bug when downloading book which contains quotes in it's filename. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/13.txt: -------------------------------------------------------------------------------- 1 | Bug fixes & some minor improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/14.txt: -------------------------------------------------------------------------------- 1 | - Added ability to filter by language when browsing books based on categories. 2 | - Added four new book languages (Esperanto, Greek, Latin & Tagalog). 3 | - Some minor UI/UX improvements and fixes. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/15.txt: -------------------------------------------------------------------------------- 1 | - Added ability switch between five different font styles in ebook reader! 2 | - Bug fixes and other improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/16.txt: -------------------------------------------------------------------------------- 1 | - Added support for images in e-book reader. 2 | - Some other minor improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/17.txt: -------------------------------------------------------------------------------- 1 | - Improved UI for wider screens like tablets. 2 | - Bug fixes and other improvements -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/18.txt: -------------------------------------------------------------------------------- 1 | - Reworked on ebook reader backend, fixed scrolling lags and other stability improvements 2 | - Added support for opening external EPUB files with inbuilt ebook reader. 3 | - Added ability to jump between chapters inside the ebook reader. 4 | - Updated target SDK to Android 14 (API 34) 5 | - Made language selection persistent across app launches. 6 | - Bug fixes and other improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/19.txt: -------------------------------------------------------------------------------- 1 | - Fixed crash when opening epub books from shared storage. 2 | - Improved mapping of extra information for books. 3 | - Some other minor fixes 7 improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/2.txt: -------------------------------------------------------------------------------- 1 | - Redesigned book details screen, added a download progress bar and re-written book download backend. 2 | - Added swipe actions in the library and added buttons to open & delete the ebook file. 3 | - Added animations in the bottom navigation bar and improved animations when navigating between screens. 4 | - Added about screen in settings, click on the settings card to open it. 5 | 6 | And more! click [here](https://github.com/Pool-Of-Tears/Myne/releases/tag/v1.1.0) for full changelog. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/20.txt: -------------------------------------------------------------------------------- 1 | - Fixed long book names getting cut after 2 lines. 2 | - Fixed images showing as html tags in some locales 3 | - Fixed flashing of Material You warning message below Android 12 4 | - Added Italian translation. 5 | - Added Romanian translation. 6 | - Updated Russian translation 7 | - Updated Arabic translation 8 | - Updated dependencies, gradle & kotlin versions 9 | - Some other minor fixes & improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/21.txt: -------------------------------------------------------------------------------- 1 | - Added ability to select/copy texts in the reader. 2 | - Updated dependencies, gradle & kotlin versions 3 | - Bug fixes & other improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/22.txt: -------------------------------------------------------------------------------- 1 | - Fix loading issues due to github raw domain being blocked by indian ISPs for god knows what reason. 2 | - Fix Images failing to load due to timeout error. 3 | - Added German translations, thanks to @vrifox -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/23.txt: -------------------------------------------------------------------------------- 1 | - Fix connection errors due to freenom domains being down. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/290.txt: -------------------------------------------------------------------------------- 1 | - Bug fixes and UI/UX improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/3.txt: -------------------------------------------------------------------------------- 1 | - Redesigned book details screen, added a download progress bar and re-written book download backend. 2 | - Added swipe actions in the library and added buttons to open & delete the ebook file. 3 | - Added animations in the bottom navigation bar and improved animations when navigating between screens. 4 | - Added about screen in settings, click on the settings card to open it. 5 | 6 | And more! click [here](https://github.com/Pool-Of-Tears/Myne/releases/tag/v1.1.0) for full changelog. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/300.txt: -------------------------------------------------------------------------------- 1 | - Added appropriate labels for talkback in bottom navigation bar. 2 | - Resolved the issue of certain books' metadata occasionally failing to load. 3 | - Added some caching and fixed the issue where the search bar or language menu would remain open after navigating away from and returning to home screen. 4 | - Some other minor bug fixes and improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/310.txt: -------------------------------------------------------------------------------- 1 | - Major improvements in the internal reader with new ToC-based EPUB parsing logic, allowing it to correctly map chapters instead of relying on a wacky spine-based parser. 2 | - Redesigned the chapter list dialog inside the ebook reader to comply with the rest of the UI design. 3 | - Added a progress indicator at the top bar in the ebook reader to track the progress of the current chapter. 4 | - Fixed the progress percentage not updating immediately when going back to the chapters menu from the reader screen. 5 | - Added two new fonts in the ebook reader called OpenDyslexia and Figerona. 6 | - Bunch of code cleanups, optimizations, and other improvements. 7 | - Updated Compose BOM, Kotlin, and other dependencies. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/320.txt: -------------------------------------------------------------------------------- 1 | - Switch to the internal files directory for storing books instead of external download directory. 2 | - Fixed books not getting saved in the library when using with multi user mode / work profiles. 3 | - Added Chinese translations, thanks to @WeiguangTWK 4 | - Added Brazilian Portuguese translations, thanks to @guiBrisson 5 | - Updated Russian translations, thanks to @Palvenok 6 | - Some other minor bug fixes and improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/325.txt: -------------------------------------------------------------------------------- 1 | - Fixed reader button showing 'resume' instead of 'start' for unread books in ebook reader. 2 | - Fixed books getting deleted from the library after reboot on some devices, particularly Xiaomi. 3 | - Some other minor Ui/UX improvements. 4 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/330.txt: -------------------------------------------------------------------------------- 1 | - Fixed ebook reader jumping to top of the chapter when selecting texts in the middle of the chapter. 2 | - Improved about screen to show more information and links. 3 | - Some other minor bug fixes and improvements. 4 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/340.txt: -------------------------------------------------------------------------------- 1 | - Fixed crash in ebook details screen in some cases. 2 | - Updated Russian translation. 3 | - Other minor fixes and improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/350.txt: -------------------------------------------------------------------------------- 1 | - Now you can import external EPUB books in your library! 2 | - Bunch of fixes and improvements in epub parser to make it more stable and reliable. 3 | - Some minor UI improvements and bug fixes. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/351.txt: -------------------------------------------------------------------------------- 1 | - Now you can import external EPUB books in your library! 2 | - Bunch of fixes and improvements in epub parser to make it more stable and reliable. 3 | - Some minor UI improvements and bug fixes. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/360.txt: -------------------------------------------------------------------------------- 1 | - Fixed a crash caused by NPE when there is no network connection on the first launch. 2 | - Enhanced navigation animations for smoother transitions between screens. 3 | - Improved the loading animation for the book list. 4 | - The chapter title font size is now 1.5x the size of the body text font size, rather than a fixed size. 5 | - Some other UI/UX improvements and fixes. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/370.txt: -------------------------------------------------------------------------------- 1 | - Fixed incorrect background image in ebook reader. 2 | - Added black AMOLED theme and improved default color scheme. 3 | - Added ability to change app language irrespective of system language. (A13+ only) 4 | - Added localization coverage for category names in all supported languages. 5 | - Some other minor fixes and improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/380.txt: -------------------------------------------------------------------------------- 1 | - Fixed copy button not dismissing in the internal reader after clicking elsewhere. 2 | - Fixed status bar not dismissing after swiping down in the internal reader. 3 | - Fixed crash when changing locale in MIUI due to Xiaomi's broken implementation of per-app locale settings on Android 13. 4 | - Some other minor fixes and improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/390.txt: -------------------------------------------------------------------------------- 1 | - Added launcher shortcuts to quickly jump back to the last read book without needing to open the app. 2 | - Added the ability to select and import multiple EPUB books at once. 3 | - Fixed an error in the EPUB parser when parsing chapters if the chapter's path is URL encoded. 4 | - Fixed some edge cases in EPUB parser related to dynamic parsing method selection. 5 | - Improved UI design of the welcome/intro screen. 6 | - Some performance improvements and other minor fixes. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/391.txt: -------------------------------------------------------------------------------- 1 | - Prevent screen from turning off in ebook reader. 2 | - Make developer email address clickable in about screen. 3 | - Updated dependencies & some other minor improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/4.txt: -------------------------------------------------------------------------------- 1 | - Added an inbuilt ebook reader. 2 | 3 | - Switched to the self-hosted Instance of GutenDex API, loading times for books and other metadata should be faster than before. 4 | 5 | And more! visit https://github.com/Pool-Of-Tears/Myne/releases/tag/v1.2.0 for full changelog. 6 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/400.txt: -------------------------------------------------------------------------------- 1 | - Bumped target SDK to v35 (Android 15). 2 | - Added handling for OPF prefix in the manifest tags in the EPUB parser. 3 | - Added Hindi translations. 4 | - Some documentation updates and other minor fixes. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/410.txt: -------------------------------------------------------------------------------- 1 | - Bunch of optimizations and bug fixes in the eBook reader. 2 | - Added more options to the text selection menu, such as meaning, translation, and search. 3 | - Display system navigation and status bars in the eBook reader when toggling the reader menu. 4 | - Added Turkish translations. 5 | - Updated dependencies and some other minor improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/420.txt: -------------------------------------------------------------------------------- 1 | - Improved book opening speed in the reader by caching previously parsed EPUB files. 2 | - Updated UI fonts from Figerona to Poppins due to licensing issues. 3 | - Added Bengali translations. 4 | - Various small fixes and performance improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/421.txt: -------------------------------------------------------------------------------- 1 | - Improved book opening speed in the reader by caching previously parsed EPUB files. 2 | - Updated UI fonts from Figerona to Poppins due to licensing issues. 3 | - Added Bengali translations. 4 | - Various small fixes and performance improvements. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/430.txt: -------------------------------------------------------------------------------- 1 | - Fixed the translucent colors of the status bar and navigation bar. 2 | - Fixed an issue where the chapter title was duplicated multiple times in the reader in some cases. 3 | - Fixed an issue where chapters would jump to the previous chapter when opening the reader menu at the start of a new chapter. 4 | - Made the font size controls in the reader more granular. 5 | - Refactored state management in the reader to improve performance & stability. 6 | - Updated dependencies and AGP to the latest versions. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/440.txt: -------------------------------------------------------------------------------- 1 | - Updated Gutendex API -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/450.txt: -------------------------------------------------------------------------------- 1 | - Added an option to disable the use of the Google Books API for fetching extra information. 2 | - Fixed a bug where all Chinese books ended up with the same filename, causing unpredictable behavior. 3 | - Improved internal filename generation to avoid conflicts. 4 | - Disabled TOC-based EPUB parsing for external/imported books due to inconsistent behavior and frequently broken chapter mapping. 5 | - Updated dependencies and other minor improvements & fixes. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/5.txt: -------------------------------------------------------------------------------- 1 | - Added material you themed monochrome icon for Android 13 2 | 3 | - Improved adaptive Icon and removed legacy icons. 4 | 5 | - Removed check for updates thingy from settings. 6 | 7 | - Some other minor improvements and fixes. 8 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/7.txt: -------------------------------------------------------------------------------- 1 | - Fixed an error when downloading e-books which contains forbidden characters in their filename. 2 | - Fixed library button texts going out of borders when user has custom font size set on their device. 3 | And more! visit https://github.com/Pool-Of-Tears/Myne/releases/tag/v1.4.0 for full changelog. 4 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/8.txt: -------------------------------------------------------------------------------- 1 | - Fixed a crash when trying to open a book from book details screen (in some cases). 2 | - Added Spanish translations; Credits: Rodrigo. 3 | - Updated Russian translation; Credits: Alex. -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/9.txt: -------------------------------------------------------------------------------- 1 | - Fixed NPE due to no epub available for certain books. 2 | - Added Czech translation; Credits: Fjuro 3 | - Code cleanups and some UI Improvements. 4 | - Updated all of the dependencies and upgraded kotlin to v1.8.0 -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/full_description.txt: -------------------------------------------------------------------------------- 1 | Myne is a FOSS Android application for downloading and reading ebooks from Project Gutenberg. It uses the GutenDex API to fetch metadata for ebooks in the backend. Additionally, it functions as an EPUB reader, allowing you to easily import and immerse yourself in your favorite EPUB books! 2 | 3 | Highlights: 4 | 5 | - Clean & beautiful UI based on Google's material design three guidelines. 6 | - Browse and download over 70k free ebooks available in multiple languages and updated daily. 7 | - Comes with inbuilt ebook reader while also having an option to use third-party ebook readers 8 | - Compatible with Android 7.0 and above (API 24+) 9 | - Supports Material You theming in devices running on Android 12+ 10 | - Comes in both light and dark mode. 11 | - MAD: UI and logic written with pure Kotlin. Single activity, no fragments, only composable destinations. 12 | 13 | PS: *The name of the app is inspired from the main character of an anime called Ascendance of a Bookworm.* 14 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/fastlane/metadata/android/en-US/images/icon.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/short_description.txt: -------------------------------------------------------------------------------- 1 | Android application to download & read ebooks from the Project GutenBerg. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/title.txt: -------------------------------------------------------------------------------- 1 | Myne: Download & Read eBooks 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/ro/full_description.txt: -------------------------------------------------------------------------------- 1 | Myne este o aplicație FOSS de Android pentru a descărca ebooks din Project GutenBerg, care folosește GutenDex API pentru a prelua metadatele ebook-urilor în backend. 2 | 3 | Aspecte importante: 4 | 5 | - Interfață curată și frumoasă, bazată pe cele trei linii directoare de material design de la Google. 6 | - Răsfoiți și descărcați peste 70k de eBook-uri gratuite, disponibile în mai multe limbi și actualizate zilnic. 7 | - Vine cu un ebook reader încorporat, având în același timp și opțiunea de a utiliza ebook readers de la terți. 8 | - Compatibil cu Android 8.0 și versiunile ulterioare (API 26+). 9 | - Suportă tema Material You în dispozitivele care rulează pe Android 12+. 10 | - Vine atât în modul luminos, cât și în cel întunecat. 11 | - MAD: UI și logică scrise cu Kotlin pur. Activitate unică, fără fragmente, doar destinații compozibile. 12 | 13 | PS: *Numele aplicației este inspirat de personajul principal al unui anime numit Ascendance of a Bookworm. 14 | -------------------------------------------------------------------------------- /fastlane/metadata/android/ro/short_description.txt: -------------------------------------------------------------------------------- 1 | Aplicație Android pentru a descărca ebook-uri din Project GutenBerg. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/ro/title.txt: -------------------------------------------------------------------------------- 1 | Myne: Descărcător de Ebook 2 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Kotlin code style for this project: "official" or "obsolete": 19 | kotlin.code.style=official 20 | # Enables namespacing of each library's R class so that its R class includes only the 21 | # resources declared in the library itself and none from the library's dependencies, 22 | # thereby reducing the size of the R class for that library 23 | android.nonTransitiveRClass=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pool-Of-Tears/Myne/1e4810ab5cc7e27b7907d821e4e373f52f25663a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Nov 21 12:06:18 IST 2022 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /legal/PRIVACY-POLICY.md: -------------------------------------------------------------------------------- 1 | ## Privacy Policy 2 | This Privacy Policy statement is made by Pool-Of-Tears, consisting of all the entities listed here (collectively referred to as "Pool-Of-Tears," "we," "us," or "our"). 3 | Our mission is to help people protect their privacy, data, and devices from online threats. Myne doesn't track you with ads or abuse your privacy. 4 | We do not require you to create any kind of account with personally identifiable information in order to use the app. 5 | We only ask for the least amount of information necessary for the proper functioning of the application, which is explained below. 6 | 7 | #### Why is Internet permission required? 8 | Internet permission is required to browse and download the ebooks catalog from the [Project Gutenberg](https://gutenberg.org)'s book library, which is hosted on the internet. 9 | 10 | #### Terms of Use 11 | Thank you for using Myne. To protect the app and our users, we require this user agreement to set rules that are necessary to use our software. 12 | Myne is a free and open-source software, which is entirely free to use for non-commercial purposes as long as you agree to our privacy policies. 13 | If you have found a bug or vulnerability in Myne, there are several ways to report the problem so we can fix it: 14 | 15 | - Writing us an email with a detailed description of the issue you're facing. 16 | - Contacting us in our [Telegram](https://t.me/PotApps) support group. 17 | - Creating an issue on the [GitHub](https://github.com/Pool-Of-Tears/Myne) repository of the app. 18 | 19 | This Privacy Policy is subject to updates without any prior notice. 20 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | google() 5 | mavenCentral() 6 | } 7 | } 8 | dependencyResolutionManagement { 9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 10 | repositories { 11 | google() 12 | mavenCentral() 13 | maven { url 'https://jitpack.io' } 14 | } 15 | } 16 | rootProject.name = "Myne" 17 | include ':app' 18 | --------------------------------------------------------------------------------