修复文件列表分享解析

This commit is contained in:
1
2024-09-19 20:24:35 +08:00
parent a22ea1a20a
commit 946f92d459
6 changed files with 109 additions and 19 deletions

View File

@@ -14,8 +14,8 @@ android {
applicationId = "com.donut.mixfile"
minSdk = 24
targetSdk = 34
versionCode = 23
versionName = "1.2.0"
versionCode = 26
versionName = "1.2.3"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {

View File

@@ -30,6 +30,7 @@ fun getUploadRoute(): suspend PipelineContext<Unit, ApplicationCall>.(Unit) -> U
return route@{
val key = generateRandomByteArray(16)
val name = call.request.queryParameters["name"]
val add = call.request.queryParameters["add"] ?: "true"
if (name.isNullOrEmpty()) {
call.respondText("需要文件名称", status = HttpStatusCode.InternalServerError)
return@route
@@ -55,7 +56,9 @@ fun getUploadRoute(): suspend PipelineContext<Unit, ApplicationCall>.(Unit) -> U
key = MixShareInfo.ENCODER.encode(key),
referer = uploader.referer
)
addUploadLog(mixShareInfo)
if (add.toBoolean()) {
addUploadLog(mixShareInfo)
}
call.respondText(mixShareInfo.toString())
}
}

View File

@@ -34,17 +34,22 @@ import com.donut.mixfile.ui.nav.MixNavPage
import com.donut.mixfile.ui.theme.colorScheme
import com.donut.mixfile.util.UseEffect
import com.donut.mixfile.util.compressGzip
import com.donut.mixfile.util.decodeHex
import com.donut.mixfile.util.decompressGzip
import com.donut.mixfile.util.encodeToBase64
import com.donut.mixfile.util.file.FileDataLog
import com.donut.mixfile.util.file.deleteFavoriteLog
import com.donut.mixfile.util.file.doUploadFile
import com.donut.mixfile.util.file.favCategories
import com.donut.mixfile.util.file.favorites
import com.donut.mixfile.util.file.selectAndUploadFile
import com.donut.mixfile.util.ignoreError
import com.donut.mixfile.util.formatFileSize
import com.donut.mixfile.util.hashSHA256
import com.donut.mixfile.util.objects.ProgressContent
import com.donut.mixfile.util.showErrorDialog
import com.donut.mixfile.util.showToast
import com.donut.mixfile.util.toJsonString
import com.donut.mixfile.util.truncate
import com.google.gson.Gson
import io.ktor.client.plugins.onDownload
import io.ktor.client.plugins.timeout
@@ -69,19 +74,55 @@ fun openCategorySelect(default: String = "", onSelect: (String) -> Unit) {
setPositiveButton("添加分类") {
createCategory()
}
if (default.isNotEmpty()) {
setNegativeButton("删除分类") {
if (default.contentEquals("默认")) {
showToast("不能删除默认分类")
if (favCategories.contains(default)) {
setNegativeButton("编辑分类") {
editCategory(default) {
closeDialog()
openCategorySelect(it, onSelect)
}
deleteCategory(default)
}
}
show()
}
}
fun deleteCategory(name: String) {
fun editCategory(name: String, callback: (String) -> Unit = {}) {
MixDialogBuilder("编辑分类").apply {
var newName by mutableStateOf(name)
setContent {
OutlinedTextField(value = newName, onValueChange = {
newName = it.substring(0, minOf(it.length, 20)).trim()
}, modifier = Modifier.fillMaxWidth())
}
setNegativeButton("删除分类") {
deleteCategory(name) {
callback(name)
closeDialog()
}
}
setPositiveButton("确定") {
if (newName.trim().isEmpty()) {
showToast("分类名不能为空")
return@setPositiveButton
}
favCategories -= name
favCategories += newName
currentCategory = newName
showToast("修改分类名称成功")
favorites.forEach {
if (it.category.contentEquals(name)) {
it.updateCategory(newName)
}
}
closeDialog()
callback(newName)
}
show()
}
}
fun deleteCategory(name: String, callback: (String) -> Unit = {}) {
MixDialogBuilder("确定删除分类?").apply {
setContent {
Text(text = "分类: ${name}")
@@ -95,6 +136,7 @@ fun deleteCategory(name: String) {
}
showToast("删除分类成功")
closeDialog()
callback(name)
}
show()
}
@@ -109,6 +151,10 @@ fun createCategory() {
}, modifier = Modifier.fillMaxWidth())
}
setPositiveButton("确认") {
if (name.trim().isEmpty()) {
showToast("分类名不能为空")
return@setPositiveButton
}
favCategories += name
showToast("添加分类成功")
closeDialog()
@@ -121,7 +167,11 @@ fun createCategory() {
fun exportFileList(fileList: List<FileDataLog>) {
val strData = fileList.toJsonString()
val compressedData = compressGzip(strData)
doUploadFile(compressedData, "__mixfile_list")
doUploadFile(
compressedData,
"__mixfile_list_${compressedData.hashSHA256().decodeHex().encodeToBase64().take(8)}",
false
)
}
fun showFileList(fileList: List<FileDataLog>) {
@@ -184,8 +234,8 @@ fun importFileList(url: String) {
}
suspend fun loadFileList(url: String, progressContent: ProgressContent): Array<FileDataLog>? {
return ignoreError {
localClient.prepareGet {
try {
return localClient.prepareGet {
timeout {
requestTimeoutMillis = 1000 * 60 * 60 * 24 * 30L
}
@@ -205,7 +255,12 @@ suspend fun loadFileList(url: String, progressContent: ProgressContent): Array<F
val extractedData = decompressGzip(data)
return@execute Gson().fromJson(extractedData, Array<FileDataLog>::class.java)
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
showErrorDialog(e, "解析分享列表失败!")
}
}
return null
}
var currentCategory: String by mutableStateOf("")
@@ -244,6 +299,10 @@ val Favorites = MixNavPage(
searchVal = it
}, label = { Text(text = "搜索") }, modifier = Modifier.fillMaxWidth())
Text(
text = "文件总大小: ${formatFileSize(result.sumOf { it.size })}",
color = colorScheme.primary
)
LaunchedEffect(key1 = searchVal, currentCategory, favorites) {
result = if (searchVal.trim().isNotEmpty()) {
@@ -271,7 +330,7 @@ val Favorites = MixNavPage(
.weight(1.0f)
.padding(10.dp, 0.dp)
) {
Text(text = "筛选分类: ${currentCategory.ifEmpty { "全部" }}")
Text(text = "分类: ${currentCategory.ifEmpty { "全部" }.truncate(3)}")
}
Button(
onClick = {
@@ -335,6 +394,4 @@ val Favorites = MixNavPage(
}
}
}
}

View File

@@ -7,12 +7,40 @@ import com.donut.mixfile.ui.routes.autoAddFavorite
import com.donut.mixfile.ui.routes.currentCategory
import com.donut.mixfile.util.cachedMutableOf
import com.donut.mixfile.util.showToast
import com.google.gson.TypeAdapter
import com.google.gson.annotations.JsonAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import java.io.IOException
import java.util.Date
class TimestampAdapter : TypeAdapter<Date?>() {
@Throws(IOException::class)
override fun write(out: JsonWriter, value: Date?) {
if (value == null) {
out.nullValue()
return
}
out.value(value.time)
}
@Throws(IOException::class)
override fun read(`in`: JsonReader): Date? {
if (`in`.peek() === JsonToken.NULL) {
`in`.nextNull()
return null
}
return Date(`in`.nextLong())
}
}
data class FileDataLog(
val shareInfoData: String,
val name: String,
val size: Long,
@JsonAdapter(TimestampAdapter::class)
val time: Date = Date(),
var category: String = "默认",
) {

View File

@@ -64,7 +64,7 @@ import kotlin.coroutines.cancellation.CancellationException
import kotlin.coroutines.coroutineContext
fun doUploadFile(data: Any?, name: String) {
fun doUploadFile(data: Any?, name: String, add: Boolean = true) {
MixDialogBuilder(
"上传中", properties = DialogProperties(
dismissOnClickOutside = false,
@@ -91,6 +91,7 @@ fun doUploadFile(data: Any?, name: String) {
url("${getLocalServerAddress()}/api/upload")
onUpload(progressContent.ktorListener)
parameter("name", name)
parameter("add", add)
setBody(data)
}
val message = response.bodyAsText()
@@ -201,7 +202,7 @@ fun showFileShareDialog(shareInfo: MixShareInfo, onDismiss: () -> Unit = {}) {
}, label = {
Text(text = "复制分享码", color = colorScheme.primary)
})
if (shareInfo.fileName.contentEquals("__mixfile_list")) {
if (shareInfo.fileName.startsWith("__mixfile_list")) {
AssistChip(onClick = {
importFileList(shareInfo.downloadUrl)
}, label = {

View File

@@ -1,6 +1,7 @@
package com.donut.mixfile
import com.donut.mixfile.util.formatFileSize
import com.donut.mixfile.util.file.FileDataLog
import com.donut.mixfile.util.toJsonString
import kotlinx.coroutines.runBlocking
import org.junit.Test