mirror of
https://github.com/gedoor/legado.git
synced 2024-07-06 23:47:49 +08:00
Compare commits
5 Commits
fd287cd506
...
ccd6914896
Author | SHA1 | Date | |
---|---|---|---|
|
ccd6914896 | ||
|
5336adc035 | ||
|
72ad27ea84 | ||
|
5eaf2f034f | ||
|
e81bb573a4 |
2
.github/workflows/web.yml
vendored
2
.github/workflows/web.yml
vendored
@ -27,7 +27,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v3
|
- uses: pnpm/action-setup@v4
|
||||||
name: Install pnpm
|
name: Install pnpm
|
||||||
id: pnpm-install
|
id: pnpm-install
|
||||||
with:
|
with:
|
||||||
|
@ -71,6 +71,8 @@ open class WebDav(
|
|||||||
<resourcetype />
|
<resourcetype />
|
||||||
</prop>
|
</prop>
|
||||||
</propfind>"""
|
</propfind>"""
|
||||||
|
|
||||||
|
private const val DEFAULT_CONTENT_TYPE = "application/octet-stream"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -304,18 +306,12 @@ open class WebDav(
|
|||||||
* 上传文件
|
* 上传文件
|
||||||
*/
|
*/
|
||||||
@Throws(WebDavException::class)
|
@Throws(WebDavException::class)
|
||||||
suspend fun upload(
|
suspend fun upload(localPath: String, contentType: String = DEFAULT_CONTENT_TYPE) {
|
||||||
localPath: String,
|
|
||||||
contentType: String = "application/octet-stream"
|
|
||||||
) {
|
|
||||||
upload(File(localPath), contentType)
|
upload(File(localPath), contentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(WebDavException::class)
|
@Throws(WebDavException::class)
|
||||||
suspend fun upload(
|
suspend fun upload(file: File, contentType: String = DEFAULT_CONTENT_TYPE) {
|
||||||
file: File,
|
|
||||||
contentType: String = "application/octet-stream"
|
|
||||||
) {
|
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
withContext(IO) {
|
withContext(IO) {
|
||||||
if (!file.exists()) throw WebDavException("文件不存在")
|
if (!file.exists()) throw WebDavException("文件不存在")
|
||||||
@ -336,7 +332,7 @@ open class WebDav(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(WebDavException::class)
|
@Throws(WebDavException::class)
|
||||||
suspend fun upload(byteArray: ByteArray, contentType: String) {
|
suspend fun upload(byteArray: ByteArray, contentType: String = DEFAULT_CONTENT_TYPE) {
|
||||||
// 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息
|
// 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
withContext(IO) {
|
withContext(IO) {
|
||||||
@ -356,7 +352,7 @@ open class WebDav(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(WebDavException::class)
|
@Throws(WebDavException::class)
|
||||||
suspend fun upload(uri: Uri, contentType: String) {
|
suspend fun upload(uri: Uri, contentType: String = DEFAULT_CONTENT_TYPE) {
|
||||||
// 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息
|
// 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
withContext(IO) {
|
withContext(IO) {
|
||||||
|
@ -14,10 +14,7 @@ import io.legado.app.model.analyzeRule.CustomUrl
|
|||||||
import io.legado.app.model.localBook.LocalBook
|
import io.legado.app.model.localBook.LocalBook
|
||||||
import io.legado.app.utils.NetworkUtils
|
import io.legado.app.utils.NetworkUtils
|
||||||
import io.legado.app.utils.isContentScheme
|
import io.legado.app.utils.isContentScheme
|
||||||
import io.legado.app.utils.readBytes
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import splitties.init.appCtx
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class RemoteBookWebDav(
|
class RemoteBookWebDav(
|
||||||
val rootBookUrl: String,
|
val rootBookUrl: String,
|
||||||
@ -71,20 +68,17 @@ class RemoteBookWebDav(
|
|||||||
override suspend fun upload(book: Book) {
|
override suspend fun upload(book: Book) {
|
||||||
if (!NetworkUtils.isAvailable()) throw NoStackTraceException("网络不可用")
|
if (!NetworkUtils.isAvailable()) throw NoStackTraceException("网络不可用")
|
||||||
val localBookUri = Uri.parse(book.bookUrl)
|
val localBookUri = Uri.parse(book.bookUrl)
|
||||||
val putUrl = "$rootBookUrl${File.separator}${book.originName}"
|
val putUrl = "$rootBookUrl${book.originName}"
|
||||||
val webDav = WebDav(putUrl, authorization)
|
val webDav = WebDav(putUrl, authorization)
|
||||||
if (localBookUri.isContentScheme()) {
|
if (localBookUri.isContentScheme()) {
|
||||||
webDav.upload(
|
webDav.upload(localBookUri)
|
||||||
byteArray = localBookUri.readBytes(appCtx),
|
|
||||||
contentType = "application/octet-stream"
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
webDav.upload(localBookUri.path!!)
|
webDav.upload(localBookUri.path!!)
|
||||||
}
|
}
|
||||||
book.origin = BookType.webDavTag + CustomUrl(putUrl)
|
book.origin = BookType.webDavTag + CustomUrl(putUrl)
|
||||||
.putAttribute("serverID", serverID)
|
.putAttribute("serverID", serverID)
|
||||||
.toString()
|
.toString()
|
||||||
book.save()
|
book.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun delete(remoteBookUrl: String) {
|
override suspend fun delete(remoteBookUrl: String) {
|
||||||
|
@ -20,7 +20,7 @@ import kotlinx.coroutines.channels.awaitClose
|
|||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import java.util.*
|
import java.util.Collections
|
||||||
|
|
||||||
class RemoteBookViewModel(application: Application) : BaseViewModel(application) {
|
class RemoteBookViewModel(application: Application) : BaseViewModel(application) {
|
||||||
var sortKey = RemoteBookSort.Default
|
var sortKey = RemoteBookSort.Default
|
||||||
@ -78,6 +78,7 @@ class RemoteBookViewModel(application: Application) : BaseViewModel(application)
|
|||||||
}
|
}
|
||||||
return@sortedWith compare
|
return@sortedWith compare
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> list.sortedWith { o1, o2 ->
|
else -> list.sortedWith { o1, o2 ->
|
||||||
val compare = -compareValues(o1.isDir, o2.isDir)
|
val compare = -compareValues(o1.isDir, o2.isDir)
|
||||||
if (compare == 0) {
|
if (compare == 0) {
|
||||||
@ -132,10 +133,8 @@ class RemoteBookViewModel(application: Application) : BaseViewModel(application)
|
|||||||
val downloadBookUri = bookWebDav.downloadRemoteBook(remoteBook)
|
val downloadBookUri = bookWebDav.downloadRemoteBook(remoteBook)
|
||||||
LocalBook.importFiles(downloadBookUri).forEach { book ->
|
LocalBook.importFiles(downloadBookUri).forEach { book ->
|
||||||
book.origin = BookType.webDavTag + CustomUrl(remoteBook.path)
|
book.origin = BookType.webDavTag + CustomUrl(remoteBook.path)
|
||||||
.putAttribute(
|
.putAttribute("serverID", bookWebDav.serverID)
|
||||||
"serverID",
|
.toString()
|
||||||
bookWebDav.serverID
|
|
||||||
).toString()
|
|
||||||
book.save()
|
book.save()
|
||||||
}
|
}
|
||||||
remoteBook.isOnBookShelf = true
|
remoteBook.isOnBookShelf = true
|
||||||
@ -152,7 +151,7 @@ class RemoteBookViewModel(application: Application) : BaseViewModel(application)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun updateCallBackFlow(filterKey: String?) {
|
fun updateCallBackFlow(filterKey: String?) {
|
||||||
dataCallback?.screen(filterKey)
|
dataCallback?.screen(filterKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DataCallback {
|
interface DataCallback {
|
||||||
|
@ -6,10 +6,8 @@ import android.graphics.Canvas
|
|||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.text.SpannableStringBuilder
|
import android.os.Build
|
||||||
import android.text.Spanned
|
|
||||||
import android.text.StaticLayout
|
import android.text.StaticLayout
|
||||||
import android.text.style.LineHeightSpan
|
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
import androidx.appcompat.widget.AppCompatTextView
|
import androidx.appcompat.widget.AppCompatTextView
|
||||||
@ -29,13 +27,6 @@ class BatteryView @JvmOverloads constructor(
|
|||||||
private val outFrame = Rect()
|
private val outFrame = Rect()
|
||||||
private val polar = Rect()
|
private val polar = Rect()
|
||||||
private val canvasRecorder = CanvasRecorderFactory.create()
|
private val canvasRecorder = CanvasRecorderFactory.create()
|
||||||
private val batterySpan = LineHeightSpan { _, _, _, _, _, fm ->
|
|
||||||
fm.top = -22
|
|
||||||
fm.ascent = -28
|
|
||||||
fm.descent = 7
|
|
||||||
fm.bottom = 1
|
|
||||||
fm.leading = 0
|
|
||||||
}
|
|
||||||
var isBattery = false
|
var isBattery = false
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
@ -48,6 +39,9 @@ class BatteryView @JvmOverloads constructor(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
setPadding(4.dpToPx(), 3.dpToPx(), 6.dpToPx(), 3.dpToPx())
|
setPadding(4.dpToPx(), 3.dpToPx(), 6.dpToPx(), 3.dpToPx())
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
isFallbackLineSpacing = false
|
||||||
|
}
|
||||||
batteryPaint.strokeWidth = 1f.dpToPx()
|
batteryPaint.strokeWidth = 1f.dpToPx()
|
||||||
batteryPaint.isAntiAlias = true
|
batteryPaint.isAntiAlias = true
|
||||||
batteryPaint.color = paint.color
|
batteryPaint.color = paint.color
|
||||||
@ -69,9 +63,9 @@ class BatteryView @JvmOverloads constructor(
|
|||||||
fun setBattery(battery: Int, text: String? = null) {
|
fun setBattery(battery: Int, text: String? = null) {
|
||||||
this.battery = battery
|
this.battery = battery
|
||||||
if (text.isNullOrEmpty()) {
|
if (text.isNullOrEmpty()) {
|
||||||
setText(getBatteryText(battery.toString()))
|
setText(battery.toString())
|
||||||
} else {
|
} else {
|
||||||
setText(getBatteryText("$text $battery"))
|
setText("$text $battery")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,17 +78,16 @@ class BatteryView @JvmOverloads constructor(
|
|||||||
if (AppConfig.optimizeRender) {
|
if (AppConfig.optimizeRender) {
|
||||||
canvasRecorder.recordIfNeededThenDraw(canvas, width, height) {
|
canvasRecorder.recordIfNeededThenDraw(canvas, width, height) {
|
||||||
super.onDraw(this)
|
super.onDraw(this)
|
||||||
if (!isBattery) return@recordIfNeededThenDraw
|
|
||||||
drawBattery(this)
|
drawBattery(this)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
super.onDraw(canvas)
|
super.onDraw(canvas)
|
||||||
if (!isBattery) return
|
|
||||||
drawBattery(canvas)
|
drawBattery(canvas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun drawBattery(canvas: Canvas) {
|
private fun drawBattery(canvas: Canvas) {
|
||||||
|
if (!isBattery) return
|
||||||
layout.getLineBounds(0, outFrame)
|
layout.getLineBounds(0, outFrame)
|
||||||
val batteryStart = layout
|
val batteryStart = layout
|
||||||
.getPrimaryHorizontal(text.length - battery.toString().length)
|
.getPrimaryHorizontal(text.length - battery.toString().length)
|
||||||
@ -120,22 +113,10 @@ class BatteryView @JvmOverloads constructor(
|
|||||||
canvas.drawRect(polar, batteryPaint)
|
canvas.drawRect(polar, batteryPaint)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getBatteryText(text: CharSequence?): SpannableStringBuilder? {
|
@Suppress("UNNECESSARY_SAFE_CALL")
|
||||||
if (text == null) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return SpannableStringBuilder(text).apply {
|
|
||||||
setSpan(batterySpan, 0, text.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun invalidate() {
|
override fun invalidate() {
|
||||||
super.invalidate()
|
super.invalidate()
|
||||||
kotlin.runCatching {
|
canvasRecorder?.invalidate()
|
||||||
canvasRecorder.invalidate()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -27,7 +27,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.0.4",
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
"eslint": "^8.40.0",
|
"eslint": "^9.2.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-prettier": "^5.0.0",
|
"eslint-plugin-prettier": "^5.0.0",
|
||||||
"eslint-plugin-vue": "^9.12.0",
|
"eslint-plugin-vue": "^9.12.0",
|
||||||
|
Loading…
Reference in New Issue
Block a user