diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index e079d60e..99dac196 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -92,19 +92,19 @@ dependencies {
implementation("androidx.activity:activity-compose:1.9.0")
// Compose BOM libraries
- implementation(platform("androidx.compose:compose-bom:2024.06.00"))
- implementation("androidx.compose.foundation:foundation")
- implementation("androidx.compose.animation:animation")
- implementation("androidx.compose.animation:animation-android")
- implementation("androidx.compose.foundation:foundation-layout")
- implementation("androidx.compose.ui:ui")
- implementation("androidx.compose.ui:ui-graphics")
- implementation("androidx.compose.ui:ui-tooling-preview")
- implementation("androidx.compose.ui:ui-android")
+ // Compose BOM was eliminated - it is recognized as Closed Source in AboutLibraries.
+ implementation("androidx.compose.foundation:foundation:1.6.8")
+ implementation("androidx.compose.animation:animation:1.6.8")
+ implementation("androidx.compose.animation:animation-android:1.6.8")
+ implementation("androidx.compose.foundation:foundation-layout:1.6.8")
+ implementation("androidx.compose.ui:ui:1.6.8")
+ implementation("androidx.compose.ui:ui-graphics:1.6.8")
+ implementation("androidx.compose.ui:ui-tooling-preview:1.6.8")
+ implementation("androidx.compose.ui:ui-android:1.6.8")
implementation("androidx.compose.material3:material3:1.3.0-alpha06")
- implementation("androidx.compose.material3:material3-window-size-class")
- implementation("androidx.compose.material:material-icons-extended")
- implementation("androidx.compose.material:material")
+ implementation("androidx.compose.material3:material3-window-size-class:1.2.1")
+ implementation("androidx.compose.material:material-icons-extended:1.6.8")
+ implementation("androidx.compose.material:material:1.6.8")
// All dependencies
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.3")
@@ -165,15 +165,4 @@ dependencies {
// About open source libraries
implementation("com.mikepenz:aboutlibraries-core:latest.release")
implementation("com.mikepenz:aboutlibraries-compose-m3:latest.release")
-
- // Translator
- implementation("com.google.mlkit:translate:latest.release") {
- exclude("com.google.android.gms", "play-services-base")
- exclude("com.google.android.datatransport", "transport-api")
- exclude("com.google.android.datatransport", "transport-backend-cct")
- exclude("com.google.android.datatransport", "transport-runtime")
- exclude("com.google.firebase", "firebase-encoders-json")
- exclude("com.google.firebase", "firebase-encoders")
- }
- implementation("com.google.mlkit:language-id:latest.release")
}
\ No newline at end of file
diff --git a/app/schemas/ua.acclorite.book_story.data.local.room.BookDatabase/4.json b/app/schemas/ua.acclorite.book_story.data.local.room.BookDatabase/4.json
new file mode 100644
index 00000000..a1d39c09
--- /dev/null
+++ b/app/schemas/ua.acclorite.book_story.data.local.room.BookDatabase/4.json
@@ -0,0 +1,126 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 4,
+ "identityHash": "c8a3497d25808dec49816f26182b61d6",
+ "entities": [
+ {
+ "tableName": "BookEntity",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `author` TEXT, `description` TEXT, `textPath` TEXT NOT NULL, `filePath` TEXT NOT NULL, `scrollIndex` INTEGER NOT NULL, `scrollOffset` INTEGER NOT NULL, `progress` REAL NOT NULL, `image` TEXT, `category` TEXT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "author",
+ "columnName": "author",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "textPath",
+ "columnName": "textPath",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filePath",
+ "columnName": "filePath",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "scrollIndex",
+ "columnName": "scrollIndex",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "scrollOffset",
+ "columnName": "scrollOffset",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "progress",
+ "columnName": "progress",
+ "affinity": "REAL",
+ "notNull": true
+ },
+ {
+ "fieldPath": "image",
+ "columnName": "image",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "HistoryEntity",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `bookId` INTEGER NOT NULL, `time` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "bookId",
+ "columnName": "bookId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "time",
+ "columnName": "time",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c8a3497d25808dec49816f26182b61d6')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a4b0fbb7..562a6ff7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -57,11 +57,6 @@
-
-
-
)
-
-
- @Upsert
- suspend fun updateLanguageHistory(history: List)
-
- @Query("SELECT * FROM languagehistoryentity")
- suspend fun getLanguageHistory(): List
}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/data/local/room/BookDatabase.kt b/app/src/main/java/ua/acclorite/book_story/data/local/room/BookDatabase.kt
index cbfb65c8..d32dfc60 100644
--- a/app/src/main/java/ua/acclorite/book_story/data/local/room/BookDatabase.kt
+++ b/app/src/main/java/ua/acclorite/book_story/data/local/room/BookDatabase.kt
@@ -2,23 +2,25 @@ package ua.acclorite.book_story.data.local.room
import androidx.room.AutoMigration
import androidx.room.Database
+import androidx.room.DeleteColumn
+import androidx.room.DeleteTable
import androidx.room.RoomDatabase
+import androidx.room.migration.AutoMigrationSpec
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import ua.acclorite.book_story.data.local.dto.BookEntity
import ua.acclorite.book_story.data.local.dto.HistoryEntity
-import ua.acclorite.book_story.data.local.dto.LanguageHistoryEntity
@Database(
entities = [
BookEntity::class,
- HistoryEntity::class,
- LanguageHistoryEntity::class
+ HistoryEntity::class
],
- version = 3,
+ version = 4,
autoMigrations = [
AutoMigration(1, 2),
AutoMigration(2, 3),
+ AutoMigration(3, 4, spec = DatabaseHelper.MIGRATION_3_4::class),
],
exportSchema = true
)
@@ -26,6 +28,7 @@ abstract class BookDatabase : RoomDatabase() {
abstract val dao: BookDao
}
+@Suppress("ClassName")
object DatabaseHelper {
val MIGRATION_2_3 = object : Migration(2, 3) {
@@ -39,4 +42,12 @@ object DatabaseHelper {
)
}
}
+
+ @DeleteColumn("BookEntity", "enableTranslator")
+ @DeleteColumn("BookEntity", "translateFrom")
+ @DeleteColumn("BookEntity", "translateTo")
+ @DeleteColumn("BookEntity", "doubleClickTranslation")
+ @DeleteColumn("BookEntity", "translateWhenOpen")
+ @DeleteTable("LanguageHistoryEntity")
+ class MIGRATION_3_4 : AutoMigrationSpec
}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/data/mapper/book/BookMapperImpl.kt b/app/src/main/java/ua/acclorite/book_story/data/mapper/book/BookMapperImpl.kt
index 8463cd87..e2953018 100644
--- a/app/src/main/java/ua/acclorite/book_story/data/mapper/book/BookMapperImpl.kt
+++ b/app/src/main/java/ua/acclorite/book_story/data/mapper/book/BookMapperImpl.kt
@@ -20,12 +20,7 @@ class BookMapperImpl @Inject constructor() : BookMapper {
textPath = book.textPath,
description = book.description,
image = if (book.coverImage != null) book.coverImage.toString() else null,
- category = book.category,
- enableTranslator = book.enableTranslator,
- translateFrom = book.translateFrom,
- translateTo = book.translateTo,
- doubleClickTranslation = book.doubleClickTranslation,
- translateWhenOpen = book.translateWhenOpen
+ category = book.category
)
}
@@ -45,11 +40,6 @@ class BookMapperImpl @Inject constructor() : BookMapper {
lastOpened = null,
category = bookEntity.category,
coverImage = if (bookEntity.image != null) Uri.parse(bookEntity.image) else null,
- enableTranslator = bookEntity.enableTranslator,
- translateFrom = bookEntity.translateFrom,
- translateTo = bookEntity.translateTo,
- doubleClickTranslation = bookEntity.doubleClickTranslation,
- translateWhenOpen = bookEntity.translateWhenOpen
)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/data/mapper/language_history/LanguageHistoryMapper.kt b/app/src/main/java/ua/acclorite/book_story/data/mapper/language_history/LanguageHistoryMapper.kt
deleted file mode 100644
index 2257aa5f..00000000
--- a/app/src/main/java/ua/acclorite/book_story/data/mapper/language_history/LanguageHistoryMapper.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package ua.acclorite.book_story.data.mapper.language_history
-
-import ua.acclorite.book_story.data.local.dto.LanguageHistoryEntity
-import ua.acclorite.book_story.domain.model.LanguageHistory
-
-interface LanguageHistoryMapper {
- suspend fun toLanguageHistoryEntity(languageHistory: LanguageHistory): LanguageHistoryEntity
-
- suspend fun toLanguageHistory(languageHistoryEntity: LanguageHistoryEntity): LanguageHistory
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/data/mapper/language_history/LanguageHistoryMapperImpl.kt b/app/src/main/java/ua/acclorite/book_story/data/mapper/language_history/LanguageHistoryMapperImpl.kt
deleted file mode 100644
index 2e2433fb..00000000
--- a/app/src/main/java/ua/acclorite/book_story/data/mapper/language_history/LanguageHistoryMapperImpl.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package ua.acclorite.book_story.data.mapper.language_history
-
-import ua.acclorite.book_story.data.local.dto.LanguageHistoryEntity
-import ua.acclorite.book_story.domain.model.LanguageHistory
-import javax.inject.Inject
-
-class LanguageHistoryMapperImpl @Inject constructor() : LanguageHistoryMapper {
-
- override suspend fun toLanguageHistoryEntity(languageHistory: LanguageHistory): LanguageHistoryEntity {
- return LanguageHistoryEntity(
- languageCode = languageHistory.languageCode,
- order = languageHistory.order
- )
- }
-
- override suspend fun toLanguageHistory(languageHistoryEntity: LanguageHistoryEntity): LanguageHistory {
- return LanguageHistory(
- languageCode = languageHistoryEntity.languageCode,
- order = languageHistoryEntity.order
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/data/parser/epub/EpubFileParser.kt b/app/src/main/java/ua/acclorite/book_story/data/parser/epub/EpubFileParser.kt
index dd71ef30..1c051501 100644
--- a/app/src/main/java/ua/acclorite/book_story/data/parser/epub/EpubFileParser.kt
+++ b/app/src/main/java/ua/acclorite/book_story/data/parser/epub/EpubFileParser.kt
@@ -55,12 +55,7 @@ class EpubFileParser @Inject constructor() : FileParser {
filePath = file.path,
lastOpened = null,
category = Category.entries[0],
- coverImage = null,
- enableTranslator = false,
- translateFrom = "",
- translateTo = "",
- doubleClickTranslation = false,
- translateWhenOpen = false
+ coverImage = null
) to coverImage
} catch (e: Exception) {
e.printStackTrace()
diff --git a/app/src/main/java/ua/acclorite/book_story/data/parser/fb2/Fb2FileParser.kt b/app/src/main/java/ua/acclorite/book_story/data/parser/fb2/Fb2FileParser.kt
index ee382b80..d03698b4 100644
--- a/app/src/main/java/ua/acclorite/book_story/data/parser/fb2/Fb2FileParser.kt
+++ b/app/src/main/java/ua/acclorite/book_story/data/parser/fb2/Fb2FileParser.kt
@@ -65,12 +65,7 @@ class Fb2FileParser @Inject constructor() : FileParser {
filePath = file.path,
lastOpened = null,
category = Category.entries[0],
- coverImage = null,
- enableTranslator = false,
- translateFrom = "",
- translateTo = "",
- doubleClickTranslation = false,
- translateWhenOpen = false
+ coverImage = null
) to null
} catch (e: Exception) {
e.printStackTrace()
diff --git a/app/src/main/java/ua/acclorite/book_story/data/parser/pdf/PdfFileParser.kt b/app/src/main/java/ua/acclorite/book_story/data/parser/pdf/PdfFileParser.kt
index 550190c2..c66e5f10 100644
--- a/app/src/main/java/ua/acclorite/book_story/data/parser/pdf/PdfFileParser.kt
+++ b/app/src/main/java/ua/acclorite/book_story/data/parser/pdf/PdfFileParser.kt
@@ -43,12 +43,7 @@ class PdfFileParser @Inject constructor(private val application: Application) :
filePath = file.path,
lastOpened = null,
category = Category.entries[0],
- coverImage = null,
- enableTranslator = false,
- translateFrom = "",
- translateTo = "",
- doubleClickTranslation = false,
- translateWhenOpen = false
+ coverImage = null
) to null
} catch (e: Exception) {
e.printStackTrace()
diff --git a/app/src/main/java/ua/acclorite/book_story/data/parser/txt/TxtFileParser.kt b/app/src/main/java/ua/acclorite/book_story/data/parser/txt/TxtFileParser.kt
index 131369fc..3588838f 100644
--- a/app/src/main/java/ua/acclorite/book_story/data/parser/txt/TxtFileParser.kt
+++ b/app/src/main/java/ua/acclorite/book_story/data/parser/txt/TxtFileParser.kt
@@ -31,12 +31,7 @@ class TxtFileParser @Inject constructor() : FileParser {
filePath = file.path,
lastOpened = null,
category = Category.entries[0],
- coverImage = null,
- enableTranslator = false,
- translateFrom = "",
- translateTo = "",
- doubleClickTranslation = false,
- translateWhenOpen = false
+ coverImage = null
) to null
} catch (e: Exception) {
e.printStackTrace()
diff --git a/app/src/main/java/ua/acclorite/book_story/data/repository/BookRepositoryImpl.kt b/app/src/main/java/ua/acclorite/book_story/data/repository/BookRepositoryImpl.kt
index cc296656..f022f72f 100644
--- a/app/src/main/java/ua/acclorite/book_story/data/repository/BookRepositoryImpl.kt
+++ b/app/src/main/java/ua/acclorite/book_story/data/repository/BookRepositoryImpl.kt
@@ -8,13 +8,6 @@ import android.os.Environment
import android.provider.MediaStore
import android.util.Log
import androidx.datastore.preferences.core.Preferences
-import com.google.mlkit.common.model.DownloadConditions
-import com.google.mlkit.common.model.RemoteModelManager
-import com.google.mlkit.nl.languageid.LanguageIdentifier
-import com.google.mlkit.nl.translate.TranslateLanguage
-import com.google.mlkit.nl.translate.TranslateRemoteModel
-import com.google.mlkit.nl.translate.Translation
-import com.google.mlkit.nl.translate.TranslatorOptions
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -23,7 +16,6 @@ import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
-import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import ua.acclorite.book_story.R
import ua.acclorite.book_story.data.local.data_store.DataStore
@@ -31,32 +23,25 @@ import ua.acclorite.book_story.data.local.notification.UpdatesNotificationServic
import ua.acclorite.book_story.data.local.room.BookDao
import ua.acclorite.book_story.data.mapper.book.BookMapper
import ua.acclorite.book_story.data.mapper.history.HistoryMapper
-import ua.acclorite.book_story.data.mapper.language_history.LanguageHistoryMapper
import ua.acclorite.book_story.data.parser.FileParser
import ua.acclorite.book_story.data.parser.TextParser
import ua.acclorite.book_story.data.remote.GithubAPI
import ua.acclorite.book_story.data.remote.dto.LatestReleaseInfo
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.model.History
-import ua.acclorite.book_story.domain.model.LanguageHistory
import ua.acclorite.book_story.domain.model.NullableBook
import ua.acclorite.book_story.domain.repository.BookRepository
import ua.acclorite.book_story.domain.util.Constants
import ua.acclorite.book_story.domain.util.CoverImage
-import ua.acclorite.book_story.domain.util.DataStoreConstants
-import ua.acclorite.book_story.domain.util.LanguageCode
import ua.acclorite.book_story.domain.util.Resource
import ua.acclorite.book_story.domain.util.UIText
import ua.acclorite.book_story.presentation.data.MainState
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
-import java.util.Locale
import java.util.UUID
import javax.inject.Inject
import javax.inject.Singleton
-import kotlin.coroutines.resume
-import kotlin.coroutines.suspendCoroutine
@Suppress("DEPRECATION")
@Singleton
@@ -64,15 +49,12 @@ class BookRepositoryImpl @Inject constructor(
private val application: Application,
private val database: BookDao,
private val dataStore: DataStore,
- private val modelManager: RemoteModelManager,
- private val languageIdentifier: LanguageIdentifier,
private val githubAPI: GithubAPI,
private val updatesNotificationService: UpdatesNotificationService,
private val bookMapper: BookMapper,
private val historyMapper: HistoryMapper,
- private val languageHistoryMapper: LanguageHistoryMapper,
private val fileParser: FileParser,
private val textParser: TextParser
@@ -190,34 +172,11 @@ class BookRepositoryImpl @Inject constructor(
}
}
- val enableTranslator = dataStore.getNullableData(DataStoreConstants.ENABLE_TRANSLATOR)
- ?: false
-
- val translateFrom = dataStore.getNullableData(DataStoreConstants.TRANSLATE_FROM)
- ?: "auto"
-
- val translateTo = dataStore.getNullableData(DataStoreConstants.TRANSLATE_TO) ?: if (
- Constants.LANGUAGES.any { Locale.getDefault().language.take(2) == it.first }
- ) {
- Locale.getDefault().language.take(2)
- } else {
- "en"
- }
-
- val doubleClickTranslation = dataStore.getNullableData(
- DataStoreConstants.DOUBLE_CLICK_TRANSLATION
- ) ?: true
-
-
val updatedBook = book.copy(
textPath = "$booksDir/$textUri",
coverImage = if (coverUri.isNotBlank()) {
Uri.fromFile(File("$coversDir/$coverUri"))
- } else null,
- enableTranslator = enableTranslator,
- translateFrom = translateFrom,
- translateTo = translateTo,
- doubleClickTranslation = doubleClickTranslation
+ } else null
)
val bookToInsert = bookMapper.toBookEntity(updatedBook)
@@ -708,174 +667,6 @@ class BookRepositoryImpl @Inject constructor(
}
}
}
-
- override suspend fun isLanguageModelDownloaded(languageCode: String): Boolean {
- val model = TranslateRemoteModel.Builder(languageCode).build()
- return suspendCancellableCoroutine { continuation ->
- modelManager.isModelDownloaded(model)
- .addOnSuccessListener {
- continuation.resume(it)
- }
- .addOnFailureListener {
- continuation.resume(false)
- }
- }
- }
-
- override suspend fun downloadLanguageModel(
- languageCode: String,
- onCompleted: () -> Unit,
- onFailure: (Exception) -> Unit
- ) {
- val isLanguageDownloaded = isLanguageModelDownloaded(languageCode)
- if (isLanguageDownloaded) {
- onCompleted()
- return
- }
-
- return suspendCancellableCoroutine { continuation ->
- continuation.invokeOnCancellation {
- Log.i("TRANSLATOR", "Downloading Model: Coroutine Canceled")
- onCompleted()
- }
-
- val language = TranslateRemoteModel.Builder(languageCode).build()
- val conditions = DownloadConditions.Builder().build()
-
- modelManager.download(language, conditions)
- .addOnSuccessListener {
- onCompleted()
- continuation.resume(Unit)
- }
- .addOnFailureListener {
- onFailure(it)
- onCompleted()
- continuation.resume(Unit)
- }
- .addOnCanceledListener {
- onCompleted()
- Log.i("TRANSLATOR", "Downloading Model: Canceled")
- continuation.resume(Unit)
- }
- }
- }
-
- override suspend fun deleteLanguageModel(languageCode: String): Boolean {
- val isLanguageDownloaded = isLanguageModelDownloaded(languageCode)
- if (!isLanguageDownloaded) {
- return true
- }
-
- return suspendCancellableCoroutine { continuation ->
- val language = TranslateRemoteModel.Builder(languageCode).build()
-
- modelManager.deleteDownloadedModel(language)
- .addOnSuccessListener {
- continuation.resume(true)
- }
- .addOnFailureListener {
- continuation.resume(false)
- }
- }
- }
-
- override suspend fun identifyLanguage(text: String): Resource {
- return suspendCancellableCoroutine { continuation ->
- languageIdentifier.identifyLanguage(text)
- .addOnSuccessListener {
- val languageCode = it.trim().lowercase().take(2)
- var identified = true
-
- if (languageCode == "ru") {
- identified = false
- }
-
- if (TranslateLanguage.fromLanguageTag(languageCode) == null) {
- identified = false
- }
-
- if (identified) {
- continuation.resume(
- Resource.Success(languageCode)
- )
- return@addOnSuccessListener
- }
-
- continuation.resume(
- Resource.Error(UIText.StringResource(R.string.error_language_not_identified))
- )
- }
- .addOnFailureListener {
- continuation.resume(
- Resource.Error(
- UIText.StringResource(
- R.string.error_query,
- it.message ?: ""
- )
- )
- )
- }
- }
- }
-
- override suspend fun translateText(
- sourceLanguage: LanguageCode,
- targetLanguage: LanguageCode,
- text: String
- ): Resource {
- return suspendCoroutine { continuation ->
- val translatorOptions = TranslatorOptions.Builder()
- .setSourceLanguage(sourceLanguage)
- .setTargetLanguage(targetLanguage)
- .build()
- val translator = Translation.getClient(translatorOptions)
-
- translator.translate(text)
- .addOnSuccessListener {
- translator.close()
- continuation.resume(
- Resource.Success(
- it.trim()
- )
- )
- }
- .addOnFailureListener {
- translator.close()
- continuation.resume(
- Resource.Error(
- UIText.StringResource(
- R.string.error_query,
- it.message ?: ""
- )
- )
- )
- }
- .addOnCanceledListener {
- translator.close()
- continuation.resume(
- Resource.Error(
- UIText.StringResource(
- R.string.error_something_went_wrong
- )
- )
- )
- }
- }
- }
-
- override suspend fun getLanguageHistory(): List {
- return database.getLanguageHistory().map {
- languageHistoryMapper.toLanguageHistory(it)
- }
- }
-
- override suspend fun updateLanguageHistory(history: List) {
- database.updateLanguageHistory(
- history.map {
- languageHistoryMapper.toLanguageHistoryEntity(it)
- }
- )
- }
}
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/model/Book.kt b/app/src/main/java/ua/acclorite/book_story/domain/model/Book.kt
index f2762588..f6d5ba17 100644
--- a/app/src/main/java/ua/acclorite/book_story/domain/model/Book.kt
+++ b/app/src/main/java/ua/acclorite/book_story/domain/model/Book.kt
@@ -22,10 +22,4 @@ data class Book(
val lastOpened: Long?,
val category: Category,
-
- val enableTranslator: Boolean,
- val translateFrom: String,
- val translateTo: String,
- val doubleClickTranslation: Boolean,
- val translateWhenOpen: Boolean
)
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/model/Language.kt b/app/src/main/java/ua/acclorite/book_story/domain/model/Language.kt
deleted file mode 100644
index e8ec13a2..00000000
--- a/app/src/main/java/ua/acclorite/book_story/domain/model/Language.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-package ua.acclorite.book_story.domain.model
-
-import androidx.compose.runtime.Immutable
-import ua.acclorite.book_story.domain.util.ID
-import ua.acclorite.book_story.domain.util.Selected
-import ua.acclorite.book_story.domain.util.UIText
-
-@Immutable
-data class Language(
- val languageCode: String,
- val displayLanguage: String,
- val isDownloading: Boolean,
- val isCanceled: Boolean,
- val isDownloaded: Boolean,
- val isSelected: Selected,
- val historyOrder: Int?
-)
-
-@Immutable
-data class SelectableLanguage(
- val languageCode: String,
- val displayLanguage: String,
- val isDownloading: Boolean,
- val isCanceled: Boolean,
- val isDownloaded: Boolean,
- val isError: Boolean,
- val errorMessage: UIText? = null,
- val isSelected: Selected,
- val canUnselect: Boolean,
- val occurrences: List?
-)
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/model/LanguageHistory.kt b/app/src/main/java/ua/acclorite/book_story/domain/model/LanguageHistory.kt
deleted file mode 100644
index f99b1869..00000000
--- a/app/src/main/java/ua/acclorite/book_story/domain/model/LanguageHistory.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package ua.acclorite.book_story.domain.model
-
-import androidx.compose.runtime.Immutable
-
-@Immutable
-data class LanguageHistory(
- val languageCode: String,
- val order: Int
-)
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/model/LineWithTranslation.kt b/app/src/main/java/ua/acclorite/book_story/domain/model/LineWithTranslation.kt
deleted file mode 100644
index 0b636587..00000000
--- a/app/src/main/java/ua/acclorite/book_story/domain/model/LineWithTranslation.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package ua.acclorite.book_story.domain.model
-
-import android.os.Parcelable
-import androidx.compose.runtime.Immutable
-import kotlinx.parcelize.Parcelize
-import ua.acclorite.book_story.domain.util.UIText
-
-@Parcelize
-@Immutable
-data class LineWithTranslation(
- val originalLine: String,
-
- val useTranslation: Boolean = false,
- val translatingFrom: String = "",
- val translatingTo: String = "",
- val translatedLine: String? = null,
-
- val isTranslationLoading: Boolean = false,
- val isTranslationFailed: Boolean = false,
- val errorMessage: UIText? = null
-) : Parcelable
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/model/ReaderLine.kt b/app/src/main/java/ua/acclorite/book_story/domain/model/ReaderLine.kt
new file mode 100644
index 00000000..cd86cd85
--- /dev/null
+++ b/app/src/main/java/ua/acclorite/book_story/domain/model/ReaderLine.kt
@@ -0,0 +1,11 @@
+package ua.acclorite.book_story.domain.model
+
+import android.os.Parcelable
+import androidx.compose.runtime.Immutable
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+@Immutable
+data class ReaderLine(
+ val line: String
+) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/repository/BookRepository.kt b/app/src/main/java/ua/acclorite/book_story/domain/repository/BookRepository.kt
index 7f83f74c..8015a2b9 100644
--- a/app/src/main/java/ua/acclorite/book_story/domain/repository/BookRepository.kt
+++ b/app/src/main/java/ua/acclorite/book_story/domain/repository/BookRepository.kt
@@ -6,10 +6,8 @@ import kotlinx.coroutines.flow.Flow
import ua.acclorite.book_story.data.remote.dto.LatestReleaseInfo
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.model.History
-import ua.acclorite.book_story.domain.model.LanguageHistory
import ua.acclorite.book_story.domain.model.NullableBook
import ua.acclorite.book_story.domain.util.CoverImage
-import ua.acclorite.book_story.domain.util.LanguageCode
import ua.acclorite.book_story.domain.util.Resource
import ua.acclorite.book_story.presentation.data.MainState
import java.io.File
@@ -91,30 +89,5 @@ interface BookRepository {
history: List
)
-
suspend fun checkForUpdates(postNotification: Boolean): LatestReleaseInfo?
-
-
- suspend fun isLanguageModelDownloaded(languageCode: String): Boolean
-
- suspend fun downloadLanguageModel(
- languageCode: String,
- onCompleted: () -> Unit,
- onFailure: (Exception) -> Unit
- )
-
- suspend fun deleteLanguageModel(languageCode: String): Boolean
-
- suspend fun identifyLanguage(text: String): Resource
-
- suspend fun translateText(
- sourceLanguage: LanguageCode,
- targetLanguage: LanguageCode,
- text: String
- ): Resource
-
-
- suspend fun getLanguageHistory(): List
-
- suspend fun updateLanguageHistory(history: List)
}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/use_case/DeleteLanguageModel.kt b/app/src/main/java/ua/acclorite/book_story/domain/use_case/DeleteLanguageModel.kt
deleted file mode 100644
index c1fa11be..00000000
--- a/app/src/main/java/ua/acclorite/book_story/domain/use_case/DeleteLanguageModel.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package ua.acclorite.book_story.domain.use_case
-
-import ua.acclorite.book_story.domain.repository.BookRepository
-import javax.inject.Inject
-
-class DeleteLanguageModel @Inject constructor(
- private val repository: BookRepository
-) {
-
- suspend fun execute(languageCode: String): Boolean {
- return repository.deleteLanguageModel(
- languageCode = languageCode
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/use_case/DownloadLanguageModel.kt b/app/src/main/java/ua/acclorite/book_story/domain/use_case/DownloadLanguageModel.kt
deleted file mode 100644
index b9101483..00000000
--- a/app/src/main/java/ua/acclorite/book_story/domain/use_case/DownloadLanguageModel.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package ua.acclorite.book_story.domain.use_case
-
-import ua.acclorite.book_story.domain.repository.BookRepository
-import javax.inject.Inject
-
-class DownloadLanguageModel @Inject constructor(
- private val repository: BookRepository
-) {
-
- suspend fun execute(
- languageCode: String,
- onCompleted: () -> Unit,
- onFailure: (Exception) -> Unit
- ) {
- repository.downloadLanguageModel(
- languageCode = languageCode,
- onCompleted = onCompleted,
- onFailure = onFailure
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/use_case/GetLanguageHistory.kt b/app/src/main/java/ua/acclorite/book_story/domain/use_case/GetLanguageHistory.kt
deleted file mode 100644
index b522c361..00000000
--- a/app/src/main/java/ua/acclorite/book_story/domain/use_case/GetLanguageHistory.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package ua.acclorite.book_story.domain.use_case
-
-import ua.acclorite.book_story.domain.model.LanguageHistory
-import ua.acclorite.book_story.domain.repository.BookRepository
-import javax.inject.Inject
-
-class GetLanguageHistory @Inject constructor(private val repository: BookRepository) {
-
- suspend fun execute(): List {
- return repository.getLanguageHistory()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/use_case/GetText.kt b/app/src/main/java/ua/acclorite/book_story/domain/use_case/GetText.kt
index 03c88ceb..e7311860 100644
--- a/app/src/main/java/ua/acclorite/book_story/domain/use_case/GetText.kt
+++ b/app/src/main/java/ua/acclorite/book_story/domain/use_case/GetText.kt
@@ -1,15 +1,15 @@
package ua.acclorite.book_story.domain.use_case
-import ua.acclorite.book_story.domain.model.LineWithTranslation
+import ua.acclorite.book_story.domain.model.ReaderLine
import ua.acclorite.book_story.domain.repository.BookRepository
import ua.acclorite.book_story.domain.util.ID
import javax.inject.Inject
class GetText @Inject constructor(private val repository: BookRepository) {
- suspend fun execute(textPath: String): Map {
+ suspend fun execute(textPath: String): Map {
return repository.getBookText(textPath = textPath).withIndex().associate {
- it.index to LineWithTranslation(originalLine = it.value)
+ it.index to ReaderLine(line = it.value)
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/use_case/IdentifyLanguage.kt b/app/src/main/java/ua/acclorite/book_story/domain/use_case/IdentifyLanguage.kt
deleted file mode 100644
index 8050d985..00000000
--- a/app/src/main/java/ua/acclorite/book_story/domain/use_case/IdentifyLanguage.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package ua.acclorite.book_story.domain.use_case
-
-import ua.acclorite.book_story.domain.repository.BookRepository
-import ua.acclorite.book_story.domain.util.LanguageCode
-import ua.acclorite.book_story.domain.util.Resource
-import javax.inject.Inject
-
-class IdentifyLanguage @Inject constructor(
- private val repository: BookRepository
-) {
-
- suspend fun execute(text: String): Resource {
- return repository.identifyLanguage(text)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/use_case/IsLanguageModelDownloaded.kt b/app/src/main/java/ua/acclorite/book_story/domain/use_case/IsLanguageModelDownloaded.kt
deleted file mode 100644
index 1b99e7f5..00000000
--- a/app/src/main/java/ua/acclorite/book_story/domain/use_case/IsLanguageModelDownloaded.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package ua.acclorite.book_story.domain.use_case
-
-import ua.acclorite.book_story.domain.repository.BookRepository
-import javax.inject.Inject
-
-class IsLanguageModelDownloaded @Inject constructor(
- private val repository: BookRepository
-) {
-
- suspend fun execute(languageCode: String): Boolean {
- return repository.isLanguageModelDownloaded(languageCode)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/use_case/TranslateText.kt b/app/src/main/java/ua/acclorite/book_story/domain/use_case/TranslateText.kt
deleted file mode 100644
index d4dcdb26..00000000
--- a/app/src/main/java/ua/acclorite/book_story/domain/use_case/TranslateText.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package ua.acclorite.book_story.domain.use_case
-
-import ua.acclorite.book_story.domain.repository.BookRepository
-import ua.acclorite.book_story.domain.util.LanguageCode
-import ua.acclorite.book_story.domain.util.Resource
-import javax.inject.Inject
-
-class TranslateText @Inject constructor(
- private val repository: BookRepository
-) {
-
- suspend fun execute(
- sourceLanguage: LanguageCode,
- targetLanguage: LanguageCode,
- text: String
- ): Resource {
- return repository.translateText(
- sourceLanguage,
- targetLanguage,
- text
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/use_case/UpdateLanguageHistory.kt b/app/src/main/java/ua/acclorite/book_story/domain/use_case/UpdateLanguageHistory.kt
deleted file mode 100644
index 3ecf61ba..00000000
--- a/app/src/main/java/ua/acclorite/book_story/domain/use_case/UpdateLanguageHistory.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package ua.acclorite.book_story.domain.use_case
-
-import ua.acclorite.book_story.domain.model.LanguageHistory
-import ua.acclorite.book_story.domain.repository.BookRepository
-import javax.inject.Inject
-
-class UpdateLanguageHistory @Inject constructor(private val repository: BookRepository) {
-
- suspend fun execute(history: List) {
- repository.updateLanguageHistory(history)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/util/Constants.kt b/app/src/main/java/ua/acclorite/book_story/domain/util/Constants.kt
index 088df6a7..1ec88b7b 100644
--- a/app/src/main/java/ua/acclorite/book_story/domain/util/Constants.kt
+++ b/app/src/main/java/ua/acclorite/book_story/domain/util/Constants.kt
@@ -291,11 +291,6 @@ object Constants {
scrollOffset = 0,
progress = 0f,
lastOpened = null,
- category = Category.READING,
- enableTranslator = false,
- translateFrom = "",
- translateTo = "",
- doubleClickTranslation = false,
- translateWhenOpen = false
+ category = Category.READING
)
}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/util/DataStoreConstants.kt b/app/src/main/java/ua/acclorite/book_story/domain/util/DataStoreConstants.kt
index c896dbfd..f0f7b8c3 100644
--- a/app/src/main/java/ua/acclorite/book_story/domain/util/DataStoreConstants.kt
+++ b/app/src/main/java/ua/acclorite/book_story/domain/util/DataStoreConstants.kt
@@ -23,8 +23,5 @@ object DataStoreConstants {
val PARAGRAPH_INDENTATION = booleanPreferencesKey("paragraph_indentation")
val CHECK_FOR_UPDATES = booleanPreferencesKey("check_for_updates")
val SIDE_PADDING = intPreferencesKey("side_padding")
- val ENABLE_TRANSLATOR = booleanPreferencesKey("enable_translator")
- val TRANSLATE_FROM = stringPreferencesKey("translate_from")
- val TRANSLATE_TO = stringPreferencesKey("translate_to")
val DOUBLE_CLICK_TRANSLATION = booleanPreferencesKey("double_click_translation")
}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/domain/util/Typealias.kt b/app/src/main/java/ua/acclorite/book_story/domain/util/Typealias.kt
index a88b6e2d..9f8b0176 100644
--- a/app/src/main/java/ua/acclorite/book_story/domain/util/Typealias.kt
+++ b/app/src/main/java/ua/acclorite/book_story/domain/util/Typealias.kt
@@ -6,6 +6,5 @@ import ua.acclorite.book_story.presentation.data.Navigator
typealias CoverImage = Bitmap
typealias Selected = Boolean
typealias ID = Int
-typealias LanguageCode = String
typealias Route = String
typealias OnNavigate = (Navigator.() -> Unit) -> Unit
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/TranslatorLanguageBottomSheet.kt b/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/TranslatorLanguageBottomSheet.kt
deleted file mode 100644
index d2054b95..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/TranslatorLanguageBottomSheet.kt
+++ /dev/null
@@ -1,298 +0,0 @@
-package ua.acclorite.book_story.presentation.components.translator_language
-
-import androidx.compose.animation.core.tween
-import androidx.compose.animation.fadeOut
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.AutoAwesome
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.TopAppBarDefaults
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.State
-import androidx.compose.runtime.collectAsState
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.input.nestedscroll.nestedScroll
-import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.unit.dp
-import androidx.hilt.navigation.compose.hiltViewModel
-import ua.acclorite.book_story.R
-import ua.acclorite.book_story.presentation.components.CategoryTitle
-import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
-import ua.acclorite.book_story.presentation.components.CustomBottomSheet
-import ua.acclorite.book_story.presentation.components.customItems
-import ua.acclorite.book_story.presentation.components.is_messages.IsEmpty
-import ua.acclorite.book_story.presentation.components.translator_language.components.TranslatorLanguageDownloadDialog
-import ua.acclorite.book_story.presentation.components.translator_language.components.TranslatorLanguageItem
-import ua.acclorite.book_story.presentation.components.translator_language.components.TranslatorLanguageItemWithIcon
-import ua.acclorite.book_story.presentation.components.translator_language.components.TranslatorLanguageTopBar
-import ua.acclorite.book_story.presentation.components.translator_language.data.TranslatorLanguageEvent
-import ua.acclorite.book_story.presentation.components.translator_language.data.TranslatorLanguageState
-import ua.acclorite.book_story.presentation.components.translator_language.data.TranslatorLanguageViewModel
-import ua.acclorite.book_story.presentation.ui.DefaultTransition
-import ua.acclorite.book_story.presentation.ui.Transitions
-
-/**
- * Translator language bottom sheet.
- * Manages downloading, deleting and selecting language for translator.
- *
- * @param selectedLanguage Current selected language.
- * @param unselectedLanguage Current unselected language(second).
- * @param translateFromSelecting Whether user selects "Translate from" or "Translate to" language.
- * @param onDismiss Dismissing BottomSheet.
- * @param onSelect Gives two variables, first - Translate from, second - Translate to. If user selects "Translate from" and then selects current unselected language(in this case "Translate to"), then it also changes "Translate to" to previous "Translate from" value.
- */
-@Composable
-fun TranslatorLanguageBottomSheet(
- selectedLanguage: String,
- unselectedLanguage: String,
- translateFromSelecting: Boolean,
- onDismiss: () -> Unit,
- onSelect: (String, String) -> Unit
-) {
- val translatorLanguageViewModel: TranslatorLanguageViewModel = hiltViewModel()
-
- val state = translatorLanguageViewModel.state.collectAsState()
- val loading = remember { mutableStateOf(true) }
-
- LaunchedEffect(Unit) {
- translatorLanguageViewModel.init(
- selectedLanguage = selectedLanguage,
- unselectedLanguage = unselectedLanguage,
- translateFromSelecting = translateFromSelecting,
- loaded = {
- loading.value = false
- }
- )
- }
-
- TranslatorLanguageBottomSheetContent(
- state = state,
- loading = loading,
- onSelect = { from, to ->
- val fromSelecting = state.value.translateFromSelecting
- val languageToChoose = if (fromSelecting) from else to
-
- if (languageToChoose != "auto") {
- translatorLanguageViewModel.onEvent(
- TranslatorLanguageEvent.OnUpdateLanguageHistory(
- languageToChoose
- )
- )
- }
- onSelect(from, to)
- },
- onDismiss = onDismiss,
- onEvent = translatorLanguageViewModel::onEvent
- )
-}
-
-@OptIn(ExperimentalMaterial3Api::class)
-@Composable
-private fun TranslatorLanguageBottomSheetContent(
- state: State,
- loading: State,
- onSelect: (String, String) -> Unit,
- onDismiss: () -> Unit,
- onEvent: (TranslatorLanguageEvent) -> Unit
-) {
- val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
-
- val languagesWithHistory = remember(state.value.languages) {
- state.value.languages.filter {
- it.historyOrder != null
- }.sortedBy {
- it.historyOrder
- }
- }
- val languages = remember(state.value.languages) {
- state.value.languages.filter {
- it.historyOrder == null
- }.sortedBy {
- it.languageCode
- }
- }
-
- CustomBottomSheet(
- hasFixedHeight = true,
- modifier = Modifier
- .fillMaxWidth()
- .fillMaxHeight(),
- dragHandle = {},
- shape = RoundedCornerShape(0),
- scrimColor = MaterialTheme.colorScheme.surface,
- onDismissRequest = {
- onDismiss()
- },
- containerColor = MaterialTheme.colorScheme.surface
- ) {
- Scaffold(
- modifier = Modifier
- .fillMaxSize()
- .nestedScroll(scrollBehavior.nestedScrollConnection),
- containerColor = Color.Transparent,
- topBar = {
- TranslatorLanguageTopBar(
- state = state,
- scrollBehavior = scrollBehavior,
- onDismissBottomSheet = onDismiss,
- onEvent = onEvent
- )
- }
- ) { paddingValues ->
- Box(
- modifier = Modifier
- .fillMaxSize()
- .padding(paddingValues),
- contentAlignment = Alignment.Center
- ) {
- DefaultTransition(
- visible = !loading.value,
- modifier = Modifier.fillMaxSize()
- ) {
- if (state.value.showDownloadLanguageDialog) {
- TranslatorLanguageDownloadDialog(
- state = state,
- onSelect = onSelect,
- onEvent = onEvent
- )
- }
-
- LazyColumn(Modifier.fillMaxSize()) {
- item {
- Spacer(
- modifier = Modifier
- .animateItem()
- .height(12.dp)
- )
- }
-
- if (
- state.value.translateFromSelecting &&
- (!state.value.showSearch || state.value.searchQuery.isEmpty())
- ) {
- item {
- val isSelected = remember(state.value.selectedLanguage) {
- state.value.selectedLanguage == "auto"
- }
-
- TranslatorLanguageItemWithIcon(
- isSelected = isSelected,
- displayLanguage = stringResource(id = R.string.translator_auto),
- customIcon = Icons.Default.AutoAwesome,
- onSelect = {
- onSelect("auto", state.value.unselectedLanguage)
- }
- )
-
- Spacer(
- modifier = Modifier
- .animateItem()
- .height(36.dp)
- )
- }
- }
-
- if (languagesWithHistory.isNotEmpty()) {
- item {
- CategoryTitle(
- title = stringResource(id = R.string.translator_recent_languages),
- color = MaterialTheme.colorScheme.primary,
- padding = 28.dp,
- modifier = Modifier.animateItem()
- )
- Spacer(
- modifier = Modifier
- .animateItem()
- .height(14.dp)
- )
- }
-
-
- customItems(
- languagesWithHistory,
- key = { it.languageCode }
- ) { language ->
- TranslatorLanguageItem(
- language = language,
- onSelect = onSelect,
- onEvent = onEvent
- )
- }
- }
-
- if (languages.isNotEmpty()) {
- item {
- if (languagesWithHistory.isNotEmpty()) {
- Spacer(
- modifier = Modifier
- .animateItem()
- .height(36.dp)
- )
- }
-
- CategoryTitle(
- title = stringResource(id = R.string.translator_all_languages),
- color = MaterialTheme.colorScheme.primary,
- padding = 28.dp,
- modifier = Modifier.animateItem()
- )
- Spacer(
- modifier = Modifier
- .animateItem()
- .height(14.dp)
- )
- }
-
- customItems(
- languages,
- key = { it.languageCode }
- ) { language ->
- TranslatorLanguageItem(
- language = language,
- onSelect = onSelect,
- onEvent = onEvent
- )
- }
- }
-
- item {
- Spacer(
- modifier = Modifier
- .animateItem()
- .height(12.dp)
- )
- }
- }
-
- CustomAnimatedVisibility(
- visible = state.value.languages.isEmpty(),
- modifier = Modifier.align(Alignment.Center),
- enter = Transitions.DefaultTransitionIn,
- exit = fadeOut(tween(0))
- ) {
- IsEmpty(
- message = stringResource(id = R.string.translator_languages_empty),
- icon = painterResource(id = R.drawable.empty_languages)
- )
- }
- }
- }
- }
- }
-}
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/components/TranslatorLanguageDownloadDialog.kt b/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/components/TranslatorLanguageDownloadDialog.kt
deleted file mode 100644
index 2a49a48b..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/components/TranslatorLanguageDownloadDialog.kt
+++ /dev/null
@@ -1,100 +0,0 @@
-package ua.acclorite.book_story.presentation.components.translator_language.components
-
-import android.widget.Toast
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Download
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.remember
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.stringResource
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-import ua.acclorite.book_story.R
-import ua.acclorite.book_story.presentation.components.custom_dialog.CustomDialogWithContent
-import ua.acclorite.book_story.presentation.components.translator_language.data.TranslatorLanguageEvent
-import ua.acclorite.book_story.presentation.components.translator_language.data.TranslatorLanguageState
-import java.util.Locale
-
-/**
- * Translator Language Download Dialog.
- * Used for downloading languages and selecting them right after.
- *
- * @param state [TranslatorLanguageState].
- * @param onSelect OnSelect callback. Happens when language is downloaded.
- * @param onEvent [TranslatorLanguageEvent] callback.
- */
-@Composable
-fun TranslatorLanguageDownloadDialog(
- state: State,
- onSelect: (String, String) -> Unit,
- onEvent: (TranslatorLanguageEvent) -> Unit
-) {
- val context = LocalContext.current
- val displayLanguage = remember(state.value.languageToSelect) {
- val locale = Locale(state.value.languageToSelect)
- locale.getDisplayLanguage(locale).replaceFirstChar {
- it.uppercase()
- }
- }
-
- CustomDialogWithContent(
- title = stringResource(id = R.string.download_language, displayLanguage),
- imageVectorIcon = Icons.Default.Download,
- description = stringResource(
- id = R.string.download_language_description
- ),
- actionText = stringResource(id = R.string.download),
- isActionEnabled = true,
- disableOnClick = true,
- onDismiss = { onEvent(TranslatorLanguageEvent.OnDismissDownloadDialog) },
- onAction = {
- val selectedLanguage = state.value.languageToSelect
-
- onEvent(TranslatorLanguageEvent.OnDismissDownloadDialog)
- onEvent(
- TranslatorLanguageEvent.OnDownloadLanguage(
- languageCode = state.value.languageToSelect,
- onComplete = {
- if (selectedLanguage == state.value.languageToSelect) {
- withContext(Dispatchers.Main) {
- Toast.makeText(
- context,
- context.getString(R.string.language_downloaded),
- Toast.LENGTH_LONG
- ).show()
- }
-
- onEvent(
- TranslatorLanguageEvent.OnSelectLanguage(
- languageCode = state.value.languageToSelect,
- onSelect = onSelect,
- onError = {
- Toast
- .makeText(
- context,
- it.asString(context),
- Toast.LENGTH_LONG
- )
- .show()
- }
- )
- )
- }
- },
- onFailure = {
- Toast.makeText(
- context,
- context.getString(
- R.string.error_query,
- it.message
- ),
- Toast.LENGTH_LONG
- ).show()
- }
- )
- )
- },
- withDivider = false
- )
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/components/TranslatorLanguageItem.kt b/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/components/TranslatorLanguageItem.kt
deleted file mode 100644
index 5f1afe22..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/components/TranslatorLanguageItem.kt
+++ /dev/null
@@ -1,243 +0,0 @@
-package ua.acclorite.book_story.presentation.components.translator_language.components
-
-import android.widget.Toast
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyItemScope
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Check
-import androidx.compose.material.icons.filled.CheckCircle
-import androidx.compose.material.icons.filled.Download
-import androidx.compose.material3.CircularProgressIndicator
-import androidx.compose.material3.Icon
-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.draw.clip
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.unit.dp
-import ua.acclorite.book_story.R
-import ua.acclorite.book_story.domain.model.Language
-import ua.acclorite.book_story.presentation.components.translator_language.data.TranslatorLanguageEvent
-import ua.acclorite.book_story.presentation.ui.DefaultTransition
-
-/**
- * Translator Language Item with Icon.
- *
- * @param isSelected Whether item is selected.
- * @param displayLanguage Display language to be shown.
- * @param customIcon Icon.
- * @param onSelect OnSelect(click) callback.
- */
-@Composable
-fun LazyItemScope.TranslatorLanguageItemWithIcon(
- isSelected: Boolean,
- displayLanguage: String,
- customIcon: ImageVector,
- onSelect: () -> Unit,
-) {
- Row(
- modifier = Modifier
- .animateItem()
- .padding(horizontal = 12.dp)
- .clip(RoundedCornerShape(100))
- .background(
- if (isSelected) MaterialTheme.colorScheme.primaryContainer
- else Color.Transparent,
- RoundedCornerShape(100)
- )
- .clickable {
- onSelect()
- }
- .padding(horizontal = 16.dp, vertical = 14.dp),
- verticalAlignment = Alignment.CenterVertically
- ) {
- if (isSelected) {
- Icon(
- imageVector = Icons.Default.Check,
- contentDescription = stringResource(R.string.selected_content_desc),
- tint = MaterialTheme.colorScheme.onPrimaryContainer,
- modifier = Modifier.size(24.dp)
- )
- Spacer(modifier = Modifier.width(16.dp))
- }
-
- Text(
- displayLanguage,
- color = if (isSelected) MaterialTheme.colorScheme.onPrimaryContainer
- else MaterialTheme.colorScheme.onSurface,
- style = MaterialTheme.typography.bodyLarge,
- modifier = Modifier.weight(1f)
- )
-
- Spacer(modifier = Modifier.width(16.dp))
- Icon(
- imageVector = customIcon,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.onSurfaceVariant,
- modifier = Modifier.size(24.dp)
- )
- }
-}
-
-/**
- * Translator Language Item with Icon.
- *
- * @param language [Language] item.
- * @param onSelect OnSelect(click) callback.
- * @param onEvent [TranslatorLanguageEvent] callback.
- */
-@Composable
-fun LazyItemScope.TranslatorLanguageItem(
- language: Language,
- onSelect: (String, String) -> Unit,
- onEvent: (TranslatorLanguageEvent) -> Unit
-) {
- val context = LocalContext.current
-
- Row(
- modifier = Modifier
- .animateItem()
- .padding(horizontal = 12.dp)
- .clip(RoundedCornerShape(100))
- .background(
- if (language.isSelected) MaterialTheme.colorScheme.primaryContainer
- else Color.Transparent,
- RoundedCornerShape(100)
- )
- .clickable(enabled = !language.isDownloading) {
- onEvent(
- TranslatorLanguageEvent.OnSelectLanguage(
- languageCode = language.languageCode,
- onSelect = onSelect,
- onError = {
- Toast
- .makeText(
- context,
- it.asString(context),
- Toast.LENGTH_LONG
- )
- .show()
- }
- )
- )
- }
- .padding(horizontal = 16.dp, vertical = 14.dp),
- verticalAlignment = Alignment.CenterVertically
- ) {
- if (language.isSelected) {
- Icon(
- imageVector = Icons.Default.Check,
- contentDescription = stringResource(R.string.selected_content_desc),
- tint = MaterialTheme.colorScheme.onPrimaryContainer,
- modifier = Modifier.size(24.dp)
- )
- Spacer(modifier = Modifier.width(16.dp))
- }
-
- Text(
- language.displayLanguage,
- color = if (language.isSelected) MaterialTheme.colorScheme.onPrimaryContainer
- else MaterialTheme.colorScheme.onSurface,
- style = MaterialTheme.typography.bodyLarge,
- modifier = Modifier.weight(1f)
- )
-
- Box(contentAlignment = Alignment.CenterEnd) {
- DefaultTransition(!language.isDownloaded && !language.isDownloading) {
- Row {
- Spacer(modifier = Modifier.width(16.dp))
- Icon(
- imageVector = Icons.Default.Download,
- contentDescription = stringResource(id = R.string.download),
- tint = if (language.isSelected) MaterialTheme.colorScheme.onSurfaceVariant
- else MaterialTheme.colorScheme.primary,
- modifier = Modifier
- .size(24.dp)
- .clickable(
- interactionSource = null,
- indication = null
- ) {
- onEvent(
- TranslatorLanguageEvent.OnDownloadLanguage(
- languageCode = language.languageCode,
- onComplete = {},
- onFailure = {
- Toast
- .makeText(
- context,
- context.getString(
- R.string.error_query,
- it.message
- ),
- Toast.LENGTH_LONG
- )
- .show()
- }
- )
- )
- }
- )
- }
- }
-
- DefaultTransition(language.isDownloading && !language.isDownloaded) {
- Row {
- Spacer(modifier = Modifier.width(16.dp))
- CircularProgressIndicator(
- strokeWidth = 2.7.dp,
- modifier = Modifier
- .size(22.dp)
- .clickable(
- interactionSource = null,
- indication = null
- ) {
- onEvent(
- TranslatorLanguageEvent.OnCancelDownload(
- languageCode = language.languageCode
- )
- )
- },
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- Spacer(modifier = Modifier.width(1.dp))
- }
- }
-
- DefaultTransition(language.isDownloaded && !language.isDownloading) {
- Row {
- Spacer(modifier = Modifier.width(16.dp))
- Icon(
- imageVector = Icons.Filled.CheckCircle,
- contentDescription = stringResource(id = R.string.done),
- tint = MaterialTheme.colorScheme.onSurfaceVariant,
- modifier = Modifier
- .size(24.dp)
- .clickable(
- interactionSource = null,
- indication = null
- ) {
- onEvent(
- TranslatorLanguageEvent.OnDeleteLanguage(
- languageCode = language.languageCode
- )
- )
- }
- )
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/components/TranslatorLanguageTopBar.kt b/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/components/TranslatorLanguageTopBar.kt
deleted file mode 100644
index 3274cbec..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/components/TranslatorLanguageTopBar.kt
+++ /dev/null
@@ -1,107 +0,0 @@
-@file:OptIn(ExperimentalMaterial3Api::class)
-
-package ua.acclorite.book_story.presentation.components.translator_language.components
-
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.ArrowBack
-import androidx.compose.material.icons.filled.Close
-import androidx.compose.material.icons.filled.Search
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.Text
-import androidx.compose.material3.TopAppBarScrollBehavior
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.FocusRequester
-import androidx.compose.ui.focus.focusRequester
-import androidx.compose.ui.layout.onGloballyPositioned
-import androidx.compose.ui.res.stringResource
-import ua.acclorite.book_story.R
-import ua.acclorite.book_story.presentation.components.AnimatedTopAppBar
-import ua.acclorite.book_story.presentation.components.CustomIconButton
-import ua.acclorite.book_story.presentation.components.CustomSearchTextField
-import ua.acclorite.book_story.presentation.components.translator_language.data.TranslatorLanguageEvent
-import ua.acclorite.book_story.presentation.components.translator_language.data.TranslatorLanguageState
-
-/**
- * Translator Language TopBar.
- *
- * @param state [TranslatorLanguageState].
- * @param scrollBehavior [TopAppBarScrollBehavior].
- * @param onDismissBottomSheet OnDismiss callback.
- * @param onEvent [TranslatorLanguageEvent] callback.
- */
-@Composable
-fun TranslatorLanguageTopBar(
- state: State,
- scrollBehavior: TopAppBarScrollBehavior,
- onDismissBottomSheet: () -> Unit,
- onEvent: (TranslatorLanguageEvent) -> Unit
-) {
- val focusRequester = remember { FocusRequester() }
-
- AnimatedTopAppBar(
- scrollBehavior = scrollBehavior,
- isTopBarScrolled = null,
-
- content1Visibility = !state.value.showSearch,
- content1NavigationIcon = {
- CustomIconButton(
- icon = Icons.Default.Close,
- contentDescription = R.string.go_back_content_desc,
- disableOnClick = true
- ) {
- onDismissBottomSheet()
- }
- },
- content1Title = {
- Text(
- text = stringResource(
- id = R.string.translator_query, stringResource(
- if (state.value.translateFromSelecting) R.string.translator_from
- else R.string.translator_to
- )
- )
- )
- },
- content1Actions = {
- CustomIconButton(
- icon = Icons.Default.Search,
- contentDescription = R.string.search_content_desc,
- disableOnClick = true
- ) {
- onEvent(TranslatorLanguageEvent.OnSearchShowHide)
- }
- },
-
- content2Visibility = state.value.showSearch,
- content2NavigationIcon = {
- CustomIconButton(
- icon = Icons.AutoMirrored.Default.ArrowBack,
- contentDescription = R.string.exit_search_content_desc,
- disableOnClick = true
- ) {
- onEvent(TranslatorLanguageEvent.OnSearchShowHide)
- }
- },
- content2Title = {
- CustomSearchTextField(
- modifier = Modifier
- .focusRequester(focusRequester)
- .onGloballyPositioned {
- onEvent(TranslatorLanguageEvent.OnRequestFocus(focusRequester))
- },
- query = state.value.searchQuery,
- onQueryChange = {
- onEvent(TranslatorLanguageEvent.OnSearchQueryChange(it))
- },
- onSearch = { onEvent(TranslatorLanguageEvent.OnSearch) },
- placeholder = stringResource(
- id = R.string.search_query,
- stringResource(id = R.string.languages)
- )
- )
- }
- )
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/data/TranslatorLanguageEvent.kt b/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/data/TranslatorLanguageEvent.kt
deleted file mode 100644
index 2adb04ac..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/data/TranslatorLanguageEvent.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package ua.acclorite.book_story.presentation.components.translator_language.data
-
-import androidx.compose.runtime.Immutable
-import androidx.compose.ui.focus.FocusRequester
-import ua.acclorite.book_story.domain.model.Language
-import ua.acclorite.book_story.domain.util.LanguageCode
-import ua.acclorite.book_story.domain.util.UIText
-
-@Immutable
-sealed class TranslatorLanguageEvent {
- data class OnSelectLanguage(
- val languageCode: String,
- val onError: suspend (UIText) -> Unit,
- val onSelect: (String, String) -> Unit
- ) : TranslatorLanguageEvent()
-
- data class OnDownloadLanguage(
- val languageCode: String,
- val onComplete: suspend () -> Unit,
- val onFailure: (Exception) -> Unit
- ) : TranslatorLanguageEvent()
-
- data class OnCancelDownload(
- val languageCode: String
- ) : TranslatorLanguageEvent()
-
- data class OnDeleteLanguage(
- val languageCode: String
- ) : TranslatorLanguageEvent()
-
- data object OnSearchShowHide : TranslatorLanguageEvent()
- data class OnRequestFocus(val focusRequester: FocusRequester) : TranslatorLanguageEvent()
- data class OnSearchQueryChange(val query: String) : TranslatorLanguageEvent()
- data object OnSearch : TranslatorLanguageEvent()
- data object OnDismissDownloadDialog : TranslatorLanguageEvent()
- data class OnUpdateLanguage(
- val languageCode: String,
- val block: (Language) -> Language
- ) : TranslatorLanguageEvent()
-
- data class OnUpdateLanguageHistory(
- val languageToChoose: LanguageCode
- ) : TranslatorLanguageEvent()
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/data/TranslatorLanguageState.kt b/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/data/TranslatorLanguageState.kt
deleted file mode 100644
index 0ffc0005..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/data/TranslatorLanguageState.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package ua.acclorite.book_story.presentation.components.translator_language.data
-
-import androidx.compose.runtime.Immutable
-import ua.acclorite.book_story.domain.model.Language
-
-@Immutable
-data class TranslatorLanguageState(
- val selectedLanguage: String = "",
- val unselectedLanguage: String = "",
- val languageToSelect: String = "",
- val translateFromSelecting: Boolean = false,
- val showDownloadLanguageDialog: Boolean = false,
-
- val unfilteredLanguages: List = emptyList(),
- val languages: List = emptyList(),
-
- val showSearch: Boolean = false,
- val searchQuery: String = "",
- val hasFocused: Boolean = false,
-
- )
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/data/TranslatorLanguageViewModel.kt b/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/data/TranslatorLanguageViewModel.kt
deleted file mode 100644
index 121672b5..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/components/translator_language/data/TranslatorLanguageViewModel.kt
+++ /dev/null
@@ -1,455 +0,0 @@
-package ua.acclorite.book_story.presentation.components.translator_language.data
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import com.google.mlkit.nl.translate.TranslateLanguage
-import dagger.hilt.android.lifecycle.HiltViewModel
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.update
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.yield
-import ua.acclorite.book_story.R
-import ua.acclorite.book_story.domain.model.Language
-import ua.acclorite.book_story.domain.model.LanguageHistory
-import ua.acclorite.book_story.domain.use_case.DeleteLanguageModel
-import ua.acclorite.book_story.domain.use_case.DownloadLanguageModel
-import ua.acclorite.book_story.domain.use_case.GetLanguageHistory
-import ua.acclorite.book_story.domain.use_case.IsLanguageModelDownloaded
-import ua.acclorite.book_story.domain.use_case.UpdateLanguageHistory
-import ua.acclorite.book_story.domain.util.UIText
-import java.util.Locale
-import javax.inject.Inject
-
-@HiltViewModel
-class TranslatorLanguageViewModel @Inject constructor(
- private val isLanguageModelDownloaded: IsLanguageModelDownloaded,
- private val downloadLanguageModel: DownloadLanguageModel,
- private val deleteLanguageModel: DeleteLanguageModel,
- private val getLanguageHistory: GetLanguageHistory,
- private val updateLanguageHistory: UpdateLanguageHistory,
-) : ViewModel() {
-
- private val _state = MutableStateFlow(TranslatorLanguageState())
- val state = _state.asStateFlow()
-
- private var job: Job? = null
-
- @Suppress("LABEL_NAME_CLASH")
- fun onEvent(event: TranslatorLanguageEvent) {
- when (event) {
- is TranslatorLanguageEvent.OnSelectLanguage -> {
- viewModelScope.launch(Dispatchers.IO) {
- if (_state.value.showDownloadLanguageDialog) {
- return@launch
- }
-
- val isDownloaded = isLanguageModelDownloaded.execute(
- event.languageCode
- )
-
- _state.update {
- it.copy(
- languageToSelect = event.languageCode
- )
- }
-
- onEvent(
- TranslatorLanguageEvent.OnUpdateLanguage(event.languageCode) {
- it.copy(
- isDownloaded = isDownloaded
- )
- }
- )
-
- if (isDownloaded) {
- val from = _state.value.translateFromSelecting
- val langToSelect = _state.value.languageToSelect
- val unselectedLang = _state.value.unselectedLanguage
- val selectedLang = _state.value.selectedLanguage
-
- val translateFrom: String
- val translateTo: String
-
- if (langToSelect == unselectedLang) {
- if (from) {
- if (selectedLang == "auto") {
- launch(Dispatchers.Main) {
- event.onError(
- UIText.StringResource(R.string.error_cannot_select_language)
- )
- }
- return@launch
- }
-
- translateFrom = langToSelect
- translateTo = selectedLang
- } else {
- translateTo = langToSelect
- translateFrom = selectedLang
- }
- } else {
- if (from) {
- translateFrom = langToSelect
- translateTo = unselectedLang
- } else {
- translateTo = langToSelect
- translateFrom = unselectedLang
- }
- }
-
- if (translateTo == "auto") {
- launch(Dispatchers.Main) {
- event.onError(
- UIText.StringResource(R.string.error_wrong_language)
- )
- }
- return@launch
- }
-
- event.onSelect(
- translateFrom,
- translateTo
- )
- return@launch
- }
-
- _state.update {
- it.copy(
- showDownloadLanguageDialog = true
- )
- }
- }
- }
-
- is TranslatorLanguageEvent.OnDownloadLanguage -> {
- viewModelScope.launch(Dispatchers.IO) {
- onEvent(
- TranslatorLanguageEvent.OnUpdateLanguage(event.languageCode) {
- it.copy(
- isDownloading = true,
- isCanceled = false
- )
- }
- )
-
- val isDownloaded = isLanguageModelDownloaded.execute(
- event.languageCode
- )
-
- onEvent(
- TranslatorLanguageEvent.OnUpdateLanguage(event.languageCode) {
- it.copy(
- isDownloaded = isDownloaded
- )
- }
- )
-
- if (isDownloaded) {
- onEvent(
- TranslatorLanguageEvent.OnUpdateLanguage(event.languageCode) {
- it.copy(
- isDownloading = false
- )
- }
- )
- return@launch
- }
-
- downloadLanguageModel.execute(
- languageCode = event.languageCode,
- onCompleted = {
- viewModelScope.launch(Dispatchers.IO) {
- val modelDownloaded = isLanguageModelDownloaded.execute(
- event.languageCode
- )
-
- onEvent(
- TranslatorLanguageEvent.OnUpdateLanguage(event.languageCode) {
- it.copy(
- isDownloading = false,
- isDownloaded = modelDownloaded
- )
- }
- )
-
- val isCanceled = _state.value.unfilteredLanguages.find {
- it.languageCode == event.languageCode
- }?.isCanceled
-
- if (isCanceled == true && modelDownloaded) {
- deleteLanguageModel.execute(
- languageCode = event.languageCode
- )
- onEvent(
- TranslatorLanguageEvent.OnUpdateLanguage(event.languageCode) {
- it.copy(
- isDownloading = false,
- isDownloaded = false,
- isCanceled = false
- )
- }
- )
- return@launch
- }
-
- event.onComplete()
- }
- },
- onFailure = {
- event.onFailure(it)
- }
- )
- }
- }
-
- is TranslatorLanguageEvent.OnCancelDownload -> {
- viewModelScope.launch(Dispatchers.IO) {
- onEvent(
- TranslatorLanguageEvent.OnUpdateLanguage(event.languageCode) {
- it.copy(
- isDownloaded = false,
- isDownloading = false,
- isCanceled = true
- )
- }
- )
- }
- }
-
- is TranslatorLanguageEvent.OnDeleteLanguage -> {
- viewModelScope.launch(Dispatchers.IO) {
- val deleted = deleteLanguageModel.execute(event.languageCode)
-
- if (deleted) {
- onEvent(
- TranslatorLanguageEvent.OnUpdateLanguage(event.languageCode) {
- it.copy(
- isDownloaded = false,
- isDownloading = false
- )
- }
- )
- }
- }
- }
-
- is TranslatorLanguageEvent.OnSearchShowHide -> {
- viewModelScope.launch(Dispatchers.IO) {
- val shouldHide = _state.value.showSearch
-
- if (shouldHide) {
- filterLanguages("")
- } else {
- _state.update {
- it.copy(
- searchQuery = "",
- hasFocused = false
- )
- }
- }
-
- _state.update {
- it.copy(
- showSearch = !shouldHide
- )
- }
- }
- }
-
- is TranslatorLanguageEvent.OnSearchQueryChange -> {
- _state.update {
- it.copy(
- searchQuery = event.query
- )
- }
- job?.cancel()
- job = viewModelScope.launch(Dispatchers.IO) {
- delay(500)
- yield()
- onEvent(TranslatorLanguageEvent.OnSearch)
- }
- }
-
- is TranslatorLanguageEvent.OnSearch -> {
- viewModelScope.launch(Dispatchers.IO) {
- filterLanguages()
- }
- }
-
- is TranslatorLanguageEvent.OnRequestFocus -> {
- if (!_state.value.hasFocused) {
- event.focusRequester.requestFocus()
- _state.update {
- it.copy(
- hasFocused = true
- )
- }
- }
- }
-
- is TranslatorLanguageEvent.OnDismissDownloadDialog -> {
- _state.update {
- it.copy(
- showDownloadLanguageDialog = false
- )
- }
- }
-
- is TranslatorLanguageEvent.OnUpdateLanguage -> {
- viewModelScope.launch(Dispatchers.IO) {
- val unfilteredLanguages = _state.value.unfilteredLanguages.map {
- if (it.languageCode == event.languageCode) {
- event.block(it)
- } else {
- it
- }
- }
-
- _state.update {
- it.copy(
- unfilteredLanguages = unfilteredLanguages
- )
- }
- filterLanguages()
- }
- }
-
- is TranslatorLanguageEvent.OnUpdateLanguageHistory -> {
- viewModelScope.launch {
- var history = getLanguageHistory
- .execute()
- .sortedBy { it.order }
- .toMutableList()
-
- val langToAdd = _state.value.languageToSelect
-
- val firstItem = history.indexOfFirst { it.languageCode == langToAdd }
- val indexOfItem = if (firstItem != -1) firstItem else null
-
- if (indexOfItem != null) {
- history.removeAt(indexOfItem)
- }
- history.add(0, LanguageHistory(langToAdd, 0))
-
- history = history.mapIndexed { index, item ->
- item.copy(
- order = index
- )
- }.toMutableList()
-
- updateLanguageHistory.execute(history)
- }
- }
- }
- }
-
- fun init(
- selectedLanguage: String,
- unselectedLanguage: String,
- translateFromSelecting: Boolean,
- loaded: () -> Unit
- ) {
- viewModelScope.launch(Dispatchers.IO) {
- val oldState = _state.value
- _state.update {
- TranslatorLanguageState()
- }
-
- val history = getLanguageHistory.execute()
- val unfilteredLanguages = TranslateLanguage.getAllLanguages()
- .filter {
- if (it == "ru") {
- return@filter false
- }
-
- true
- }
- .map { languageCode ->
- val previousLanguage = oldState.languages.find {
- it.languageCode == languageCode
- }
-
- val locale = Locale(languageCode)
- val displayLanguage = locale.getDisplayLanguage(locale).replaceFirstChar {
- it.uppercase()
- }
-
- val isDownloading = previousLanguage?.isDownloading ?: false
- val isCancelled = previousLanguage?.isCanceled ?: false
- val isSelected = selectedLanguage == languageCode
-
- val historyOrder = history.find {
- it.languageCode == languageCode
- }?.order
-
- Language(
- languageCode = languageCode,
- displayLanguage = displayLanguage,
- isDownloading = isDownloading,
- isDownloaded = false,
- isCanceled = isCancelled,
- isSelected = isSelected,
- historyOrder = historyOrder
- )
- }
-
-
- _state.update {
- it.copy(
- selectedLanguage = selectedLanguage,
- unselectedLanguage = unselectedLanguage,
- translateFromSelecting = translateFromSelecting,
- unfilteredLanguages = unfilteredLanguages
- )
- }
- filterLanguages()
- loaded()
- loadDownloadedState()
- }
- }
-
- private suspend fun loadDownloadedState() {
- viewModelScope.launch(Dispatchers.IO) {
- _state.value.unfilteredLanguages.map { language ->
- val isDownloaded = isLanguageModelDownloaded.execute(
- language.languageCode
- )
- val isDownloading = if (isDownloaded) false else null
-
- onEvent(
- TranslatorLanguageEvent.OnUpdateLanguage(
- languageCode = language.languageCode,
- block = {
- it.copy(
- isDownloaded = isDownloaded,
- isDownloading = isDownloading ?: it.isDownloading
- )
- }
- )
- )
- }
- }
- }
-
- private fun filterLanguages(
- query: String = if (_state.value.showSearch) _state.value.searchQuery else ""
- ) {
- _state.update {
- it.copy(
- languages = it.unfilteredLanguages.filter { language ->
- if (query.isBlank()) {
- return@filter true
- }
-
- language.displayLanguage.lowercase().trim().contains(
- query.lowercase().trim()
- )
- }
- )
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/data/ArithmeticOperations.kt b/app/src/main/java/ua/acclorite/book_story/presentation/data/ArithmeticOperations.kt
index 91d8f848..71b426bd 100644
--- a/app/src/main/java/ua/acclorite/book_story/presentation/data/ArithmeticOperations.kt
+++ b/app/src/main/java/ua/acclorite/book_story/presentation/data/ArithmeticOperations.kt
@@ -8,63 +8,4 @@ fun String.removeTrailingZero(): String {
.dropLastWhile { it == '.' }
}
-fun Double.removeDigits(digits: Int) = "%.${digits}f".format(this).replace(",", ".")
-
-fun Map.update(item: Pair): Map {
- val keyExists = containsKey(item.first)
-
- return if (!keyExists) this
- else this.plus(item)
-}
-
-fun Map.update(items: List>): Map {
- var map = this
-
- for (item in items) {
- map = map.update(item)
- }
-
- return map
-}
-
-fun Map.update(items: Map): Map {
- var map = this
-
- for (item in items) {
- map = map.update(item.toPair())
- }
-
- return map
-}
-
-fun Map.updateWithCopy(
- calculation: (T) -> T
-): Map {
- var map = this
-
- for (item in this) {
- map = map.update(item.key to calculation(item.value))
- }
-
- return map
-}
-
-fun Map.removeKeys(
- keys: Set
-): Map {
- val map = this.toMutableMap()
-
- for (key in keys) {
- map.remove(key)
- }
-
- return map.toMap()
-}
-
-fun Map.removeKey(
- key: K
-): Map {
- val map = this.toMutableMap()
- map.remove(key)
- return map.toMap()
-}
\ No newline at end of file
+fun Double.removeDigits(digits: Int) = "%.${digits}f".format(this).replace(",", ".")
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainEvent.kt b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainEvent.kt
index d9243fc7..f914b000 100644
--- a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainEvent.kt
+++ b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainEvent.kt
@@ -17,8 +17,5 @@ sealed class MainEvent {
data class OnChangeShowStartScreen(val bool: Boolean) : MainEvent()
data class OnChangeCheckForUpdates(val bool: Boolean) : MainEvent()
data class OnChangeSidePadding(val sidePadding: Int) : MainEvent()
- data class OnChangeEnableTranslator(val bool: Boolean) : MainEvent()
- data class OnChangeTranslateFrom(val languageCode: String) : MainEvent()
- data class OnChangeTranslateTo(val languageCode: String) : MainEvent()
data class OnChangeDoubleClickTranslation(val bool: Boolean) : MainEvent()
}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainState.kt b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainState.kt
index 120c18c5..3b7013ac 100644
--- a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainState.kt
+++ b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainState.kt
@@ -5,7 +5,6 @@ import android.os.Parcelable
import androidx.annotation.Keep
import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.Color
-import com.google.mlkit.nl.translate.TranslateLanguage
import kotlinx.parcelize.Parcelize
import ua.acclorite.book_story.domain.util.Constants
import ua.acclorite.book_story.domain.util.DataStoreConstants
@@ -44,9 +43,6 @@ data class MainState(
val showStartScreen: Boolean? = null,
val checkForUpdates: Boolean? = null,
val sidePadding: Int? = null,
- val enableTranslator: Boolean? = null,
- val translateFrom: String? = null,
- val translateTo: String? = null,
val doubleClickTranslation: Boolean? = null
) : Parcelable {
companion object {
@@ -109,23 +105,9 @@ data class MainState(
val sidePadding: Int = data[SIDE_PADDING.name] as? Int
?: 6
- val enableTranslator: Boolean = data[ENABLE_TRANSLATOR.name] as? Boolean
- ?: false
-
- val translateFrom: String = data[TRANSLATE_FROM.name] as? String
- ?: "auto"
-
- val translateTo: String = data[TRANSLATE_TO.name] as? String ?: if (
- TranslateLanguage.getAllLanguages().any { it == language }
- ) {
- language
- } else {
- "en"
- }
-
val doubleClickTranslation: Boolean =
data[DOUBLE_CLICK_TRANSLATION.name] as? Boolean
- ?: true
+ ?: false
return MainState(
language = language,
@@ -144,9 +126,6 @@ data class MainState(
paragraphIndentation = paragraphIndentation,
checkForUpdates = checkForUpdates,
sidePadding = sidePadding,
- enableTranslator = enableTranslator,
- translateFrom = translateFrom,
- translateTo = translateTo,
doubleClickTranslation = doubleClickTranslation
)
}
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainViewModel.kt b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainViewModel.kt
index ae3cc71f..11f10914 100644
--- a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainViewModel.kt
+++ b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainViewModel.kt
@@ -228,39 +228,6 @@ class MainViewModel @Inject constructor(
}
}
- is MainEvent.OnChangeEnableTranslator -> {
- viewModelScope.launch(Dispatchers.IO) {
- setDatastore.execute(DataStoreConstants.ENABLE_TRANSLATOR, event.bool)
- updateStateWithSavedHandle {
- it.copy(
- enableTranslator = event.bool
- )
- }
- }
- }
-
- is MainEvent.OnChangeTranslateFrom -> {
- viewModelScope.launch(Dispatchers.IO) {
- setDatastore.execute(DataStoreConstants.TRANSLATE_FROM, event.languageCode)
- updateStateWithSavedHandle {
- it.copy(
- translateFrom = event.languageCode
- )
- }
- }
- }
-
- is MainEvent.OnChangeTranslateTo -> {
- viewModelScope.launch(Dispatchers.IO) {
- setDatastore.execute(DataStoreConstants.TRANSLATE_TO, event.languageCode)
- updateStateWithSavedHandle {
- it.copy(
- translateTo = event.languageCode
- )
- }
- }
- }
-
is MainEvent.OnChangeDoubleClickTranslation -> {
viewModelScope.launch(Dispatchers.IO) {
setDatastore.execute(DataStoreConstants.DOUBLE_CLICK_TRANSLATION, event.bool)
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/components/confirm_update_dialog/BookInfoConfirmUpdateDialogItem.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/components/confirm_update_dialog/BookInfoConfirmUpdateDialogItem.kt
deleted file mode 100644
index ad2c8d7a..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/components/confirm_update_dialog/BookInfoConfirmUpdateDialogItem.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package ua.acclorite.book_story.presentation.screens.book_info.components.confirm_update_dialog
-
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-
-/**
- * Confirm update dialog item.
- */
-@Composable
-fun BookInfoConfirmUpdateDialogItem(title: String) {
- Text(
- text = "• $title",
- color = MaterialTheme.colorScheme.onSurfaceVariant,
- style = MaterialTheme.typography.bodyMedium,
- modifier = Modifier.padding(horizontal = 24.dp, vertical = 4.dp)
- )
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/data/BookInfoViewModel.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/data/BookInfoViewModel.kt
index 8620b2cb..36b8a6d0 100644
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/data/BookInfoViewModel.kt
+++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/book_info/data/BookInfoViewModel.kt
@@ -534,7 +534,7 @@ class BookInfoViewModel @Inject constructor(
val updatedText = updatedBook.text
val text = getText.execute(book.textPath)
- if (updatedText != text.map { it.value.originalLine }) {
+ if (updatedText != text.map { it.value.line }) {
textUpdated = true
}
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/ReaderScreen.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/ReaderScreen.kt
index 3a1c1eb9..119d3084 100644
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/ReaderScreen.kt
+++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/ReaderScreen.kt
@@ -40,7 +40,6 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
@@ -55,7 +54,6 @@ import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
import ua.acclorite.book_story.presentation.components.CustomSelectionContainer
import ua.acclorite.book_story.presentation.components.customItems
import ua.acclorite.book_story.presentation.components.is_messages.IsError
-import ua.acclorite.book_story.presentation.components.translator_language.TranslatorLanguageBottomSheet
import ua.acclorite.book_story.presentation.data.LocalNavigator
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
@@ -66,13 +64,11 @@ import ua.acclorite.book_story.presentation.screens.history.data.HistoryViewMode
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
import ua.acclorite.book_story.presentation.screens.library.data.LibraryViewModel
import ua.acclorite.book_story.presentation.screens.reader.components.ReaderEndItem
+import ua.acclorite.book_story.presentation.screens.reader.components.ReaderTextParagraph
import ua.acclorite.book_story.presentation.screens.reader.components.app_bar.ReaderBottomBar
import ua.acclorite.book_story.presentation.screens.reader.components.app_bar.ReaderTopBar
-import ua.acclorite.book_story.presentation.screens.reader.components.download_language_dialog.ReaderDownloadLanguageDialog
import ua.acclorite.book_story.presentation.screens.reader.components.settings_bottom_sheet.ReaderSettingsBottomSheet
import ua.acclorite.book_story.presentation.screens.reader.components.start_item.ReaderStartItem
-import ua.acclorite.book_story.presentation.screens.reader.components.text.ReaderTextParagraph
-import ua.acclorite.book_story.presentation.screens.reader.components.translator_bottom_sheet.ReaderTranslatorBottomSheet
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderEvent
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderState
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderViewModel
@@ -163,7 +159,6 @@ private fun ReaderScreen(
onHistoryEvent: (HistoryEvent) -> Unit,
) {
val context = LocalContext.current as ComponentActivity
- val density = LocalDensity.current
val nestedScrollConnection = remember(state) {
object : NestedScrollConnection {
@@ -214,45 +209,6 @@ private fun ReaderScreen(
}
}
- if (state.value.showTranslatorBottomSheet) {
- ReaderTranslatorBottomSheet(
- state = state,
- onEvent = onEvent
- )
- }
- if (state.value.showLanguageBottomSheet) {
- TranslatorLanguageBottomSheet(
- selectedLanguage = if (state.value.languageBottomSheetTranslateFrom) {
- state.value.book.translateFrom
- } else state.value.book.translateTo,
-
- unselectedLanguage = if (!state.value.languageBottomSheetTranslateFrom) {
- state.value.book.translateFrom
- } else state.value.book.translateTo,
-
- translateFromSelecting = state.value.languageBottomSheetTranslateFrom,
- onSelect = { from, to ->
- onEvent(
- ReaderEvent.OnChangeTranslatorSettings(
- translateFrom = from,
- translateTo = to
- )
- )
- onEvent(
- ReaderEvent.OnShowHideLanguageBottomSheet(
- show = false
- )
- )
- },
- onDismiss = {
- onEvent(
- ReaderEvent.OnShowHideLanguageBottomSheet(
- show = false
- )
- )
- }
- )
- }
if (state.value.showSettingsBottomSheet) {
ReaderSettingsBottomSheet(
mainState = mainState,
@@ -260,12 +216,6 @@ private fun ReaderScreen(
onMainEvent = onMainEvent
)
}
- if (state.value.showDownloadLanguageDialog) {
- ReaderDownloadLanguageDialog(
- state = state,
- onEvent = onEvent
- )
- }
Scaffold(
Modifier
@@ -379,11 +329,7 @@ private fun ReaderScreen(
text, key = { key -> key.first }
) { line ->
ReaderTextParagraph(
- state = state,
- id = line.first,
line = line.second,
- context = context,
- density = density,
fontFamily = fontFamily,
fontColor = fontColor,
lineHeight = lineHeight,
@@ -391,8 +337,6 @@ private fun ReaderScreen(
fontSize = mainState.value.fontSize!!.sp,
sidePadding = sidePadding,
paragraphIndentation = mainState.value.paragraphIndentation!!,
- toolbarHidden = toolbarHidden,
- onEvent = onEvent
)
}
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/ReaderTextParagraph.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/ReaderTextParagraph.kt
new file mode 100644
index 00000000..b953fa18
--- /dev/null
+++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/ReaderTextParagraph.kt
@@ -0,0 +1,71 @@
+package ua.acclorite.book_story.presentation.screens.reader.components
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyItemScope
+import androidx.compose.foundation.text.BasicText
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.font.FontStyle
+import androidx.compose.ui.text.style.LineBreak
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.TextUnit
+import ua.acclorite.book_story.domain.model.FontWithName
+import ua.acclorite.book_story.domain.model.ReaderLine
+
+/**
+ * Reader Text Paragraph item.
+ *
+ * @param line Current line.
+ * @param fontFamily Line's font family.
+ * @param fontColor Line's font color.
+ * @param lineHeight Line's line height.
+ * @param fontStyle Line's font style.
+ * @param fontSize Line's font size.
+ * @param sidePadding Line's side padding.
+ * @param paragraphIndentation Whether Paragraph Indentation is enabled for this line.
+ */
+@Composable
+fun LazyItemScope.ReaderTextParagraph(
+ line: ReaderLine,
+ fontFamily: FontWithName,
+ fontColor: Color,
+ lineHeight: TextUnit,
+ fontStyle: FontStyle,
+ fontSize: TextUnit,
+ sidePadding: Dp,
+ paragraphIndentation: Boolean
+) {
+ Column(
+ modifier = Modifier
+ .animateItem(fadeInSpec = null, fadeOutSpec = null)
+ .fillMaxWidth()
+ .padding(
+ horizontal = sidePadding
+ ),
+ verticalArrangement = Arrangement.Center
+ ) {
+ BasicText(
+ text = buildAnnotatedString {
+ if (paragraphIndentation) {
+ append(" ")
+ }
+
+ append(line.line)
+ },
+ style = TextStyle(
+ fontFamily = fontFamily.font,
+ fontStyle = fontStyle,
+ fontSize = fontSize,
+ lineHeight = lineHeight,
+ color = fontColor,
+ lineBreak = LineBreak.Paragraph
+ )
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/app_bar/ReaderTopBar.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/app_bar/ReaderTopBar.kt
index df8a8f2b..ff2d99b8 100644
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/app_bar/ReaderTopBar.kt
+++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/app_bar/ReaderTopBar.kt
@@ -8,9 +8,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Settings
-import androidx.compose.material.icons.filled.Translate
import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
@@ -141,17 +139,6 @@ fun ReaderTopBar(
}
},
actions = {
- CustomIconButton(
- icon = Icons.Default.Translate,
- contentDescription = R.string.translator_content_desc,
- disableOnClick = false,
- enabled = !state.value.lockMenu,
- color = if (state.value.book.enableTranslator) {
- MaterialTheme.colorScheme.primary
- } else LocalContentColor.current
- ) {
- onEvent(ReaderEvent.OnShowHideTranslatorBottomSheet())
- }
CustomIconButton(
icon = Icons.Default.Settings,
contentDescription = R.string.open_reader_settings_content_desc,
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/download_language_dialog/ReaderDownloadLanguageDialog.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/download_language_dialog/ReaderDownloadLanguageDialog.kt
deleted file mode 100644
index 7ee3d1f3..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/download_language_dialog/ReaderDownloadLanguageDialog.kt
+++ /dev/null
@@ -1,116 +0,0 @@
-package ua.acclorite.book_story.presentation.screens.reader.components.download_language_dialog
-
-import android.widget.Toast
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Download
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.stringResource
-import ua.acclorite.book_story.R
-import ua.acclorite.book_story.presentation.components.customItems
-import ua.acclorite.book_story.presentation.components.custom_dialog.CustomDialogWithLazyColumn
-import ua.acclorite.book_story.presentation.screens.reader.data.ReaderEvent
-import ua.acclorite.book_story.presentation.screens.reader.data.ReaderState
-
-/**
- * Reader Download Language Dialog. Downloads multiple language models at the same time.
- *
- * @param state [ReaderState].
- * @param onEvent [ReaderEvent] callback.
- */
-@Composable
-fun ReaderDownloadLanguageDialog(
- state: State,
- onEvent: (ReaderEvent) -> Unit
-) {
- val context = LocalContext.current
- var isOnClickEnabled by remember { mutableStateOf(true) }
- val isDownloading by remember {
- derivedStateOf {
- state.value.languagesToTranslate.any { it.isDownloading }
- }
- }
- val isDownloaded by remember {
- derivedStateOf {
- state.value.languagesToTranslate.filter { it.isSelected }.none { !it.isDownloaded }
- }
- }
- val languages = remember(state.value.languagesToTranslate, isDownloading) {
- if (isDownloading) {
- state.value.languagesToTranslate.sortedByDescending { it.isDownloading }
- } else {
- state.value.languagesToTranslate
- }
- }
-
- CustomDialogWithLazyColumn(
- title = stringResource(id = R.string.download_languages),
- imageVectorIcon = Icons.Default.Download,
- description = stringResource(
- id = R.string.download_languages_description
- ),
- actionText = stringResource(
- if (!isDownloaded) R.string.download
- else R.string.continue_download
- ),
- disableOnClick = false,
- isActionEnabled = isOnClickEnabled,
- onDismiss = { onEvent(ReaderEvent.OnDismissDownloadLanguageDialog) },
- onAction = {
- isOnClickEnabled = false
- onEvent(
- ReaderEvent.OnDownloadLanguages(
- onSuccess = {
- Toast.makeText(
- context,
- context.getString(R.string.languages_downloaded),
- Toast.LENGTH_LONG
- ).show()
-
- onEvent(
- ReaderEvent.OnTranslateText(
- it.keys,
- error = { error ->
- Toast.makeText(
- context,
- error.asString(context),
- Toast.LENGTH_LONG
- ).show()
- }
- )
- )
- },
- error = {
- Toast.makeText(
- context,
- it.asString(context),
- Toast.LENGTH_LONG
- ).show()
- }
- )
- )
- },
- withDivider = true,
- items = {
- customItems(
- languages, key = { it.languageCode }
- ) {
- ReaderDownloadLanguageDialogItem(
- language = it,
- isEnabled = !isDownloading,
- onClick = {
- onEvent(
- ReaderEvent.OnSelectLanguage(it)
- )
- }
- )
- }
- }
- )
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/download_language_dialog/ReaderDownloadLanguageDialogItem.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/download_language_dialog/ReaderDownloadLanguageDialogItem.kt
deleted file mode 100644
index 86f4237e..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/download_language_dialog/ReaderDownloadLanguageDialogItem.kt
+++ /dev/null
@@ -1,177 +0,0 @@
-package ua.acclorite.book_story.presentation.screens.reader.components.download_language_dialog
-
-import android.widget.Toast
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
-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.foundation.lazy.LazyItemScope
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.DownloadDone
-import androidx.compose.material.icons.filled.Error
-import androidx.compose.material3.CircularProgressIndicator
-import androidx.compose.material3.Icon
-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.draw.clip
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.unit.dp
-import ua.acclorite.book_story.R
-import ua.acclorite.book_story.domain.model.SelectableLanguage
-import ua.acclorite.book_story.presentation.components.CustomCheckbox
-import ua.acclorite.book_story.presentation.ui.DefaultTransition
-
-/**
- * Reader Download Language Dialog Item.
- *
- * @param language [SelectableLanguage] item.
- * @param isEnabled Whether OnClick is enabled or not.
- * @param onClick OnClick callback.
- */
-@Composable
-fun LazyItemScope.ReaderDownloadLanguageDialogItem(
- language: SelectableLanguage,
- isEnabled: Boolean = true,
- onClick: () -> Unit
-) {
- val context = LocalContext.current
-
- if (
- isEnabled || language.isDownloading || language.isDownloaded || language.isError
- ) {
- Row(
- modifier = Modifier
- .animateItem(
- fadeInSpec = null,
- fadeOutSpec = null
- )
- .fillMaxWidth()
- .clickable(
- enabled = !language.isDownloading &&
- !language.isDownloaded &&
- language.canUnselect &&
- isEnabled || language.isError
- ) {
- if (!language.isError) {
- onClick()
- } else if (language.errorMessage != null) {
- Toast
- .makeText(
- context,
- language.errorMessage.asString(context),
- Toast.LENGTH_LONG
- )
- .show()
- }
- }
- .padding(vertical = 12.dp, horizontal = 24.dp),
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(Modifier.weight(1f)) {
- Text(
- text = language.displayLanguage,
- color = MaterialTheme.colorScheme.onSurface,
- style = MaterialTheme.typography.bodyLarge,
- maxLines = 1,
- overflow = TextOverflow.Ellipsis
- )
- if (!language.occurrences.isNullOrEmpty()) {
- Text(
- text = stringResource(
- id = R.string.translator_occurrences,
- language.occurrences.size
- ),
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant,
- maxLines = 1,
- overflow = TextOverflow.Ellipsis
- )
- }
- }
-
-
- Box(contentAlignment = Alignment.CenterEnd) {
- DefaultTransition(
- language.isDownloading && !language.isDownloaded && !language.isError
- ) {
- Row {
- Spacer(modifier = Modifier.width(24.dp))
- CircularProgressIndicator(
- strokeWidth = 2.5.dp,
- modifier = Modifier
- .size(22.dp),
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- Spacer(modifier = Modifier.width(4.dp))
- }
- }
-
-
- DefaultTransition(
- language.isDownloaded && !language.isDownloading && !language.isError
- ) {
- Row {
- Spacer(modifier = Modifier.width(24.dp))
- Icon(
- imageVector = Icons.Default.DownloadDone,
- tint = MaterialTheme.colorScheme.onSurfaceVariant,
- modifier = Modifier
- .clip(CircleShape)
- .background(
- MaterialTheme.colorScheme.outlineVariant,
- shape = CircleShape
- )
- .padding(6.dp)
- .size(17.dp),
- contentDescription = stringResource(id = R.string.downloaded_content_desc)
- )
- }
- }
-
- DefaultTransition(
- !language.isDownloaded && !language.isDownloading && isEnabled && !language.isError
- ) {
- Row {
- Spacer(modifier = Modifier.width(24.dp))
- CustomCheckbox(
- selected = language.isSelected,
- size = 20.dp,
- containerColor =
- if (language.canUnselect) MaterialTheme.colorScheme.surfaceContainerHigh
- else MaterialTheme.colorScheme.surfaceContainerHigh
- )
- }
- }
-
- DefaultTransition(
- !language.isDownloaded && !language.isDownloading && language.isError
- ) {
- Row {
- Spacer(modifier = Modifier.width(24.dp))
- Icon(
- imageVector = Icons.Default.Error,
- tint = MaterialTheme.colorScheme.error,
- modifier = Modifier
- .size(27.dp),
- contentDescription = stringResource(id = R.string.error_content_desc)
- )
- Spacer(modifier = Modifier.width(1.5.dp))
- }
- }
- }
- }
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/text/ReaderTextParagraph.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/text/ReaderTextParagraph.kt
deleted file mode 100644
index 482a9086..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/text/ReaderTextParagraph.kt
+++ /dev/null
@@ -1,220 +0,0 @@
-package ua.acclorite.book_story.presentation.screens.reader.components.text
-
-import android.content.Context
-import android.widget.Toast
-import androidx.activity.ComponentActivity
-import androidx.compose.animation.core.tween
-import androidx.compose.animation.expandVertically
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.shrinkVertically
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.combinedClickable
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.lazy.LazyItemScope
-import androidx.compose.foundation.text.BasicText
-import androidx.compose.foundation.text.appendInlineContent
-import androidx.compose.foundation.text.selection.DisableSelection
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.buildAnnotatedString
-import androidx.compose.ui.text.font.FontStyle
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.text.style.LineBreak
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.TextUnit
-import ua.acclorite.book_story.R
-import ua.acclorite.book_story.domain.model.FontWithName
-import ua.acclorite.book_story.domain.model.LineWithTranslation
-import ua.acclorite.book_story.domain.util.ID
-import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
-import ua.acclorite.book_story.presentation.screens.reader.data.ReaderEvent
-import ua.acclorite.book_story.presentation.screens.reader.data.ReaderState
-import java.util.Locale
-
-/**
- * Reader Text Paragraph item.
- *
- * @param state [ReaderState].
- * @param id Current paragraph [ID].
- * @param line Current line.
- * @param context Context.
- * @param density [Density] from LocalDensity.current.
- * @param fontFamily Line's font family.
- * @param fontColor Line's font color.
- * @param lineHeight Line's line height.
- * @param fontStyle Line's font style.
- * @param fontSize Line's font size.
- * @param sidePadding Line's side padding.
- * @param paragraphIndentation Whether Paragraph Indentation is enabled for this line.
- * @param toolbarHidden Whether selection toolbar is hidden.
- * @param onEvent [ReaderEvent] callback.
- */
-@OptIn(ExperimentalFoundationApi::class)
-@Composable
-fun LazyItemScope.ReaderTextParagraph(
- state: State,
- id: ID,
- line: LineWithTranslation,
- context: Context,
- density: Density,
- fontFamily: FontWithName,
- fontColor: Color,
- lineHeight: TextUnit,
- fontStyle: FontStyle,
- fontSize: TextUnit,
- sidePadding: Dp,
- paragraphIndentation: Boolean,
- toolbarHidden: Boolean,
- onEvent: (ReaderEvent) -> Unit
-) {
- val text = remember(
- line.useTranslation, line.translatedLine, line.originalLine
- ) {
- if (line.useTranslation && line.translatedLine != null) line.translatedLine
- else line.originalLine
- }
-
- val translated = remember(line.useTranslation, line.translatedLine) {
- line.useTranslation && line.translatedLine != null
- }
- val showTrailingContent = remember(
- line.isTranslationLoading, line.isTranslationFailed
- ) {
- line.isTranslationLoading || line.isTranslationFailed
- }
-
- val translatingFrom = remember(line.translatingFrom) {
- val locale = Locale(line.translatingFrom)
- locale.getDisplayName(locale).replaceFirstChar { char ->
- char.uppercase()
- }
- }
- val translatingTo = remember(line.translatingTo) {
- val locale = Locale(line.translatingTo)
- locale.getDisplayName(locale).replaceFirstChar { char ->
- char.uppercase()
- }
- }
-
- Column(
- modifier = Modifier
- .animateItem(fadeInSpec = null, fadeOutSpec = null)
- .fillMaxWidth()
- .padding(
- horizontal = sidePadding
- ),
- verticalArrangement = Arrangement.Center
- ) {
- CustomAnimatedVisibility(
- modifier = Modifier.animateItem(
- placementSpec = tween(10),
- fadeInSpec = null,
- fadeOutSpec = null
- ),
- visible = translated,
- enter = fadeIn(tween(250)) + expandVertically(tween(250)),
- exit = fadeOut(tween(250)) + shrinkVertically(tween(250)),
- ) {
- DisableSelection {
- Text(
- text = stringResource(
- id = R.string.translator_show_original,
- translatingFrom,
- translatingTo
- ),
- color = fontColor,
- fontStyle = FontStyle.Italic,
- fontWeight = FontWeight.Light,
- style = MaterialTheme.typography.bodyMedium,
- modifier = Modifier.clickable(interactionSource = null, indication = null) {
- onEvent(ReaderEvent.OnUndoTranslation(id))
- }
- )
- }
- }
-
- BasicText(
- text = buildAnnotatedString {
- if (paragraphIndentation) {
- append(" ")
- }
-
- append(text)
-
- if (showTrailingContent) {
- append(" ")
- appendInlineContent("translator")
- }
- },
- modifier = Modifier
- .then(
- if (
- state.value.book.enableTranslator &&
- state.value.book.doubleClickTranslation &&
- toolbarHidden
- ) {
- Modifier.combinedClickable(
- interactionSource = null,
- indication = null,
- onDoubleClick = {
- if (line.isTranslationLoading) {
- return@combinedClickable
- }
-
- if (translated) {
- onEvent(ReaderEvent.OnUndoTranslation(id))
- } else {
- onEvent(
- ReaderEvent.OnTranslateText(setOf(id)) {
- Toast
- .makeText(
- context,
- it.asString(context),
- Toast.LENGTH_LONG
- )
- .show()
- }
- )
- }
- },
- onClick = {
- onEvent(
- ReaderEvent.OnShowHideMenu(context = context as ComponentActivity)
- )
- }
- )
- } else {
- Modifier
- }
- ),
- inlineContent = readerTextTrailingContent(
- line = line,
- color = fontColor,
- textSize = fontSize,
- context = context,
- density = density
- ),
- style = TextStyle(
- fontFamily = fontFamily.font,
- fontStyle = fontStyle,
- fontSize = fontSize,
- lineHeight = lineHeight,
- color = fontColor,
- lineBreak = LineBreak.Paragraph
- )
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/text/ReaderTextTrailingContent.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/text/ReaderTextTrailingContent.kt
deleted file mode 100644
index 55c9850e..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/text/ReaderTextTrailingContent.kt
+++ /dev/null
@@ -1,97 +0,0 @@
-package ua.acclorite.book_story.presentation.screens.reader.components.text
-
-import android.content.Context
-import android.widget.Toast
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.text.InlineTextContent
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Error
-import androidx.compose.material3.CircularProgressIndicator
-import androidx.compose.material3.Icon
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.Placeholder
-import androidx.compose.ui.text.PlaceholderVerticalAlign
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.TextUnit
-import ua.acclorite.book_story.R
-import ua.acclorite.book_story.domain.model.LineWithTranslation
-import ua.acclorite.book_story.presentation.ui.DefaultTransition
-
-/**
- * [ReaderTextParagraph]'s trailing content.
- *
- * @param line [ReaderTextParagraph]'s line.
- * @param color Color.
- * @param textSize Font size.
- * @param context Context.
- * @param density [Density] from LocalDensity.current.
- */
-@Composable
-fun readerTextTrailingContent(
- line: LineWithTranslation,
- color: Color,
- textSize: TextUnit,
- context: Context,
- density: Density
-): Map {
- val sizeDp = remember(textSize, density) { with(density) { textSize.toDp() } }
- return remember(line.isTranslationLoading, line.isTranslationFailed, sizeDp, color, textSize) {
- mapOf(
- Pair(
- "translator",
- InlineTextContent(
- placeholder = Placeholder(
- width = textSize,
- height = textSize,
- placeholderVerticalAlign = PlaceholderVerticalAlign.Center
- ),
- ) {
- Box(
- Modifier.fillMaxSize(),
- contentAlignment = Alignment.CenterEnd
- ) {
- DefaultTransition(line.isTranslationLoading) {
- CircularProgressIndicator(
- strokeWidth = sizeDp / 12,
- modifier = Modifier
- .fillMaxSize(0.7f),
- color = color
- )
- }
-
- DefaultTransition(line.isTranslationFailed && !line.isTranslationLoading) {
- Icon(
- imageVector = Icons.Filled.Error,
- contentDescription = stringResource(id = R.string.error_content_desc),
- tint = color,
- modifier = Modifier
- .fillMaxSize()
- .clickable(
- interactionSource = null,
- indication = null
- ) {
- line.errorMessage?.let {
- Toast
- .makeText(
- context,
- it.asString(context),
- Toast.LENGTH_LONG
- )
- .show()
- }
- }
- )
- }
- }
- }
- )
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/translator_bottom_sheet/ReaderTranslatorBottomSheet.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/translator_bottom_sheet/ReaderTranslatorBottomSheet.kt
deleted file mode 100644
index b5280e28..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/translator_bottom_sheet/ReaderTranslatorBottomSheet.kt
+++ /dev/null
@@ -1,318 +0,0 @@
-package ua.acclorite.book_story.presentation.screens.reader.components.translator_bottom_sheet
-
-import android.widget.Toast
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.Button
-import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.CircularProgressIndicator
-import androidx.compose.material3.LocalContentColor
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Switch
-import androidx.compose.material3.SwitchDefaults
-import androidx.compose.material3.Text
-import androidx.compose.material3.contentColorFor
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.graphics.StrokeCap
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import ua.acclorite.book_story.R
-import ua.acclorite.book_story.presentation.components.CustomBottomSheet
-import ua.acclorite.book_story.presentation.screens.reader.data.ReaderEvent
-import ua.acclorite.book_story.presentation.screens.reader.data.ReaderState
-import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle
-import java.util.Locale
-
-/**
- * Reader Translator Bottom Sheet. You can set up preferences for an individual book here and apply/cancel translation.
- *
- * @param state [ReaderState].
- * @param onEvent [ReaderEvent] callback.
- */
-@Composable
-fun ReaderTranslatorBottomSheet(
- state: State,
- onEvent: (ReaderEvent) -> Unit
-) {
- val context = LocalContext.current
- val book = remember(state.value) { state.value.book }
-
- val translateFrom = remember(book.translateFrom) {
- if (book.translateFrom == "auto") {
- return@remember context.getString(R.string.translator_auto_short)
- }
-
- val locale = Locale(book.translateFrom)
- locale.getDisplayName(locale).replaceFirstChar { char ->
- char.uppercase()
- }
- }
- val translateTo = remember(book.translateTo) {
- val locale = Locale(book.translateTo)
- locale.getDisplayName(locale).replaceFirstChar { char ->
- char.uppercase()
- }
- }
-
- val loading = remember { mutableStateOf(false) }
- val textTranslated = remember(state.value.isTranslating, state.value.text) {
- loading.value = true
-
- val hasTranslatedText = state.value.text.any {
- it.value.useTranslation && it.value.translatedLine != null
- }
- val loaded = state.value.text.none {
- it.value.isTranslationLoading
- }
-
- loading.value = false
-
- !state.value.isTranslating && hasTranslatedText && loaded
- }
-
- CustomBottomSheet(
- onDismissRequest = {
- onEvent(ReaderEvent.OnShowHideTranslatorBottomSheet())
- }
- ) {
- LazyColumn(Modifier.fillMaxWidth()) {
- item {
- Row(
- Modifier
- .fillMaxWidth()
- .padding(horizontal = 18.dp)
- .clip(RoundedCornerShape(25.dp))
- .background(
- if (book.enableTranslator) MaterialTheme.colorScheme.primary
- else MaterialTheme.colorScheme.outline,
- RoundedCornerShape(25.dp)
- )
- .clickable {
- if (book.enableTranslator) {
- onEvent(ReaderEvent.OnCancelTranslation)
- }
-
- onEvent(
- ReaderEvent.OnChangeTranslatorSettings(
- enableTranslator = !book.enableTranslator
- )
- )
- }
- .padding(horizontal = 15.dp, vertical = 16.dp),
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.SpaceBetween
- ) {
- Text(
- text = stringResource(id = R.string.translator_reader_settings),
- color = if (book.enableTranslator) MaterialTheme.colorScheme.onPrimary
- else MaterialTheme.colorScheme.surface,
- fontSize = 17.5.sp
- )
- Switch(
- checked = book.enableTranslator,
- onCheckedChange = null,
- colors = SwitchDefaults.colors(
- checkedThumbColor = MaterialTheme.colorScheme.primary,
- checkedTrackColor = MaterialTheme.colorScheme.secondaryContainer,
- uncheckedBorderColor = MaterialTheme.colorScheme.surfaceContainerHighest
- )
- )
- }
- }
-
- item {
- Spacer(modifier = Modifier.height(12.dp))
- }
-
- item {
- ReaderTranslatorBottomSheetLanguageChooser(
- fromLanguage = translateFrom,
- toLanguage = translateTo,
- onFromClick = {
- onEvent(
- ReaderEvent.OnShowHideLanguageBottomSheet(
- show = true,
- translateFrom = true
- )
- )
- },
- onToClick = {
- onEvent(
- ReaderEvent.OnShowHideLanguageBottomSheet(
- show = true,
- translateFrom = false
- )
- )
- },
- enabled = !state.value.isTranslating,
- switchEnabled = book.translateFrom != "auto",
- onSwitchClick = {
- onEvent(
- ReaderEvent.OnChangeTranslatorSettings(
- translateFrom = book.translateTo,
- translateTo = book.translateFrom
- )
- )
- }
- )
- }
-
- item {
- Spacer(modifier = Modifier.height(6.dp))
- }
-
- item {
- SwitchWithTitle(
- selected = book.doubleClickTranslation,
- title = stringResource(id = R.string.translator_double_click_to_translate_option),
- description = stringResource(id = R.string.translator_double_click_to_translate_option_desc),
- verticalPadding = 6.dp,
- onClick = {
- onEvent(
- ReaderEvent.OnChangeTranslatorSettings(
- doubleClickTranslation = !book.doubleClickTranslation
- )
- )
- }
- )
- }
-
- item {
- SwitchWithTitle(
- selected = book.translateWhenOpen,
- title = stringResource(id = R.string.translator_translate_on_start_option),
- description = stringResource(id = R.string.translator_translate_on_start_option_desc),
- verticalPadding = 6.dp,
- onClick = {
- onEvent(
- ReaderEvent.OnChangeTranslatorSettings(
- translateWhenOpen = !book.translateWhenOpen
- )
- )
- }
- )
- }
-
- item {
- Spacer(modifier = Modifier.height(48.dp))
- }
-
- item {
- Box(
- modifier = Modifier
- .fillMaxWidth()
- .padding(horizontal = 18.dp),
- contentAlignment = Alignment.CenterEnd
- ) {
- Button(
- modifier = Modifier.fillMaxWidth(1f),
- onClick = {
- if (loading.value) {
- return@Button
- }
-
- if (!state.value.isTranslating) {
- if (!textTranslated) {
- Toast.makeText(
- context,
- context.getString(R.string.translator_starting),
- Toast.LENGTH_SHORT
- ).show()
- onEvent(
- ReaderEvent.OnTranslateText(
- keys = null, /* means translating the whole text */
- error = {
- Toast.makeText(
- context,
- it.asString(context),
- Toast.LENGTH_LONG
- ).show()
- }
- )
- )
- } else {
- Toast.makeText(
- context,
- context.getString(R.string.translator_text_canceling),
- Toast.LENGTH_SHORT
- ).show()
- onEvent(
- ReaderEvent.OnUndoTranslation(
- null /* means canceling the whole text translation */
- )
- )
- }
- } else {
- Toast.makeText(
- context,
- context.getString(R.string.translator_canceling),
- Toast.LENGTH_SHORT
- ).show()
-
- loading.value = true
- onEvent(
- ReaderEvent.OnCancelTranslation
- )
- }
- },
- colors = ButtonDefaults.buttonColors(
- containerColor = if (state.value.isTranslating || textTranslated) {
- MaterialTheme.colorScheme.secondary
- } else {
- MaterialTheme.colorScheme.primary
- },
- contentColor = contentColorFor(
- if (state.value.isTranslating || textTranslated) {
- MaterialTheme.colorScheme.secondary
- } else {
- MaterialTheme.colorScheme.primary
- }
- )
- )
- ) {
- if (!state.value.isTranslating && !loading.value) {
- Text(
- text = if (textTranslated) stringResource(
- id = R.string.undo_translation
- ) else stringResource(id = R.string.translate)
- )
- } else {
- CircularProgressIndicator(
- color = LocalContentColor.current,
- strokeCap = StrokeCap.Round,
- modifier = Modifier.size(21.dp),
- strokeWidth = 2.3.dp
- )
- }
- }
- }
- }
-
- item {
- Spacer(
- modifier = Modifier.height(
- 8.dp + it
- )
- )
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/translator_bottom_sheet/ReaderTranslatorBottomSheetLanguageChooser.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/translator_bottom_sheet/ReaderTranslatorBottomSheetLanguageChooser.kt
deleted file mode 100644
index 192b2ac4..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/translator_bottom_sheet/ReaderTranslatorBottomSheetLanguageChooser.kt
+++ /dev/null
@@ -1,191 +0,0 @@
-package ua.acclorite.book_story.presentation.screens.reader.components.translator_bottom_sheet
-
-import androidx.compose.animation.core.tween
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.scaleOut
-import androidx.compose.animation.slideInHorizontally
-import androidx.compose.animation.slideOutHorizontally
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
-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.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.CompareArrows
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.yield
-import ua.acclorite.book_story.R
-import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
-import ua.acclorite.book_story.presentation.components.CustomIconButton
-
-/**
- * Reader Translator BottomSheet Language Chooser.
- *
- * @param fromLanguage Current translate from language.
- * @param toLanguage Current translate to language.
- * @param enabled Whether it is enabled.
- * @param switchEnabled Whether switch languages button is enabled.
- * @param horizontalPadding Horizontal item padding.
- * @param onFromClick OnFromClick callback.
- * @param onToClick OnToClick callback.
- * @param onSwitchClick OnSwitchClick callback.
- */
-@Composable
-fun ReaderTranslatorBottomSheetLanguageChooser(
- fromLanguage: String,
- toLanguage: String,
- enabled: Boolean = true,
- switchEnabled: Boolean = true,
- horizontalPadding: Dp = 18.dp,
- onFromClick: () -> Unit,
- onToClick: () -> Unit,
- onSwitchClick: () -> Unit
-) {
- val switchLanguage = remember { mutableStateOf(false) }
- val scope = rememberCoroutineScope()
- var job: Job? = null
-
- Row(
- Modifier
- .fillMaxWidth()
- .padding(horizontal = horizontalPadding),
- verticalAlignment = Alignment.CenterVertically
- ) {
- Box(modifier = Modifier.weight(1f)) {
- CustomLanguageSwitchingAnimation(
- visible = switchLanguage.value,
- rightPlacement = false
- ) {
- LanguageItem(text = fromLanguage, enabled = enabled) {
- onFromClick()
- }
- }
-
- CustomLanguageSwitchingAnimation(
- visible = !switchLanguage.value,
- rightPlacement = false
- ) {
- LanguageItem(text = fromLanguage, enabled = enabled) {
- onFromClick()
- }
- }
- }
-
-
-
- Spacer(modifier = Modifier.width(4.dp))
- CustomIconButton(
- icon = Icons.AutoMirrored.Filled.CompareArrows,
- contentDescription = R.string.translator_language_content_desc,
- disableOnClick = false,
- color = MaterialTheme.colorScheme.onSurfaceVariant,
- modifier = Modifier.size(24.dp),
- enabled = enabled && switchEnabled,
- onClick = {
- job?.cancel()
- job = scope.launch {
- switchLanguage.value = !switchLanguage.value
-
- delay(100)
- yield()
-
- onSwitchClick()
- }
- }
- )
- Spacer(modifier = Modifier.width(4.dp))
-
- Box(modifier = Modifier.weight(1f)) {
- CustomLanguageSwitchingAnimation(
- visible = switchLanguage.value,
- rightPlacement = true
- ) {
- LanguageItem(text = toLanguage, enabled = enabled) {
- onToClick()
- }
- }
-
- CustomLanguageSwitchingAnimation(
- visible = !switchLanguage.value,
- rightPlacement = true
- ) {
- LanguageItem(text = toLanguage, enabled = enabled) {
- onToClick()
- }
- }
- }
- }
-}
-
-@Composable
-private fun CustomLanguageSwitchingAnimation(
- visible: Boolean,
- rightPlacement: Boolean,
- content: @Composable () -> Unit
-) {
- val exitRightAnimation = remember {
- fadeOut(tween(200)) +
- slideOutHorizontally(tween(250)) { -it / 2 } +
- scaleOut(tween(250), 0.4f)
- }
- val enterRightAnimation = remember {
- slideInHorizontally(tween(350)) { -it / 2 } + fadeIn(tween(200))
- }
-
- val exitLeftAnimation = remember {
- fadeOut(tween(200)) +
- slideOutHorizontally(tween(250)) { it / 2 } +
- scaleOut(tween(250), 0.4f)
- }
- val enterLeftAnimation = remember {
- slideInHorizontally(tween(350)) { it / 2 } + fadeIn(tween(200))
- }
-
- CustomAnimatedVisibility(
- visible = visible,
- enter = if (rightPlacement) enterRightAnimation else enterLeftAnimation,
- exit = if (rightPlacement) exitRightAnimation else exitLeftAnimation
- ) {
- content()
- }
-}
-
-@Composable
-private fun LanguageItem(text: String, enabled: Boolean, onClick: () -> Unit) {
- Box(
- modifier = Modifier
- .fillMaxWidth()
- .clip(MaterialTheme.shapes.large)
- .background(MaterialTheme.colorScheme.surfaceContainerHigh, MaterialTheme.shapes.large)
- .clickable(enabled = enabled) {
- onClick()
- }
- .padding(horizontal = 4.dp, vertical = 14.dp),
- contentAlignment = Alignment.Center
- ) {
- Text(
- text = text,
- color = MaterialTheme.colorScheme.onSurface,
- style = MaterialTheme.typography.bodyMedium,
- maxLines = 1
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderEvent.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderEvent.kt
index e57586b7..9134a288 100644
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderEvent.kt
+++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderEvent.kt
@@ -4,10 +4,6 @@ import androidx.activity.ComponentActivity
import androidx.compose.foundation.pager.PagerState
import androidx.compose.runtime.Immutable
import ua.acclorite.book_story.domain.model.Book
-import ua.acclorite.book_story.domain.model.LineWithTranslation
-import ua.acclorite.book_story.domain.model.SelectableLanguage
-import ua.acclorite.book_story.domain.util.ID
-import ua.acclorite.book_story.domain.util.LanguageCode
import ua.acclorite.book_story.domain.util.OnNavigate
import ua.acclorite.book_story.domain.util.UIText
@@ -25,44 +21,6 @@ sealed class ReaderEvent {
val context: ComponentActivity
) : ReaderEvent()
- data class OnShowHideTranslatorBottomSheet(val show: Boolean? = null) : ReaderEvent()
-
- data class OnChangeTranslatorSettings(
- val enableTranslator: Boolean? = null,
- val translateFrom: String? = null,
- val translateTo: String? = null,
- val doubleClickTranslation: Boolean? = null,
- val translateWhenOpen: Boolean? = null
- ) : ReaderEvent()
-
- data class OnShowHideLanguageBottomSheet(
- val show: Boolean? = null,
- val translateFrom: Boolean? = null
- ) : ReaderEvent()
-
- data class OnTranslateText(
- val keys: Set?,
- val error: suspend (UIText) -> Unit
- ) : ReaderEvent()
-
- data object OnDismissDownloadLanguageDialog : ReaderEvent()
-
- data object OnCancelTranslation : ReaderEvent()
-
- data class OnUndoTranslation(val id: ID?) : ReaderEvent()
-
- data class OnDownloadLanguages(
- val onSuccess: suspend (Map) -> Unit,
- val error: suspend (UIText) -> Unit
- ) : ReaderEvent()
-
- data class OnSelectLanguage(val language: SelectableLanguage) : ReaderEvent()
-
- data class OnUpdateLanguage(
- val languageCode: LanguageCode,
- val calculation: (SelectableLanguage) -> SelectableLanguage
- ) : ReaderEvent()
-
data class OnGoBack(
val context: ComponentActivity,
val navigate: () -> Unit,
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderState.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderState.kt
index 75442a85..d290483f 100644
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderState.kt
+++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderState.kt
@@ -3,8 +3,7 @@ package ua.acclorite.book_story.presentation.screens.reader.data
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Immutable
import ua.acclorite.book_story.domain.model.Book
-import ua.acclorite.book_story.domain.model.LineWithTranslation
-import ua.acclorite.book_story.domain.model.SelectableLanguage
+import ua.acclorite.book_story.domain.model.ReaderLine
import ua.acclorite.book_story.domain.util.Constants
import ua.acclorite.book_story.domain.util.ID
import ua.acclorite.book_story.domain.util.UIText
@@ -12,25 +11,17 @@ import ua.acclorite.book_story.domain.util.UIText
@Immutable
data class ReaderState(
val book: Book = Constants.EMPTY_BOOK,
- val text: Map = emptyMap(),
+ val text: Map = emptyMap(),
val words: Int = 0,
val letters: Int = 0,
val listState: LazyListState = LazyListState(),
- val languagesToTranslate: List = emptyList(),
- val showDownloadLanguageDialog: Boolean = false,
- val isTranslating: Boolean = false,
-
val errorMessage: UIText? = null,
val loading: Boolean = true,
val showMenu: Boolean = false,
val lockMenu: Boolean = false,
- val showTranslatorBottomSheet: Boolean = false,
- val showLanguageBottomSheet: Boolean = false,
- val languageBottomSheetTranslateFrom: Boolean = false,
-
val showSettingsBottomSheet: Boolean = false,
val currentPage: Int = 0,
)
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderViewModel.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderViewModel.kt
index 5ac93746..99645f84 100644
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderViewModel.kt
+++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderViewModel.kt
@@ -13,10 +13,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.FlowPreview
-import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
-import kotlinx.coroutines.async
-import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -25,34 +22,18 @@ import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
-import kotlinx.coroutines.yield
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.Book
import ua.acclorite.book_story.domain.model.Category
-import ua.acclorite.book_story.domain.model.LineWithTranslation
-import ua.acclorite.book_story.domain.model.SelectableLanguage
-import ua.acclorite.book_story.domain.use_case.DeleteLanguageModel
-import ua.acclorite.book_story.domain.use_case.DownloadLanguageModel
import ua.acclorite.book_story.domain.use_case.GetBookById
import ua.acclorite.book_story.domain.use_case.GetLatestHistory
import ua.acclorite.book_story.domain.use_case.GetText
-import ua.acclorite.book_story.domain.use_case.IdentifyLanguage
-import ua.acclorite.book_story.domain.use_case.IsLanguageModelDownloaded
-import ua.acclorite.book_story.domain.use_case.TranslateText
import ua.acclorite.book_story.domain.use_case.UpdateBooks
-import ua.acclorite.book_story.domain.util.ID
-import ua.acclorite.book_story.domain.util.LanguageCode
import ua.acclorite.book_story.domain.util.OnNavigate
-import ua.acclorite.book_story.domain.util.Resource
import ua.acclorite.book_story.domain.util.UIText
import ua.acclorite.book_story.presentation.data.Screen
-import ua.acclorite.book_story.presentation.data.removeKey
-import ua.acclorite.book_story.presentation.data.removeKeys
-import ua.acclorite.book_story.presentation.data.update
-import ua.acclorite.book_story.presentation.data.updateWithCopy
import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
-import java.util.Locale
import javax.inject.Inject
import kotlin.math.roundToInt
@@ -62,12 +43,7 @@ class ReaderViewModel @Inject constructor(
private val updateBooks: UpdateBooks,
private val getText: GetText,
private val getLatestHistory: GetLatestHistory,
- private val getBookById: GetBookById,
- private val identifyLanguage: IdentifyLanguage,
- private val isLanguageModelDownloaded: IsLanguageModelDownloaded,
- private val downloadLanguageModel: DownloadLanguageModel,
- private val deleteLanguageModel: DeleteLanguageModel,
- private val translateText: TranslateText,
+ private val getBookById: GetBookById
) : ViewModel() {
private val _state = MutableStateFlow(ReaderState())
@@ -75,12 +51,6 @@ class ReaderViewModel @Inject constructor(
private var eventJob = SupervisorJob()
- private var dismissTranslatorJob: Job? = null
- private var cancelTranslationJob: Job? = null
- private var translatorJob: Job? = null
- private var undoTranslationJob: Job? = null
- private var downloadLanguageJob: Job? = null
-
fun onEvent(event: ReaderEvent) {
viewModelScope.launch(eventJob + Dispatchers.Main) {
when (event) {
@@ -102,7 +72,7 @@ class ReaderViewModel @Inject constructor(
}
val textAsLine = text
- .map { it.value.originalLine }
+ .map { it.value.line }
.joinToString(
separator = "\n"
)
@@ -181,17 +151,6 @@ class ReaderViewModel @Inject constructor(
)
}
- if (
- _state.value.book.translateWhenOpen &&
- _state.value.book.enableTranslator
- ) {
- onEvent(
- ReaderEvent.OnTranslateText(null) {
- event.onError(it)
- }
- )
- }
-
return@collectLatest
}
}
@@ -229,653 +188,6 @@ class ReaderViewModel @Inject constructor(
}
}
- is ReaderEvent.OnShowHideTranslatorBottomSheet -> {
- _state.update {
- it.copy(
- showTranslatorBottomSheet = event.show
- ?: !it.showTranslatorBottomSheet
- )
- }
- }
-
- is ReaderEvent.OnChangeTranslatorSettings -> {
- launch(Dispatchers.IO) {
- val book = _state.value.book
- val updatedBook = book.copy(
- enableTranslator = event.enableTranslator ?: book.enableTranslator,
- translateFrom = event.translateFrom ?: book.translateFrom,
- translateTo = event.translateTo ?: book.translateTo,
- doubleClickTranslation = event.doubleClickTranslation
- ?: book.doubleClickTranslation,
- translateWhenOpen = event.translateWhenOpen
- ?: book.translateWhenOpen
- )
-
- _state.update {
- it.copy(
- book = updatedBook
- )
- }
- updateBooks.execute(listOf(updatedBook))
- }
- }
-
- is ReaderEvent.OnShowHideLanguageBottomSheet -> {
- _state.update {
- it.copy(
- showLanguageBottomSheet = event.show ?: !it.showLanguageBottomSheet,
- languageBottomSheetTranslateFrom = event.translateFrom ?: false
- )
- }
- }
-
- is ReaderEvent.OnTranslateText -> {
- _state.update {
- it.copy(
- isTranslating = true
- )
- }
-
- launch {
- joinJobs()
-
- translatorJob = launch(Dispatchers.IO) {
- onEvent(
- ReaderEvent.OnChangeTranslatorSettings(
- enableTranslator = true
- )
- )
-
- val keys = event.keys ?: _state.value.text.keys
- var linesToTranslate = if (keys.size >= _state.value.text.size) {
- _state.value.text
- } else {
- _state.value.text.filterKeys { keys.any { key -> key == it } }
- }
-
- val languages = mutableMapOf?>()
-
- yield()
- linesToTranslate = linesToTranslate.updateWithCopy {
- it.copy(
- isTranslationLoading = true,
- isTranslationFailed = false,
- errorMessage = null,
- useTranslation = false
- )
- }
-
- yield()
- onUpdateTextLines(
- linesToTranslate,
- wholeText = linesToTranslate.size >= _state.value.text.size
- )
-
- yield()
- if (_state.value.book.translateFrom == "auto") {
- val identifiedLanguages =
- mutableListOf>()
- val errors = mutableMapOf()
-
- for (line in linesToTranslate.toMap()) {
- yield()
- val result =
- identifyLanguage.execute(line.value.originalLine)
-
- when (result) {
- is Resource.Success -> {
- identifiedLanguages.add(
- result.data!! to line.key
- )
- }
-
- is Resource.Error -> {
- errors[line.key] = line.value.copy(
- isTranslationFailed = true,
- isTranslationLoading = false,
- errorMessage = result.message
- )
- }
- }
- }
-
- yield()
- if (errors.isNotEmpty()) {
- onUpdateTextLines(
- errors,
- errors.size >= _state.value.text.size
- )
- linesToTranslate = linesToTranslate.removeKeys(errors.keys)
- }
-
- yield()
- languages.putAll(
- identifiedLanguages
- .groupBy {
- it.first
- }.mapValues { (_, value) ->
- value.map { it.second }
- }
- )
- } else {
- languages[_state.value.book.translateFrom] = emptyList()
- }
-
- yield()
- if (languages.isEmpty()) {
- _state.update {
- it.copy(
- isTranslating = false
- )
- }
-
- yield()
- launch(Dispatchers.Main) {
- event.error(UIText.StringResource(R.string.error_languages_not_identified))
- }
- return@launch
- }
-
- var shouldShowDialog = false
-
- if (languages.any { !isLanguageModelDownloaded.execute(it.key) }) {
- shouldShowDialog = true
- }
-
- if (!isLanguageModelDownloaded.execute(_state.value.book.translateTo)) {
- shouldShowDialog = true
- }
-
- yield()
- if (shouldShowDialog) {
- val languagesToDownload = mutableListOf()
-
- val translateToLocale = Locale(_state.value.book.translateTo)
- val translateToDisplayLanguage = translateToLocale
- .getDisplayLanguage(translateToLocale)
- .replaceFirstChar {
- it.uppercase()
- }
-
- val translateToCanceled =
- _state.value.languagesToTranslate.find {
- it.languageCode == _state.value.book.translateTo
- }?.isCanceled ?: false
-
- languagesToDownload.add(
- SelectableLanguage(
- languageCode = _state.value.book.translateTo,
- displayLanguage = translateToDisplayLanguage,
- isDownloading = false,
- isCanceled = translateToCanceled,
- isError = false,
- isDownloaded = isLanguageModelDownloaded.execute(_state.value.book.translateTo),
- isSelected = true,
- canUnselect = false,
- occurrences = languages[_state.value.book.translateTo]
- )
- )
- languagesToDownload.addAll(
- languages
- .filterNot { it.key == _state.value.book.translateTo }
- .toList()
- .sortedByDescending { it.second?.size }
- .mapIndexed { index, language ->
- val locale = Locale(language.first)
- val displayLanguage = locale
- .getDisplayLanguage(locale)
- .replaceFirstChar {
- it.uppercase()
- }
-
- val isCanceled =
- _state.value.languagesToTranslate.find {
- it.languageCode == language.first
- }?.isCanceled ?: false
-
- SelectableLanguage(
- languageCode = language.first,
- displayLanguage = displayLanguage,
- isDownloading = false,
- isCanceled = isCanceled,
- isDownloaded = isLanguageModelDownloaded.execute(
- language.first
- ),
- isError = false,
- isSelected = index == 0,
- canUnselect = index > 0,
- occurrences = language.second
- )
- }
- )
-
- yield()
- _state.update {
- it.copy(
- languagesToTranslate = languagesToDownload,
- showDownloadLanguageDialog = true
- )
- }
- return@launch
- }
-
- yield()
- for (i in 0.. result.data!!
- is Resource.Error -> continue
- }
- } else {
- _state.value.book.translateFrom
- }
- val targetLanguage = _state.value.book.translateTo
-
- yield()
- if (
- line.translatingFrom == sourceLanguage &&
- line.translatingTo == targetLanguage &&
- line.translatedLine != null
- ) {
- val translatedLine = line.copy(
- useTranslation = true,
- isTranslationFailed = false,
- isTranslationLoading = false,
- errorMessage = null
- )
-
- yield()
- _state.update {
- it.copy(
- text = it.text.update(
- closestLine to translatedLine
- )
- )
- }
- linesToTranslate = linesToTranslate.removeKey(closestLine)
- continue
- }
-
- var translation: String? = null
- var error: UIText? = null
-
- yield()
- val result = translateText.execute(
- sourceLanguage = sourceLanguage,
- targetLanguage = targetLanguage,
- text = line.originalLine
- )
-
- when (result) {
- is Resource.Success -> {
- translation = result.data
- }
-
- is Resource.Error -> {
- error = result.message
- }
- }
-
- val translatedLine = line.copy(
- useTranslation = translation != null,
- translatedLine = translation,
- translatingFrom = sourceLanguage,
- translatingTo = targetLanguage,
- isTranslationFailed = translation == null,
- isTranslationLoading = false,
- errorMessage = error
- )
-
- yield()
- _state.update {
- it.copy(
- text = it.text.update(
- closestLine to translatedLine
- )
- )
- }
- linesToTranslate = linesToTranslate.removeKey(closestLine)
- }
-
- yield()
- _state.update {
- it.copy(
- isTranslating = false
- )
- }
- }
- }
- }
-
- is ReaderEvent.OnDismissDownloadLanguageDialog -> {
- _state.update {
- it.copy(
- showDownloadLanguageDialog = false,
- isTranslating = false
- )
- }
-
- launch {
- joinJobs()
-
- dismissTranslatorJob = launch(Dispatchers.IO) {
- val languagesToDownload = _state.value.languagesToTranslate
-
- yield()
- _state.update {
- it.copy(
- languagesToTranslate = it.languagesToTranslate.map { lang ->
- lang.copy(
- isCanceled = true,
- isDownloading = false,
- isError = false
- )
- },
- showDownloadLanguageDialog = false
- )
- }
-
- yield()
-
- downloadLanguageJob?.cancel()
- val lines = getLinesFromLanguages(languagesToDownload)
- onUpdateTextLines(
- lines.updateWithCopy {
- it.copy(
- isTranslationLoading = false,
- useTranslation = false
- )
- },
- wholeText = lines.size >= _state.value.text.size
- )
- }
- }
- }
-
- is ReaderEvent.OnCancelTranslation -> {
- launch {
- cancelTranslationJob?.join()
- undoTranslationJob?.join()
- dismissTranslatorJob?.cancel()
- translatorJob?.cancel()
-
- cancelTranslationJob = launch(Dispatchers.IO) {
- _state.update {
- it.copy(
- isTranslating = false,
- showDownloadLanguageDialog = false
- )
- }
-
- yield()
- onUpdateTextLines(
- _state.value.text.updateWithCopy {
- if (it.useTranslation) {
- return@updateWithCopy it
- }
-
- it.copy(
- isTranslationLoading = false,
- useTranslation = false
- )
- },
- wholeText = true
- )
- }
- }
- }
-
- is ReaderEvent.OnUndoTranslation -> {
- launch {
- cancelTranslationJob?.join()
- undoTranslationJob?.join()
-
- cancelTranslationJob = launch(Dispatchers.IO) {
- yield()
-
- if (event.id != null) {
- _state.update {
- val line = it.text[event.id]?.copy(
- useTranslation = false,
- isTranslationLoading = false
- )
-
- if (line == null) {
- return@update it
- }
-
- it.copy(
- text = it.text.update(event.id to line)
- )
- }
- } else {
- _state.update {
- it.copy(
- text = it.text.updateWithCopy { line ->
- if (!line.useTranslation) {
- return@updateWithCopy line
- }
-
- line.copy(
- isTranslationLoading = false,
- useTranslation = false
- )
- }
- )
- }
- }
- }
- }
- }
-
- is ReaderEvent.OnDownloadLanguages -> {
- launch {
- downloadLanguageJob?.cancel()
-
- downloadLanguageJob = launch(Dispatchers.IO) {
- _state.update {
- it.copy(
- languagesToTranslate = it.languagesToTranslate.map { lang ->
- val isDownloaded = isLanguageModelDownloaded.execute(
- lang.languageCode
- )
-
- lang.copy(
- isDownloading = !isDownloaded && lang.isSelected,
- isCanceled = false,
- isDownloaded = isDownloaded
- )
- }
- )
- }
-
- val shouldDownload = _state.value.languagesToTranslate.filter {
- it.isSelected
- }.any {
- it.isDownloading
- }
-
- if (!shouldDownload) {
- _state.update {
- it.copy(
- languagesToTranslate = it.languagesToTranslate.filter { lang ->
- lang.isDownloaded
- },
- showDownloadLanguageDialog = false
- )
- }
-
- onUnselectLines()
- launch(Dispatchers.Main) {
- event.onSuccess(getLinesFromLanguages(_state.value.languagesToTranslate))
- }
- return@launch
- }
-
- val languagesToDownload = _state.value.languagesToTranslate.filter {
- it.isSelected
- }
- val jobs = languagesToDownload.map { lang ->
- async {
- downloadLanguageModel.execute(
- languageCode = lang.languageCode,
- onCompleted = {
- launch(Dispatchers.IO) {
- yield()
-
- val modelDownloaded =
- isLanguageModelDownloaded.execute(lang.languageCode)
- if (!modelDownloaded) {
- onEvent(
- ReaderEvent.OnUpdateLanguage(lang.languageCode) {
- it.copy(
- isError = true,
- isDownloading = false,
- isDownloaded = false,
- errorMessage = UIText.StringResource(
- R.string.error_could_not_download_language
- )
- )
- }
- )
- return@launch
- }
-
- onEvent(
- ReaderEvent.OnUpdateLanguage(lang.languageCode) {
- it.copy(
- isDownloading = false,
- isDownloaded = true
- )
- }
- )
-
- val isCanceled =
- _state.value.languagesToTranslate.find {
- it.languageCode == lang.languageCode
- }?.isCanceled ?: true
-
- if (isCanceled) {
- deleteLanguageModel.execute(
- languageCode = lang.languageCode
- )
- onEvent(
- ReaderEvent.OnUpdateLanguage(lang.languageCode) {
- it.copy(
- isDownloading = false,
- isDownloaded = false,
- isCanceled = false
- )
- }
- )
- return@launch
- }
- }
- },
- onFailure = { error ->
- onEvent(
- ReaderEvent.OnUpdateLanguage(lang.languageCode) {
- it.copy(
- isError = true,
- isDownloading = false,
- isDownloaded = false,
- errorMessage = UIText.StringResource(
- R.string.error_query,
- error.message ?: ""
- )
- )
- }
- )
- }
- )
- }
- }
- jobs.awaitAll()
-
- yield()
-
- _state.update {
- it.copy(
- languagesToTranslate = it.languagesToTranslate.filter { lang ->
- isLanguageModelDownloaded.execute(lang.languageCode)
- }.map { lang -> lang.copy(isDownloaded = true) },
- showDownloadLanguageDialog = false
- )
- }
-
- if (languagesToDownload.isEmpty()) {
- yield()
- launch(Dispatchers.Main) {
- event.error(
- UIText.StringResource(
- R.string.error_could_not_download_languages
- )
- )
- }
- onEvent(ReaderEvent.OnDismissDownloadLanguageDialog)
- return@launch
- }
-
- yield()
-
- onUnselectLines()
- launch(Dispatchers.Main) {
- event.onSuccess(getLinesFromLanguages(_state.value.languagesToTranslate))
- }
- }
- }
- }
-
- is ReaderEvent.OnSelectLanguage -> {
- launch(Dispatchers.IO) {
- val editedList = _state.value.languagesToTranslate.map {
- if (it.languageCode == event.language.languageCode) {
- it.copy(
- isSelected = !it.isSelected
- )
- } else {
- it
- }
- }
-
- _state.update {
- it.copy(
- languagesToTranslate = editedList
- )
- }
- }
- }
-
- is ReaderEvent.OnUpdateLanguage -> {
- launch(Dispatchers.IO) {
- val editedList = _state.value.languagesToTranslate.map {
- if (it.languageCode == event.languageCode) {
- event.calculation(it)
- } else {
- it
- }
- }
-
- _state.update {
- it.copy(
- languagesToTranslate = editedList
- )
- }
- }
- }
-
is ReaderEvent.OnGoBack -> {
launch {
_state.update {
@@ -1061,174 +373,6 @@ class ReaderViewModel @Inject constructor(
}
}
- private suspend fun joinJobs() {
- cancelTranslationJob?.join()
- translatorJob?.join()
- dismissTranslatorJob?.join()
- undoTranslationJob?.join()
- }
-
- private suspend fun findClosestLineToTranslate(
- translatingLines: Map
- ): ID? {
- val lines = translatingLines.toMutableMap()
- val visibleItems = _state.value.listState.layoutInfo.visibleItemsInfo
- val listStateIndex = (visibleItems.getOrNull(visibleItems.size / 2)?.index ?: 0) - 1
- .coerceAtLeast(0)
-
- var closestLineIndex: Int? = null
- var searchUpperLine = false
- var currentLineIndex = listStateIndex
- val invalidIndices = mutableListOf()
-
- while (true) {
- yield()
-
- if (lines.isEmpty()) {
- break
- }
-
- currentLineIndex = currentLineIndex.coerceIn(0..lines.maxOf { it.key })
-
- if (lines[currentLineIndex] == null) {
- invalidIndices.add(currentLineIndex)
-
- if (searchUpperLine) {
- val invalid = invalidIndices.filterNot {
- it >= currentLineIndex
- }
- var minus = 1
-
- while (true) {
- if (invalid.any { currentLineIndex - minus == it }) {
- minus++
- continue
- }
- break
- }
-
- currentLineIndex -= minus
- } else {
- val invalid = invalidIndices.filterNot {
- it <= currentLineIndex
- }
- var plus = 1
-
- while (true) {
- if (invalid.any { currentLineIndex + plus == it }) {
- plus++
- continue
- }
- break
- }
-
- currentLineIndex += plus
- }
- searchUpperLine = !searchUpperLine
- continue
- }
-
- if (
- lines[currentLineIndex]?.useTranslation == true ||
- lines[currentLineIndex]?.isTranslationFailed == true
- ) {
- invalidIndices.add(currentLineIndex)
- lines.remove(currentLineIndex)
-
- if (searchUpperLine) {
- val invalid = invalidIndices.filterNot {
- it >= currentLineIndex
- }
- var minus = 1
-
- while (true) {
- if (invalid.any { currentLineIndex - minus == it }) {
- minus++
- continue
- }
- break
- }
-
- currentLineIndex -= minus
- } else {
- val invalid = invalidIndices.filterNot {
- it <= currentLineIndex
- }
- var plus = 1
-
- while (true) {
- if (invalid.any { currentLineIndex + plus == it }) {
- plus++
- continue
- }
- break
- }
-
- currentLineIndex += plus
- }
- searchUpperLine = !searchUpperLine
- continue
- }
-
- closestLineIndex = currentLineIndex
- break
- }
-
- yield()
- return closestLineIndex
- }
-
- private suspend fun onUpdateTextLines(
- newLines: Map,
- wholeText: Boolean
- ) {
- val newText = if (wholeText) newLines
- else _state.value.text.update(newLines)
-
- yield()
- _state.update {
- it.copy(
- text = newText
- )
- }
- }
-
- private suspend fun onUnselectLines() {
- onUpdateTextLines(
- _state.value.text.updateWithCopy {
- it.copy(isTranslationLoading = false)
- },
- wholeText = true
- )
- }
-
- private suspend fun getLinesFromLanguages(
- languages: List
- ): Map {
- val lines = mutableMapOf()
-
- yield()
- for (language in languages) {
- yield()
-
- if (language.occurrences == null) {
- continue
- }
-
- if (language.occurrences.isEmpty()) {
- lines += _state.value.text
- break
- }
-
- lines += language.occurrences.associateWith {
- _state.value.text[it]!!
- }
- }
- yield()
-
- return lines
- }
-
fun init(
screen: Screen.Reader,
onNavigate: OnNavigate,
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/data/SettingsEvent.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/data/SettingsEvent.kt
index a32c8e28..c9bfa87f 100644
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/data/SettingsEvent.kt
+++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/data/SettingsEvent.kt
@@ -15,9 +15,4 @@ sealed class SettingsEvent {
val notificationsPermissionState: PermissionState,
val onChangeCheckForUpdates: (Boolean) -> Unit
) : SettingsEvent()
-
- data class OnReaderShowHideTranslatorLanguageBottomSheet(
- val show: Boolean? = null,
- val translateFrom: Boolean? = null
- ) : SettingsEvent()
}
\ No newline at end of file
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/data/SettingsState.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/data/SettingsState.kt
deleted file mode 100644
index 91c6fc42..00000000
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/data/SettingsState.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package ua.acclorite.book_story.presentation.screens.settings.data
-
-import androidx.compose.runtime.Immutable
-
-@Immutable
-data class SettingsState(
- val showReaderTranslatorLanguageBottomSheet: Boolean = false,
- val readerTranslatorLanguageBottomSheetTranslateFrom: Boolean = false,
-)
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/data/SettingsViewModel.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/data/SettingsViewModel.kt
index 7c44c99c..58e802dd 100644
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/data/SettingsViewModel.kt
+++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/data/SettingsViewModel.kt
@@ -11,9 +11,6 @@ import com.google.accompanist.permissions.shouldShowRationale
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
import javax.inject.Inject
@@ -24,9 +21,6 @@ class SettingsViewModel @Inject constructor(
) : ViewModel() {
- private val _state = MutableStateFlow(SettingsState())
- val state = _state.asStateFlow()
-
private var notificationsPermissionJob: Job? = null
fun onEvent(event: SettingsEvent) {
@@ -77,17 +71,6 @@ class SettingsViewModel @Inject constructor(
}
}
}
-
- is SettingsEvent.OnReaderShowHideTranslatorLanguageBottomSheet -> {
- _state.update {
- it.copy(
- showReaderTranslatorLanguageBottomSheet = event.show
- ?: !it.showReaderTranslatorLanguageBottomSheet,
- readerTranslatorLanguageBottomSheetTranslateFrom = event.translateFrom
- ?: false
- )
- }
- }
}
}
}
diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/ReaderSettings.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/ReaderSettings.kt
index 28a1e068..9faadb65 100644
--- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/ReaderSettings.kt
+++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/ReaderSettings.kt
@@ -20,7 +20,6 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
-import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.unit.dp
@@ -32,35 +31,25 @@ import ua.acclorite.book_story.domain.util.OnNavigate
import ua.acclorite.book_story.presentation.components.CategoryTitle
import ua.acclorite.book_story.presentation.components.GoBackButton
import ua.acclorite.book_story.presentation.components.collapsibleUntilExitScrollBehaviorWithLazyListState
-import ua.acclorite.book_story.presentation.components.translator_language.TranslatorLanguageBottomSheet
import ua.acclorite.book_story.presentation.data.LocalNavigator
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.data.MainViewModel
-import ua.acclorite.book_story.presentation.screens.reader.components.translator_bottom_sheet.ReaderTranslatorBottomSheetLanguageChooser
import ua.acclorite.book_story.presentation.screens.settings.components.ChipsWithTitle
import ua.acclorite.book_story.presentation.screens.settings.components.SliderWithTitle
import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle
-import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
-import ua.acclorite.book_story.presentation.screens.settings.data.SettingsState
-import ua.acclorite.book_story.presentation.screens.settings.data.SettingsViewModel
-import java.util.Locale
@Composable
fun ReaderSettingsRoot() {
val navigator = LocalNavigator.current
val mainViewModel: MainViewModel = hiltViewModel()
- val settingsViewModel: SettingsViewModel = hiltViewModel()
val state = mainViewModel.state.collectAsState()
- val settingsState = settingsViewModel.state.collectAsState()
ReaderSettings(
state = state,
- settingsState = settingsState,
onNavigate = { navigator.it() },
- onMainEvent = mainViewModel::onEvent,
- onEvent = settingsViewModel::onEvent
+ onMainEvent = mainViewModel::onEvent
)
}
@@ -68,70 +57,16 @@ fun ReaderSettingsRoot() {
@Composable
private fun ReaderSettings(
state: State,
- settingsState: State,
onNavigate: OnNavigate,
- onMainEvent: (MainEvent) -> Unit,
- onEvent: (SettingsEvent) -> Unit
+ onMainEvent: (MainEvent) -> Unit
) {
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
- val context = LocalContext.current
val fontFamily = remember(state.value.fontFamily) {
Constants.FONTS.find {
it.id == state.value.fontFamily
} ?: Constants.FONTS[0]
}
- val translateFrom = remember(state.value.translateFrom) {
- if (state.value.translateFrom!! == "auto") {
- return@remember context.getString(R.string.translator_auto_short)
- }
-
- val locale = Locale(state.value.translateFrom!!)
- locale.getDisplayName(locale).replaceFirstChar { char ->
- char.uppercase()
- }
- }
- val translateTo = remember(state.value.translateTo) {
- val locale = Locale(state.value.translateTo!!)
- locale.getDisplayName(locale).replaceFirstChar { char ->
- char.uppercase()
- }
- }
-
- if (settingsState.value.showReaderTranslatorLanguageBottomSheet) {
- TranslatorLanguageBottomSheet(
- selectedLanguage = if (
- settingsState.value.readerTranslatorLanguageBottomSheetTranslateFrom
- ) {
- state.value.translateFrom!!
- } else state.value.translateTo!!,
-
- unselectedLanguage = if (
- !settingsState.value.readerTranslatorLanguageBottomSheetTranslateFrom
- ) {
- state.value.translateFrom!!
- } else state.value.translateTo!!,
-
- translateFromSelecting = settingsState.value.readerTranslatorLanguageBottomSheetTranslateFrom,
- onSelect = { from, to ->
- onMainEvent(MainEvent.OnChangeTranslateFrom(from))
- onMainEvent(MainEvent.OnChangeTranslateTo(to))
-
- onEvent(
- SettingsEvent.OnReaderShowHideTranslatorLanguageBottomSheet(
- show = false
- )
- )
- },
- onDismiss = {
- onEvent(
- SettingsEvent.OnReaderShowHideTranslatorLanguageBottomSheet(
- show = false
- )
- )
- }
- )
- }
Scaffold(
Modifier
@@ -164,91 +99,6 @@ private fun ReaderSettings(
item {
Spacer(modifier = Modifier.height(16.dp))
}
- item {
- CategoryTitle(
- title = stringResource(id = R.string.translator_reader_settings),
- color = MaterialTheme.colorScheme.primary
- )
- }
- item {
- Spacer(modifier = Modifier.height(8.dp))
- }
-
- item {
- SwitchWithTitle(
- selected = state.value.enableTranslator!!,
- title = stringResource(id = R.string.translator_enable_default_option),
- description = stringResource(id = R.string.translator_enable_default_option_desc),
- onClick = {
- onMainEvent(
- MainEvent.OnChangeEnableTranslator(
- !state.value.enableTranslator!!
- )
- )
- }
- )
- }
-
- item {
- Spacer(modifier = Modifier.height(8.dp))
-
- CategoryTitle(
- title = stringResource(id = R.string.translator_language_option)
- )
-
- Spacer(modifier = Modifier.height(8.dp))
-
- ReaderTranslatorBottomSheetLanguageChooser(
- fromLanguage = translateFrom,
- toLanguage = translateTo,
- onFromClick = {
- onEvent(
- SettingsEvent.OnReaderShowHideTranslatorLanguageBottomSheet(
- show = true,
- translateFrom = true
- )
- )
- },
- onToClick = {
- onEvent(
- SettingsEvent.OnReaderShowHideTranslatorLanguageBottomSheet(
- show = true,
- translateFrom = false
- )
- )
- },
- switchEnabled = state.value.translateFrom != "auto",
- onSwitchClick = {
- val from = state.value.translateFrom!!
- val to = state.value.translateTo!!
-
- onMainEvent(MainEvent.OnChangeTranslateFrom(to))
- onMainEvent(MainEvent.OnChangeTranslateTo(from))
- }
- )
-
- Spacer(modifier = Modifier.height(8.dp))
- }
-
-
- item {
- SwitchWithTitle(
- selected = state.value.doubleClickTranslation!!,
- title = stringResource(id = R.string.translator_double_click_to_translate_option),
- description = stringResource(id = R.string.translator_double_click_to_translate_option_desc),
- onClick = {
- onMainEvent(
- MainEvent.OnChangeDoubleClickTranslation(
- !state.value.doubleClickTranslation!!
- )
- )
- }
- )
- }
-
- item {
- Spacer(modifier = Modifier.height(22.dp))
- }
item {
CategoryTitle(
title = stringResource(id = R.string.font_reader_settings),
diff --git a/app/src/main/res/drawable/empty_languages.png b/app/src/main/res/drawable/empty_languages.png
deleted file mode 100644
index fadacf56..00000000
Binary files a/app/src/main/res/drawable/empty_languages.png and /dev/null differ
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 2f752898..70fee74e 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -36,8 +36,6 @@
Перемістити книгу?
Видалити історію читання?
Підтвердити оновлення?
- Завантажити %1$s?
- Завантажити мови?
@@ -79,17 +77,6 @@
Натиснувши на кнопку «Завантажити», ви перейдете в ваш браузер
та завантажете останнє оновлення автоматично.
-
- Вам потрібно завантажити цю мову перед використанням.
- Після завантаження, вона буде доступна офлайн та не потребуватиме інтернету.
- Кожна мова має розмір близько ~30мб, для завантаження рекомендується використовувати Wi-Fi.
-
-
- Вам потрібно завантажити ці мови перед використанням.
- Кожна мова має розмір близько ~30мб, для завантаження рекомендується використовувати Wi-Fi.
- Ви можете вибрати мови, які ви хочете завантажити,
- всі не вибрані мови не будуть перекладені.
-
@@ -116,12 +103,6 @@
Щось пішло не так.
Спробуйте пізніше.
- Мова не була ідентифікована.
- Не вдалося ідентифікувати жодної мови.
- Неможливо вибрати ту саму мову двічі.
- Не можна вибрати цю мову.
- Не вдалося завантажити мову.
- Не вдалося завантажити мови.
Не вдалося скинути обкладинку.
Закритий код
@@ -136,9 +117,6 @@
Нехай ваша остання прочитана книга відкриє перед
вами сторінки нової великої історії вашого читацького шляху
-
- Не існує мови з такою назвою, або вона не підтримується
-
%1$s обрано
@@ -173,14 +151,11 @@
Ні
Завантажити
Готово
- Відмінити
- Далі
файли
книги
історію
- мови
Невідомий
@@ -194,8 +169,6 @@
Видалити обкладинку
Видаліть нинішню обкладинку книги
Автор
- Опис
- Текст
Читаю
@@ -237,13 +210,8 @@
Перевіряти на оновлення
Перевіряти на новішу версію застосунку при запуску
Бокові відступи
- Мова перекладача
- Увімкнути перекладач
- Увімкнути перекладач при додаванні книги за замовчуванням
Переклад подвійним кліком
Двічі клацніть на абзац, щоб перекласти його
- Перекладати при відкритті книги
- Автоматично перекладати весь текст при відкритті книги
Червоний
@@ -291,11 +259,6 @@
Скопійовано
Історія була успішно видалена.
Остання версія застосунка вже встановлена.
- Мова була успішно завантажена та вибрана.
- Всі необхідні мови завантажені. Переклад почнеться незабаром.
- Переклад відміняється. Будь ласка, зачекайте.
- Перекладений текст відміняється. Будь ласка, зачекайте.
- Переклад скоро почнеться. Будь ласка, зачекайте.
Обкладинка була успішно скинута.
@@ -325,17 +288,6 @@
%1$s букв(а), %2$s слів.
-
- Визначити мову
- Визначити
- Перекласти %1$s
- з
- на
- Всі мови
- Недавні мови
- %1$s абзац(ів)
- Показати оригінал (%1$s на %2$s)
-
Версія застосунка
Book\'s Story v%1$s
@@ -577,8 +529,5 @@
Скинути початковий посібник
Вийти з режиму редагування
Відкрити в браузері
- Перекладач
- Поміняти мови місцями
- Завантажено
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 24880cb2..f2a609da 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -55,8 +55,6 @@
Move book?
Delete reading history?
Confirm update?
- Download %1$s?
- Download languages?
@@ -98,17 +96,6 @@
By clicking the «Download» button you will be transferred
to your browser and download the latest update automatically.
-
- You need to download this language before using it.
- After downloading, it will be available offline and will not require internet.
- Each language is about ~30mb in size, it is recommended to use Wi-Fi to download it.
-
-
- You need to download these languages before.
- Each language is about ~30mb in size, it is recommended to use Wi-Fi to download it.
- You can select which languages you want to download,
- all unselected languages will not be translated.
-
@@ -135,12 +122,6 @@
Something went wrong.
Try again later.
- Could not identify language.
- Could not identify any languages.
- Cannot select same language twice.
- Cannot select this language.
- Could not download language.
- Could not download languages.
Could not reset cover image.
Closed source
@@ -154,9 +135,6 @@
Let your last book you read open the pages of a new great story of your reading journey
-
- There is no such language with this name, or it is not supported
-
%1$s selected
@@ -191,14 +169,11 @@
No
Download
Done
- Undo
- Continue
files
books
history
- languages
Unknown
@@ -212,8 +187,6 @@
Delete cover image
Delete current cover image of the book
Author
- Description
- Text
Reading
@@ -255,13 +228,8 @@
Check for updates
Check for newer app version on startup
Side padding
- Translator language
- Enable translator
- Enable translator when adding a book by default
Double click translation
Double click on paragraph to translate it
- Translate when open a book
- Automatically translate the whole text when open a book
Red
@@ -309,13 +277,6 @@
Copied
History was successfully deleted.
The latest version of the app is already installed.
- Language was successfully downloaded and selected.
-
- All required languages are downloaded. Translation will start soon.
-
- Translation is canceling. Please wait.
- Translated text is canceling. Please wait.
- Translation will start soon. Please wait.
Cover image was successfully reset.
@@ -345,17 +306,6 @@
%1$s characters, %2$s words.
-
- Detect language
- Detect
- Translate %1$s
- from
- to
- All languages
- Recent languages
- %1$s paragraph(s)
- Show original (%1$s to %2$s)
-
App version
Book\'s Story v%1$s
@@ -598,8 +548,5 @@
Reset start guide
Exit editing mode
Open in web
- Translator
- Change language places
- Downloaded
\ No newline at end of file