🚀 Add and Improve Parsers
Added new supported file extensions: ".zip", ".html" and ".htm". Improved parsers: ".epub". Partly Resolves(no ".cbz"): #48
This commit is contained in:
parent
5e2cc28c92
commit
e1fdac0f39
13 changed files with 987 additions and 536 deletions
|
|
@ -2,8 +2,11 @@ package ua.acclorite.book_story.data.parser
|
|||
|
||||
import ua.acclorite.book_story.data.parser.epub.EpubFileParser
|
||||
import ua.acclorite.book_story.data.parser.fb2.Fb2FileParser
|
||||
import ua.acclorite.book_story.data.parser.htm.HtmFileParser
|
||||
import ua.acclorite.book_story.data.parser.html.HtmlFileParser
|
||||
import ua.acclorite.book_story.data.parser.pdf.PdfFileParser
|
||||
import ua.acclorite.book_story.data.parser.txt.TxtFileParser
|
||||
import ua.acclorite.book_story.data.parser.zip.ZipFileParser
|
||||
import ua.acclorite.book_story.domain.model.Book
|
||||
import ua.acclorite.book_story.domain.util.CoverImage
|
||||
import java.io.File
|
||||
|
|
@ -13,32 +16,48 @@ class FileParserImpl @Inject constructor(
|
|||
private val txtFileParser: TxtFileParser,
|
||||
private val pdfFileParser: PdfFileParser,
|
||||
private val epubFileParser: EpubFileParser,
|
||||
private val fb2FileParser: Fb2FileParser
|
||||
private val fb2FileParser: Fb2FileParser,
|
||||
private val zipFileParser: ZipFileParser,
|
||||
private val htmlFileParser: HtmlFileParser,
|
||||
private val htmFileParser: HtmFileParser,
|
||||
) : FileParser {
|
||||
override suspend fun parse(file: File): Pair<Book, CoverImage?>? {
|
||||
if (!file.exists()) {
|
||||
return null
|
||||
}
|
||||
|
||||
val fileFormat = ".${file.name.substringAfterLast(".")}".lowercase().trim()
|
||||
val fileFormat = ".${file.extension}".lowercase().trim()
|
||||
return when (fileFormat) {
|
||||
".pdf" -> {
|
||||
pdfFileParser.parse(file)
|
||||
}
|
||||
|
||||
if (fileFormat == ".pdf") {
|
||||
return pdfFileParser.parse(file)
|
||||
".epub" -> {
|
||||
epubFileParser.parse(file)
|
||||
}
|
||||
|
||||
".txt" -> {
|
||||
txtFileParser.parse(file)
|
||||
}
|
||||
|
||||
".fb2" -> {
|
||||
fb2FileParser.parse(file)
|
||||
}
|
||||
|
||||
".zip" -> {
|
||||
zipFileParser.parse(file)
|
||||
}
|
||||
|
||||
".html" -> {
|
||||
htmlFileParser.parse(file)
|
||||
}
|
||||
|
||||
".htm" -> {
|
||||
htmFileParser.parse(file)
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (fileFormat == ".epub") {
|
||||
return epubFileParser.parse(file)
|
||||
}
|
||||
|
||||
if (fileFormat == ".txt") {
|
||||
return txtFileParser.parse(file)
|
||||
}
|
||||
|
||||
if (fileFormat == ".fb2") {
|
||||
return fb2FileParser.parse(file)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package ua.acclorite.book_story.data.parser
|
||||
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.data.parser.epub.EpubTextParser
|
||||
import ua.acclorite.book_story.data.parser.fb2.Fb2TextParser
|
||||
import ua.acclorite.book_story.data.parser.htm.HtmTextParser
|
||||
import ua.acclorite.book_story.data.parser.html.HtmlTextParser
|
||||
import ua.acclorite.book_story.data.parser.pdf.PdfTextParser
|
||||
import ua.acclorite.book_story.data.parser.txt.TxtTextParser
|
||||
import ua.acclorite.book_story.data.parser.zip.ZipTextParser
|
||||
import ua.acclorite.book_story.domain.util.Resource
|
||||
import ua.acclorite.book_story.domain.util.UIText
|
||||
import java.io.File
|
||||
|
|
@ -13,8 +15,11 @@ import javax.inject.Inject
|
|||
class TextParserImpl @Inject constructor(
|
||||
private val txtTextParser: TxtTextParser,
|
||||
private val pdfTextParser: PdfTextParser,
|
||||
private val epubTextParser: EpubTextParser,
|
||||
private val fb2TextParser: Fb2TextParser
|
||||
private val epubTextParser: HtmlTextParser,
|
||||
private val fb2TextParser: Fb2TextParser,
|
||||
private val zipTextParser: ZipTextParser,
|
||||
private val htmlTextParser: HtmlTextParser,
|
||||
private val htmTextParser: HtmTextParser,
|
||||
) : TextParser {
|
||||
override suspend fun parse(file: File): Resource<List<String>> {
|
||||
if (!file.exists()) {
|
||||
|
|
@ -23,25 +28,38 @@ class TextParserImpl @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
val fileFormat = ".${file.name.substringAfterLast(".")}".lowercase().trim()
|
||||
val fileFormat = ".${file.extension}".lowercase().trim()
|
||||
return when (fileFormat) {
|
||||
".pdf" -> {
|
||||
pdfTextParser.parse(file)
|
||||
}
|
||||
|
||||
if (fileFormat == ".pdf") {
|
||||
return pdfTextParser.parse(file)
|
||||
".epub" -> {
|
||||
epubTextParser.parse(file)
|
||||
}
|
||||
|
||||
".txt" -> {
|
||||
txtTextParser.parse(file)
|
||||
}
|
||||
|
||||
".fb2" -> {
|
||||
fb2TextParser.parse(file)
|
||||
}
|
||||
|
||||
".zip" -> {
|
||||
zipTextParser.parse(file)
|
||||
}
|
||||
|
||||
".html" -> {
|
||||
htmlTextParser.parse(file)
|
||||
}
|
||||
|
||||
".htm" -> {
|
||||
htmTextParser.parse(file)
|
||||
}
|
||||
|
||||
else -> Resource.Error(UIText.StringResource(R.string.error_wrong_file_format))
|
||||
}
|
||||
|
||||
if (fileFormat == ".epub") {
|
||||
return epubTextParser.parse(file)
|
||||
}
|
||||
|
||||
if (fileFormat == ".txt") {
|
||||
return txtTextParser.parse(file)
|
||||
}
|
||||
|
||||
if (fileFormat == ".fb2") {
|
||||
return fb2TextParser.parse(file)
|
||||
}
|
||||
|
||||
return Resource.Error(UIText.StringResource(R.string.error_wrong_file_format))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import android.graphics.BitmapFactory
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jsoup.Jsoup
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.data.parser.FileParser
|
||||
import ua.acclorite.book_story.domain.model.Book
|
||||
import ua.acclorite.book_story.domain.model.Category
|
||||
|
|
@ -36,30 +37,43 @@ class EpubFileParser @Inject constructor() : FileParser {
|
|||
.use { it.readText() }
|
||||
val document = Jsoup.parse(opfContent)
|
||||
|
||||
val title = document.select("metadata > dc|title").text().trim()
|
||||
val author = UIText.StringValue(
|
||||
document.select("metadata > dc|creator").text().trim()
|
||||
)
|
||||
val title = document.select("metadata > dc|title").text().trim().run {
|
||||
ifBlank {
|
||||
file.nameWithoutExtension.trim()
|
||||
}
|
||||
}
|
||||
|
||||
val author = document.select("metadata > dc|creator").text().trim().run {
|
||||
if (isBlank()) {
|
||||
UIText.StringResource(R.string.unknown_author)
|
||||
} else {
|
||||
UIText.StringValue(this)
|
||||
}
|
||||
}
|
||||
|
||||
val description = Jsoup.parse(
|
||||
document.select("metadata > dc|description").text()
|
||||
).text()
|
||||
).text().run {
|
||||
ifBlank {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
var coverImagePath: String? = null
|
||||
|
||||
val coverId = document
|
||||
val coverImage = document
|
||||
.select("metadata > meta[name=cover]")
|
||||
.attr("content")
|
||||
if (coverId.isNotBlank()) {
|
||||
coverImagePath = document
|
||||
.select("manifest > item[id=$coverId]")
|
||||
.attr("href")
|
||||
}
|
||||
.run {
|
||||
if (isNotBlank()) {
|
||||
document
|
||||
.select("manifest > item[id=$this]")
|
||||
.attr("href")
|
||||
.apply { if (isNotBlank()) return@run this }
|
||||
}
|
||||
|
||||
if (coverImagePath.isNullOrBlank()) {
|
||||
coverImagePath = document
|
||||
.select("manifest > item[media-type*=image]")
|
||||
.firstOrNull()?.attr("href")
|
||||
}
|
||||
document
|
||||
.select("manifest > item[media-type*=image]")
|
||||
.firstOrNull()?.attr("href")
|
||||
}
|
||||
|
||||
book = Book(
|
||||
title = title,
|
||||
|
|
@ -73,7 +87,7 @@ class EpubFileParser @Inject constructor() : FileParser {
|
|||
lastOpened = null,
|
||||
category = Category.entries[0],
|
||||
coverImage = null
|
||||
) to extractCoverImageBitmap(file, coverImagePath)
|
||||
) to extractCoverImageBitmap(file, coverImage)
|
||||
}
|
||||
}
|
||||
return book
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class Fb2FileParser @Inject constructor() : FileParser {
|
|||
}
|
||||
|
||||
val titleFromFile = extractElementContent(document, "book-title")
|
||||
val title = titleFromFile ?: file.name.dropLast(4).trim()
|
||||
val title = titleFromFile ?: file.nameWithoutExtension.trim()
|
||||
|
||||
val authorFirstName = extractElementContent(document, "first-name")
|
||||
val authorLastName = extractElementContent(document, "last-name")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
package ua.acclorite.book_story.data.parser.htm
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.data.parser.FileParser
|
||||
import ua.acclorite.book_story.domain.model.Book
|
||||
import ua.acclorite.book_story.domain.model.Category
|
||||
import ua.acclorite.book_story.domain.util.CoverImage
|
||||
import ua.acclorite.book_story.domain.util.UIText
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
class HtmFileParser @Inject constructor() : FileParser {
|
||||
|
||||
override suspend fun parse(file: File): Pair<Book, CoverImage?>? {
|
||||
if (!file.name.endsWith(".htm", true) || !file.exists()) {
|
||||
return null
|
||||
}
|
||||
|
||||
try {
|
||||
val document = Jsoup.parse(file)
|
||||
|
||||
val title = document.select("head > title").text().trim().run {
|
||||
ifBlank {
|
||||
file.nameWithoutExtension.trim()
|
||||
}
|
||||
}
|
||||
|
||||
return Book(
|
||||
title = title,
|
||||
author = UIText.StringResource(R.string.unknown_author),
|
||||
description = null,
|
||||
textPath = "",
|
||||
scrollIndex = 0,
|
||||
scrollOffset = 0,
|
||||
progress = 0f,
|
||||
filePath = file.path,
|
||||
lastOpened = null,
|
||||
category = Category.entries[0],
|
||||
coverImage = null
|
||||
) to null
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package ua.acclorite.book_story.data.parser.htm
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.data.parser.TextParser
|
||||
import ua.acclorite.book_story.domain.util.Resource
|
||||
import ua.acclorite.book_story.domain.util.UIText
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class HtmTextParser @Inject constructor() : TextParser {
|
||||
|
||||
override suspend fun parse(file: File): Resource<List<String>> {
|
||||
if (!file.name.endsWith(".htm", true) || !file.exists()) {
|
||||
return Resource.Error(UIText.StringResource(R.string.error_wrong_file_format))
|
||||
}
|
||||
|
||||
try {
|
||||
val lines = mutableListOf<String>()
|
||||
|
||||
val document = Jsoup.parse(file)
|
||||
document.select("p").append("\n")
|
||||
document
|
||||
.wholeText()
|
||||
.lines()
|
||||
.forEach { line ->
|
||||
if (line.isNotBlank()) {
|
||||
lines.add(line.trim())
|
||||
}
|
||||
}
|
||||
|
||||
if (lines.isEmpty()) {
|
||||
return Resource.Error(UIText.StringResource(R.string.error_file_empty))
|
||||
}
|
||||
|
||||
return Resource.Success(lines)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return Resource.Error(
|
||||
UIText.StringResource(
|
||||
R.string.error_query,
|
||||
e.message?.take(40)?.trim() ?: ""
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package ua.acclorite.book_story.data.parser.html
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.data.parser.FileParser
|
||||
import ua.acclorite.book_story.domain.model.Book
|
||||
import ua.acclorite.book_story.domain.model.Category
|
||||
import ua.acclorite.book_story.domain.util.CoverImage
|
||||
import ua.acclorite.book_story.domain.util.UIText
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
class HtmlFileParser @Inject constructor() : FileParser {
|
||||
|
||||
override suspend fun parse(file: File): Pair<Book, CoverImage?>? {
|
||||
if (!file.name.endsWith(".html", true) || !file.exists()) {
|
||||
return null
|
||||
}
|
||||
|
||||
try {
|
||||
val document = Jsoup.parse(file)
|
||||
|
||||
val title = document.select("head > title").text().trim().run {
|
||||
ifBlank {
|
||||
file.nameWithoutExtension.trim()
|
||||
}
|
||||
}
|
||||
|
||||
return Book(
|
||||
title = title,
|
||||
author = UIText.StringResource(R.string.unknown_author),
|
||||
description = null,
|
||||
textPath = "",
|
||||
scrollIndex = 0,
|
||||
scrollOffset = 0,
|
||||
progress = 0f,
|
||||
filePath = file.path,
|
||||
lastOpened = null,
|
||||
category = Category.entries[0],
|
||||
coverImage = null
|
||||
) to null
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package ua.acclorite.book_story.data.parser.html
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.data.parser.TextParser
|
||||
import ua.acclorite.book_story.domain.util.Resource
|
||||
import ua.acclorite.book_story.domain.util.UIText
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class HtmlTextParser @Inject constructor() : TextParser {
|
||||
|
||||
override suspend fun parse(file: File): Resource<List<String>> {
|
||||
if (!file.name.endsWith(".html", true) || !file.exists()) {
|
||||
return Resource.Error(UIText.StringResource(R.string.error_wrong_file_format))
|
||||
}
|
||||
|
||||
try {
|
||||
val lines = mutableListOf<String>()
|
||||
|
||||
val document = Jsoup.parse(file)
|
||||
document.select("p").append("\n")
|
||||
document
|
||||
.wholeText()
|
||||
.lines()
|
||||
.forEach { line ->
|
||||
if (line.isNotBlank()) {
|
||||
lines.add(line.trim())
|
||||
}
|
||||
}
|
||||
|
||||
if (lines.isEmpty()) {
|
||||
return Resource.Error(UIText.StringResource(R.string.error_file_empty))
|
||||
}
|
||||
|
||||
return Resource.Success(lines)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return Resource.Error(
|
||||
UIText.StringResource(
|
||||
R.string.error_query,
|
||||
e.message?.take(40)?.trim() ?: ""
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,10 +24,11 @@ class PdfFileParser @Inject constructor(private val application: Application) :
|
|||
|
||||
val document = PDDocument.load(file)
|
||||
|
||||
val title = document.documentInformation.title ?: file.name.dropLast(4).trim()
|
||||
val fileAuthor = document.documentInformation.author
|
||||
val author = if (fileAuthor != null) UIText.StringValue(fileAuthor)
|
||||
else UIText.StringResource(R.string.unknown_author)
|
||||
val title = document.documentInformation.title ?: file.nameWithoutExtension.trim()
|
||||
val author = document.documentInformation.author.run {
|
||||
if (isNullOrBlank()) UIText.StringResource(R.string.unknown_author)
|
||||
else UIText.StringValue(this)
|
||||
}
|
||||
val description = document.documentInformation.subject ?: null
|
||||
|
||||
document.close()
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class TxtFileParser @Inject constructor() : FileParser {
|
|||
}
|
||||
|
||||
try {
|
||||
val title = file.name.trim().dropLast(4)
|
||||
val title = file.nameWithoutExtension.trim()
|
||||
val author = UIText.StringResource(R.string.unknown_author)
|
||||
|
||||
return Book(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
package ua.acclorite.book_story.data.parser.zip
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jsoup.Jsoup
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.data.parser.FileParser
|
||||
import ua.acclorite.book_story.domain.model.Book
|
||||
import ua.acclorite.book_story.domain.model.Category
|
||||
import ua.acclorite.book_story.domain.util.CoverImage
|
||||
import ua.acclorite.book_story.domain.util.UIText
|
||||
import java.io.File
|
||||
import java.util.zip.ZipFile
|
||||
import javax.inject.Inject
|
||||
|
||||
class ZipFileParser @Inject constructor() : FileParser {
|
||||
|
||||
override suspend fun parse(file: File): Pair<Book, CoverImage?>? {
|
||||
if (!file.name.endsWith(".zip", true) || !file.exists()) {
|
||||
return null
|
||||
}
|
||||
|
||||
try {
|
||||
var book: Pair<Book, CoverImage?>? = null
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
ZipFile(file).use { zip ->
|
||||
val opfEntry = zip.entries().asSequence().find { entry ->
|
||||
entry.name.endsWith(".opf")
|
||||
} ?: return@withContext
|
||||
|
||||
val opfContent = zip
|
||||
.getInputStream(opfEntry)
|
||||
.bufferedReader()
|
||||
.use { it.readText() }
|
||||
val document = Jsoup.parse(opfContent)
|
||||
|
||||
val title = document.select("metadata > dc|title").text().trim().run {
|
||||
ifBlank {
|
||||
file.nameWithoutExtension.trim()
|
||||
}
|
||||
}
|
||||
|
||||
val author = document.select("metadata > dc|creator").text().trim().run {
|
||||
if (isBlank()) {
|
||||
UIText.StringResource(R.string.unknown_author)
|
||||
} else {
|
||||
UIText.StringValue(this)
|
||||
}
|
||||
}
|
||||
|
||||
val description = Jsoup.parse(
|
||||
document.select("metadata > dc|description").text()
|
||||
).text().run {
|
||||
ifBlank {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
val coverImage = document
|
||||
.select("metadata > meta[name=cover]")
|
||||
.attr("content")
|
||||
.run {
|
||||
if (isNotBlank()) {
|
||||
document
|
||||
.select("manifest > item[id=$this]")
|
||||
.attr("href")
|
||||
.apply { if (isNotBlank()) return@run this }
|
||||
}
|
||||
|
||||
document
|
||||
.select("manifest > item[media-type*=image]")
|
||||
.firstOrNull()?.attr("href")
|
||||
}
|
||||
|
||||
book = Book(
|
||||
title = title,
|
||||
author = author,
|
||||
description = description,
|
||||
textPath = "",
|
||||
scrollIndex = 0,
|
||||
scrollOffset = 0,
|
||||
progress = 0f,
|
||||
filePath = file.path,
|
||||
lastOpened = null,
|
||||
category = Category.entries[0],
|
||||
coverImage = null
|
||||
) to extractCoverImageBitmap(file, coverImage)
|
||||
}
|
||||
}
|
||||
return book
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractCoverImageBitmap(file: File, coverImagePath: String?): Bitmap? {
|
||||
if (coverImagePath.isNullOrBlank()) {
|
||||
return null
|
||||
}
|
||||
|
||||
ZipFile(file).use { zip ->
|
||||
zip.entries().asSequence().forEach { entry ->
|
||||
if (entry.name.endsWith(coverImagePath)) {
|
||||
val imageBytes = zip.getInputStream(entry).readBytes()
|
||||
return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package ua.acclorite.book_story.data.parser.zip
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jsoup.Jsoup
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.data.parser.TextParser
|
||||
import ua.acclorite.book_story.domain.util.Resource
|
||||
import ua.acclorite.book_story.domain.util.UIText
|
||||
import java.io.File
|
||||
import java.util.zip.ZipFile
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class ZipTextParser @Inject constructor() : TextParser {
|
||||
|
||||
override suspend fun parse(file: File): Resource<List<String>> {
|
||||
if (!file.name.endsWith(".zip", true) || !file.exists()) {
|
||||
return Resource.Error(UIText.StringResource(R.string.error_wrong_file_format))
|
||||
}
|
||||
|
||||
try {
|
||||
val lines = mutableListOf<String>()
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
ZipFile(file).use { zip ->
|
||||
zip.entries().asSequence().forEach { entry ->
|
||||
if (
|
||||
entry.name.endsWith(".xhtml")
|
||||
|| entry.name.endsWith(".html")
|
||||
|| entry.name.endsWith(".xml")
|
||||
|| entry.name.endsWith(".htm")
|
||||
) {
|
||||
val content = zip.getInputStream(entry).bufferedReader()
|
||||
.use {
|
||||
it.readText()
|
||||
}
|
||||
|
||||
val document = Jsoup.parse(content)
|
||||
document.select("p").append("\n")
|
||||
document
|
||||
.wholeText()
|
||||
.lines()
|
||||
.forEach { line ->
|
||||
if (line.isNotBlank()) {
|
||||
lines.add(line.trim())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lines.isEmpty()) {
|
||||
return Resource.Error(UIText.StringResource(R.string.error_file_empty))
|
||||
}
|
||||
|
||||
return Resource.Success(lines)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return Resource.Error(
|
||||
UIText.StringResource(
|
||||
R.string.error_query,
|
||||
e.message?.take(40)?.trim() ?: ""
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,497 +27,521 @@ object Constants {
|
|||
const val MAIN_STATE = "main_state"
|
||||
|
||||
// Supported file extensions
|
||||
val EXTENSIONS = listOf(".epub", ".pdf", ".fb2", ".txt")
|
||||
val EXTENSIONS = provideSupportedExtensions()
|
||||
|
||||
// Supported languages
|
||||
val LANGUAGES = listOf(
|
||||
Pair("en", "English"),
|
||||
Pair("uk", "Українська"),
|
||||
)
|
||||
val LANGUAGES = provideLanguages()
|
||||
|
||||
// Navigation items for NavigationBars.
|
||||
val NAVIGATION_ITEMS = listOf(
|
||||
NavigationItem(
|
||||
screen = Screen.Library,
|
||||
title = R.string.library_screen,
|
||||
tooltip = R.string.library_content_desc,
|
||||
selectedIcon = R.drawable.library_screen_filled,
|
||||
unselectedIcon = R.drawable.library_screen_outlined
|
||||
),
|
||||
NavigationItem(
|
||||
screen = Screen.History,
|
||||
title = R.string.history_screen,
|
||||
tooltip = R.string.history_content_desc,
|
||||
selectedIcon = R.drawable.history_screen_filled,
|
||||
unselectedIcon = R.drawable.history_screen_outlined
|
||||
),
|
||||
NavigationItem(
|
||||
screen = Screen.Browse,
|
||||
title = R.string.browse_screen,
|
||||
tooltip = R.string.browse_content_desc,
|
||||
selectedIcon = R.drawable.browse_screen_filled,
|
||||
unselectedIcon = R.drawable.browse_screen_outlined
|
||||
)
|
||||
)
|
||||
val NAVIGATION_ITEMS = provideNavigationItems()
|
||||
|
||||
// Supported themes
|
||||
val THEMES = listOf(
|
||||
Pair(Theme.DYNAMIC, UIText.StringResource(R.string.dynamic_theme)),
|
||||
Pair(Theme.BLUE, UIText.StringResource(R.string.blue_theme)),
|
||||
Pair(Theme.GREEN, UIText.StringResource(R.string.green_theme)),
|
||||
Pair(Theme.RED, UIText.StringResource(R.string.red_theme)),
|
||||
Pair(Theme.PURPLE, UIText.StringResource(R.string.purple_theme)),
|
||||
Pair(Theme.PINK, UIText.StringResource(R.string.pink_theme)),
|
||||
Pair(Theme.YELLOW, UIText.StringResource(R.string.yellow_theme)),
|
||||
Pair(Theme.AQUA, UIText.StringResource(R.string.aqua_theme)),
|
||||
)
|
||||
val THEMES = provideThemes()
|
||||
|
||||
// Credits
|
||||
val CREDITS = listOf(
|
||||
Credit(
|
||||
name = "Tachiyomi (Mihon)",
|
||||
source = "GitHub",
|
||||
credits = listOf(
|
||||
UIText.StringResource(R.string.credits_design),
|
||||
UIText.StringValue("Readme")
|
||||
),
|
||||
website = "https://www.github.com/mihonapp/mihon"
|
||||
),
|
||||
Credit(
|
||||
name = "Kitsune",
|
||||
source = "GitHub",
|
||||
credits = listOf(
|
||||
UIText.StringResource(R.string.credits_updates)
|
||||
),
|
||||
website = "https://www.github.com/Drumber/Kitsune"
|
||||
),
|
||||
Credit(
|
||||
name = "Material Design Icons",
|
||||
source = "Google Fonts",
|
||||
credits = listOf(
|
||||
UIText.StringResource(R.string.credits_icon)
|
||||
),
|
||||
website = "https://fonts.google.com/icons"
|
||||
),
|
||||
)
|
||||
val CREDITS = provideCredits()
|
||||
|
||||
// Help Tips
|
||||
val HELP_TIPS = listOf(
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_find_books,
|
||||
description = { _, _ ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_find_books))
|
||||
},
|
||||
customContent = { onHelpEvent ->
|
||||
HelpFindBooksContent(onEvent = onHelpEvent)
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_add_books,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_add_books_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Browse, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_add_books_2))
|
||||
}
|
||||
append(". ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_add_books_3) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Library, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_add_books_4))
|
||||
}
|
||||
append(".")
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_customize_app,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_customize_app_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Settings, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_customize_app_2))
|
||||
}
|
||||
append(". ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_customize_app_3))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_move_or_delete_books,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_move_or_delete_books_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Library, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_move_or_delete_books_2))
|
||||
}
|
||||
append(". ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_move_or_delete_books_3))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_edit_book,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_edit_book_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Library, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_edit_book_2))
|
||||
}
|
||||
append(" ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_edit_book_3))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_read_book,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_read_book_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Library, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_read_book_2))
|
||||
}
|
||||
append(". ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_read_book_3))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_customize_reader,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_customize_reader_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Settings, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_customize_reader_2))
|
||||
}
|
||||
append(" ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_customize_reader_3))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_update_book,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_update_book_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Library, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_update_book_2))
|
||||
}
|
||||
append(" ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_update_book_3))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_manage_history,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_manage_history_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.History, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_manage_history_2))
|
||||
}
|
||||
append(". ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_manage_history_3))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_use_tooltip,
|
||||
description = { _, _ ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_use_tooltip_1))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_use_double_click_translation,
|
||||
description = { _, _ ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_use_double_click_translation_1))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_create_color_presets,
|
||||
description = { _, _ ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_create_color_presets_1))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_use_color_presets,
|
||||
description = { _, _ ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_use_color_presets_1))
|
||||
}
|
||||
),
|
||||
)
|
||||
val HELP_TIPS = provideHelpTips()
|
||||
|
||||
// About Badges
|
||||
val ABOUT_BADGES = listOf(
|
||||
Badge(
|
||||
id = "x",
|
||||
drawable = R.drawable.x_logo,
|
||||
imageVector = null,
|
||||
contentDescription = R.string.x_content_desc,
|
||||
url = "https://www.x.com/acclorite"
|
||||
),
|
||||
Badge(
|
||||
id = "reddit",
|
||||
drawable = R.drawable.reddit,
|
||||
imageVector = null,
|
||||
contentDescription = R.string.reddit_content_desc,
|
||||
url = "https://www.reddit.com/user/Acclorite/"
|
||||
),
|
||||
Badge(
|
||||
id = "tryzub",
|
||||
drawable = R.drawable.tryzub,
|
||||
imageVector = null,
|
||||
contentDescription = R.string.tryzub_content_desc,
|
||||
url = null
|
||||
),
|
||||
Badge(
|
||||
id = "github_project",
|
||||
drawable = R.drawable.github,
|
||||
imageVector = null,
|
||||
contentDescription = R.string.github_project_content_desc,
|
||||
url = "https://www.github.com/Acclorite/book-story"
|
||||
),
|
||||
Badge(
|
||||
id = "github_profile",
|
||||
drawable = null,
|
||||
imageVector = Icons.Default.Person,
|
||||
contentDescription = R.string.github_profile_content_desc,
|
||||
url = "https://www.github.com/Acclorite"
|
||||
),
|
||||
)
|
||||
val ABOUT_BADGES = provideAboutBadges()
|
||||
|
||||
// Fonts for Reader
|
||||
val FONTS = listOf(
|
||||
FontWithName(
|
||||
"default",
|
||||
UIText.StringResource(R.string.default_font),
|
||||
FontFamily.Default
|
||||
val FONTS = provideFonts()
|
||||
|
||||
// Empty Book (Used for Default Screen values)
|
||||
val EMPTY_BOOK = provideEmptyBook()
|
||||
|
||||
// Default Color Preset (Used when creating new color presets)
|
||||
val DEFAULT_COLOR_PRESET = provideDefaultColorPreset()
|
||||
}
|
||||
|
||||
private fun provideSupportedExtensions() = listOf(
|
||||
".epub", ".pdf", ".fb2", ".txt", ".zip", ".html", ".htm"
|
||||
)
|
||||
|
||||
private fun provideLanguages() = listOf(
|
||||
Pair("en", "English"),
|
||||
Pair("uk", "Українська"),
|
||||
)
|
||||
|
||||
private fun provideNavigationItems() = listOf(
|
||||
NavigationItem(
|
||||
screen = Screen.Library,
|
||||
title = R.string.library_screen,
|
||||
tooltip = R.string.library_content_desc,
|
||||
selectedIcon = R.drawable.library_screen_filled,
|
||||
unselectedIcon = R.drawable.library_screen_outlined
|
||||
),
|
||||
NavigationItem(
|
||||
screen = Screen.History,
|
||||
title = R.string.history_screen,
|
||||
tooltip = R.string.history_content_desc,
|
||||
selectedIcon = R.drawable.history_screen_filled,
|
||||
unselectedIcon = R.drawable.history_screen_outlined
|
||||
),
|
||||
NavigationItem(
|
||||
screen = Screen.Browse,
|
||||
title = R.string.browse_screen,
|
||||
tooltip = R.string.browse_content_desc,
|
||||
selectedIcon = R.drawable.browse_screen_filled,
|
||||
unselectedIcon = R.drawable.browse_screen_outlined
|
||||
)
|
||||
)
|
||||
|
||||
private fun provideThemes() = listOf(
|
||||
Pair(Theme.DYNAMIC, UIText.StringResource(R.string.dynamic_theme)),
|
||||
Pair(Theme.BLUE, UIText.StringResource(R.string.blue_theme)),
|
||||
Pair(Theme.GREEN, UIText.StringResource(R.string.green_theme)),
|
||||
Pair(Theme.RED, UIText.StringResource(R.string.red_theme)),
|
||||
Pair(Theme.PURPLE, UIText.StringResource(R.string.purple_theme)),
|
||||
Pair(Theme.PINK, UIText.StringResource(R.string.pink_theme)),
|
||||
Pair(Theme.YELLOW, UIText.StringResource(R.string.yellow_theme)),
|
||||
Pair(Theme.AQUA, UIText.StringResource(R.string.aqua_theme)),
|
||||
)
|
||||
|
||||
private fun provideCredits() = listOf(
|
||||
Credit(
|
||||
name = "Tachiyomi (Mihon)",
|
||||
source = "GitHub",
|
||||
credits = listOf(
|
||||
UIText.StringResource(R.string.credits_design),
|
||||
UIText.StringValue("Readme")
|
||||
),
|
||||
FontWithName(
|
||||
"raleway",
|
||||
UIText.StringValue("Raleway"),
|
||||
FontFamily(
|
||||
Font(R.font.raleway_regular),
|
||||
Font(R.font.raleway_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
website = "https://www.github.com/mihonapp/mihon"
|
||||
),
|
||||
Credit(
|
||||
name = "Kitsune",
|
||||
source = "GitHub",
|
||||
credits = listOf(
|
||||
UIText.StringResource(R.string.credits_updates)
|
||||
),
|
||||
FontWithName(
|
||||
"open_sans",
|
||||
UIText.StringValue("Open Sans"),
|
||||
FontFamily(
|
||||
Font(R.font.opensans_regular),
|
||||
Font(R.font.opensans_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
website = "https://www.github.com/Drumber/Kitsune"
|
||||
),
|
||||
Credit(
|
||||
name = "Material Design Icons",
|
||||
source = "Google Fonts",
|
||||
credits = listOf(
|
||||
UIText.StringResource(R.string.credits_icon)
|
||||
),
|
||||
FontWithName(
|
||||
"mulish",
|
||||
UIText.StringValue("Mulish"),
|
||||
FontFamily(
|
||||
Font(R.font.mulish_regular),
|
||||
Font(R.font.mulish_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"arimo",
|
||||
UIText.StringValue("Arimo"),
|
||||
FontFamily(
|
||||
Font(R.font.arimo_regular),
|
||||
Font(R.font.arimo_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"garamond",
|
||||
UIText.StringValue("Garamond"),
|
||||
FontFamily(
|
||||
Font(R.font.garamond_regular),
|
||||
Font(R.font.garamond_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"roboto_serif",
|
||||
UIText.StringValue("Roboto Serif"),
|
||||
FontFamily(
|
||||
Font(R.font.robotoserif_regular),
|
||||
Font(R.font.robotoserif_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"noto_serif",
|
||||
UIText.StringValue("Noto Serif"),
|
||||
FontFamily(
|
||||
Font(R.font.notoserif_regular),
|
||||
Font(R.font.notoserif_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"noto_sans",
|
||||
UIText.StringValue("Noto Sans"),
|
||||
FontFamily(
|
||||
Font(R.font.notosans_regular),
|
||||
Font(R.font.notosans_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"roboto",
|
||||
UIText.StringValue("Roboto"),
|
||||
FontFamily(
|
||||
Font(R.font.roboto_regular),
|
||||
Font(R.font.roboto_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"jost",
|
||||
UIText.StringValue("Jost"),
|
||||
FontFamily(
|
||||
Font(R.font.jost_regular),
|
||||
Font(R.font.jost_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"merriweather",
|
||||
UIText.StringValue("Merriweather"),
|
||||
FontFamily(
|
||||
Font(R.font.merriweather_regular),
|
||||
Font(R.font.merriweather_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"montserrat",
|
||||
UIText.StringValue("Montserrat"),
|
||||
FontFamily(
|
||||
Font(R.font.montserrat_regular),
|
||||
Font(R.font.montserrat_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"nunito",
|
||||
UIText.StringValue("Nunito"),
|
||||
FontFamily(
|
||||
Font(R.font.nunito_regular),
|
||||
Font(R.font.nunito_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"roboto_slab",
|
||||
UIText.StringValue("Roboto Slab"),
|
||||
FontFamily(
|
||||
Font(R.font.robotoslab_regular)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"lora",
|
||||
UIText.StringValue("Lora"),
|
||||
FontFamily(
|
||||
Font(R.font.lora_regular),
|
||||
Font(R.font.lora_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
website = "https://fonts.google.com/icons"
|
||||
),
|
||||
)
|
||||
|
||||
private fun provideHelpTips() = listOf(
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_find_books,
|
||||
description = { _, _ ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_find_books))
|
||||
},
|
||||
customContent = { onHelpEvent ->
|
||||
HelpFindBooksContent(onEvent = onHelpEvent)
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_add_books,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_add_books_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Browse, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_add_books_2))
|
||||
}
|
||||
append(". ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_add_books_3) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Library, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_add_books_4))
|
||||
}
|
||||
append(".")
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_customize_app,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_customize_app_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Settings, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_customize_app_2))
|
||||
}
|
||||
append(". ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_customize_app_3))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_move_or_delete_books,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_move_or_delete_books_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Library, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_move_or_delete_books_2))
|
||||
}
|
||||
append(". ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_move_or_delete_books_3))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_edit_book,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_edit_book_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Library, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_edit_book_2))
|
||||
}
|
||||
append(" ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_edit_book_3))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_read_book,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_read_book_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Library, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_read_book_2))
|
||||
}
|
||||
append(". ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_read_book_3))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_customize_reader,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_customize_reader_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Settings, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_customize_reader_2))
|
||||
}
|
||||
append(" ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_customize_reader_3))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_update_book,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_update_book_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.Library, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_update_book_2))
|
||||
}
|
||||
append(" ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_update_book_3))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_manage_history,
|
||||
description = { onNavigate, fromStart ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_manage_history_1) + " ")
|
||||
|
||||
HelpAnnotation(
|
||||
onClick = {
|
||||
if (!fromStart) {
|
||||
onNavigate {
|
||||
navigate(Screen.History, useBackAnimation = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
append(stringResource(id = R.string.help_desc_how_to_manage_history_2))
|
||||
}
|
||||
append(". ")
|
||||
|
||||
append(stringResource(id = R.string.help_desc_how_to_manage_history_3))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_use_tooltip,
|
||||
description = { _, _ ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_use_tooltip_1))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_use_double_click_translation,
|
||||
description = { _, _ ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_use_double_click_translation_1))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_create_color_presets,
|
||||
description = { _, _ ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_create_color_presets_1))
|
||||
}
|
||||
),
|
||||
|
||||
HelpTip(
|
||||
title = R.string.help_title_how_to_use_color_presets,
|
||||
description = { _, _ ->
|
||||
append(stringResource(id = R.string.help_desc_how_to_use_color_presets_1))
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
private fun provideAboutBadges() = listOf(
|
||||
Badge(
|
||||
id = "x",
|
||||
drawable = R.drawable.x_logo,
|
||||
imageVector = null,
|
||||
contentDescription = R.string.x_content_desc,
|
||||
url = "https://www.x.com/acclorite"
|
||||
),
|
||||
Badge(
|
||||
id = "reddit",
|
||||
drawable = R.drawable.reddit,
|
||||
imageVector = null,
|
||||
contentDescription = R.string.reddit_content_desc,
|
||||
url = "https://www.reddit.com/user/Acclorite/"
|
||||
),
|
||||
Badge(
|
||||
id = "tryzub",
|
||||
drawable = R.drawable.tryzub,
|
||||
imageVector = null,
|
||||
contentDescription = R.string.tryzub_content_desc,
|
||||
url = null
|
||||
),
|
||||
Badge(
|
||||
id = "github_project",
|
||||
drawable = R.drawable.github,
|
||||
imageVector = null,
|
||||
contentDescription = R.string.github_project_content_desc,
|
||||
url = "https://www.github.com/Acclorite/book-story"
|
||||
),
|
||||
Badge(
|
||||
id = "github_profile",
|
||||
drawable = null,
|
||||
imageVector = Icons.Default.Person,
|
||||
contentDescription = R.string.github_profile_content_desc,
|
||||
url = "https://www.github.com/Acclorite"
|
||||
),
|
||||
)
|
||||
|
||||
private fun provideFonts() = listOf(
|
||||
FontWithName(
|
||||
"default",
|
||||
UIText.StringResource(R.string.default_font),
|
||||
FontFamily.Default
|
||||
),
|
||||
FontWithName(
|
||||
"raleway",
|
||||
UIText.StringValue("Raleway"),
|
||||
FontFamily(
|
||||
Font(R.font.raleway_regular),
|
||||
Font(R.font.raleway_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"open_sans",
|
||||
UIText.StringValue("Open Sans"),
|
||||
FontFamily(
|
||||
Font(R.font.opensans_regular),
|
||||
Font(R.font.opensans_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"mulish",
|
||||
UIText.StringValue("Mulish"),
|
||||
FontFamily(
|
||||
Font(R.font.mulish_regular),
|
||||
Font(R.font.mulish_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"arimo",
|
||||
UIText.StringValue("Arimo"),
|
||||
FontFamily(
|
||||
Font(R.font.arimo_regular),
|
||||
Font(R.font.arimo_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"garamond",
|
||||
UIText.StringValue("Garamond"),
|
||||
FontFamily(
|
||||
Font(R.font.garamond_regular),
|
||||
Font(R.font.garamond_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"roboto_serif",
|
||||
UIText.StringValue("Roboto Serif"),
|
||||
FontFamily(
|
||||
Font(R.font.robotoserif_regular),
|
||||
Font(R.font.robotoserif_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"noto_serif",
|
||||
UIText.StringValue("Noto Serif"),
|
||||
FontFamily(
|
||||
Font(R.font.notoserif_regular),
|
||||
Font(R.font.notoserif_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"noto_sans",
|
||||
UIText.StringValue("Noto Sans"),
|
||||
FontFamily(
|
||||
Font(R.font.notosans_regular),
|
||||
Font(R.font.notosans_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"roboto",
|
||||
UIText.StringValue("Roboto"),
|
||||
FontFamily(
|
||||
Font(R.font.roboto_regular),
|
||||
Font(R.font.roboto_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"jost",
|
||||
UIText.StringValue("Jost"),
|
||||
FontFamily(
|
||||
Font(R.font.jost_regular),
|
||||
Font(R.font.jost_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"merriweather",
|
||||
UIText.StringValue("Merriweather"),
|
||||
FontFamily(
|
||||
Font(R.font.merriweather_regular),
|
||||
Font(R.font.merriweather_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"montserrat",
|
||||
UIText.StringValue("Montserrat"),
|
||||
FontFamily(
|
||||
Font(R.font.montserrat_regular),
|
||||
Font(R.font.montserrat_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"nunito",
|
||||
UIText.StringValue("Nunito"),
|
||||
FontFamily(
|
||||
Font(R.font.nunito_regular),
|
||||
Font(R.font.nunito_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"roboto_slab",
|
||||
UIText.StringValue("Roboto Slab"),
|
||||
FontFamily(
|
||||
Font(R.font.robotoslab_regular)
|
||||
)
|
||||
),
|
||||
FontWithName(
|
||||
"lora",
|
||||
UIText.StringValue("Lora"),
|
||||
FontFamily(
|
||||
Font(R.font.lora_regular),
|
||||
Font(R.font.lora_regular_italic, style = FontStyle.Italic)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val EMPTY_BOOK = Book(
|
||||
id = -1,
|
||||
title = "",
|
||||
author = UIText.StringValue(""),
|
||||
description = null,
|
||||
textPath = "",
|
||||
filePath = "",
|
||||
coverImage = null,
|
||||
scrollIndex = 0,
|
||||
scrollOffset = 0,
|
||||
progress = 0f,
|
||||
lastOpened = null,
|
||||
category = Category.READING
|
||||
)
|
||||
private fun provideEmptyBook() = Book(
|
||||
id = -1,
|
||||
title = "",
|
||||
author = UIText.StringValue(""),
|
||||
description = null,
|
||||
textPath = "",
|
||||
filePath = "",
|
||||
coverImage = null,
|
||||
scrollIndex = 0,
|
||||
scrollOffset = 0,
|
||||
progress = 0f,
|
||||
lastOpened = null,
|
||||
category = Category.READING
|
||||
)
|
||||
|
||||
val DEFAULT_COLOR_PRESET = ColorPreset(
|
||||
id = -1,
|
||||
name = null,
|
||||
backgroundColor = Color.DarkGray,
|
||||
fontColor = Color.LightGray,
|
||||
isSelected = false
|
||||
)
|
||||
}
|
||||
private fun provideDefaultColorPreset() = ColorPreset(
|
||||
id = -1,
|
||||
name = null,
|
||||
backgroundColor = Color.DarkGray,
|
||||
fontColor = Color.LightGray,
|
||||
isSelected = false
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue