Horis 2 лет назад
Родитель
Сommit
4040be7bf0

+ 6 - 2
app/src/main/java/io/legado/app/model/ReadBook.kt

@@ -2,7 +2,11 @@ package io.legado.app.model
 
 import io.legado.app.constant.AppLog
 import io.legado.app.data.appDb
-import io.legado.app.data.entities.*
+import io.legado.app.data.entities.Book
+import io.legado.app.data.entities.BookChapter
+import io.legado.app.data.entities.BookProgress
+import io.legado.app.data.entities.BookSource
+import io.legado.app.data.entities.ReadRecord
 import io.legado.app.help.AppWebDav
 import io.legado.app.help.book.BookHelp
 import io.legado.app.help.book.ContentProcessor
@@ -88,7 +92,7 @@ object ReadBook : CoroutineScope by MainScope() {
         upWebBook(book)
         lastBookPress = null
         webBookProgress = null
-        TextFile.txtBuffer = null
+        TextFile.clear()
         synchronized(this) {
             loadingChapters.clear()
         }

+ 1 - 1
app/src/main/java/io/legado/app/model/localBook/LocalBook.kt

@@ -82,7 +82,7 @@ object LocalBook {
         }
     }
 
-    @Throws(Exception::class)
+    @Throws(TocEmptyException::class)
     fun getChapterList(book: Book): ArrayList<BookChapter> {
         val chapters = when {
             book.isEpub -> {

+ 72 - 45
app/src/main/java/io/legado/app/model/localBook/TextFile.kt

@@ -16,56 +16,37 @@ import java.util.regex.Matcher
 import java.util.regex.Pattern
 import kotlin.math.min
 
-class TextFile(private val book: Book) {
+class TextFile(private var book: Book) {
 
+    @Suppress("ConstPropertyName")
     companion object {
         private val padRegex = "^[\\n\\s]+".toRegex()
-        private const val bufferSize = 8 * 1024 * 1024
-        private var bufferStart = -1
-        private var bufferEnd = -1
-        var txtBuffer: ByteArray? = null
-        var bookUrl = ""
+        private const val txtBufferSize = 8 * 1024 * 1024
+        private var textFile: TextFile? = null
+
+        @Synchronized
+        private fun getTextFile(book: Book): TextFile {
+            if (textFile == null || textFile?.book?.bookUrl != book.bookUrl) {
+                textFile = TextFile(book)
+                return textFile!!
+            }
+            textFile?.book = book
+            return textFile!!
+        }
 
         @Throws(FileNotFoundException::class)
         fun getChapterList(book: Book): ArrayList<BookChapter> {
-            return TextFile(book).getChapterList()
+            return getTextFile(book).getChapterList()
         }
 
         @Synchronized
         @Throws(FileNotFoundException::class)
         fun getContent(book: Book, bookChapter: BookChapter): String {
-            if (txtBuffer == null || bookUrl != book.bookUrl || bookChapter.start!! > bufferEnd || bookChapter.end!! < bufferStart) {
-                bookUrl = book.bookUrl
-                LocalBook.getBookInputStream(book).use { bis ->
-                    bufferStart = bufferSize * (bookChapter.start!! / bufferSize).toInt()
-                    txtBuffer = ByteArray(min(bufferSize, bis.available() - bufferStart))
-                    bufferEnd = bufferStart + txtBuffer!!.size
-                    bis.skip(bufferStart.toLong())
-                    bis.read(txtBuffer)
-                }
-            }
-
-            val count = (bookChapter.end!! - bookChapter.start!!).toInt()
-            val buffer = ByteArray(count)
-
-            if (bookChapter.start!! < bufferEnd && bookChapter.end!! > bufferEnd || bookChapter.start!! < bufferStart && bookChapter.end!! > bufferStart) {
-                /** 章节内容在缓冲区交界处 */
-                LocalBook.getBookInputStream(book).use { bis ->
-                    bis.skip(bookChapter.start!!)
-                    bis.read(buffer)
-                }
-            } else {
-                /** 章节内容在缓冲区内 */
-                txtBuffer!!.copyInto(
-                    buffer,
-                    0,
-                    (bookChapter.start!! - bufferStart).toInt(),
-                    (bookChapter.end!! - bufferStart).toInt()
-                )
-            }
+            return getTextFile(book).getContent(bookChapter)
+        }
 
-            return String(buffer, book.fileCharset()).substringAfter(bookChapter.title)
-                .replace(padRegex, "  ")
+        fun clear() {
+            textFile = null
         }
 
     }
@@ -83,10 +64,14 @@ class TextFile(private val book: Book) {
 
     private var charset: Charset = book.fileCharset()
 
+    private var txtBuffer: ByteArray? = null
+    private var bufferStart = -1L
+    private var bufferEnd = -1L
+
     /**
      * 获取目录
      */
-    @Throws(FileNotFoundException::class)
+    @Throws(FileNotFoundException::class, SecurityException::class, EmptyFileException::class)
     fun getChapterList(): ArrayList<BookChapter> {
         if (book.charset == null || book.tocUrl.isBlank()) {
             LocalBook.getBookInputStream(book).use { bis ->
@@ -112,6 +97,43 @@ class TextFile(private val book: Book) {
         return toc
     }
 
+    fun getContent(chapter: BookChapter): String {
+        val start = chapter.start!!
+        val end = chapter.end!!
+        if (txtBuffer == null || start > bufferEnd || end < bufferStart) {
+            LocalBook.getBookInputStream(book).use { bis ->
+                bufferStart = txtBufferSize * (start / txtBufferSize)
+                txtBuffer = ByteArray(min(txtBufferSize, bis.available() - bufferStart.toInt()))
+                bufferEnd = bufferStart + txtBuffer!!.size
+                bis.skip(bufferStart)
+                bis.read(txtBuffer)
+            }
+        }
+
+        val count = (end - start).toInt()
+        val buffer = ByteArray(count)
+
+        if (bufferEnd in start..end || bufferStart in start..end) {
+            /** 章节内容在缓冲区交界处 */
+            LocalBook.getBookInputStream(book).use { bis ->
+                bis.skip(start)
+                bis.read(buffer)
+            }
+        } else {
+            /** 章节内容在缓冲区内 */
+            txtBuffer!!.copyInto(
+                buffer,
+                0,
+                (start - bufferStart).toInt(),
+                (end - bufferStart).toInt()
+            )
+        }
+
+        return String(buffer, charset)
+            .substringAfter(chapter.title)
+            .replace(padRegex, "  ")
+    }
+
     /**
      * 按规则解析目录
      */
@@ -162,7 +184,7 @@ class TextFile(private val book: Book) {
                     val chapterStart = matcher.start()
                     //获取章节内容
                     val chapterContent = blockContent.substring(seekPos, chapterStart)
-                    val chapterLength = chapterContent.toByteArray(charset).size
+                    val chapterLength = chapterContent.toByteArray(charset).size.toLong()
                     val lastStart = toc.lastOrNull()?.start ?: curOffset
                     if (book.getSplitLongChapter() && curOffset + chapterLength - lastStart > maxLengthWithToc) {
                         toc.lastOrNull()?.let {
@@ -186,7 +208,7 @@ class TextFile(private val book: Book) {
                         curChapter.start = curOffset + chapterLength
                         toc.add(curChapter)
                     } else if (seekPos == 0 && chapterStart != 0) {
-                        /*
+                        /**
                          * 如果 seekPos == 0 && chapterStart != 0 表示当前block处前面有一段内容
                          * 第一种情况一定是序章 第二种情况是上一个章节的内容
                          */
@@ -196,13 +218,18 @@ class TextFile(private val book: Book) {
                                 val qyChapter = BookChapter()
                                 qyChapter.title = "前言"
                                 qyChapter.start = curOffset
-                                qyChapter.end = curOffset + chapterLength.toLong()
+                                qyChapter.end = curOffset + chapterLength
                                 toc.add(qyChapter)
+                                book.intro = if (chapterContent.length <= 500) {
+                                    chapterContent
+                                } else {
+                                    chapterContent.substring(0, 500)
+                                }
                             }
                             //创建当前章节
                             val curChapter = BookChapter()
                             curChapter.title = matcher.group()
-                            curChapter.start = curOffset + chapterLength.toLong()
+                            curChapter.start = curOffset + chapterLength
                             toc.add(curChapter)
                         } else { //否则就block分割之后,上一个章节的剩余内容
                             //获取上一章节
@@ -210,7 +237,7 @@ class TextFile(private val book: Book) {
                             lastChapter.isVolume =
                                 chapterContent.substringAfter(lastChapter.title).isBlank()
                             //将当前段落添加上一章去
-                            lastChapter.end = lastChapter.end!! + chapterLength.toLong()
+                            lastChapter.end = lastChapter.end!! + chapterLength
                             //创建当前章节
                             val curChapter = BookChapter()
                             curChapter.title = matcher.group()
@@ -224,7 +251,7 @@ class TextFile(private val book: Book) {
                             lastChapter.isVolume =
                                 chapterContent.substringAfter(lastChapter.title).isBlank()
                             lastChapter.end =
-                                lastChapter.start!! + chapterContent.toByteArray(charset).size.toLong()
+                                lastChapter.start!! + chapterLength
                             //创建当前章节
                             val curChapter = BookChapter()
                             curChapter.title = matcher.group()

+ 1 - 99
app/src/main/java/io/legado/app/ui/book/explore/ExploreShowActivity.kt

@@ -1,45 +1,27 @@
 package io.legado.app.ui.book.explore
 
 import android.os.Bundle
-import android.view.Menu
-import android.view.MenuItem
 import androidx.activity.viewModels
 import androidx.recyclerview.widget.RecyclerView
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
-import io.legado.app.constant.AppLog
-import io.legado.app.data.appDb
 import io.legado.app.data.entities.Book
 import io.legado.app.data.entities.SearchBook
 import io.legado.app.databinding.ActivityExploreShowBinding
-import io.legado.app.databinding.DialogPageChoiceBinding
 import io.legado.app.databinding.ViewLoadMoreBinding
-import io.legado.app.help.coroutine.Coroutine
-import io.legado.app.lib.dialogs.alert
-import io.legado.app.lib.theme.backgroundColor
-import io.legado.app.model.webBook.WebBook
-import io.legado.app.ui.book.group.GroupSelectDialog
 import io.legado.app.ui.book.info.BookInfoActivity
-import io.legado.app.ui.widget.dialog.WaitDialog
 import io.legado.app.ui.widget.recycler.LoadMoreView
 import io.legado.app.ui.widget.recycler.VerticalDivider
-import io.legado.app.utils.showDialogFragment
 import io.legado.app.utils.startActivity
 import io.legado.app.utils.viewbindingdelegate.viewBinding
-import kotlinx.coroutines.Dispatchers.Main
-import kotlinx.coroutines.launch
 
 class ExploreShowActivity : VMBaseActivity<ActivityExploreShowBinding, ExploreShowViewModel>(),
-    ExploreShowAdapter.CallBack,
-    GroupSelectDialog.CallBack {
+    ExploreShowAdapter.CallBack {
     override val binding by viewBinding(ActivityExploreShowBinding::inflate)
     override val viewModel by viewModels<ExploreShowViewModel>()
 
     private val adapter by lazy { ExploreShowAdapter(this, this) }
     private val loadMoreView by lazy { LoadMoreView(this) }
-    private val waitDialog by lazy {
-        WaitDialog(this)
-    }
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {
         binding.titleBar.title = intent.getStringExtra("exploreName")
@@ -116,84 +98,4 @@ class ExploreShowActivity : VMBaseActivity<ActivityExploreShowBinding, ExploreSh
             putExtra("bookUrl", book.bookUrl)
         }
     }
-
-    override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
-        menuInflater.inflate(R.menu.explore_show, menu)
-        return super.onCompatCreateOptionsMenu(menu)
-    }
-
-    override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
-        when (item.itemId) {
-            R.id.menu_add_all_to_bookshelf -> addAllToBookshelf()
-        }
-        return super.onCompatOptionsItemSelected(item)
-    }
-
-    private fun addAllToBookshelf() {
-        showDialogFragment(GroupSelectDialog(0))
-    }
-
-    override fun upGroup(requestCode: Int, groupId: Long) {
-
-        alert("选择页数范围") {
-            val alertBinding = DialogPageChoiceBinding.inflate(layoutInflater).apply {
-                root.setBackgroundColor(root.context.backgroundColor)
-            }
-            customView { alertBinding.root }
-            yesButton {
-                alertBinding.run {
-                    val start = editStart.text
-                        .runCatching {
-                            toString().toInt()
-                        }.getOrDefault(1)
-                    val end = editEnd.text
-                        .runCatching {
-                            toString().toInt()
-                        }.getOrDefault(9)
-                    addAllToBookshelf(start, end, groupId)
-                }
-            }
-            noButton()
-        }
-
-    }
-
-    private fun addAllToBookshelf(start: Int, end: Int, groupId: Long) {
-        val job = Coroutine.async {
-            launch(Main) {
-                waitDialog.setText("加载列表中...")
-                waitDialog.show()
-            }
-            val searchBooks = viewModel.loadExploreBooks(start, end)
-            val books = searchBooks.map {
-                it.toBook()
-            }
-            launch(Main) {
-                waitDialog.setText("添加书架中...")
-            }
-            books.forEach {
-                appDb.bookDao.getBook(it.bookUrl)?.let { book ->
-                    book.group = book.group or groupId
-                    it.order = appDb.bookDao.minOrder - 1
-                    book.save()
-                    return@forEach
-                }
-                if (it.tocUrl.isEmpty()) {
-                    val source = appDb.bookSourceDao.getBookSource(it.origin)!!
-                    WebBook.getBookInfoAwait(source, it)
-                }
-                it.order = appDb.bookDao.minOrder - 1
-                it.group = groupId
-                it.save()
-            }
-        }.onError {
-            AppLog.put("添加书架出错\n${it.localizedMessage}", it)
-        }.onFinally {
-            waitDialog.dismiss()
-        }
-        waitDialog.setOnCancelListener {
-            job.cancel()
-        }
-    }
-
 }

+ 0 - 14
app/src/main/java/io/legado/app/ui/book/explore/ExploreShowViewModel.kt

@@ -70,18 +70,4 @@ class ExploreShowViewModel(application: Application) : BaseViewModel(application
             }
     }
 
-    suspend fun loadExploreBooks(start: Int, end: Int): List<SearchBook> {
-        val source = bookSource
-        val url = exploreUrl
-        if (source == null || url == null) return emptyList()
-        val searchBooks = arrayListOf<SearchBook>()
-        for (page in start..end) {
-            val books = WebBook.exploreBookAwait(source, url, page)
-            if (books.isEmpty()) break
-            searchBooks.addAll(books)
-        }
-        searchBooks.reverse()
-        return searchBooks
-    }
-
 }

+ 0 - 74
app/src/main/res/layout/dialog_page_choice.xml

@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/ll_content"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:background="@color/background"
-    android:gravity="center"
-    android:orientation="horizontal"
-    android:padding="16dp">
-
-    <View
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_weight="1" />
-
-    <EditText
-        android:id="@+id/edit_start"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:background="@drawable/bg_edit"
-        android:hint="@string/start"
-        android:importantForAutofill="no"
-        android:inputType="number"
-        android:lines="1"
-        android:maxLength="5"
-        android:minWidth="60dp"
-        android:paddingLeft="5dp"
-        android:paddingTop="4dp"
-        android:paddingRight="5dp"
-        android:paddingBottom="4dp"
-        android:textColor="@color/primaryText"
-        android:textCursorDrawable="@drawable/shape_text_cursor"
-        android:textSize="14sp"
-        tools:ignore="TouchTargetSizeCheck,TextContrastCheck" />
-
-    <TextView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:layout_marginLeft="5dp"
-        android:layout_marginRight="5dp"
-        android:text="@string/page_to"
-        android:textColor="@color/primaryText"
-        android:textSize="16sp" />
-
-    <EditText
-        android:id="@+id/edit_end"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:background="@drawable/bg_edit"
-        android:hint="@string/end"
-        android:importantForAutofill="no"
-        android:inputType="number"
-        android:lines="1"
-        android:maxLength="5"
-        android:minWidth="60dp"
-        android:paddingLeft="5dp"
-        android:paddingTop="4dp"
-        android:paddingRight="5dp"
-        android:paddingBottom="4dp"
-        android:textColor="@color/primaryText"
-        android:textCursorDrawable="@drawable/shape_text_cursor"
-        android:textSize="14sp"
-        tools:ignore="TouchTargetSizeCheck,SpeakableTextPresentCheck,TextContrastCheck" />
-
-    <View
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_weight="1" />
-
-</LinearLayout>

+ 0 - 8
app/src/main/res/menu/explore_show.xml

@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item
-        android:id="@+id/menu_add_all_to_bookshelf"
-        android:title="@string/add_all_to_bookshelf" />
-
-</menu>

+ 0 - 2
app/src/main/res/values-es-rES/strings.xml

@@ -1117,8 +1117,6 @@
     <string name="test">测试</string>
     <string name="show_wait_up_count">显示等待更新数量</string>
     <string name="exit_app">退出软件</string>
-    <string name="add_all_to_bookshelf">全部加入书架</string>
-    <string name="page_to">页至</string>
     <string name="result_analyzed">Analyzed</string>
     <string name="bookshelf_px_4">Comprehensive</string>
     <string name="effective_replaces">起效的替换</string>

+ 0 - 2
app/src/main/res/values-ja-rJP/strings.xml

@@ -1120,8 +1120,6 @@
     <string name="test">测试</string>
     <string name="show_wait_up_count">显示等待更新数量</string>
     <string name="exit_app">退出软件</string>
-    <string name="add_all_to_bookshelf">全部加入书架</string>
-    <string name="page_to">页至</string>
     <string name="result_analyzed">Analyzed</string>
     <string name="bookshelf_px_4">Comprehensive</string>
     <string name="effective_replaces">起效的替换</string>

+ 0 - 2
app/src/main/res/values-pt-rBR/strings.xml

@@ -1120,8 +1120,6 @@
     <string name="test">测试</string>
     <string name="show_wait_up_count">显示等待更新数量</string>
     <string name="exit_app">退出软件</string>
-    <string name="add_all_to_bookshelf">全部加入书架</string>
-    <string name="page_to">页至</string>
     <string name="result_analyzed">Analyzed</string>
     <string name="bookshelf_px_4">Comprehensive</string>
     <string name="effective_replaces">起效的替换</string>

+ 0 - 2
app/src/main/res/values-vi/strings.xml

@@ -1116,8 +1116,6 @@ Còn </string>
      <string name="test">Kiểm tra</string>
      <string name="show_wait_up_count">Hiển thị số bản cập nhật đang đợi</string>
      <string name="exit_app">Thoát khỏi phần mềm</string>
-     <string name="add_all_to_bookshelf">Thêm tất cả vào giá sách</string>
-    <string name="page_to">Trang tới</string>
     <string name="result_analyzed">Analyzed</string>
     <string name="bookshelf_px_4">Comprehensive</string>
     <string name="effective_replaces">起效的替换</string>

+ 0 - 2
app/src/main/res/values-zh-rHK/strings.xml

@@ -1117,8 +1117,6 @@
     <string name="test">测试</string>
     <string name="show_wait_up_count">显示等待更新数量</string>
     <string name="exit_app">退出软件</string>
-    <string name="add_all_to_bookshelf">全部加入书架</string>
-    <string name="page_to">页至</string>
     <string name="result_analyzed">解析示例</string>
     <string name="bookshelf_px_4">綜合排序</string>
     <string name="effective_replaces">起效的替换</string>

+ 0 - 2
app/src/main/res/values-zh-rTW/strings.xml

@@ -1119,8 +1119,6 @@
     <string name="test">测试</string>
     <string name="show_wait_up_count">显示等待更新数量</string>
     <string name="exit_app">退出软件</string>
-    <string name="add_all_to_bookshelf">全部加入书架</string>
-    <string name="page_to">页至</string>
     <string name="result_analyzed">解析示例</string>
     <string name="bookshelf_px_4">綜合排序</string>
     <string name="effective_replaces">起效的替换</string>

+ 0 - 2
app/src/main/res/values-zh/strings.xml

@@ -1119,8 +1119,6 @@
     <string name="test">测试</string>
     <string name="show_wait_up_count">显示等待更新数量</string>
     <string name="exit_app">退出软件</string>
-    <string name="add_all_to_bookshelf">全部加入书架</string>
-    <string name="page_to">页至</string>
     <string name="result_analyzed">解析示例</string>
     <string name="bookshelf_px_4">综合排序</string>
     <string name="effective_replaces">起效的替换</string>

+ 0 - 2
app/src/main/res/values/strings.xml

@@ -1120,8 +1120,6 @@
     <string name="test">Test</string>
     <string name="show_wait_up_count">Display the number of pending updates</string>
     <string name="exit_app">Exit</string>
-    <string name="add_all_to_bookshelf">全部加入书架</string>
-    <string name="page_to">页至</string>
     <string name="result_analyzed">Analyzed</string>
     <string name="bookshelf_px_4">Comprehensive</string>
     <string name="effective_replaces">Effective replacement</string>