Преглед изворни кода

fix:优化导入逻辑和调整界面

Xwite пре 4 година
родитељ
комит
b81dcd7ff0

+ 1 - 0
app/src/main/java/io/legado/app/constant/EventBus.kt

@@ -28,4 +28,5 @@ object EventBus {
     const val TIP_COLOR = "tipColor"
     const val TIP_COLOR = "tipColor"
     const val SOURCE_CHANGED = "sourceChanged"
     const val SOURCE_CHANGED = "sourceChanged"
     const val SEARCH_RESULT = "searchResult"
     const val SEARCH_RESULT = "searchResult"
+    const val BOOK_URL_CHANGED = "bookUrlChanged"
 }
 }

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

@@ -94,13 +94,11 @@ object LocalBook {
      */
      */
     fun importFileOnLine(
     fun importFileOnLine(
         str: String,
         str: String,
-        fileName: String? = null,
+        fileName: String,
         source: BaseSource? = null,
         source: BaseSource? = null,
-        onLineBook: Book? = null
     ): Book {
     ): Book {
-        val fileUri = saveBookFile(str, fileName, source, onLineBook)
-        return importFile(fileUri).let {
-            mergeBook(it, onLineBook)
+        return saveBookFile(str, fileName, source).let {
+            importFile(it)
         }
         }
     }
     }
 
 
@@ -205,41 +203,32 @@ object LocalBook {
 
 
     /**
     /**
      * 下载在线的文件
      * 下载在线的文件
-     * fileName为空时 传入onLineBook
      */
      */
     fun saveBookFile(
     fun saveBookFile(
         str: String,
         str: String,
-        fileName: String? = null,
+        fileName: String,
         source: BaseSource? = null,
         source: BaseSource? = null,
-        onLineBook: Book? = null
     ): Uri {
     ): Uri {
         val bytes = when {
         val bytes = when {
             str.isAbsUrl() -> AnalyzeUrl(str, source = source).getByteArray()
             str.isAbsUrl() -> AnalyzeUrl(str, source = source).getByteArray()
             str.isDataUrl() -> Base64.decode(str.substringAfter("base64,"), Base64.DEFAULT)
             str.isDataUrl() -> Base64.decode(str.substringAfter("base64,"), Base64.DEFAULT)
             else -> throw NoStackTraceException("在线导入书籍支持http/https/DataURL")
             else -> throw NoStackTraceException("在线导入书籍支持http/https/DataURL")
         }
         }
-        val mFileName = fileName ?: extractDownloadName(str, onLineBook)
-        return saveBookFile(bytes, mFileName)
+        return saveBookFile(bytes, fileName)
     }
     }
 
 
     /**
     /**
-     * 分析下载文件类书源的下载链接
+     * 分析下载文件类书源的下载链接的文件后缀
      * https://www.example.com/download/{fileName}.{type} 含有文件名和后缀
      * https://www.example.com/download/{fileName}.{type} 含有文件名和后缀
-     * https://www.example.com/download/?fileid=1234, {type: "txt"}
+     * https://www.example.com/download/?fileid=1234, {type: "txt"} 规则设置
      */
      */
-    fun extractDownloadName(uri: String, onLineBook: Book?): String {
-        val analyzeUrl = AnalyzeUrl(uri)
+    fun parseFileSuffix(url: String): String {
+        val analyzeUrl = AnalyzeUrl(url)
         val urlNoOption = analyzeUrl.url
         val urlNoOption = analyzeUrl.url
         val lastPath = urlNoOption.substringAfterLast("/")
         val lastPath = urlNoOption.substringAfterLast("/")
         val fileType = lastPath.substringAfterLast(".")
         val fileType = lastPath.substringAfterLast(".")
         val type = analyzeUrl.type
         val type = analyzeUrl.type
-        val fileName = when {
-            onLineBook != null -> "${onLineBook.name}_${onLineBook.author}_${onLineBook.origin}"
-            type == null-> lastPath
-            else -> lastPath.substringBeforeLast(".")
-        }
-        val fileSuffix = fileType ?: type ?: "unknown"
-        return "${fileName}.${fileSuffix}"
+        return type ?: fileType ?: "unknown"
     }
     }
 
 
     private fun saveBookFile(
     private fun saveBookFile(

+ 49 - 69
app/src/main/java/io/legado/app/ui/association/ImportOnLineBookFileDialog.kt

@@ -1,6 +1,5 @@
 package io.legado.app.ui.association
 package io.legado.app.ui.association
 
 
-import android.annotation.SuppressLint
 import android.content.Context
 import android.content.Context
 import android.content.DialogInterface
 import android.content.DialogInterface
 import android.os.Bundle
 import android.os.Bundle
@@ -21,7 +20,6 @@ import io.legado.app.lib.theme.primaryColor
 import io.legado.app.ui.widget.dialog.WaitDialog
 import io.legado.app.ui.widget.dialog.WaitDialog
 import io.legado.app.utils.*
 import io.legado.app.utils.*
 import io.legado.app.utils.viewbindingdelegate.viewBinding
 import io.legado.app.utils.viewbindingdelegate.viewBinding
-import splitties.views.onClick
 
 
 
 
 /**
 /**
@@ -39,61 +37,50 @@ class ImportOnLineBookFileDialog() : BaseDialogFragment(R.layout.dialog_recycler
         setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
         setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
     }
     }
 
 
-    @SuppressLint("NotifyDataSetChanged")
     override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
     override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
         val bookUrl = arguments?.getString("bookUrl")
         val bookUrl = arguments?.getString("bookUrl")
-        val infoHtml = arguments?.getString("infoHtml")
-        viewModel.initData(bookUrl, infoHtml)
+        viewModel.initData(bookUrl)
         binding.toolBar.setBackgroundColor(primaryColor)
         binding.toolBar.setBackgroundColor(primaryColor)
-        //标题
-        binding.toolBar.setTitle("导入在线书籍文件")
+        binding.toolBar.setTitle(R.string.download_and_import_file)
         binding.rotateLoading.show()
         binding.rotateLoading.show()
         binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
         binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
         binding.recyclerView.adapter = adapter
         binding.recyclerView.adapter = adapter
-        binding.tvCancel.visible()
-        binding.tvCancel.setOnClickListener {
-            dismissAllowingStateLoss()
-        }
-        binding.tvOk.visible()
-        binding.tvOk.setOnClickListener {
-            val waitDialog = WaitDialog(requireContext())
-            waitDialog.show()
-            viewModel.importSelect {
-                waitDialog.dismiss()
-                dismissAllowingStateLoss()
+        viewModel.errorLiveData.observe(this) {
+            binding.rotateLoading.hide()
+            binding.tvMsg.apply {
+                text = it
+                visible()
             }
             }
         }
         }
-        binding.tvFooterLeft.visible()
-        binding.tvFooterLeft.setOnClickListener {
-            val selectAll = viewModel.isSelectAll
-            viewModel.selectStatus.forEachIndexed { index, b ->
-                if (b != !selectAll) {
-                    viewModel.selectStatus[index] = !selectAll
-                }
+        viewModel.successLiveData.observe(this) {
+            binding.rotateLoading.hide()
+            if (it > 0) {
+                adapter.setItems(viewModel.allBookFiles)
             }
             }
-            adapter.notifyDataSetChanged()
-            upSelectText()
         }
         }
-        adapter.setItems(viewModel.allBookFiles)
-        upSelectText()
+        viewModel.savedFileUriData.observe(this) {
+            requireContext().openFileUri(it, "*/*")
+        }
     }
     }
 
 
-    private fun upSelectText() {
-        if (viewModel.isSelectAll) {
-            binding.tvFooterLeft.text = getString(
-                R.string.select_cancel_count,
-                viewModel.selectCount,
-                viewModel.allBookFiles.size
-            )
-        } else {
-            binding.tvFooterLeft.text = getString(
-                R.string.select_all_count,
-                viewModel.selectCount,
-                viewModel.allBookFiles.size
-            )
+    private fun importFileAndUpdate(url: String, fileName: String) {
+        val waitDialog = WaitDialog(requireContext())
+        waitDialog.show()
+        viewModel.importOnLineBookFile(url, fileName) {
+           waitDialog.dismiss()
+           dismissAllowingStateLoss()
         }
         }
     }
     }
 
 
+    private fun downloadFile(url: String, fileName: String) {
+        val waitDialog = WaitDialog(requireContext())
+        waitDialog.show()
+        viewModel.downloadUrl(url, fileName) {
+            waitDialog.dismiss()
+            dismissAllowingStateLoss()
+    }
+}
+
     inner class BookFileAdapter(context: Context) :
     inner class BookFileAdapter(context: Context) :
         RecyclerAdapter<Triple<String, String, Boolean>
         RecyclerAdapter<Triple<String, String, Boolean>
 , ItemBookFileImportBinding>(context) {
 , ItemBookFileImportBinding>(context) {
@@ -109,39 +96,32 @@ class ImportOnLineBookFileDialog() : BaseDialogFragment(R.layout.dialog_recycler
             payloads: MutableList<Any>
             payloads: MutableList<Any>
         ) {
         ) {
             binding.apply {
             binding.apply {
-                cbFileName.isChecked = viewModel.selectStatus[holder.layoutPosition] 
                 cbFileName.text = item.second
                 cbFileName.text = item.second
-                if (item.third) {
-                    tvOpen.invisible()
-                } else {
-                    tvOpen.visible()
-                }
             }
             }
         }
         }
 
 
-        override fun registerListener(holder: ItemViewHolder, binding: ItemBookFileImportBinding) {
+        override fun registerListener(
+            holder: ItemViewHolder,
+            binding: ItemBookFileImportBinding
+        ) {
             binding.apply {
             binding.apply {
-                cbFileName.setOnCheckedChangeListener { buttonView, isChecked ->
-                    if (buttonView.isPressed) {
-                        val selectFile = viewModel.allBookFiles[holder.layoutPosition]
-                        if (selectFile.third) {
-                            viewModel.selectStatus[holder.layoutPosition] = isChecked
-                        } else {
-                            toastOnUi("不支持直接导入")
+                cbFileName.setOnClickListener {
+                    val selectFile = viewModel.allBookFiles[holder.layoutPosition]
+                    if (selectFile.third) {
+                        importFileAndUpdate(selectFile.first, selectFile.second)
+                    } else {
+                        alert(
+                            title = getString(R.string.draw),
+                            message = getString(R.string.file_not_supported, selectFile.second)
+                        ) {
+                            okButton {
+                                importFileAndUpdate(selectFile.first, selectFile.second)
+                            }
+                            neutralButton(R.string.open_fun) {
+                                downloadFile(selectFile.first, selectFile.second)
+                            }
+                            cancelButton()
                         }
                         }
-                        upSelectText()
-                    }
-                }
-                root.onClick {
-                    cbFileName.isChecked = !cbFileName.isChecked
-                    viewModel.selectStatus[holder.layoutPosition] = cbFileName.isChecked
-                    upSelectText()
-                }
-                tvOpen.setOnClickListener {
-                    val bookFile = viewModel.allBookFiles[holder.layoutPosition]
-                    //intent解压
-                    viewModel.downloadUrl(bookFile.first, bookFile.second) {
-                        //openFileUri(it)
                     }
                     }
                 }
                 }
             }
             }

+ 21 - 55
app/src/main/java/io/legado/app/ui/association/ImportOnLineBookFileViewModel.kt

@@ -7,6 +7,7 @@ import io.legado.app.R
 import io.legado.app.base.BaseViewModel
 import io.legado.app.base.BaseViewModel
 import io.legado.app.constant.AppPattern
 import io.legado.app.constant.AppPattern
 import io.legado.app.constant.AppLog
 import io.legado.app.constant.AppLog
+import io.legado.app.constant.EventBus
 import io.legado.app.data.appDb
 import io.legado.app.data.appDb
 import io.legado.app.data.entities.Book
 import io.legado.app.data.entities.Book
 import io.legado.app.exception.NoStackTraceException
 import io.legado.app.exception.NoStackTraceException
@@ -18,9 +19,11 @@ import io.legado.app.utils.*
 class ImportOnLineBookFileViewModel(app: Application) : BaseViewModel(app) {
 class ImportOnLineBookFileViewModel(app: Application) : BaseViewModel(app) {
 
 
     val allBookFiles = arrayListOf<Triple<String, String, Boolean>>()
     val allBookFiles = arrayListOf<Triple<String, String, Boolean>>()
-    val selectStatus = arrayListOf<Boolean>()
+    val errorLiveData = MutableLiveData<String>()
+    val successLiveData = MutableLiveData<Int>()
+    val savedFileUriData = MutableLiveData<Uri>()
 
 
-    fun initData(bookUrl: String?, infoHtml: String?) {
+    fun initData(bookUrl: String?) {
         execute {
         execute {
             bookUrl ?: throw NoStackTraceException("书籍详情页链接为空")
             bookUrl ?: throw NoStackTraceException("书籍详情页链接为空")
             val book = appDb.searchBookDao.getSearchBook(bookUrl)?.toBook()
             val book = appDb.searchBookDao.getSearchBook(bookUrl)?.toBook()
@@ -28,85 +31,48 @@ class ImportOnLineBookFileViewModel(app: Application) : BaseViewModel(app) {
             val bookSource = appDb.bookSourceDao.getBookSource(book.origin)
             val bookSource = appDb.bookSourceDao.getBookSource(book.origin)
                 ?: throw NoStackTraceException("bookSource is null")
                 ?: throw NoStackTraceException("bookSource is null")
             val ruleDownloadUrls = bookSource?.getBookInfoRule()?.downloadUrls
             val ruleDownloadUrls = bookSource?.getBookInfoRule()?.downloadUrls
-            var content = infoHtml
-            if (content.isNullOrBlank()) {
-                content = AnalyzeUrl(bookUrl, source = bookSource).getStrResponse().body
-            }
+            val content = AnalyzeUrl(bookUrl, source = bookSource).getStrResponse().body
             val analyzeRule = AnalyzeRule(book, bookSource)
             val analyzeRule = AnalyzeRule(book, bookSource)
             analyzeRule.setContent(content).setBaseUrl(bookUrl)
             analyzeRule.setContent(content).setBaseUrl(bookUrl)
+            val fileName = "${book.name} 作者:${book.author}"
             analyzeRule.getStringList(ruleDownloadUrls, isUrl = true)?.let {
             analyzeRule.getStringList(ruleDownloadUrls, isUrl = true)?.let {
                 it.forEach { url ->
                 it.forEach { url ->
-                    val fileName = LocalBook.extractDownloadName(url, book)
                     val isSupportedFile = AppPattern.bookFileRegex.matches(fileName)
                     val isSupportedFile = AppPattern.bookFileRegex.matches(fileName)
-                    allBookFiles.add(Triple(url, fileName, isSupportedFile))
-                    selectStatus.add(isSupportedFile)
+                    val mFileName = "${fileName}.${LocalBook.parseFileSuffix(url)}"
+                    allBookFiles.add(Triple(url, mFileName, isSupportedFile))
                 }
                 }
             } ?: throw NoStackTraceException("下载链接规则解析为空")
             } ?: throw NoStackTraceException("下载链接规则解析为空")
+        }.onSuccess {
+            successLiveData.postValue(allBookFiles.size)
         }.onError {
         }.onError {
+            errorLiveData.postValue(it.localizedMessage ?: "")
             context.toastOnUi("获取书籍下载链接失败\n${it.localizedMessage}")
             context.toastOnUi("获取书籍下载链接失败\n${it.localizedMessage}")
         }
         }
         
         
     }
     }
 
 
-    val isSelectAll: Boolean
-        get() {
-            selectStatus.forEach {
-                if (!it) {
-                    return false
-                }
-            }
-            return true
-        }
-
-    val selectCount: Int
-        get() {
-            var count = 0
-            selectStatus.forEach {
-                if (it) {
-                    count++
-                }
-            }
-            return count
-        }
-
-    fun importSelect(success: () -> Unit) {
+    fun downloadUrl(url: String, fileName: String, success: () -> Unit) {
         execute {
         execute {
-            selectStatus.forEachIndexed { index, selected ->
-                if (selected) {
-                    val selectedFile = allBookFiles[index]
-                    val isSupportedFile = selectedFile.third
-                    val fileUrl: String = selectedFile.first
-                    val fileName: String = selectedFile.second
-                    when {
-                        isSupportedFile -> importOnLineBookFile(fileUrl, fileName)
-                        else -> {
-                            downloadUrl(fileUrl, fileName) {
-                              //  AppLog.putDebug("下载文件路径: ${it.toString()}")
-                            }
-                        }
-                    }
-                }
+            LocalBook.saveBookFile(url, fileName).let {
+                savedFileUriData.postValue(it)
             }
             }
         }.onSuccess {
         }.onSuccess {
             success.invoke()
             success.invoke()
         }.onError {
         }.onError {
-        
+            context.toastOnUi("下载书籍文件失败\n${it.localizedMessage}")
         }
         }
     }
     }
 
 
-
-    fun downloadUrl(url: String, fileName: String, success: () -> Unit) {
+    fun importOnLineBookFile(url: String, fileName: String, success: () -> Unit) {
         execute {
         execute {
-            LocalBook.saveBookFile(url, fileName)
+            LocalBook.importFileOnLine(url, fileName).let {
+                postEvent(EventBus.BOOK_URL_CHANGED, it.bookUrl)
+            }
         }.onSuccess {
         }.onSuccess {
-            success.invoke()
+           success.invoke()
         }.onError {
         }.onError {
             context.toastOnUi("下载书籍文件失败\n${it.localizedMessage}")
             context.toastOnUi("下载书籍文件失败\n${it.localizedMessage}")
         }
         }
     }
     }
 
 
-    fun importOnLineBookFile(url: String, fileName: String) {
-        LocalBook.importFileOnLine(url, fileName)
-    }
-
 }
 }

+ 6 - 1
app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt

@@ -12,6 +12,7 @@ import androidx.activity.viewModels
 import io.legado.app.R
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
 import io.legado.app.base.VMBaseActivity
 import io.legado.app.constant.BookType
 import io.legado.app.constant.BookType
+import io.legado.app.constant.EventBus
 import io.legado.app.constant.Theme
 import io.legado.app.constant.Theme
 import io.legado.app.data.appDb
 import io.legado.app.data.appDb
 import io.legado.app.data.entities.Book
 import io.legado.app.data.entities.Book
@@ -283,7 +284,6 @@ class BookInfoActivity :
                 if (viewModel.isImportBookOnLine) {
                 if (viewModel.isImportBookOnLine) {
                     showDialogFragment<ImportOnLineBookFileDialog> {
                     showDialogFragment<ImportOnLineBookFileDialog> {
                         putString("bookUrl", book.bookUrl)
                         putString("bookUrl", book.bookUrl)
-                        putString("infoHtml", book.infoHtml)
                     }
                     }
                 } else {
                 } else {
                     readBook(book)
                     readBook(book)
@@ -490,4 +490,9 @@ class BookInfoActivity :
         }
         }
     }
     }
 
 
+    override fun observeLiveBus() {
+        observeEvent<String>(EventBus.BOOK_URL_CHANGED) {
+            viewModel.changeToLocalBook(it)
+        }
+    }
 }
 }

+ 13 - 6
app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt

@@ -119,6 +119,9 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
                     WebBook.getBookInfo(this, bookSource, book, canReName = canReName)
                     WebBook.getBookInfo(this, bookSource, book, canReName = canReName)
                         .onSuccess(IO) {
                         .onSuccess(IO) {
                             bookData.postValue(book)
                             bookData.postValue(book)
+                            if (isImportBookOnLine) {
+                                appDb.searchBookDao.update(book.toSearchBook())
+                            }
                             if (inBookshelf) {
                             if (inBookshelf) {
                                 appDb.bookDao.update(book)
                                 appDb.bookDao.update(book)
                             }
                             }
@@ -291,13 +294,17 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
         }
         }
     }
     }
 
 
-    private fun changeToLocalBook(book: Book) {
-        bookData.postValue(book)
-        LocalBook.getChapterList(book).let {
-            chapterListData.postValue(it)
+    fun changeToLocalBook(bookUrl: String) {
+        appDb.bookDao.getBook(bookUrl)?.let { localBook ->
+            LocalBook.mergeBook(localBook, bookData.value).let {
+                bookData.postValue(it)
+            }
+            LocalBook.getChapterList(localBook).let {
+                chapterListData.postValue(it)
+            }
+            isImportBookOnLine = false
+            inBookshelf = true
         }
         }
-        isImportBookOnLine = false
-        inBookshelf = true
     }
     }
 
 
 }
 }

+ 4 - 15
app/src/main/res/layout/item_book_file_import.xml

@@ -6,11 +6,12 @@
     android:layout_height="wrap_content"
     android:layout_height="wrap_content"
     android:padding="8dp">
     android:padding="8dp">
 
 
-    <io.legado.app.lib.theme.view.ThemeCheckBox
+    <TextView
         android:id="@+id/cb_file_name"
         android:id="@+id/cb_file_name"
         android:layout_width="wrap_content"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_height="wrap_content"
-        android:maxLines="1"
+        android:textColor="@color/primaryText"
+        android:textSize="14sp"
         app:layout_constrainedWidth="true"
         app:layout_constrainedWidth="true"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintHorizontal_bias="0"
         app:layout_constraintHorizontal_bias="0"
@@ -19,16 +20,4 @@
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintTop_toTopOf="parent"
         tools:ignore="TouchTargetSizeCheck" />
         tools:ignore="TouchTargetSizeCheck" />
 
 
- 
-    <TextView
-        android:id="@+id/tv_open"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:padding="8dp"
-        android:text="@string/open"
-        android:textColor="@color/secondaryText"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>

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

@@ -981,5 +981,7 @@
     <string name="auto_save_cookie">CookieJar</string>
     <string name="auto_save_cookie">CookieJar</string>
     <string name="click_read_button_load">点击阅读加载目录</string>
     <string name="click_read_button_load">点击阅读加载目录</string>
     <string name="cookie">清除cookie</string>
     <string name="cookie">清除cookie</string>
+    <string name="download_and_import_file">导入在线书籍文件</string>
+
     <!-- string end -->
     <!-- string end -->
 </resources>
 </resources>

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

@@ -984,5 +984,7 @@
     <string name="auto_save_cookie">CookieJar</string>
     <string name="auto_save_cookie">CookieJar</string>
     <string name="click_read_button_load">点击阅读加载目录</string>
     <string name="click_read_button_load">点击阅读加载目录</string>
     <string name="cookie">清除cookie</string>
     <string name="cookie">清除cookie</string>
+    <string name="download_and_import_file">导入在线书籍文件</string>
+
     <!-- string end -->
     <!-- string end -->
 </resources>
 </resources>

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

@@ -984,5 +984,7 @@
     <string name="auto_save_cookie">CookieJar</string>
     <string name="auto_save_cookie">CookieJar</string>
     <string name="click_read_button_load">点击阅读加载目录</string>
     <string name="click_read_button_load">点击阅读加载目录</string>
     <string name="cookie">清除cookie</string>
     <string name="cookie">清除cookie</string>
+    <string name="download_and_import_file">导入在线书籍文件</string>
+
     <!-- string end -->
     <!-- string end -->
 </resources>
 </resources>

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

@@ -981,5 +981,7 @@
     <string name="auto_save_cookie">CookieJar</string>
     <string name="auto_save_cookie">CookieJar</string>
     <string name="click_read_button_load">点击阅读加载目录</string>
     <string name="click_read_button_load">点击阅读加载目录</string>
     <string name="cookie">清除cookie</string>
     <string name="cookie">清除cookie</string>
+    <string name="download_and_import_file">导入在线书籍文件</string>
+
     <!-- string end -->
     <!-- string end -->
 </resources>
 </resources>

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

@@ -983,5 +983,7 @@
     <string name="auto_save_cookie">CookieJar</string>
     <string name="auto_save_cookie">CookieJar</string>
     <string name="click_read_button_load">点击阅读加载目录</string>
     <string name="click_read_button_load">点击阅读加载目录</string>
     <string name="cookie">清除cookie</string>
     <string name="cookie">清除cookie</string>
+    <string name="download_and_import_file">导入在线书籍文件</string>
+
     <!-- string end -->
     <!-- string end -->
 </resources>
 </resources>

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

@@ -983,5 +983,6 @@
     <string name="auto_save_cookie">CookieJar</string>
     <string name="auto_save_cookie">CookieJar</string>
     <string name="click_read_button_load">点击阅读加载目录</string>
     <string name="click_read_button_load">点击阅读加载目录</string>
     <string name="cookie">清除cookie</string>
     <string name="cookie">清除cookie</string>
+    <string name="download_and_import_file">导入在线书籍文件</string>
     <!-- string end -->
     <!-- string end -->
 </resources>
 </resources>

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

@@ -984,5 +984,7 @@
     <string name="auto_save_cookie">CookieJar</string>
     <string name="auto_save_cookie">CookieJar</string>
     <string name="click_read_button_load">点击阅读加载目录</string>
     <string name="click_read_button_load">点击阅读加载目录</string>
     <string name="cookie">清除cookie</string>
     <string name="cookie">清除cookie</string>
+    <string name="download_and_import_file">导入在线书籍文件</string>
+
     <!-- string end -->
     <!-- string end -->
 </resources>
 </resources>