Merge branch 'gedoor:master' into rar7z
This commit is contained in:
@@ -13,7 +13,10 @@
|
|||||||
* 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。
|
* 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。
|
||||||
* 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
|
* 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
|
||||||
|
|
||||||
**2023/03/11**
|
**2023/03/13**
|
||||||
|
* 文件类书源支持zip 7z rar4解压
|
||||||
|
|
||||||
|
**2023/03/12**
|
||||||
|
|
||||||
* 远程书籍添加webDav多配置
|
* 远程书籍添加webDav多配置
|
||||||
* 更新文件类书源详情页界面逻辑
|
* 更新文件类书源详情页界面逻辑
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ abstract class RecyclerAdapter<ITEM, VB : ViewBinding>(protected val context: Co
|
|||||||
|
|
||||||
fun getItemByLayoutPosition(position: Int) = items.getOrNull(getActualPosition(position))
|
fun getItemByLayoutPosition(position: Int) = items.getOrNull(getActualPosition(position))
|
||||||
|
|
||||||
fun getItems(): List<ITEM> = items
|
fun getItems(): List<ITEM> = items.toList()
|
||||||
|
|
||||||
protected open fun getItemViewType(item: ITEM, position: Int) = 0
|
protected open fun getItemViewType(item: ITEM, position: Int) = 0
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ object AppPattern {
|
|||||||
|
|
||||||
//本地书籍支持类型
|
//本地书籍支持类型
|
||||||
val bookFileRegex = Regex(".*\\.(txt|epub|umd|pdf)", RegexOption.IGNORE_CASE)
|
val bookFileRegex = Regex(".*\\.(txt|epub|umd|pdf)", RegexOption.IGNORE_CASE)
|
||||||
|
//压缩文件支持类型
|
||||||
|
val archiveFileRegex = Regex(".*\\.(zip|rar|7z)", RegexOption.IGNORE_CASE)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 所有标点
|
* 所有标点
|
||||||
|
|||||||
@@ -54,9 +54,6 @@ interface BookSourceDao {
|
|||||||
@Query("select * from book_sources where enabledExplore = 1 and trim(exploreUrl) <> '' order by customOrder asc")
|
@Query("select * from book_sources where enabledExplore = 1 and trim(exploreUrl) <> '' order by customOrder asc")
|
||||||
fun flowExplore(): Flow<List<BookSource>>
|
fun flowExplore(): Flow<List<BookSource>>
|
||||||
|
|
||||||
// @Query("select * from book_sources where enabledReview = 1 order by customOrder asc")
|
|
||||||
// fun flowReview(): Flow<List<BookSource>>
|
|
||||||
|
|
||||||
@Query("select * from book_sources where loginUrl is not null and loginUrl != ''")
|
@Query("select * from book_sources where loginUrl is not null and loginUrl != ''")
|
||||||
fun flowLogin(): Flow<List<BookSource>>
|
fun flowLogin(): Flow<List<BookSource>>
|
||||||
|
|
||||||
|
|||||||
@@ -157,18 +157,10 @@ object LocalBook {
|
|||||||
*/
|
*/
|
||||||
fun importFile(uri: Uri): Book {
|
fun importFile(uri: Uri): Book {
|
||||||
val bookUrl: String
|
val bookUrl: String
|
||||||
val updateTime: Long
|
//updateTime变量不要修改,否则会导致读取不到缓存
|
||||||
//这个变量不要修改,否则会导致读取不到缓存
|
val (fileName, _, _, updateTime, _) = FileDoc.fromUri(uri, false).apply {
|
||||||
val fileName = if (uri.isContentScheme()) {
|
if (size == 0L) throw EmptyFileException("Unexpected empty File")
|
||||||
bookUrl = uri.toString()
|
bookUrl = toString()
|
||||||
val doc = DocumentFile.fromSingleUri(appCtx, uri)!!
|
|
||||||
updateTime = doc.lastModified()
|
|
||||||
doc.name!!
|
|
||||||
} else {
|
|
||||||
bookUrl = uri.path!!
|
|
||||||
val file = File(bookUrl)
|
|
||||||
updateTime = file.lastModified()
|
|
||||||
file.name
|
|
||||||
}
|
}
|
||||||
var book = appDb.bookDao.getBook(bookUrl)
|
var book = appDb.bookDao.getBook(bookUrl)
|
||||||
if (book == null) {
|
if (book == null) {
|
||||||
@@ -291,7 +283,6 @@ object LocalBook {
|
|||||||
fileName: String
|
fileName: String
|
||||||
): Uri {
|
): Uri {
|
||||||
inputStream.use {
|
inputStream.use {
|
||||||
if (it.isEmpty()) throw EmptyFileException("Unexpected empty inputStream")
|
|
||||||
val defaultBookTreeUri = AppConfig.defaultBookTreeUri
|
val defaultBookTreeUri = AppConfig.defaultBookTreeUri
|
||||||
if (defaultBookTreeUri.isNullOrBlank()) throw NoStackTraceException("没有设置书籍保存位置!")
|
if (defaultBookTreeUri.isNullOrBlank()) throw NoStackTraceException("没有设置书籍保存位置!")
|
||||||
val treeUri = Uri.parse(defaultBookTreeUri)
|
val treeUri = Uri.parse(defaultBookTreeUri)
|
||||||
|
|||||||
@@ -507,6 +507,13 @@ class BookInfoActivity :
|
|||||||
viewModel.importOrDownloadWebFile<Book>(webFile) {
|
viewModel.importOrDownloadWebFile<Book>(webFile) {
|
||||||
onClick?.invoke(it)
|
onClick?.invoke(it)
|
||||||
}
|
}
|
||||||
|
} else if (webFile.isSupportDecompress) {
|
||||||
|
/* 解压筛选后再选择导入项 */
|
||||||
|
viewModel.importOrDownloadWebFile<Uri>(webFile) { uri ->
|
||||||
|
viewModel.deCompress(uri) {
|
||||||
|
showDecompressFileImportAlert(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
alert(
|
alert(
|
||||||
title = getString(R.string.draw),
|
title = getString(R.string.draw),
|
||||||
@@ -514,8 +521,8 @@ class BookInfoActivity :
|
|||||||
) {
|
) {
|
||||||
neutralButton(R.string.open_fun) {
|
neutralButton(R.string.open_fun) {
|
||||||
/* download only */
|
/* download only */
|
||||||
viewModel.importOrDownloadWebFile<Uri>(webFile) { uri ->
|
viewModel.importOrDownloadWebFile<Uri>(webFile) {
|
||||||
openFileUri(uri, "*/*")
|
openFileUri(it, "*/*")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
noButton()
|
noButton()
|
||||||
@@ -524,6 +531,22 @@ class BookInfoActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showDecompressFileImportAlert(
|
||||||
|
fileDocs: List<FileDoc>
|
||||||
|
) {
|
||||||
|
if (fileDocs.isEmpty()) {
|
||||||
|
toastOnUi(R.string.unsupport_archivefile_entry)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val selectorNames = fileDocs.map { it.name }
|
||||||
|
selector(
|
||||||
|
R.string.import_select_book,
|
||||||
|
selectorNames
|
||||||
|
) { _, _, index ->
|
||||||
|
viewModel.importBook(fileDocs[index])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun readBook(book: Book) {
|
private fun readBook(book: Book) {
|
||||||
if (!viewModel.inBookshelf) {
|
if (!viewModel.inBookshelf) {
|
||||||
viewModel.saveBook(book) {
|
viewModel.saveBook(book) {
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ import io.legado.app.model.BookCover
|
|||||||
import io.legado.app.model.ReadBook
|
import io.legado.app.model.ReadBook
|
||||||
import io.legado.app.model.localBook.LocalBook
|
import io.legado.app.model.localBook.LocalBook
|
||||||
import io.legado.app.model.webBook.WebBook
|
import io.legado.app.model.webBook.WebBook
|
||||||
import io.legado.app.utils.isContentScheme
|
import io.legado.app.utils.*
|
||||||
import io.legado.app.utils.postEvent
|
|
||||||
import io.legado.app.utils.toastOnUi
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
|
||||||
@@ -242,7 +240,8 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
book.downloadUrls!!.map {
|
book.downloadUrls!!.map {
|
||||||
val mFileName = "${fileName}.${LocalBook.parseFileSuffix(it)}"
|
val mFileName = "${fileName}.${LocalBook.parseFileSuffix(it)}"
|
||||||
val isSupportedFile = AppPattern.bookFileRegex.matches(mFileName)
|
val isSupportedFile = AppPattern.bookFileRegex.matches(mFileName)
|
||||||
WebFile(it, mFileName, isSupportedFile)
|
val isSupportDecompress = AppPattern.archiveFileRegex.matches(mFileName)
|
||||||
|
WebFile(it, mFileName, isSupportedFile, isSupportDecompress)
|
||||||
}
|
}
|
||||||
}.onError {
|
}.onError {
|
||||||
context.toastOnUi("LoadWebFileError\n${it.localizedMessage}")
|
context.toastOnUi("LoadWebFileError\n${it.localizedMessage}")
|
||||||
@@ -251,6 +250,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 导入或者下载在线文件 */
|
||||||
fun <T> importOrDownloadWebFile(webFile: WebFile, success: ((T) -> Unit)?) {
|
fun <T> importOrDownloadWebFile(webFile: WebFile, success: ((T) -> Unit)?) {
|
||||||
bookSource ?: return
|
bookSource ?: return
|
||||||
execute {
|
execute {
|
||||||
@@ -272,6 +272,22 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun deCompress(archiveFileUri: Uri, onSuccess: (List<FileDoc>) -> Unit) {
|
||||||
|
execute {
|
||||||
|
ArchiveUtils.deCompress(archiveFileUri).list {
|
||||||
|
AppPattern.bookFileRegex.matches(it.name)
|
||||||
|
} ?: emptyList()
|
||||||
|
}.onError {
|
||||||
|
context.toastOnUi("DeCompress Error:\n${it.localizedMessage}")
|
||||||
|
}.onSuccess {
|
||||||
|
onSuccess.invoke(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun importBook(fileDoc: FileDoc) {
|
||||||
|
LocalBook.importFile(fileDoc.uri).let { changeToLocalBook(it) }
|
||||||
|
}
|
||||||
|
|
||||||
fun changeTo(source: BookSource, book: Book, toc: List<BookChapter>) {
|
fun changeTo(source: BookSource, book: Book, toc: List<BookChapter>) {
|
||||||
changeSourceCoroutine?.cancel()
|
changeSourceCoroutine?.cancel()
|
||||||
changeSourceCoroutine = execute {
|
changeSourceCoroutine = execute {
|
||||||
@@ -398,7 +414,10 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
data class WebFile(
|
data class WebFile(
|
||||||
val url: String,
|
val url: String,
|
||||||
val name: String,
|
val name: String,
|
||||||
val isSupported: Boolean
|
// txt epub umd pdf等文件
|
||||||
|
val isSupported: Boolean,
|
||||||
|
// 压缩包形式的txt epub umd pdf文件
|
||||||
|
val isSupportDecompress: Boolean
|
||||||
) {
|
) {
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return name
|
return name
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
|||||||
override val viewModel by viewModels<BookSourceViewModel>()
|
override val viewModel by viewModels<BookSourceViewModel>()
|
||||||
private val importRecordKey = "bookSourceRecordKey"
|
private val importRecordKey = "bookSourceRecordKey"
|
||||||
private val adapter by lazy { BookSourceAdapter(this, this) }
|
private val adapter by lazy { BookSourceAdapter(this, this) }
|
||||||
|
private val itemTouchCallback by lazy { ItemTouchCallback(adapter) }
|
||||||
private val searchView: SearchView by lazy {
|
private val searchView: SearchView by lazy {
|
||||||
binding.titleBar.findViewById(R.id.search_view)
|
binding.titleBar.findViewById(R.id.search_view)
|
||||||
}
|
}
|
||||||
@@ -197,8 +198,6 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
|||||||
dragSelectTouchHelper.attachToRecyclerView(binding.recyclerView)
|
dragSelectTouchHelper.attachToRecyclerView(binding.recyclerView)
|
||||||
dragSelectTouchHelper.activeSlideSelect()
|
dragSelectTouchHelper.activeSlideSelect()
|
||||||
// Note: need judge selection first, so add ItemTouchHelper after it.
|
// Note: need judge selection first, so add ItemTouchHelper after it.
|
||||||
val itemTouchCallback = ItemTouchCallback(adapter)
|
|
||||||
itemTouchCallback.isCanDrag = true
|
|
||||||
ItemTouchHelper(itemTouchCallback).attachToRecyclerView(binding.recyclerView)
|
ItemTouchHelper(itemTouchCallback).attachToRecyclerView(binding.recyclerView)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,6 +275,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
|||||||
AppLog.put("书源界面更新书源出错", it)
|
AppLog.put("书源界面更新书源出错", it)
|
||||||
}.conflate().collect { data ->
|
}.conflate().collect { data ->
|
||||||
adapter.setItems(data, adapter.diffItemCallback)
|
adapter.setItems(data, adapter.diffItemCallback)
|
||||||
|
itemTouchCallback.isCanDrag = sort == Sort.Default
|
||||||
delay(500)
|
delay(500)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -596,8 +596,8 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun upOrder() {
|
override fun upOrder(items: List<BookSource>) {
|
||||||
viewModel.upOrder()
|
viewModel.upOrder(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toTop(bookSource: BookSource) {
|
override fun toTop(bookSource: BookSource) {
|
||||||
|
|||||||
@@ -263,15 +263,11 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
|||||||
val srcItem = getItem(srcPosition)
|
val srcItem = getItem(srcPosition)
|
||||||
val targetItem = getItem(targetPosition)
|
val targetItem = getItem(targetPosition)
|
||||||
if (srcItem != null && targetItem != null) {
|
if (srcItem != null && targetItem != null) {
|
||||||
if (srcItem.customOrder == targetItem.customOrder) {
|
val srcOrder = srcItem.customOrder
|
||||||
callBack.upOrder()
|
srcItem.customOrder = targetItem.customOrder
|
||||||
} else {
|
targetItem.customOrder = srcOrder
|
||||||
val srcOrder = srcItem.customOrder
|
movedItems.add(srcItem)
|
||||||
srcItem.customOrder = targetItem.customOrder
|
movedItems.add(targetItem)
|
||||||
targetItem.customOrder = srcOrder
|
|
||||||
movedItems.add(srcItem)
|
|
||||||
movedItems.add(targetItem)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
swapItem(srcPosition, targetPosition)
|
swapItem(srcPosition, targetPosition)
|
||||||
return true
|
return true
|
||||||
@@ -281,7 +277,15 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
|||||||
|
|
||||||
override fun onClearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
override fun onClearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||||
if (movedItems.isNotEmpty()) {
|
if (movedItems.isNotEmpty()) {
|
||||||
callBack.update(*movedItems.toTypedArray())
|
val sortNumberSet = hashSetOf<Int>()
|
||||||
|
movedItems.forEach {
|
||||||
|
sortNumberSet.add(it.customOrder)
|
||||||
|
}
|
||||||
|
if (movedItems.size > sortNumberSet.size) {
|
||||||
|
callBack.upOrder(getItems())
|
||||||
|
} else {
|
||||||
|
callBack.update(*movedItems.toTypedArray())
|
||||||
|
}
|
||||||
movedItems.clear()
|
movedItems.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -319,7 +323,7 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
|
|||||||
fun toBottom(bookSource: BookSource)
|
fun toBottom(bookSource: BookSource)
|
||||||
fun searchBook(bookSource: BookSource)
|
fun searchBook(bookSource: BookSource)
|
||||||
fun debug(bookSource: BookSource)
|
fun debug(bookSource: BookSource)
|
||||||
fun upOrder()
|
fun upOrder(items: List<BookSource>)
|
||||||
fun upCountView()
|
fun upCountView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,13 +51,14 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
|
|||||||
execute { appDb.bookSourceDao.update(*bookSource) }
|
execute { appDb.bookSourceDao.update(*bookSource) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun upOrder() {
|
fun upOrder(items: List<BookSource>) {
|
||||||
|
if (items.isEmpty()) return
|
||||||
execute {
|
execute {
|
||||||
val sources = appDb.bookSourceDao.all
|
val firstSortNumber = items[0].customOrder
|
||||||
for ((index: Int, source: BookSource) in sources.withIndex()) {
|
items.forEachIndexed { index, bookSource ->
|
||||||
source.customOrder = index + 1
|
bookSource.customOrder = firstSortNumber + index
|
||||||
|
appDb.bookSourceDao.update(bookSource)
|
||||||
}
|
}
|
||||||
appDb.bookSourceDao.update(*sources.toTypedArray())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package io.legado.app.utils
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.documentfile.provider.DocumentFile
|
||||||
|
import java.io.File
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
import splitties.init.appCtx
|
||||||
|
|
||||||
|
/* 自动判断压缩文件后缀 然后再调用具体的实现 */
|
||||||
|
object ArchiveUtils {
|
||||||
|
|
||||||
|
// 临时目录 下次启动自动删除
|
||||||
|
val TEMP_PATH: String by lazy {
|
||||||
|
appCtx.externalCache.getFile("ArchiveTemp").createFolderReplace().absolutePath
|
||||||
|
}
|
||||||
|
|
||||||
|
val ZIP_REGEX = Regex(".*\\.zip", RegexOption.IGNORE_CASE)
|
||||||
|
val RAR_REGEX = Regex(".*\\.rar", RegexOption.IGNORE_CASE)
|
||||||
|
val SERVEZ_REGEX = Regex(".*\\.7z", RegexOption.IGNORE_CASE)
|
||||||
|
|
||||||
|
fun deCompress(
|
||||||
|
archiveUri: Uri,
|
||||||
|
path: String = TEMP_PATH
|
||||||
|
): FileDoc {
|
||||||
|
return deCompress(FileDoc.fromUri(archiveUri, false), path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deCompress(
|
||||||
|
archivePath: String,
|
||||||
|
path: String = TEMP_PATH
|
||||||
|
): FileDoc {
|
||||||
|
return deCompress(Uri.parse(archivePath), path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deCompress(
|
||||||
|
archiveFile: File,
|
||||||
|
path: String = TEMP_PATH
|
||||||
|
): FileDoc {
|
||||||
|
return deCompress(FileDoc.fromFile(archiveFile), path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deCompress(
|
||||||
|
archiveDoc: DocumentFile,
|
||||||
|
path: String = TEMP_PATH
|
||||||
|
): FileDoc {
|
||||||
|
return deCompress(FileDoc.fromDocumentFile(archiveDoc), path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deCompress(
|
||||||
|
archiveFileDoc: FileDoc,
|
||||||
|
path: String = TEMP_PATH
|
||||||
|
): FileDoc {
|
||||||
|
if (archiveFileDoc.isDir) throw IllegalArgumentException("Unexpected Folder input")
|
||||||
|
val name = archiveFileDoc.name
|
||||||
|
archiveFileDoc.uri.inputStream(appCtx).getOrThrow().use {
|
||||||
|
when {
|
||||||
|
ZIP_REGEX.matches(name) -> ZipUtils.unZipToPath(it, path)
|
||||||
|
RAR_REGEX.matches(name) -> RarUtils.unRarToPath(it, path)
|
||||||
|
SERVEZ_REGEX.matches(name) -> SevenZipUtils.un7zToPath(it, path)
|
||||||
|
else -> throw IllegalArgumentException("Unexpected archive format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getCacheFolderFileDoc(name, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCacheFolderFileDoc(
|
||||||
|
archiveName: String,
|
||||||
|
workPath: String
|
||||||
|
): FileDoc {
|
||||||
|
return FileDoc.fromUri(Uri.parse(workPath), true)
|
||||||
|
.createFolderIfNotExist(MD5Utils.md5Encode16(archiveName))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,15 +23,3 @@ fun InputStream?.contains(str: String): Boolean {
|
|||||||
return scanner.findWithinHorizon(str, 0) != null
|
return scanner.findWithinHorizon(str, 0) != null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun InputStream?.isEmpty(): Boolean {
|
|
||||||
this ?: return true
|
|
||||||
return if (markSupported()) {
|
|
||||||
mark(0)
|
|
||||||
val isEmpty = read(ByteArray(1)) == -1
|
|
||||||
reset()
|
|
||||||
isEmpty
|
|
||||||
} else {
|
|
||||||
available() == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1080,4 +1080,5 @@
|
|||||||
<string name="keep_group">保留分组</string>
|
<string name="keep_group">保留分组</string>
|
||||||
<string name="server_config">服务器配置</string>
|
<string name="server_config">服务器配置</string>
|
||||||
<string name="sure_upload">Remote webDav url exists, Continue?</string>
|
<string name="sure_upload">Remote webDav url exists, Continue?</string>
|
||||||
|
<string name="unsupport_archivefile_entry">Cannot find supported files in archive</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1083,4 +1083,5 @@
|
|||||||
<string name="keep_group">保留分组</string>
|
<string name="keep_group">保留分组</string>
|
||||||
<string name="server_config">服务器配置</string>
|
<string name="server_config">服务器配置</string>
|
||||||
<string name="sure_upload">Remote webDav url exists, Continue?</string>
|
<string name="sure_upload">Remote webDav url exists, Continue?</string>
|
||||||
|
<string name="unsupport_archivefile_entry">Cannot find supported files in archive</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1083,4 +1083,5 @@
|
|||||||
<string name="keep_group">保留分组</string>
|
<string name="keep_group">保留分组</string>
|
||||||
<string name="server_config">服务器配置</string>
|
<string name="server_config">服务器配置</string>
|
||||||
<string name="sure_upload">Remote webDav url exists, Continue?</string>
|
<string name="sure_upload">Remote webDav url exists, Continue?</string>
|
||||||
|
<string name="unsupport_archivefile_entry">Cannot find supported files in archive</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1080,4 +1080,5 @@
|
|||||||
<string name="keep_group">保留分组</string>
|
<string name="keep_group">保留分组</string>
|
||||||
<string name="server_config">服务器配置</string>
|
<string name="server_config">服务器配置</string>
|
||||||
<string name="sure_upload">远程webDav链接已存在,是否继续</string>
|
<string name="sure_upload">远程webDav链接已存在,是否继续</string>
|
||||||
|
<string name="unsupport_archivefile_entry">压缩文件内没有支持的文件</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1082,4 +1082,5 @@
|
|||||||
<string name="keep_group">保留分组</string>
|
<string name="keep_group">保留分组</string>
|
||||||
<string name="server_config">服务器配置</string>
|
<string name="server_config">服务器配置</string>
|
||||||
<string name="sure_upload">远程webDav链接已存在,是否继续</string>
|
<string name="sure_upload">远程webDav链接已存在,是否继续</string>
|
||||||
|
<string name="unsupport_archivefile_entry">压缩文件内没有支持的文件</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1082,4 +1082,5 @@
|
|||||||
<string name="keep_group">保留分组</string>
|
<string name="keep_group">保留分组</string>
|
||||||
<string name="server_config">服务器配置</string>
|
<string name="server_config">服务器配置</string>
|
||||||
<string name="sure_upload">远程webDav链接已存在,是否继续</string>
|
<string name="sure_upload">远程webDav链接已存在,是否继续</string>
|
||||||
|
<string name="unsupport_archivefile_entry">压缩文件内没有支持的文件</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1083,4 +1083,5 @@
|
|||||||
<string name="keep_group">Keep group</string>
|
<string name="keep_group">Keep group</string>
|
||||||
<string name="server_config">服务器配置</string>
|
<string name="server_config">服务器配置</string>
|
||||||
<string name="sure_upload">Remote webDav url exists, Continue?</string>
|
<string name="sure_upload">Remote webDav url exists, Continue?</string>
|
||||||
|
<string name="unsupport_archivefile_entry">Cannot find supported files in archive</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user