Merge branch 'gedoor:master' into master

pull/1121/head
bushixuanqi 3 years ago committed by GitHub
commit db32614eac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      app/src/main/java/io/legado/app/help/BookHelp.kt
  2. 97
      app/src/main/java/io/legado/app/help/JsExtensions.kt
  3. 2
      app/src/main/java/io/legado/app/help/storage/BookWebDav.kt
  4. 4
      app/src/main/java/io/legado/app/model/localBook/EpubFile.kt
  5. 2
      app/src/main/java/io/legado/app/model/localBook/LocalBook.kt
  6. 7
      app/src/main/java/io/legado/app/model/localBook/UmdFile.kt
  7. 4
      app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt
  8. 18
      app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt
  9. 4
      app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt
  10. 4
      app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt
  11. 2
      app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt
  12. 4
      app/src/main/java/io/legado/app/utils/ContextExtensions.kt
  13. 3
      app/src/main/java/io/legado/app/utils/FileUtils.kt

@ -23,7 +23,7 @@ import kotlin.math.min
object BookHelp { object BookHelp {
private const val cacheFolderName = "book_cache" private const val cacheFolderName = "book_cache"
private const val cacheImageFolderName = "images" private const val cacheImageFolderName = "images"
private val downloadDir: File = appCtx.externalFilesDir private val downloadDir: File = appCtx.externalFiles
private val downloadImages = CopyOnWriteArraySet<String>() private val downloadImages = CopyOnWriteArraySet<String>()
fun clearCache() { fun clearCache() {

@ -85,6 +85,7 @@ interface JsExtensions {
/** /**
* 实现16进制字符串转文件 * 实现16进制字符串转文件
* @return 相对路径
*/ */
fun downloadFile(content: String, url: String): String { fun downloadFile(content: String, url: String): String {
val type = AnalyzeUrl(url).type ?: return "" val type = AnalyzeUrl(url).type ?: return ""
@ -99,45 +100,7 @@ interface JsExtensions {
zipFile.writeBytes(it) zipFile.writeBytes(it)
} }
} }
return zipPath return zipPath.substring(FileUtils.getCachePath().length)
}
/**
* js实现压缩文件解压
*/
fun unzipFile(zipPath: String): String {
if (zipPath.isEmpty()) return ""
val unzipPath = FileUtils.getPath(
FileUtils.createFolderIfNotExist(FileUtils.getCachePath()),
FileUtils.getNameExcludeExtension(zipPath)
)
FileUtils.deleteFile(unzipPath)
val zipFile = FileUtils.createFileIfNotExist(zipPath)
val unzipFolder = FileUtils.createFolderIfNotExist(unzipPath)
ZipUtils.unzipFile(zipFile, unzipFolder)
FileUtils.deleteFile(zipPath)
return unzipPath
}
/**
* js实现文件夹内所有文件读取
*/
fun getTxtInFolder(unzipPath: String): String {
if (unzipPath.isEmpty()) return ""
val unzipFolder = FileUtils.createFolderIfNotExist(unzipPath)
val contents = StringBuilder()
unzipFolder.listFiles().let {
if (it != null) {
for (f in it) {
val charsetName = EncodingDetect.getEncode(f)
contents.append(String(f.readBytes(), charset(charsetName)))
.append("\n")
}
contents.deleteCharAt(contents.length - 1)
}
}
FileUtils.deleteFile(unzipPath)
return contents.toString()
} }
/** /**
@ -257,13 +220,15 @@ interface JsExtensions {
return HtmlFormatter.formatKeepImg(str) return HtmlFormatter.formatKeepImg(str)
} }
//****************文件操作******************//
/** /**
* 获取本地文件 * 获取本地文件
* @param path 相对路径 * @param path 相对路径
* @return File * @return File
*/ */
fun getFile(path: String): File { fun getFile(path: String): File {
val cachePath = appCtx.eCacheDir.path val cachePath = appCtx.externalCache.absolutePath
val aPath = if (path.startsWith(File.separator)) { val aPath = if (path.startsWith(File.separator)) {
cachePath + path cachePath + path
} else { } else {
@ -306,13 +271,43 @@ interface JsExtensions {
} }
/** /**
* 解析字体,返回字体解析类 * js实现压缩文件解压
* @param zipPath 相对路径
* @return 相对路径
*/ */
fun queryBase64TTF(base64: String?): QueryTTF? { fun unzipFile(zipPath: String): String {
base64DecodeToByteArray(base64)?.let { if (zipPath.isEmpty()) return ""
return QueryTTF(it) val unzipPath = FileUtils.getPath(
FileUtils.createFolderIfNotExist(FileUtils.getCachePath()),
FileUtils.getNameExcludeExtension(zipPath)
)
FileUtils.deleteFile(unzipPath)
val zipFile = getFile(zipPath)
val unzipFolder = FileUtils.createFolderIfNotExist(unzipPath)
ZipUtils.unzipFile(zipFile, unzipFolder)
FileUtils.deleteFile(zipPath)
return unzipPath.substring(FileUtils.getCachePath().length)
} }
return null
/**
* js实现文件夹内所有文件读取
*/
fun getTxtInFolder(unzipPath: String): String {
if (unzipPath.isEmpty()) return ""
val unzipFolder = getFile(unzipPath)
val contents = StringBuilder()
unzipFolder.listFiles().let {
if (it != null) {
for (f in it) {
val charsetName = EncodingDetect.getEncode(f)
contents.append(String(f.readBytes(), charset(charsetName)))
.append("\n")
}
contents.deleteCharAt(contents.length - 1)
}
}
FileUtils.deleteFile(unzipPath)
return contents.toString()
} }
/** /**
@ -368,6 +363,18 @@ interface JsExtensions {
return null return null
} }
//******************文件操作************************//
/**
* 解析字体,返回字体解析类
*/
fun queryBase64TTF(base64: String?): QueryTTF? {
base64DecodeToByteArray(base64)?.let {
return QueryTTF(it)
}
return null
}
/** /**
* 返回字体解析类 * 返回字体解析类
* @param str 支持url,本地文件,base64,自动判断,自动缓存 * @param str 支持url,本地文件,base64,自动判断,自动缓存

@ -23,7 +23,7 @@ import java.util.*
object BookWebDav { object BookWebDav {
private const val defaultWebDavUrl = "https://dav.jianguoyun.com/dav/" private const val defaultWebDavUrl = "https://dav.jianguoyun.com/dav/"
private val bookProgressUrl = "${rootWebDavUrl}bookProgress/" private val bookProgressUrl = "${rootWebDavUrl}bookProgress/"
private val zipFilePath = "${FileUtils.getCachePath()}${File.separator}backup.zip" private val zipFilePath = "${appCtx.externalFiles.absolutePath}${File.separator}backup.zip"
private val rootWebDavUrl: String private val rootWebDavUrl: String
get() { get() {

@ -9,7 +9,7 @@ import io.legado.app.help.BookHelp
import io.legado.app.utils.FileUtils import io.legado.app.utils.FileUtils
import io.legado.app.utils.HtmlFormatter import io.legado.app.utils.HtmlFormatter
import io.legado.app.utils.MD5Utils import io.legado.app.utils.MD5Utils
import io.legado.app.utils.externalFilesDir import io.legado.app.utils.externalFiles
import me.ag2s.epublib.domain.EpubBook import me.ag2s.epublib.domain.EpubBook
import me.ag2s.epublib.epub.EpubReader import me.ag2s.epublib.epub.EpubReader
import org.jsoup.Jsoup import org.jsoup.Jsoup
@ -80,7 +80,7 @@ class EpubFile(var book: Book) {
epubBook?.let { epubBook?.let {
if (book.coverUrl.isNullOrEmpty()) { if (book.coverUrl.isNullOrEmpty()) {
book.coverUrl = FileUtils.getPath( book.coverUrl = FileUtils.getPath(
appCtx.externalFilesDir, appCtx.externalFiles,
"covers", "covers",
"${MD5Utils.md5Encode16(book.bookUrl)}.jpg" "${MD5Utils.md5Encode16(book.bookUrl)}.jpg"
) )

@ -119,7 +119,7 @@ object LocalBook {
author = author, author = author,
originName = fileName, originName = fileName,
coverUrl = FileUtils.getPath( coverUrl = FileUtils.getPath(
appCtx.externalFilesDir, appCtx.externalFiles,
"covers", "covers",
"${MD5Utils.md5Encode16(path)}.jpg" "${MD5Utils.md5Encode16(path)}.jpg"
) )

@ -4,17 +4,16 @@ import android.net.Uri
import android.util.Log import android.util.Log
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
import io.legado.app.utils.FileUtils import io.legado.app.utils.FileUtils
import io.legado.app.utils.MD5Utils import io.legado.app.utils.MD5Utils
import io.legado.app.utils.externalFilesDir import io.legado.app.utils.externalFiles
import io.legado.app.utils.isContentScheme import io.legado.app.utils.isContentScheme
import me.ag2s.umdlib.domain.UmdBook import me.ag2s.umdlib.domain.UmdBook
import me.ag2s.umdlib.umd.UmdReader import me.ag2s.umdlib.umd.UmdReader
import splitties.init.appCtx import splitties.init.appCtx
import java.io.File import java.io.File
import java.io.InputStream import java.io.InputStream
import java.util.ArrayList import java.util.*
class UmdFile(var book: Book) { class UmdFile(var book: Book) {
companion object { companion object {
@ -74,7 +73,7 @@ class UmdFile(var book: Book) {
umdBook?.let { umdBook?.let {
if (book.coverUrl.isNullOrEmpty()) { if (book.coverUrl.isNullOrEmpty()) {
book.coverUrl = FileUtils.getPath( book.coverUrl = FileUtils.getPath(
appCtx.externalFilesDir, appCtx.externalFiles,
"covers", "covers",
"${MD5Utils.md5Encode16(book.bookUrl)}.jpg" "${MD5Utils.md5Encode16(book.bookUrl)}.jpg"
) )

@ -108,7 +108,7 @@ class BookInfoEditActivity :
if (uri.isContentScheme()) { if (uri.isContentScheme()) {
val doc = DocumentFile.fromSingleUri(this, uri) val doc = DocumentFile.fromSingleUri(this, uri)
doc?.name?.let { doc?.name?.let {
var file = this.externalFilesDir var file = this.externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", it) file = FileUtils.createFileIfNotExist(file, "covers", it)
kotlin.runCatching { kotlin.runCatching {
DocumentUtils.readBytes(this, doc.uri) DocumentUtils.readBytes(this, doc.uri)
@ -128,7 +128,7 @@ class BookInfoEditActivity :
RealPathUtil.getPath(this, uri)?.let { path -> RealPathUtil.getPath(this, uri)?.let { path ->
val imgFile = File(path) val imgFile = File(path)
if (imgFile.exists()) { if (imgFile.exists()) {
var file = this.externalFilesDir var file = this.externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", imgFile.name) file = FileUtils.createFileIfNotExist(file, "covers", imgFile.name)
file.writeBytes(imgFile.readBytes()) file.writeBytes(imgFile.readBytes())
coverChangeTo(file.absolutePath) coverChangeTo(file.absolutePath)

@ -224,7 +224,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
} }
execute { execute {
val exportFiles = arrayListOf<File>() val exportFiles = arrayListOf<File>()
val configDirPath = FileUtils.getPath(requireContext().eCacheDir, "readConfig") val configDirPath = FileUtils.getPath(requireContext().externalCache, "readConfig")
FileUtils.deleteFile(configDirPath) FileUtils.deleteFile(configDirPath)
val configDir = FileUtils.createFolderIfNotExist(configDirPath) val configDir = FileUtils.createFolderIfNotExist(configDirPath)
val configExportPath = FileUtils.getPath(configDir, "readConfig.json") val configExportPath = FileUtils.getPath(configDir, "readConfig.json")
@ -269,7 +269,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
exportFiles.add(bgExportFile) exportFiles.add(bgExportFile)
} }
} }
val configZipPath = FileUtils.getPath(requireContext().eCacheDir, configFileName) val configZipPath = FileUtils.getPath(requireContext().externalCache, configFileName)
if (ZipUtils.zipFiles(exportFiles, File(configZipPath))) { if (ZipUtils.zipFiles(exportFiles, File(configZipPath))) {
if (uri.isContentScheme()) { if (uri.isContentScheme()) {
DocumentFile.fromTreeUri(requireContext(), uri)?.let { treeDoc -> DocumentFile.fromTreeUri(requireContext(), uri)?.let { treeDoc ->
@ -331,11 +331,11 @@ class BgTextConfigDialog : BaseDialogFragment() {
@Suppress("BlockingMethodInNonBlockingContext") @Suppress("BlockingMethodInNonBlockingContext")
private fun importConfig(byteArray: ByteArray) { private fun importConfig(byteArray: ByteArray) {
execute { execute {
val configZipPath = FileUtils.getPath(requireContext().eCacheDir, configFileName) val configZipPath = FileUtils.getPath(requireContext().externalCache, configFileName)
FileUtils.deleteFile(configZipPath) FileUtils.deleteFile(configZipPath)
val zipFile = FileUtils.createFileIfNotExist(configZipPath) val zipFile = FileUtils.createFileIfNotExist(configZipPath)
zipFile.writeBytes(byteArray) zipFile.writeBytes(byteArray)
val configDirPath = FileUtils.getPath(requireContext().eCacheDir, "readConfig") val configDirPath = FileUtils.getPath(requireContext().externalCache, "readConfig")
FileUtils.deleteFile(configDirPath) FileUtils.deleteFile(configDirPath)
ZipUtils.unzipFile(zipFile, FileUtils.createFolderIfNotExist(configDirPath)) ZipUtils.unzipFile(zipFile, FileUtils.createFolderIfNotExist(configDirPath))
val configDir = FileUtils.createFolderIfNotExist(configDirPath) val configDir = FileUtils.createFolderIfNotExist(configDirPath)
@ -344,7 +344,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
if (config.textFont.isNotEmpty()) { if (config.textFont.isNotEmpty()) {
val fontName = FileUtils.getName(config.textFont) val fontName = FileUtils.getName(config.textFont)
val fontPath = val fontPath =
FileUtils.getPath(requireContext().externalFilesDir, "font", fontName) FileUtils.getPath(requireContext().externalFiles, "font", fontName)
if (!FileUtils.exist(fontPath)) { if (!FileUtils.exist(fontPath)) {
FileUtils.getFile(configDir, fontName).copyTo(File(fontPath)) FileUtils.getFile(configDir, fontName).copyTo(File(fontPath))
} }
@ -352,7 +352,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
} }
if (config.bgType == 2) { if (config.bgType == 2) {
val bgName = FileUtils.getName(config.bgStr) val bgName = FileUtils.getName(config.bgStr)
val bgPath = FileUtils.getPath(requireContext().externalFilesDir, "bg", bgName) val bgPath = FileUtils.getPath(requireContext().externalFiles, "bg", bgName)
if (!FileUtils.exist(bgPath)) { if (!FileUtils.exist(bgPath)) {
val bgFile = FileUtils.getFile(configDir, bgName) val bgFile = FileUtils.getFile(configDir, bgName)
if (bgFile.exists()) { if (bgFile.exists()) {
@ -362,7 +362,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
} }
if (config.bgTypeNight == 2) { if (config.bgTypeNight == 2) {
val bgName = FileUtils.getName(config.bgStrNight) val bgName = FileUtils.getName(config.bgStrNight)
val bgPath = FileUtils.getPath(requireContext().externalFilesDir, "bg", bgName) val bgPath = FileUtils.getPath(requireContext().externalFiles, "bg", bgName)
if (!FileUtils.exist(bgPath)) { if (!FileUtils.exist(bgPath)) {
val bgFile = FileUtils.getFile(configDir, bgName) val bgFile = FileUtils.getFile(configDir, bgName)
if (bgFile.exists()) { if (bgFile.exists()) {
@ -372,7 +372,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
} }
if (config.bgTypeEInk == 2) { if (config.bgTypeEInk == 2) {
val bgName = FileUtils.getName(config.bgStrEInk) val bgName = FileUtils.getName(config.bgStrEInk)
val bgPath = FileUtils.getPath(requireContext().externalFilesDir, "bg", bgName) val bgPath = FileUtils.getPath(requireContext().externalFiles, "bg", bgName)
if (!FileUtils.exist(bgPath)) { if (!FileUtils.exist(bgPath)) {
val bgFile = FileUtils.getFile(configDir, bgName) val bgFile = FileUtils.getFile(configDir, bgName)
if (bgFile.exists()) { if (bgFile.exists()) {
@ -395,7 +395,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
val doc = DocumentFile.fromSingleUri(requireContext(), uri) val doc = DocumentFile.fromSingleUri(requireContext(), uri)
doc?.name?.let { doc?.name?.let {
val file = val file =
FileUtils.createFileIfNotExist(requireContext().externalFilesDir, "bg", it) FileUtils.createFileIfNotExist(requireContext().externalFiles, "bg", it)
kotlin.runCatching { kotlin.runCatching {
DocumentUtils.readBytes(requireContext(), doc.uri) DocumentUtils.readBytes(requireContext(), doc.uri)
}.getOrNull()?.let { byteArray -> }.getOrNull()?.let { byteArray ->

@ -226,7 +226,7 @@ class OtherConfigFragment : BasePreferenceFragment(),
if (uri.isContentScheme()) { if (uri.isContentScheme()) {
val doc = DocumentFile.fromSingleUri(requireContext(), uri) val doc = DocumentFile.fromSingleUri(requireContext(), uri)
doc?.name?.let { doc?.name?.let {
var file = requireContext().externalFilesDir var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", it) file = FileUtils.createFileIfNotExist(file, "covers", it)
kotlin.runCatching { kotlin.runCatching {
DocumentUtils.readBytes(requireContext(), doc.uri) DocumentUtils.readBytes(requireContext(), doc.uri)
@ -247,7 +247,7 @@ class OtherConfigFragment : BasePreferenceFragment(),
RealPathUtil.getPath(requireContext(), uri)?.let { path -> RealPathUtil.getPath(requireContext(), uri)?.let { path ->
val imgFile = File(path) val imgFile = File(path)
if (imgFile.exists()) { if (imgFile.exists()) {
var file = requireContext().externalFilesDir var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", imgFile.name) file = FileUtils.createFileIfNotExist(file, "covers", imgFile.name)
file.writeBytes(imgFile.readBytes()) file.writeBytes(imgFile.readBytes())
putPrefString(PreferKey.defaultCover, file.absolutePath) putPrefString(PreferKey.defaultCover, file.absolutePath)

@ -225,7 +225,7 @@ class ThemeConfigFragment : BasePreferenceFragment(),
if (uri.isContentScheme()) { if (uri.isContentScheme()) {
val doc = DocumentFile.fromSingleUri(requireContext(), uri) val doc = DocumentFile.fromSingleUri(requireContext(), uri)
doc?.name?.let { doc?.name?.let {
var file = requireContext().externalFilesDir var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, preferenceKey, it) file = FileUtils.createFileIfNotExist(file, preferenceKey, it)
kotlin.runCatching { kotlin.runCatching {
DocumentUtils.readBytes(requireContext(), doc.uri) DocumentUtils.readBytes(requireContext(), doc.uri)
@ -247,7 +247,7 @@ class ThemeConfigFragment : BasePreferenceFragment(),
RealPathUtil.getPath(requireContext(), uri)?.let { path -> RealPathUtil.getPath(requireContext(), uri)?.let { path ->
val imgFile = File(path) val imgFile = File(path)
if (imgFile.exists()) { if (imgFile.exists()) {
var file = requireContext().externalFilesDir var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, preferenceKey, imgFile.name) file = FileUtils.createFileIfNotExist(file, preferenceKey, imgFile.name)
file.writeBytes(imgFile.readBytes()) file.writeBytes(imgFile.readBytes())
putPrefString(preferenceKey, file.absolutePath) putPrefString(preferenceKey, file.absolutePath)

@ -139,7 +139,7 @@ class FontSelectDialog : BaseDialogFragment(),
private fun getLocalFonts(): ArrayList<DocItem> { private fun getLocalFonts(): ArrayList<DocItem> {
val fontItems = arrayListOf<DocItem>() val fontItems = arrayListOf<DocItem>()
val fontDir = val fontDir =
FileUtils.createFolderIfNotExist(requireContext().externalFilesDir, "font") FileUtils.createFolderIfNotExist(requireContext().externalFiles, "font")
fontDir.listFiles { pathName -> fontDir.listFiles { pathName ->
pathName.name.lowercase(Locale.getDefault()).matches(fontRegex) pathName.name.lowercase(Locale.getDefault()).matches(fontRegex)
}?.forEach { }?.forEach {

@ -224,10 +224,10 @@ val Context.sysBattery: Int
return batteryStatus?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1 return batteryStatus?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1
} }
val Context.externalFilesDir: File val Context.externalFiles: File
get() = this.getExternalFilesDir(null) ?: this.filesDir get() = this.getExternalFilesDir(null) ?: this.filesDir
val Context.eCacheDir: File val Context.externalCache: File
get() = this.externalCacheDir ?: this.cacheDir get() = this.externalCacheDir ?: this.cacheDir
fun Context.openUrl(url: String) { fun Context.openUrl(url: String) {

@ -105,8 +105,7 @@ object FileUtils {
} }
fun getCachePath(): String { fun getCachePath(): String {
return appCtx.externalCacheDir?.absolutePath return appCtx.externalCache.absolutePath
?: appCtx.cacheDir.absolutePath
} }
fun getSdCardPath(): String { fun getSdCardPath(): String {

Loading…
Cancel
Save