├── .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 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/appInsightsSettings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
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 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/migrations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
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 |
5 |
6 |
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 |
5 |
6 |
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 |
--------------------------------------------------------------------------------