Merge branch 'master' into file-tree-browse-feature
This commit is contained in:
commit
24598c79f4
18 changed files with 3210 additions and 127 deletions
73
README.md
73
README.md
|
|
@ -1,13 +1,39 @@
|
|||
# <p align="center">Book's Story 📖</p>
|
||||
<!------------ Header ------------>
|
||||
|
||||
<div align="center">
|
||||
|
||||
<a href="">[](https://github.com/Acclorite/book-story/releases)</a>
|
||||
<a href="">[]()</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="">[](https://github.com/Acclorite/book-story/releases)</a>
|
||||
<a href="">[](https://f-droid.org/packages/ua.acclorite.book_story/)</a>
|
||||
<a href="">[](https://apt.izzysoft.de/fdroid/index/apk/ua.acclorite.book_story)</a>
|
||||
<a href="">[]()</a>
|
||||
<a href="">[](https://github.com/Acclorite/book-story/stargazers)</a>
|
||||
<a href="">[](https://github.com/Acclorite/book-story/commits/)</a>
|
||||
<a href="">[](https://github.com/Acclorite/book-story/commits/)</a>
|
||||
<a href="">[](/LICENSE)</a>
|
||||
<a href="">[]()</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.
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
16
app/proguard-rules.pro
vendored
16
app/proguard-rules.pro
vendored
|
|
@ -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(); }
|
||||
|
|
@ -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">
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
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()) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -144,8 +144,10 @@ private fun AboutScreen(
|
|||
)
|
||||
append("\n")
|
||||
append(stringResource(id = R.string.app_version_option_desc_2))
|
||||
}
|
||||
},
|
||||
showLoading = state.value.updateLoading
|
||||
) {
|
||||
if (!state.value.alreadyCheckedForUpdates) {
|
||||
onEvent(
|
||||
AboutEvent.OnCheckForUpdates(
|
||||
context = context,
|
||||
|
|
@ -165,6 +167,13 @@ private fun AboutScreen(
|
|||
}
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.no_updates),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,18 +40,20 @@ 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
|
||||
) {
|
||||
Column(Modifier.weight(1f)) {
|
||||
Text(
|
||||
title,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
|
|
@ -51,4 +69,16 @@ fun AboutItem(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
FadeTransitionPreservingSpace(visible = showLoading) {
|
||||
Row {
|
||||
Spacer(modifier = Modifier.width(18.dp))
|
||||
CircularProgressIndicator(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
strokeCap = StrokeCap.Round,
|
||||
modifier = Modifier.size(28.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -331,6 +331,7 @@ private fun ReaderScreen(
|
|||
)
|
||||
.readerFastColorPresetChange(
|
||||
fastColorPresetChangeEnabled = mainState.value.fastColorPresetChange!!,
|
||||
isLoading = state.value.loading,
|
||||
toolbarHidden = toolbarHidden,
|
||||
onSettingsEvent = onSettingsEvent,
|
||||
presetChanged = {
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
2947
app/src/main/res/raw/aboutlibraries.json
Normal file
2947
app/src/main/res/raw/aboutlibraries.json
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -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
BIN
assets/readme/app_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9 KiB |
Loading…
Add table
Add a link
Reference in a new issue