Merge branch 'master' into file-tree-browse-feature

This commit is contained in:
acclorite 2024-08-10 12:59:31 +03:00
commit 24598c79f4
18 changed files with 3210 additions and 127 deletions

View file

@ -1,13 +1,39 @@
# <p align="center">Book's Story 📖</p> <!------------ Header ------------>
<div align="center"> <div align="center">
<a href="">[![Latest Stable Release](https://img.shields.io/github/release/Acclorite/book-story.svg?label=Release&logo=GitHub)](https://github.com/Acclorite/book-story/releases)</a> <img src="https://github.com/Acclorite/book-story/blob/master/assets/readme/app_icon.png" width="120" />
<a href="">[![Downloads](https://img.shields.io/github/downloads/Acclorite/book-story/total?color=0273b3&label=Downloads&logo=GitHub)]()</a>
</div> </div>
# <p align="center">Book's Story</p>
### <p align="center">Material3 Book Reader for Android</p>
<p align="center">Dive into the world of adventure as you discover your favorite book's story!</p>
<!------------ Badges ------------>
<div align="center">
<a href="">[![Latest Stable Release](https://img.shields.io/github/release/Acclorite/book-story.svg?labelColor=27303D&color=3f719b&label=Release&logo=GitHub)](https://github.com/Acclorite/book-story/releases)</a>
<a href="">[![F-Droid Release](https://img.shields.io/f-droid/v/ua.acclorite.book_story?labelColor=27303D&color=3f9b5a&label=F-Droid&logo=f-droid)](https://f-droid.org/packages/ua.acclorite.book_story/)</a>
<a href="">[![IzzyOnDroid Release](https://img.shields.io/endpoint?url=https://apt.izzysoft.de/fdroid/api/v1/shield/ua.acclorite.book_story&labelColor=27303D&color=3f9b84&label=IzzyOnDroid&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAADAFBMVEUA0////wAA0v8A0v8A0////wD//wAFz/QA0/8A0/8A0/8A0/8A0v///wAA0/8A0/8A0/8A0/8A0//8/gEA0/8A0/8B0/4A0/8A0/8A0/+j5QGAwwIA0//C9yEA0/8A0/8A0/8A0/8A0/8A0/+n4SAA0/8A0/8A0/+o6gCw3lKt7QCv5SC+422b3wC19AC36zAA0/+d1yMA0/8A0/+W2gEA0/+w8ACz8gCKzgG7+QC+9CFLfwkA0/8A0////wAA0/8A0/8A0/8A0/+f2xym3iuHxCGq5BoA1P+m2joI0vONyiCz3mLO7oYA0/8M1Piq3Ei78CbB8EPe8LLj9Ly751G77zWQ1AC96UYC0fi37CL//wAA0/8A0////wD//wCp3jcA0/+j3SGj2i/I72Sx4zHE8FLB8zak1kYeycDI6nRl3qEA0/7V7psA0v6WzTa95mGi2RvB5XkPy9zH5YJ3uwGV1yxVihRLiwdxtQ1ZkAf//wD//wD//wD//wD//wCn5gf//wD//wD//wD//wD//wAA0/+h4A3R6p8A0/+X1w565OD6/ARg237n9csz2vPz+gNt37V/vifO8HW68B/L6ZOCwxXY8KRQsWRzhExAtG/E612a1Rd/pTBpmR9qjysduKVhmxF9mTY51aUozK+CsDSA52T//wD//wAA0////wD//wBJ1JRRxFWjzlxDyXRc0pGT1wCG0CWB3VGUzSTh8h6c0TSr5CCJ5FFxvl6s4H3m8xML0/DA5CvK51EX1N+Y2gSt4Dag3ChE3fax2ki68yO57NF10FRZnUPl88eJxhuCxgCz5EOLwEGf1DFutmahzGW98x0W1PGk3R154MHE6bOn69qv3gy92oG90o+Hn07B7rhCmiyMwECv1nO+0pQfwrCo57xF2daXsVhKrEdenQAduaee1Bsjr42z5D9RoCXy+QNovXpy2Z5MtWDO/TiSukaF3UtE1K6j3B4YwLc5wXlzpyIK0u5zy3uJqg4pu5RTpkZmpVKyAP8A0wBHcExHcEyBUSeEAAABAHRSTlP///9F9wjAAxD7FCEGzBjd08QyEL39abMd6///8P/ZWAnipIv/cC6B//7////////L/1Dz/0D///////86/vYnquY3/v///5T//v///17///////////////84S3QNB/8L/////////////7r/////NP////9l/////wPD4yis/x7Ym2lWSP+em////0n////////v///////////////////7//7pdGN3Urr6/+v/6aT////+//H/o2P/1v+7r7jp4PM/3p4g////g///K///481LxO///v////9w////8v/////9/p3J///a+P9v/5KR/+n///+p/xf//8P//wAAe7FyaAAABCZJREFUSMdj+E8iYKBUgwIHnwQ3N7cEHxcH+///VayoAE0Dh41qR7aBnCIQ8MsJKHH9/99czYYMWlA0cIkJGjMgAKfq//9RNYzIgLcBWYOTiCgDMhDn+B9bh6LebiWyH6L5UZQzONoAHWSHoqEpDkkDsyKqelv1//9rG1HUN9YihZK9AKp6BkG+/6xNqA5ajhSsCkrIipmYGGRa//9vQXVQXSySBnkWJOUMfn5Myuz/G3hR1NdEIUUchwiy+bkTsg4dbW/fu6W/e1c3XMMy5JiOZkFxUFZo74mgKTqaKXu0+2HqVwkja3BH9kFu361JwcHTfPJD4mdfe8ULAdVRyGlJAcVFfg+CQOozZ4XrJ85+JgwBsVXIGriQw5Tp4ZScezd8JiWnBupru30qwJZa+ZAjmWlC8fUZM4qB6kPnLNSPLMWqQQ5ZQ5aOzs1HmamBaQHzFs6y+qAmJCTE8f9/QgKSBg4DJPWc6zVDQkIC09JkZSPD38kukpExFpT4z67uYI/QwCOOCCK/izvu5CWl6AcEWMnKWml7LWbKZfH9/99UkknQHhGsynDz+65eWXv3/JmJrq5eXienVlRUfH/z8VvCf45soKQIH1yDEQsszrp6gwq9C73T87xcXadKl5TkFev4A/2tygmSBqYXqAYJmK+ZuoJydDR1vP09DA0NOy2kpdML81+U/heCpH1JU3jig7lJ5nKOT4i/t6ZHkqGzs4lJmIVHfrj+JR4HqLQSD0yDkCNEpGNn5ix9D03/eJdElTZdKV2TpNOhkwt8YUlNUgimgV0dLMBvf1gz1MolPd5FRcVNSkpDQ8owJeBCDyIhrIDnOD5QcuIU+3/2QKSs9laQ+noNLS0zLWdtqyP7mBAFAw88TwsJgMuJYweBGjYngtWbmeuZOW+bvNQToUFOAlFqOBk4Ov3/L7Z60/aN0p1tUhpa5nqWlub7C3p2I9QzyAghlUvczOz/1fhzPT3XSIfpSmmYAdVbmm1gV0dSz8DSilpUQsqCddIWIA3meuZaJqdMJZEzl6gRqgZIWZAxUdoizERXN8yi5MltcZTChzMaRQM3JNUWHS8rL/+yaPGvMmvr5ywoGoxtkDWwQ+Pb89ycBeWfGSJeL/la+RS1eOPnRtbQKgMRjZg+t8x6PkP273nWQAoFOPAgaeAThKXAmXMrK39Kmr5fsuBlBqoXfJGLe3VbmHjG9Mczi9T//3h7vygXtcDlQtJg44iQiIjIBRbGPO7gghPJy0ZIxT2HOLIUgwxQzsgYrUR350HSIMaJLidhgKY+mw+pflBDrX8E7OGBjPCAPc76gQFSTqAIiYrb/8dRP4CyosJ/rmwU5XIxHMilt4QBJwsSkBMClxOQULBlkRRwEONmR2kJcDGjADX2/+xO8r5iqjExqmLyrWpcPFRta1BfAwCtyN3XpuJ4RgAAAABJRU5ErkJggg==
)](https://apt.izzysoft.de/fdroid/index/apk/ua.acclorite.book_story)</a>
<a href="">[![Downloads](https://img.shields.io/github/downloads/Acclorite/book-story/total?color=3f8f9b&labelColor=27303D&label=Downloads&logo=GitHub)]()</a>
<a href="">[![Stars](https://img.shields.io/github/stars/Acclorite/book-story?style=flat&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIC05NjAgOTYwIDk2MCIgd2lkdGg9IjI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxwYXRoIGQ9Im0zNTQtMjQ3IDEyNi03NiAxMjYgNzctMzMtMTQ0IDExMS05Ni0xNDYtMTMtNTgtMTM2LTU4IDEzNS0xNDYgMTMgMTExIDk3LTMzIDE0M1pNMjMzLTgwbDY1LTI4MUw4MC01NTBsMjg4LTI1IDExMi0yNjUgMTEyIDI2NSAyODggMjUtMjE4IDE4OSA2NSAyODEtMjQ3LTE0OUwyMzMtODBabTI0Ny0zNTBaIiBzdHlsZT0iZmlsbDogcmdiKDI0NSwgMjI3LCA2Nik7Ii8%2BCjwvc3ZnPg%3D%3D&color=949b3f&labelColor=27303D&label=Stars)](https://github.com/Acclorite/book-story/stargazers)</a>
<a href="">[![Development Stage](https://img.shields.io/badge/Active-9b3f90?label=Development%20stage&labelColor=27303D)](https://github.com/Acclorite/book-story/commits/)</a>
<a href="">[![Last Commit](https://img.shields.io/github/last-commit/Acclorite/book-story?label=Last%20commit&labelColor=27303D&color=749b3f)](https://github.com/Acclorite/book-story/commits/)</a>
<a href="">[![License: GPL-3.0](https://img.shields.io/github/license/Acclorite/book-story?label=License&labelColor=27303D&color=3f9b75)](/LICENSE)</a>
<a href="">[![Repository Size](https://img.shields.io/github/repo-size/Acclorite/book-story?label=Repository%20size&labelColor=27303D&color=563f9b)]()</a>
</div>
<!------------ Overview ------------>
# <p align="center">Overview</p>
<img src="https://github.com/Acclorite/book-story/blob/master/assets/readme/github_overview.png"> <img src="https://github.com/Acclorite/book-story/blob/master/assets/readme/github_overview.png">
Material3 Book Reader built with Jetpack Compose and Kotlin. Built using Jetpack Compose and Kotlin.
<!------------ Screenshots ------------>
## 🖌️ Screenshots + GIF ## 🖌️ Screenshots + GIF
@ -24,25 +50,40 @@ Material3 Book Reader built with Jetpack Compose and Kotlin.
_You can find more screenshots in [assets](https://github.com/Acclorite/book-story/tree/master/assets) folder._ _You can find more screenshots in [assets](https://github.com/Acclorite/book-story/tree/master/assets) folder._
<!------------ Download guide ------------>
## ✈️ Download ## ✈️ Download
- _Please note, that the app supports Android versions only from Android 8.0_ - _Please note, that the app supports Android versions only from Android 8.0_
<div align="start"> <div align="left">
[<img src="https://raw.githubusercontent.com/ismartcoding/plain-app/main/assets/get-it-on-github.png" alt='Get it on GitHub' height="80">](https://github.com/Acclorite/book-story/releases/latest) [<img src="https://raw.githubusercontent.com/ismartcoding/plain-app/main/assets/get-it-on-github.png" alt='Get it on GitHub' height="80">](https://github.com/Acclorite/book-story/releases/latest)
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" alt="Get it on F-Droid" height="80">](https://f-droid.org/en/packages/ua.acclorite.book_story/)
[<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png" alt="Get it on IzzyOnDroid" height="80">](https://apt.izzysoft.de/fdroid/index/apk/ua.acclorite.book_story)
</div> </div>
_Currently the app is only available on Github, Fdroid is coming.._ _Don't see your favorite app store? Create an [Issue](https://github.com/Acclorite/book-story/issues)! (Except Play Store, this app won't be there)_
### 📲 How to download and install ### 📲 How to download and install
- _Install from Github_: Click on the "Get it on GitHub" badge above, scroll down and download **book-story.apk** or download the last apk from GitHub [here](https://github.com/Acclorite/book-story/releases/latest/download/book-story.apk). After that, find downloaded file and install it. If you don't understand how to do so, follow [this guide](https://www.lifewire.com/install-apk-on-android-4177185). - _**Install from Github**_: Click on the "Get it on GitHub" badge above, scroll down and download **book-story.apk** or download the last apk from GitHub [here](https://github.com/Acclorite/book-story/releases/latest/download/book-story.apk). After that, find downloaded APK and install it.
- _Install from F-Droid_: Coming soon... - _**Install from F-Droid**_: Click on the "Get it on F-Droid" badge above, scroll down and click "Download APK" under desired Release Version to download the APK file. After that, find downloaded APK and install it.
- _**Install from IzzyOnDroid**_: Click on the "Get it on IzzyOnDroid" badge above, scroll down and click "Download" to download the last APK from IzzyOnDroid. After that, find downloaded APK and install it.
- If you don't know how to install APK file, follow [this guide](https://www.lifewire.com/install-apk-on-android-4177185).
### 🗳️ APK Verification
- _APK Verification is an important step to ensure APK integrity and prevent risks from getting infected one._
- For verification you can use tool called [apksigner](https://developer.android.com/tools/apksigner). Which is the part of Android SDK Build Tools, so you need to install that first.
| APK SHA-256 certificate |
|-------------------------------------------------------------------|
| a661a0c81f138e53dff32f8fdc1dd19f8130523914027e2c0296fe245131a7d4 |
### 🧭 Afterwards ### 🧭 Afterwards
- Open the app and follow basic instructions. - Open the app and follow basic instructions.
- If you don't understand how to use the app, please read everything in the app's Help Screen. (You can find it in: Library, History, Browse → Three Dots → Help) - If you don't understand how to use the app, please read everything in the app's Help Screen. (You can find it in: Library, History, Browse → Three Dots → Help)
- If you still have questions, please feel free to ask in [Discussions](https://github.com/Acclorite/book-story/discussions/categories/q-a), or create an [Issue](https://github.com/Acclorite/book-story/issues) if you feel like some area should be documented better. - If you still have questions, please feel free to ask in [Discussions](https://github.com/Acclorite/book-story/discussions/categories/q-a), or create an [Issue](https://github.com/Acclorite/book-story/issues) if you feel like some area should be documented better.
<!------------ Features ------------>
## ✨ Features ## ✨ Features
- 4 supported file formats(.pdf, .txt, .epub, .fb2) - 4 supported file formats(.pdf, .txt, .epub, .fb2)
@ -61,16 +102,30 @@ _Currently the app is only available on Github, Fdroid is coming.._
- Detailed app functions explanation(Help screen tips) - Detailed app functions explanation(Help screen tips)
- More.. - More..
<!------------ Roadmap ------------>
## 😵‍💫 Upcoming features / Roadmap ## 😵‍💫 Upcoming features / Roadmap
- _You can track project's progress, see what's coming and what is already implemented in [Book's Story: Development Roadmap](https://github.com/users/Acclorite/projects/1)._ - _You can track project's progress, see what's coming and what is already implemented in [Book's Story: Development Roadmap](https://github.com/users/Acclorite/projects/1)._
<!------------ Translation ------------>
## 🌐 Translation ## 🌐 Translation
- English (Default) - English (Default)
- Ukrainian (Default) - Ukrainian (Default)
<!------------ Contribution ------------>
## 🤝 How to contribute
- **The most improtant thing is I do not want someone's code.** This project is maintaining only by me and I want it to be this way. Creating Pull Requests will not have much sense as they will probably be closed.
- **Share your ideas and suggestions.** Your ideas and suggestions are always welcome, if you miss some feature or got an interesting idea, feel free to create a new [Issue](https://github.com/Acclorite/book-story/issues).
- **Report bugs**. Had a crash or something went wrong? Create a new [Issue](https://github.com/Acclorite/book-story/issues), the more information you can give the better it is.
- **Enjoy the app**. Your best contribution is using my app and enjoying it!
- _**About localization**. Planning to implement localiztion platform, so users can do what I physically cannot - translate the app on multiple languages. You can find more information about this in the corresponding issue([#22](https://github.com/Acclorite/book-story/issues/22))._
<!------------ Credits and License ------------>
## 🤗 Credits ## 🤗 Credits
- [Tachiyomi (Mihon)](https://github.com/mihonapp/mihon) (Github) - [Tachiyomi (Mihon)](https://github.com/mihonapp/mihon) (Github)
- [Libre-Sudoku](https://github.com/kaajjo/Libre-Sudoku) (Github)
- [Kitsune](https://github.com/Drumber/Kitsune) (Github) - [Kitsune](https://github.com/Drumber/Kitsune) (Github)
- [Material Design Icons](https://fonts.google.com/icons) (Google Fonts) - [Material Design Icons](https://fonts.google.com/icons) (Google Fonts)
- Also listed in About > Credits. - Also listed in About > Credits.

View file

@ -1,3 +1,5 @@
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
plugins { plugins {
id("com.android.application") id("com.android.application")
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
@ -17,8 +19,8 @@ android {
applicationId = "ua.acclorite.book_story" applicationId = "ua.acclorite.book_story"
minSdk = 26 minSdk = 26
targetSdk = 34 targetSdk = 34
versionCode = 5 versionCode = 6
versionName = "1.1.0" versionName = "1.1.1"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables { vectorDrawables {
@ -34,21 +36,19 @@ android {
getByName("debug") { getByName("debug") {
applicationIdSuffix = ".debug" applicationIdSuffix = ".debug"
} }
getByName("release") {
isMinifyEnabled = true
isShrinkResources = false
proguardFiles("proguard-rules.pro")
}
create("release-debug") { create("release-debug") {
initWith(getByName("release")) initWith(getByName("release"))
applicationIdSuffix = ".release.debug" applicationIdSuffix = ".release.debug"
signingConfig = signingConfigs.getByName("debug") signingConfig = signingConfigs.getByName("debug")
} }
getByName("release") {
isMinifyEnabled = false
isShrinkResources = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
} }
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_17 sourceCompatibility = JavaVersion.VERSION_17
@ -63,6 +63,10 @@ android {
composeOptions { composeOptions {
kotlinCompilerExtensionVersion = "1.5.7" kotlinCompilerExtensionVersion = "1.5.7"
} }
dependenciesInfo {
includeInApk = false
includeInBundle = false
}
packaging { packaging {
resources { resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}" excludes += "/META-INF/{AL2.0,LGPL2.1}"
@ -72,12 +76,9 @@ android {
} }
aboutLibraries { aboutLibraries {
outputFileName = "aboutlibraries.json" registerAndroidTasks = false
prettyPrint = true
gitHubApiToken = properties["github-key"] as? String gitHubApiToken = gradleLocalProperties(rootDir, providers)["github-key"] as? String
offlineMode = false
fetchRemoteLicense = true
fetchRemoteFunding = false
filterVariants = arrayOf("debug", "release", "release-debug") filterVariants = arrayOf("debug", "release", "release-debug")
excludeFields = arrayOf("generated", "funding", "description") excludeFields = arrayOf("generated", "funding", "description")
@ -107,13 +108,13 @@ dependencies {
// All dependencies // All dependencies
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4") implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4")
implementation("com.google.accompanist:accompanist-swiperefresh:0.24.2-alpha") implementation("com.google.accompanist:accompanist-swiperefresh:0.34.0")
// Dagger - Hilt // Dagger - Hilt
implementation("com.google.dagger:hilt-android:2.51.1") implementation("com.google.dagger:hilt-android:2.52")
ksp("com.google.dagger:hilt-android-compiler:2.51") ksp("com.google.dagger:hilt-android-compiler:2.52")
implementation("com.google.dagger:hilt-compiler:latest.release") implementation("com.google.dagger:hilt-compiler:2.52")
ksp("androidx.hilt:hilt-compiler:latest.release") ksp("androidx.hilt:hilt-compiler:1.2.0")
implementation("androidx.hilt:hilt-navigation-compose:1.2.0") implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
// Room // Room
@ -124,47 +125,45 @@ dependencies {
implementation("androidx.room:room-ktx:2.6.1") implementation("androidx.room:room-ktx:2.6.1")
// Datastore // Datastore
implementation("androidx.datastore:datastore-preferences:latest.release") implementation("androidx.datastore:datastore-preferences:1.1.1")
// Splash API // Splash API
implementation("androidx.core:core-splashscreen:latest.release") implementation("androidx.core:core-splashscreen:1.0.1")
// Permission Handling // Permission Handling
implementation("com.google.accompanist:accompanist-permissions:latest.release") implementation("com.google.accompanist:accompanist-permissions:0.34.0")
// Pdf parser // Pdf parser
implementation("com.tom-roush:pdfbox-android:latest.release") implementation("com.tom-roush:pdfbox-android:2.0.27.0")
// Epub parser // Epub parser
implementation("com.positiondev.epublib:epublib-core:3.1") { implementation("com.positiondev.epublib:epublib-core:3.1") {
exclude("org.slf4j")
exclude("xmlpull") exclude("xmlpull")
} }
implementation("org.slf4j:slf4j-android:latest.release") implementation("org.jsoup:jsoup:1.18.1")
implementation("org.jsoup:jsoup:latest.release")
// Fb2 parser // Fb2 parser
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:latest.release") implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.1")
// App Compat for Language Switcher // App Compat for Language Switcher
implementation("androidx.appcompat:appcompat:latest.release") implementation("androidx.appcompat:appcompat:1.7.0")
implementation("androidx.appcompat:appcompat-resources:latest.release") implementation("androidx.appcompat:appcompat-resources:1.7.0")
// Coil for loading bitmaps // Coil for loading bitmaps
implementation("io.coil-kt:coil-compose:2.6.0") implementation("io.coil-kt:coil-compose:2.7.0")
// Retrofit // Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0") implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("com.squareup.retrofit2:converter-moshi:2.9.0") implementation("com.squareup.retrofit2:converter-moshi:2.11.0")
implementation("com.squareup.moshi:moshi:1.15.1") implementation("com.squareup.moshi:moshi:1.15.1")
implementation("com.squareup.moshi:moshi-kotlin:1.15.1") implementation("com.squareup.moshi:moshi-kotlin:1.15.1")
implementation("com.squareup.okhttp3:okhttp:4.12.0") implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.9.1") implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
// About open source libraries // About open source libraries
implementation("com.mikepenz:aboutlibraries-core:latest.release") implementation("com.mikepenz:aboutlibraries-core:11.2.2")
implementation("com.mikepenz:aboutlibraries-compose-m3:latest.release") implementation("com.mikepenz:aboutlibraries-compose-m3:11.2.2")
// Drag & Drop // Drag & Drop
implementation("sh.calvin.reorderable:reorderable:2.2.0") implementation("sh.calvin.reorderable:reorderable:2.3.0")
} }

View file

@ -1,5 +1,5 @@
# Proguard-rules # Proguard-rules
-dontwarn org.xmlpull.v1.** -dontwarn android.content.res.**
-dontwarn com.gemalto.jp2.JP2Decoder -dontwarn com.gemalto.jp2.JP2Decoder
-dontwarn com.google.auto.service.AutoService -dontwarn com.google.auto.service.AutoService
-dontwarn javax.lang.model.SourceVersion -dontwarn javax.lang.model.SourceVersion
@ -31,11 +31,17 @@
-dontwarn javax.lang.model.util.SimpleTypeVisitor8 -dontwarn javax.lang.model.util.SimpleTypeVisitor8
-dontwarn javax.lang.model.util.Types -dontwarn javax.lang.model.util.Types
-dontwarn javax.tools.Diagnostic$Kind -dontwarn javax.tools.Diagnostic$Kind
-dontwarn org.kxml2.io.** -dontwarn org.kxml2.io.KXml**
-dontwarn org.slf4j.Logger
-dontwarn org.slf4j.LoggerFactory
-dontwarn org.xmlpull.v1.XmlPullParserFactory
-keep class com.mikepenz.aboutlibraries.** { *; } # Fixes issue with displaying .xml files, but may produce reproducibility issues
-keep class org.xmlpull.** { *; } -keep class org.xmlpull.** { *; }
-keepclassmembers class org.xmlpull.** { *; } -keepclassmembers class org.xmlpull.** { *; }
# Debug rule # Keeping names of classes that produce undeterministic results
#-keepnames class ** { *; } -keepnames class **
-keepnames class org.xmlpull.** { *; }
-keepclassmembernames class org.xmlpull.** { *; }
-keepnames class kotlin.reflect.jvm.internal.impl.builtins.PrimitiveType { values(); }

View file

@ -12,6 +12,11 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<!-- Removing DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION, which is not used -->
<uses-permission
android:name="ua.acclorite.book_story.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
tools:node="remove" />
<queries> <queries>
<!-- Translator --> <!-- Translator -->
@ -43,6 +48,7 @@
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:enableOnBackInvokedCallback="true" android:enableOnBackInvokedCallback="true"
android:usesCleartextTraffic="false" android:usesCleartextTraffic="false"
android:largeHeap="true"
tools:targetApi="tiramisu" tools:targetApi="tiramisu"
tools:ignore="DataExtractionRules"> tools:ignore="DataExtractionRules">

View file

@ -53,20 +53,6 @@ class PdfTextParser @Inject constructor(private val application: Application) :
return@forEachIndexed return@forEachIndexed
} }
if (
line.all {
if (it == ' ') {
true
} else if (it.isUpperCase() || it.isDigit() || it == '-') {
true
} else {
false
}
}
) {
return@forEachIndexed
}
if (line.all { it.isDigit() }) { if (line.all { it.isDigit() }) {
return@forEachIndexed return@forEachIndexed
} }

View file

@ -401,10 +401,15 @@ class BookRepositoryImpl @Inject constructor(
val byteArray = stream.toByteArray() val byteArray = stream.toByteArray()
val defaultCover = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size) val defaultCover = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
val currentCover = MediaStore.Images.Media.getBitmap( val currentCover = try {
application.contentResolver, MediaStore.Images.Media.getBitmap(
Uri.parse(book.image) application.contentResolver,
) Uri.parse(book.image)
)
} catch (e: Exception) {
e.printStackTrace()
return true
}
return !defaultCover.sameAs(currentCover) return !defaultCover.sameAs(currentCover)
} }
@ -485,6 +490,16 @@ class BookRepositoryImpl @Inject constructor(
.map { bookMapper.toBook(it) } .map { bookMapper.toBook(it) }
val primaryDirectory = Environment.getExternalStorageDirectory() val primaryDirectory = Environment.getExternalStorageDirectory()
if (
!primaryDirectory.exists() ||
(Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED &&
Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED_READ_ONLY)
) {
emit(Resource.Success(null))
return@flow
}
val allFiles = getAllFilesInDirectory(primaryDirectory) val allFiles = getAllFilesInDirectory(primaryDirectory)
if (allFiles.isEmpty()) { if (allFiles.isEmpty()) {

View file

@ -83,14 +83,6 @@ object Constants {
), ),
website = "https://www.github.com/mihonapp/mihon" website = "https://www.github.com/mihonapp/mihon"
), ),
Credit(
name = "Libre-Sudoku",
source = "GitHub",
credits = listOf(
UIText.StringValue("Readme")
),
website = "https://www.github.com/kaajjo/Libre-Sudoku"
),
Credit( Credit(
name = "Kitsune", name = "Kitsune",
source = "GitHub", source = "GitHub",
@ -107,15 +99,6 @@ object Constants {
), ),
website = "https://fonts.google.com/icons" website = "https://fonts.google.com/icons"
), ),
Credit(
name = "Crocus",
source = null,
credits = listOf(
UIText.StringResource(R.string.credits_motivation),
UIText.StringValue("UwU")
),
website = null
),
) )
// Help Tips // Help Tips

View file

@ -144,27 +144,36 @@ private fun AboutScreen(
) )
append("\n") append("\n")
append(stringResource(id = R.string.app_version_option_desc_2)) append(stringResource(id = R.string.app_version_option_desc_2))
} },
showLoading = state.value.updateLoading
) { ) {
onEvent( if (!state.value.alreadyCheckedForUpdates) {
AboutEvent.OnCheckForUpdates( onEvent(
context = context, AboutEvent.OnCheckForUpdates(
noUpdatesFound = { context = context,
Toast.makeText( noUpdatesFound = {
context, Toast.makeText(
context.getString(R.string.no_updates), context,
Toast.LENGTH_LONG context.getString(R.string.no_updates),
).show() Toast.LENGTH_LONG
}, ).show()
error = { },
Toast.makeText( error = {
context, Toast.makeText(
context.getString(R.string.error_check_internet), context,
Toast.LENGTH_LONG context.getString(R.string.error_check_internet),
).show() Toast.LENGTH_LONG
} ).show()
}
)
) )
) } else {
Toast.makeText(
context,
context.getString(R.string.no_updates),
Toast.LENGTH_LONG
).show()
}
} }
} }

View file

@ -1,22 +1,38 @@
package ua.acclorite.book_story.presentation.screens.about.components package ua.acclorite.book_story.presentation.screens.about.components
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import ua.acclorite.book_story.presentation.ui.FadeTransitionPreservingSpace
/** /**
* About screen item. * About Screen Item.
* Clickable item, that has title, description and loading state.
*
* @param modifier [Modifier].
* @param title Title of the item.
* @param description Description of the item.
* @param verticalPadding Vertical item padding.
* @param showLoading Whether loading indicator is shown.
* @param isOnClickEnabled Whether this item is clickable.
* @param onClick OnClick callback.
*/ */
@Composable @Composable
fun AboutItem( fun AboutItem(
@ -24,31 +40,45 @@ fun AboutItem(
title: String, title: String,
description: AnnotatedString?, description: AnnotatedString?,
verticalPadding: Dp = 12.dp, verticalPadding: Dp = 12.dp,
showLoading: Boolean = false,
isOnClickEnabled: Boolean = true, isOnClickEnabled: Boolean = true,
onClick: () -> Unit = {} onClick: () -> Unit = {}
) { ) {
Column( Row(
modifier modifier
.fillMaxWidth() .fillMaxWidth()
.clickable(enabled = isOnClickEnabled) { .clickable(enabled = isOnClickEnabled) {
onClick() onClick()
} }
.padding(horizontal = 18.dp, vertical = verticalPadding), .padding(horizontal = 18.dp, vertical = verticalPadding),
verticalArrangement = Arrangement.Center verticalAlignment = Alignment.CenterVertically
) { ) {
Text( Column(Modifier.weight(1f)) {
title,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurface,
fontSize = 18.sp
)
description?.let {
Text( Text(
it, title,
overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.bodyLarge,
style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurface,
color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 18.sp
) )
description?.let {
Text(
it,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
FadeTransitionPreservingSpace(visible = showLoading) {
Row {
Spacer(modifier = Modifier.width(18.dp))
CircularProgressIndicator(
color = MaterialTheme.colorScheme.onSurfaceVariant,
strokeCap = StrokeCap.Round,
modifier = Modifier.size(28.dp)
)
}
} }
} }
} }

View file

@ -6,5 +6,7 @@ import ua.acclorite.book_story.data.remote.dto.LatestReleaseInfo
@Immutable @Immutable
data class AboutState( data class AboutState(
val showUpdateDialog: Boolean = false, val showUpdateDialog: Boolean = false,
val alreadyCheckedForUpdates: Boolean = false,
val updateLoading: Boolean = false,
val updateInfo: LatestReleaseInfo? = null val updateInfo: LatestReleaseInfo? = null
) )

View file

@ -40,9 +40,19 @@ class AboutViewModel @Inject constructor(
is AboutEvent.OnCheckForUpdates -> { is AboutEvent.OnCheckForUpdates -> {
viewModelScope.launch { viewModelScope.launch {
_state.update {
it.copy(
updateLoading = true
)
}
val result = checkForUpdates.execute(false) val result = checkForUpdates.execute(false)
if (result == null) { if (result == null) {
_state.update {
it.copy(
updateLoading = false
)
}
event.error() event.error()
return@launch return@launch
} }
@ -52,12 +62,19 @@ class AboutViewModel @Inject constructor(
if (version == currentVersion) { if (version == currentVersion) {
event.noUpdatesFound() event.noUpdatesFound()
_state.update {
it.copy(
updateLoading = false,
alreadyCheckedForUpdates = true
)
}
return@launch return@launch
} }
_state.update { _state.update {
it.copy( it.copy(
showUpdateDialog = true, showUpdateDialog = true,
updateLoading = false,
updateInfo = result updateInfo = result
) )
} }

View file

@ -4,13 +4,14 @@ import android.content.Context
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.mikepenz.aboutlibraries.Libs import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.util.withContext import com.mikepenz.aboutlibraries.util.withJson
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import ua.acclorite.book_story.R
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
@ -29,7 +30,7 @@ class LicensesViewModel @Inject constructor(
val licenses = Libs val licenses = Libs
.Builder() .Builder()
.withContext(context) .withJson(context, R.raw.aboutlibraries)
.build() .build()
.libraries .libraries
.toList() .toList()

View file

@ -331,6 +331,7 @@ private fun ReaderScreen(
) )
.readerFastColorPresetChange( .readerFastColorPresetChange(
fastColorPresetChangeEnabled = mainState.value.fastColorPresetChange!!, fastColorPresetChangeEnabled = mainState.value.fastColorPresetChange!!,
isLoading = state.value.loading,
toolbarHidden = toolbarHidden, toolbarHidden = toolbarHidden,
onSettingsEvent = onSettingsEvent, onSettingsEvent = onSettingsEvent,
presetChanged = { presetChanged = {

View file

@ -14,6 +14,7 @@ import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
* Detects horizontal swipe gestures. * Detects horizontal swipe gestures.
* *
* @param fastColorPresetChangeEnabled Whether this is enabled. * @param fastColorPresetChangeEnabled Whether this is enabled.
* @param isLoading Whether Reader is loading.
* @param toolbarHidden Whether toolbar(selection) is hidden. * @param toolbarHidden Whether toolbar(selection) is hidden.
* @param onSettingsEvent [SettingsEvent] callback. * @param onSettingsEvent [SettingsEvent] callback.
* @param presetChanged Callback when Color Preset was changed. * @param presetChanged Callback when Color Preset was changed.
@ -21,13 +22,14 @@ import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
@Composable @Composable
fun Modifier.readerFastColorPresetChange( fun Modifier.readerFastColorPresetChange(
fastColorPresetChangeEnabled: Boolean, fastColorPresetChangeEnabled: Boolean,
isLoading: Boolean,
toolbarHidden: Boolean, toolbarHidden: Boolean,
onSettingsEvent: (SettingsEvent) -> Unit, onSettingsEvent: (SettingsEvent) -> Unit,
presetChanged: (UIText) -> Unit presetChanged: (UIText) -> Unit
): Modifier { ): Modifier {
val offset = remember { mutableFloatStateOf(0f) } val offset = remember { mutableFloatStateOf(0f) }
return this.then( return this.then(
if (fastColorPresetChangeEnabled && toolbarHidden) { if (fastColorPresetChangeEnabled && toolbarHidden && !isLoading) {
Modifier.pointerInput(Unit) { Modifier.pointerInput(Unit) {
detectHorizontalDragGestures( detectHorizontalDragGestures(
onDragStart = { offset.floatValue = 0f }, onDragStart = { offset.floatValue = 0f },

View file

@ -1,5 +1,8 @@
package ua.acclorite.book_story.presentation.ui package ua.acclorite.book_story.presentation.ui
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.EaseInOut
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
@ -8,8 +11,11 @@ import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutHorizontally import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.slideOutVertically import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
@ -87,3 +93,21 @@ fun SlidingTransition(
content = content content = content
) )
} }
@Composable
fun FadeTransitionPreservingSpace(
visible: Boolean,
modifier: Modifier = Modifier,
animationSpec: AnimationSpec<Float> = tween(durationMillis = 150, easing = EaseInOut),
content: @Composable () -> Unit
) {
val alpha by animateFloatAsState(
if (visible) 1f else 0f,
label = "",
animationSpec = animationSpec
)
Box(modifier = modifier.alpha(alpha)) {
content.invoke()
}
}

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="InconsistentArrays"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="InconsistentArrays">
<!-- Basic Strings --> <!-- Basic Strings -->
<string name="app_version" translatable="false">1.1.0</string> <string name="app_version" translatable="false">1.1.1</string>
<string name="app_name">Book\'s Story</string> <string name="app_name">Book\'s Story</string>
<!-- Book sources --> <!-- Book sources -->

BIN
assets/readme/app_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB