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">
<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>
<a href="">[![Downloads](https://img.shields.io/github/downloads/Acclorite/book-story/total?color=0273b3&label=Downloads&logo=GitHub)]()</a>
<img src="https://github.com/Acclorite/book-story/blob/master/assets/readme/app_icon.png" width="120" />
</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">
Material3 Book Reader built with Jetpack Compose and Kotlin.
Built using Jetpack Compose and Kotlin.
<!------------ Screenshots ------------>
## 🖌️ 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._
<!------------ Download guide ------------>
## ✈️ Download
- _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://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>
_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
- _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 F-Droid_: Coming soon...
- _**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**_: 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
- 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 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
- 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)
- More..
<!------------ 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)._
<!------------ Translation ------------>
## 🌐 Translation
- English (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
- [Tachiyomi (Mihon)](https://github.com/mihonapp/mihon) (Github)
- [Libre-Sudoku](https://github.com/kaajjo/Libre-Sudoku) (Github)
- [Kitsune](https://github.com/Drumber/Kitsune) (Github)
- [Material Design Icons](https://fonts.google.com/icons) (Google Fonts)
- Also listed in About > Credits.

View file

@ -1,3 +1,5 @@
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
@ -17,8 +19,8 @@ android {
applicationId = "ua.acclorite.book_story"
minSdk = 26
targetSdk = 34
versionCode = 5
versionName = "1.1.0"
versionCode = 6
versionName = "1.1.1"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
@ -34,21 +36,19 @@ android {
getByName("debug") {
applicationIdSuffix = ".debug"
}
getByName("release") {
isMinifyEnabled = true
isShrinkResources = false
proguardFiles("proguard-rules.pro")
}
create("release-debug") {
initWith(getByName("release"))
applicationIdSuffix = ".release.debug"
signingConfig = signingConfigs.getByName("debug")
}
getByName("release") {
isMinifyEnabled = false
isShrinkResources = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
@ -63,6 +63,10 @@ android {
composeOptions {
kotlinCompilerExtensionVersion = "1.5.7"
}
dependenciesInfo {
includeInApk = false
includeInBundle = false
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
@ -72,12 +76,9 @@ android {
}
aboutLibraries {
outputFileName = "aboutlibraries.json"
gitHubApiToken = properties["github-key"] as? String
offlineMode = false
fetchRemoteLicense = true
fetchRemoteFunding = false
registerAndroidTasks = false
prettyPrint = true
gitHubApiToken = gradleLocalProperties(rootDir, providers)["github-key"] as? String
filterVariants = arrayOf("debug", "release", "release-debug")
excludeFields = arrayOf("generated", "funding", "description")
@ -107,13 +108,13 @@ dependencies {
// All dependencies
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
implementation("com.google.dagger:hilt-android:2.51.1")
ksp("com.google.dagger:hilt-android-compiler:2.51")
implementation("com.google.dagger:hilt-compiler:latest.release")
ksp("androidx.hilt:hilt-compiler:latest.release")
implementation("com.google.dagger:hilt-android:2.52")
ksp("com.google.dagger:hilt-android-compiler:2.52")
implementation("com.google.dagger:hilt-compiler:2.52")
ksp("androidx.hilt:hilt-compiler:1.2.0")
implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
// Room
@ -124,47 +125,45 @@ dependencies {
implementation("androidx.room:room-ktx:2.6.1")
// Datastore
implementation("androidx.datastore:datastore-preferences:latest.release")
implementation("androidx.datastore:datastore-preferences:1.1.1")
// Splash API
implementation("androidx.core:core-splashscreen:latest.release")
implementation("androidx.core:core-splashscreen:1.0.1")
// Permission Handling
implementation("com.google.accompanist:accompanist-permissions:latest.release")
implementation("com.google.accompanist:accompanist-permissions:0.34.0")
// Pdf parser
implementation("com.tom-roush:pdfbox-android:latest.release")
implementation("com.tom-roush:pdfbox-android:2.0.27.0")
// Epub parser
implementation("com.positiondev.epublib:epublib-core:3.1") {
exclude("org.slf4j")
exclude("xmlpull")
}
implementation("org.slf4j:slf4j-android:latest.release")
implementation("org.jsoup:jsoup:latest.release")
implementation("org.jsoup:jsoup:1.18.1")
// 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
implementation("androidx.appcompat:appcompat:latest.release")
implementation("androidx.appcompat:appcompat-resources:latest.release")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("androidx.appcompat:appcompat-resources:1.7.0")
// Coil for loading bitmaps
implementation("io.coil-kt:coil-compose:2.6.0")
implementation("io.coil-kt:coil-compose:2.7.0")
// Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-moshi:2.9.0")
implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("com.squareup.retrofit2:converter-moshi:2.11.0")
implementation("com.squareup.moshi:moshi:1.15.1")
implementation("com.squareup.moshi:moshi-kotlin:1.15.1")
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
implementation("com.mikepenz:aboutlibraries-core:latest.release")
implementation("com.mikepenz:aboutlibraries-compose-m3:latest.release")
implementation("com.mikepenz:aboutlibraries-core:11.2.2")
implementation("com.mikepenz:aboutlibraries-compose-m3:11.2.2")
// 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
-dontwarn org.xmlpull.v1.**
-dontwarn android.content.res.**
-dontwarn com.gemalto.jp2.JP2Decoder
-dontwarn com.google.auto.service.AutoService
-dontwarn javax.lang.model.SourceVersion
@ -31,11 +31,17 @@
-dontwarn javax.lang.model.util.SimpleTypeVisitor8
-dontwarn javax.lang.model.util.Types
-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.** { *; }
-keepclassmembers class org.xmlpull.** { *; }
# Debug rule
#-keepnames class ** { *; }
# Keeping names of classes that produce undeterministic results
-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.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>
<!-- Translator -->
@ -43,6 +48,7 @@
android:requestLegacyExternalStorage="true"
android:enableOnBackInvokedCallback="true"
android:usesCleartextTraffic="false"
android:largeHeap="true"
tools:targetApi="tiramisu"
tools:ignore="DataExtractionRules">

View file

@ -53,20 +53,6 @@ class PdfTextParser @Inject constructor(private val application: Application) :
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() }) {
return@forEachIndexed
}

View file

@ -401,10 +401,15 @@ class BookRepositoryImpl @Inject constructor(
val byteArray = stream.toByteArray()
val defaultCover = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
val currentCover = MediaStore.Images.Media.getBitmap(
application.contentResolver,
Uri.parse(book.image)
)
val currentCover = try {
MediaStore.Images.Media.getBitmap(
application.contentResolver,
Uri.parse(book.image)
)
} catch (e: Exception) {
e.printStackTrace()
return true
}
return !defaultCover.sameAs(currentCover)
}
@ -485,6 +490,16 @@ class BookRepositoryImpl @Inject constructor(
.map { bookMapper.toBook(it) }
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)
if (allFiles.isEmpty()) {

View file

@ -83,14 +83,6 @@ object Constants {
),
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(
name = "Kitsune",
source = "GitHub",
@ -107,15 +99,6 @@ object Constants {
),
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

View file

@ -144,27 +144,36 @@ private fun AboutScreen(
)
append("\n")
append(stringResource(id = R.string.app_version_option_desc_2))
}
},
showLoading = state.value.updateLoading
) {
onEvent(
AboutEvent.OnCheckForUpdates(
context = context,
noUpdatesFound = {
Toast.makeText(
context,
context.getString(R.string.no_updates),
Toast.LENGTH_LONG
).show()
},
error = {
Toast.makeText(
context,
context.getString(R.string.error_check_internet),
Toast.LENGTH_LONG
).show()
}
if (!state.value.alreadyCheckedForUpdates) {
onEvent(
AboutEvent.OnCheckForUpdates(
context = context,
noUpdatesFound = {
Toast.makeText(
context,
context.getString(R.string.no_updates),
Toast.LENGTH_LONG
).show()
},
error = {
Toast.makeText(
context,
context.getString(R.string.error_check_internet),
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
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
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.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.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
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
fun AboutItem(
@ -24,31 +40,45 @@ fun AboutItem(
title: String,
description: AnnotatedString?,
verticalPadding: Dp = 12.dp,
showLoading: Boolean = false,
isOnClickEnabled: Boolean = true,
onClick: () -> Unit = {}
) {
Column(
Row(
modifier
.fillMaxWidth()
.clickable(enabled = isOnClickEnabled) {
onClick()
}
.padding(horizontal = 18.dp, vertical = verticalPadding),
verticalArrangement = Arrangement.Center
verticalAlignment = Alignment.CenterVertically
) {
Text(
title,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurface,
fontSize = 18.sp
)
description?.let {
Column(Modifier.weight(1f)) {
Text(
it,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
title,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurface,
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
data class AboutState(
val showUpdateDialog: Boolean = false,
val alreadyCheckedForUpdates: Boolean = false,
val updateLoading: Boolean = false,
val updateInfo: LatestReleaseInfo? = null
)

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,8 @@
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.fadeIn
import androidx.compose.animation.fadeOut
@ -8,8 +11,11 @@ import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
@ -87,3 +93,21 @@ fun SlidingTransition(
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">
<!-- 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>
<!-- Book sources -->

BIN
assets/readme/app_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB