diff --git a/app/src/main/java/io/legado/app/base/BaseDialogFragment.kt b/app/src/main/java/io/legado/app/base/BaseDialogFragment.kt index 84e9d4b0b..7e016521a 100644 --- a/app/src/main/java/io/legado/app/base/BaseDialogFragment.kt +++ b/app/src/main/java/io/legado/app/base/BaseDialogFragment.kt @@ -4,6 +4,7 @@ import android.os.Bundle import android.view.View import androidx.fragment.app.DialogFragment import io.legado.app.help.coroutine.Coroutine +import io.legado.app.lib.theme.ThemeStore import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -21,6 +22,7 @@ abstract class BaseDialogFragment : DialogFragment(), CoroutineScope { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + view.setBackgroundColor(ThemeStore.backgroundColor()) onFragmentCreated(view, savedInstanceState) observeLiveBus() } diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index 104520ff3..02106085a 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -60,6 +60,10 @@ data class Book( return isLocalBook() && originName.endsWith(".txt", true) } + fun isEpub(): Boolean { + return originName.endsWith(".epub", true) + } + fun isOnLineTxt(): Boolean { return !isLocalBook() && type == 0 } diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 3c0fa644e..d6d36bf9a 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -6,7 +6,7 @@ import io.legado.app.constant.EventBus import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.ReplaceRule -import io.legado.app.model.localBook.AnalyzeTxtFile +import io.legado.app.model.localBook.LocalBook import io.legado.app.utils.FileUtils import io.legado.app.utils.MD5Utils import io.legado.app.utils.postEvent @@ -81,7 +81,7 @@ object BookHelp { fun getContent(book: Book, bookChapter: BookChapter): String? { if (book.isLocalBook()) { - return AnalyzeTxtFile.getContent(book, bookChapter) + return LocalBook.getContext(book, bookChapter) } else { val file = FileUtils.getFile( downloadDir, diff --git a/app/src/main/java/io/legado/app/model/localBook/AnalyzeTxtFile.kt b/app/src/main/java/io/legado/app/model/localBook/AnalyzeTxtFile.kt index f9cfb846c..86666598a 100644 --- a/app/src/main/java/io/legado/app/model/localBook/AnalyzeTxtFile.kt +++ b/app/src/main/java/io/legado/app/model/localBook/AnalyzeTxtFile.kt @@ -1,6 +1,5 @@ package io.legado.app.model.localBook -import android.content.Context import android.net.Uri import io.legado.app.App import io.legado.app.data.entities.Book @@ -19,8 +18,8 @@ class AnalyzeTxtFile { private lateinit var charset: Charset @Throws(Exception::class) - fun analyze(context: Context, book: Book): ArrayList { - val bookFile = getBookFile(context, book) + fun analyze(book: Book): ArrayList { + val bookFile = getBookFile(book) book.charset = EncodingDetect.getEncode(bookFile) charset = book.fileCharset() val rulePattern = if (book.tocUrl.isNotEmpty()) { @@ -253,7 +252,7 @@ class AnalyzeTxtFile { } fun getContent(book: Book, bookChapter: BookChapter): String { - val bookFile = getBookFile(App.INSTANCE, book) + val bookFile = getBookFile(book) //获取文件流 val bookStream = RandomAccessFile(bookFile, "r") val content = ByteArray((bookChapter.end!! - bookChapter.start!!).toInt()) @@ -262,13 +261,13 @@ class AnalyzeTxtFile { return String(content, book.fileCharset()) } - private fun getBookFile(context: Context, book: Book): File { + private fun getBookFile(book: Book): File { if (book.bookUrl.isContentPath()) { val uri = Uri.parse(book.bookUrl) val bookFile = FileUtils.getFile(cacheFolder, book.originName, subDirs = *arrayOf()) if (!bookFile.exists()) { bookFile.createNewFile() - DocumentUtils.readBytes(context, uri)?.let { + DocumentUtils.readBytes(App.INSTANCE, uri)?.let { bookFile.writeBytes(it) } } diff --git a/app/src/main/java/io/legado/app/model/localBook/EPUBFile.kt b/app/src/main/java/io/legado/app/model/localBook/EPUBFile.kt index 33986f094..1a4b512b1 100644 --- a/app/src/main/java/io/legado/app/model/localBook/EPUBFile.kt +++ b/app/src/main/java/io/legado/app/model/localBook/EPUBFile.kt @@ -1,8 +1,8 @@ package io.legado.app.model.localBook -import android.content.Context import android.net.Uri import android.text.TextUtils +import io.legado.app.App import io.legado.app.data.entities.BookChapter import io.legado.app.utils.htmlFormat import io.legado.app.utils.isContentPath @@ -15,8 +15,30 @@ import java.io.IOException import java.nio.charset.Charset import java.util.* -class EPUBFile(context: Context, val book: io.legado.app.data.entities.Book) { - var epubBook: Book? = null +class EPUBFile(val book: io.legado.app.data.entities.Book) { + + companion object { + private var eFile: EPUBFile? = null + + @Synchronized + fun getEFile(book: io.legado.app.data.entities.Book): EPUBFile { + if (eFile == null || eFile?.book?.bookUrl == book.bookUrl) { + eFile = EPUBFile(book) + return eFile!! + } + return eFile!! + } + + fun getChapterList(book: io.legado.app.data.entities.Book): ArrayList { + return getEFile(book).getChapterList() + } + + fun getContent(book: io.legado.app.data.entities.Book, chapter: BookChapter): String? { + return getEFile(book).getContent(chapter) + } + } + + private var epubBook: Book? = null private lateinit var mCharset: Charset init { @@ -24,7 +46,7 @@ class EPUBFile(context: Context, val book: io.legado.app.data.entities.Book) { val epubReader = EpubReader() val inputStream = if (book.bookUrl.isContentPath()) { val uri = Uri.parse(book.bookUrl) - context.contentResolver.openInputStream(uri) + App.INSTANCE.contentResolver.openInputStream(uri) } else { File(book.bookUrl).inputStream() } @@ -33,88 +55,90 @@ class EPUBFile(context: Context, val book: io.legado.app.data.entities.Book) { } } - fun getContent(chapter: BookChapter): String { - val resource = epubBook!!.resources.getByHref(chapter.url) - val content = StringBuilder() - val doc = Jsoup.parse(String(resource.data, mCharset)) - val elements = doc.allElements - for (element in elements) { - val contentEs = element.textNodes() - for (i in contentEs.indices) { - val text = contentEs[i].text().trim { it <= ' ' }.htmlFormat() - if (elements.size > 1) { - if (text.isNotEmpty()) { - if (content.isNotEmpty()) { - content.append("\r\n") + fun getContent(chapter: BookChapter): String? { + epubBook?.let { eBook -> + val resource = eBook.resources.getByHref(chapter.url) + val content = StringBuilder() + val doc = Jsoup.parse(String(resource.data, mCharset)) + val elements = doc.allElements + for (element in elements) { + val contentEs = element.textNodes() + for (i in contentEs.indices) { + val text = contentEs[i].text().trim { it <= ' ' }.htmlFormat() + if (elements.size > 1) { + if (text.isNotEmpty()) { + if (content.isNotEmpty()) { + content.append("\r\n") + } + content.append("\u3000\u3000").append(text) } - content.append("\u3000\u3000").append(text) + } else { + content.append(text) } - } else { - content.append(text) } } + return content.toString() } - return content.toString() + return null } - fun getChapterList(epubBook: Book): ArrayList { - val metadata = epubBook.metadata - book.name = metadata.firstTitle - if (metadata.authors.size > 0) { - val author = - metadata.authors[0].toString().replace("^, |, $".toRegex(), "") - book.author = author - } - if (metadata.descriptions.size > 0) { - book.intro = Jsoup.parse(metadata.descriptions[0]).text() - } + fun getChapterList(): ArrayList { val chapterList = ArrayList() - val refs = - epubBook.tableOfContents.tocReferences - if (refs == null || refs.isEmpty()) { - val spineReferences = - epubBook.spine.spineReferences - var i = 0 - val size = spineReferences.size - while (i < size) { - val resource = - spineReferences[i].resource - var title = resource.title - if (TextUtils.isEmpty(title)) { - try { - val doc = - Jsoup.parse(String(resource.data, mCharset)) - val elements = doc.getElementsByTag("title") - if (elements.size > 0) { - title = elements[0].text() + epubBook?.let { eBook -> + val metadata = eBook.metadata + book.name = metadata.firstTitle + if (metadata.authors.size > 0) { + val author = + metadata.authors[0].toString().replace("^, |, $".toRegex(), "") + book.author = author + } + if (metadata.descriptions.size > 0) { + book.intro = Jsoup.parse(metadata.descriptions[0]).text() + } + + val refs = eBook.tableOfContents.tocReferences + if (refs == null || refs.isEmpty()) { + val spineReferences = eBook.spine.spineReferences + var i = 0 + val size = spineReferences.size + while (i < size) { + val resource = + spineReferences[i].resource + var title = resource.title + if (TextUtils.isEmpty(title)) { + try { + val doc = + Jsoup.parse(String(resource.data, mCharset)) + val elements = doc.getElementsByTag("title") + if (elements.size > 0) { + title = elements[0].text() + } + } catch (e: IOException) { + e.printStackTrace() } - } catch (e: IOException) { - e.printStackTrace() } + val chapter = BookChapter() + chapter.index = i + chapter.bookUrl = book.bookUrl + chapter.url = resource.href + if (i == 0 && title.isEmpty()) { + chapter.title = "封面" + } else { + chapter.title = title + } + chapterList.add(chapter) + i++ } - val chapter = BookChapter() - chapter.index = i - chapter.bookUrl = book.bookUrl - chapter.url = resource.href - if (i == 0 && title.isEmpty()) { - chapter.title = "封面" - } else { - chapter.title = title + } else { + parseMenu(chapterList, refs, 0) + for (i in chapterList.indices) { + chapterList[i].index = i } - chapterList.add(chapter) - i++ - } - } else { - parseMenu(chapterList, refs, 0) - for (i in chapterList.indices) { - chapterList[i].index = i } } - return chapterList } - private fun parseMenu( chapterList: ArrayList, refs: List?, diff --git a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt index 9195c87a5..7986f03ad 100644 --- a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt +++ b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt @@ -4,6 +4,7 @@ import android.net.Uri import androidx.documentfile.provider.DocumentFile import io.legado.app.App import io.legado.app.data.entities.Book +import io.legado.app.data.entities.BookChapter import io.legado.app.help.BookHelp import io.legado.app.utils.FileUtils import io.legado.app.utils.isContentPath @@ -12,6 +13,22 @@ import java.io.File object LocalBook { + fun getChapterList(book: Book): ArrayList { + return if (book.isEpub()) { + EPUBFile.getChapterList(book) + } else { + AnalyzeTxtFile().analyze(book) + } + } + + fun getContext(book: Book, chapter: BookChapter): String? { + return if (book.isEpub()) { + EPUBFile.getContent(book, chapter) + } else { + AnalyzeTxtFile.getContent(book, chapter) + } + } + fun importFile(path: String) { val fileName = if (path.isContentPath()) { val doc = DocumentFile.fromSingleUri(App.INSTANCE, Uri.parse(path)) diff --git a/app/src/main/java/io/legado/app/ui/book/group/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/book/group/GroupManageDialog.kt index a5d719b57..0f0865cfc 100644 --- a/app/src/main/java/io/legado/app/ui/book/group/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/group/GroupManageDialog.kt @@ -10,7 +10,6 @@ import android.view.View import android.view.ViewGroup import android.widget.EditText import androidx.appcompat.widget.Toolbar -import androidx.fragment.app.DialogFragment import androidx.lifecycle.Observer import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ItemTouchHelper @@ -18,6 +17,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import io.legado.app.App import io.legado.app.R +import io.legado.app.base.BaseDialogFragment import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.constant.Theme @@ -41,7 +41,7 @@ import org.jetbrains.anko.sdk27.listeners.onClick import java.util.* import kotlin.collections.ArrayList -class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { +class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { private lateinit var viewModel: GroupViewModel private lateinit var adapter: GroupAdapter private val callBack: CallBack? get() = parentFragment as? CallBack @@ -62,8 +62,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { return inflater.inflate(R.layout.dialog_recycler_view, container) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { tool_bar.title = getString(R.string.group_manage) initData() initMenu() diff --git a/app/src/main/java/io/legado/app/ui/book/group/GroupSelectDialog.kt b/app/src/main/java/io/legado/app/ui/book/group/GroupSelectDialog.kt index 9440a7c46..53619816e 100644 --- a/app/src/main/java/io/legado/app/ui/book/group/GroupSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/group/GroupSelectDialog.kt @@ -10,7 +10,6 @@ import android.view.View import android.view.ViewGroup import android.widget.EditText import androidx.appcompat.widget.Toolbar -import androidx.fragment.app.DialogFragment import androidx.fragment.app.FragmentManager import androidx.lifecycle.Observer import androidx.recyclerview.widget.ItemTouchHelper @@ -18,6 +17,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import io.legado.app.App import io.legado.app.R +import io.legado.app.base.BaseDialogFragment import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.constant.Theme @@ -40,7 +40,7 @@ import kotlinx.android.synthetic.main.item_group_select.view.* import org.jetbrains.anko.sdk27.listeners.onClick import java.util.* -class GroupSelectDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { +class GroupSelectDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { companion object { const val tag = "groupSelectDialog" @@ -78,8 +78,7 @@ class GroupSelectDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { return inflater.inflate(R.layout.dialog_book_group_picker, container) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { callBack = activity as? CallBack arguments?.let { groupId = it.getInt("groupId") diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt index e6d6b57e3..c7d812fc2 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt @@ -11,7 +11,7 @@ import io.legado.app.help.AppConfig import io.legado.app.help.BookHelp import io.legado.app.help.IntentDataHelp import io.legado.app.model.WebBook -import io.legado.app.model.localBook.AnalyzeTxtFile +import io.legado.app.model.localBook.LocalBook import io.legado.app.service.BaseReadAloudService import io.legado.app.service.help.ReadAloud import io.legado.app.service.help.ReadBook @@ -109,7 +109,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { ) { execute { if (book.isLocalBook()) { - AnalyzeTxtFile().analyze(context, book).let { + LocalBook.getChapterList(book).let { App.db.bookChapterDao().delByBook(book.bookUrl) App.db.bookChapterDao().insert(*it.toTypedArray()) App.db.bookDao().update(book) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditDialog.kt b/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditDialog.kt index 0027f3209..e66ce611d 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditDialog.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditDialog.kt @@ -10,10 +10,10 @@ import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.widget.EditText import android.widget.PopupWindow import androidx.appcompat.widget.Toolbar -import androidx.fragment.app.DialogFragment import androidx.fragment.app.FragmentManager import androidx.lifecycle.Observer import io.legado.app.R +import io.legado.app.base.BaseDialogFragment import io.legado.app.constant.AppConst import io.legado.app.constant.Theme import io.legado.app.data.entities.ReplaceRule @@ -24,7 +24,7 @@ import io.legado.app.utils.toast import kotlinx.android.synthetic.main.dialog_replace_edit.* import org.jetbrains.anko.sdk27.listeners.onFocusChange -class ReplaceEditDialog : DialogFragment(), +class ReplaceEditDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener, KeyboardToolPop.CallBack { @@ -63,8 +63,7 @@ class ReplaceEditDialog : DialogFragment(), return inflater.inflate(R.layout.dialog_replace_edit, container) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { mSoftKeyboardTool = KeyboardToolPop(requireContext(), AppConst.keyboardToolChars, this) tool_bar.inflateMenu(R.menu.replace_edit) tool_bar.menu.applyTint(requireContext(), Theme.getTheme()) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt index ce2313f5a..b5a92d099 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt @@ -10,11 +10,11 @@ import android.view.View import android.view.ViewGroup import android.widget.EditText import androidx.appcompat.widget.Toolbar -import androidx.fragment.app.DialogFragment import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R +import io.legado.app.base.BaseDialogFragment import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.constant.Theme @@ -30,7 +30,7 @@ import kotlinx.android.synthetic.main.dialog_recycler_view.* import kotlinx.android.synthetic.main.item_group_manage.view.* import org.jetbrains.anko.sdk27.listeners.onClick -class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { +class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { private lateinit var viewModel: RssSourceViewModel private lateinit var adapter: GroupAdapter @@ -50,12 +50,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { return inflater.inflate(R.layout.dialog_recycler_view, container) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - initData() - } - - private fun initData() { + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { tool_bar.title = getString(R.string.group_manage) tool_bar.inflateMenu(R.menu.group_manage) tool_bar.menu.applyTint(requireContext(), Theme.getTheme()) diff --git a/app/src/main/java/io/legado/app/ui/widget/prefs/IconListPreference.kt b/app/src/main/java/io/legado/app/ui/widget/prefs/IconListPreference.kt index fa8b4eeb7..eea138375 100644 --- a/app/src/main/java/io/legado/app/ui/widget/prefs/IconListPreference.kt +++ b/app/src/main/java/io/legado/app/ui/widget/prefs/IconListPreference.kt @@ -10,12 +10,12 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView -import androidx.fragment.app.DialogFragment import androidx.fragment.app.FragmentActivity import androidx.preference.ListPreference import androidx.preference.PreferenceViewHolder import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R +import io.legado.app.base.BaseDialogFragment import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.utils.getCompatDrawable @@ -109,7 +109,7 @@ class IconListPreference(context: Context, attrs: AttributeSet) : ListPreference return "icon_$key" } - class IconDialog : DialogFragment() { + class IconDialog : BaseDialogFragment() { var onChanged: ((value: String) -> Unit)? = null var dialogValue: String? = null @@ -135,8 +135,7 @@ class IconListPreference(context: Context, attrs: AttributeSet) : ListPreference return inflater.inflate(R.layout.dialog_recycler_view, container) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { tool_bar.setTitle(R.string.change_icon) recycler_view.layoutManager = LinearLayoutManager(requireContext()) val adapter = Adapter(requireContext()) diff --git a/app/src/main/res/layout/dialog_file_chooser.xml b/app/src/main/res/layout/dialog_file_chooser.xml index ab5974114..7615ba752 100644 --- a/app/src/main/res/layout/dialog_file_chooser.xml +++ b/app/src/main/res/layout/dialog_file_chooser.xml @@ -2,7 +2,8 @@ + android:layout_height="match_parent" + android:background="@color/background"> + android:background="@color/background"> + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="parent" />