mirror of
https://github.com/InvertGeek/MixFile.git
synced 2026-06-02 17:41:06 +08:00
1.16.7
This commit is contained in:
@@ -16,8 +16,8 @@ android {
|
||||
applicationId = "com.donut.mixfile"
|
||||
minSdk = 26
|
||||
targetSdk = 35
|
||||
versionCode = 124
|
||||
versionName = "1.16.6"
|
||||
versionCode = 125
|
||||
versionName = "1.16.7"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
|
||||
@@ -341,7 +341,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
|
||||
button {
|
||||
font-size: max(.6rem, 14px);
|
||||
}
|
||||
`;function qx({fileList:e}){const[t,r]=st(!1),[n,i]=st(`文件分享-${tP()}`);return D(hU,{className:"shadow",children:[D("h4",{children:"导出文件列表"}),D("div",{class:"content",children:D(iC,{label:"文件列表名称",variant:"outlined",value:n,onChange:a=>{i(a.target.value.trim)}})}),D(si,{variant:"contained",disabled:t,onClick:async()=>{const a=e.map(({name:c,size:l,shareInfoData:u})=>({name:c,size:l,category:"",time:new Date().getTime(),shareInfoData:u})),o=tx.gzip(JSON.stringify(a)),s=`${zo}api/upload?name=${encodeURIComponent(`${n}.mix_list`)}&add=false`;r(!0);try{let c=await Bt.put(s,o,{});ud(c.data)}finally{r(!1)}},children:"确认导出"})]})}const pU=bn.div`
|
||||
`;function qx({fileList:e}){const[t,r]=st(!1),[n,i]=st(`文件分享-${tP()}`);return D(hU,{className:"shadow",children:[D("h4",{children:"导出文件列表"}),D("div",{class:"content",children:D(iC,{label:"文件列表名称",variant:"outlined",value:n,onChange:a=>{i(a.target.value.trim())}})}),D(si,{variant:"contained",disabled:t,onClick:async()=>{const a=e.map(({name:c,size:l,shareInfoData:u})=>({name:c,size:l,category:"",time:new Date().getTime(),shareInfoData:u})),o=tx.gzip(JSON.stringify(a)),s=`${zo}api/upload?name=${encodeURIComponent(`${n}.mix_list`)}&add=false`;r(!0);try{let c=await Bt.put(s,o,{});ud(c.data)}finally{r(!1)}},children:"确认导出"})]})}const pU=bn.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
@@ -1,16 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="chs">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<link rel="icon" href="/icon.png"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1"
|
||||
name="viewport"/>
|
||||
<title>MixFile</title>
|
||||
<script type="module" crossorigin src="/assets/index-22ohecZ7.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Ub7aM_kp.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
</body>
|
||||
<!DOCTYPE html>
|
||||
<html lang="chs">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<link rel="icon" href="/icon.png"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1"
|
||||
name="viewport"/>
|
||||
<title>MixFile</title>
|
||||
<script type="module" crossorigin src="/assets/index-BCd7FO_p.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Ub7aM_kp.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -4,6 +4,8 @@ import android.annotation.SuppressLint
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.size
|
||||
@@ -35,8 +37,8 @@ fun CenterControl(
|
||||
visible: Boolean,
|
||||
modifier: Modifier,
|
||||
player: ExoPlayer,
|
||||
onPause: () -> Unit = {},
|
||||
onMediaChange: () -> Unit = {}
|
||||
onClick: () -> Unit = {},
|
||||
onMediaChange: () -> Unit = {},
|
||||
) {
|
||||
var isPlaying by remember { mutableStateOf(true) }
|
||||
var isBuffering by remember { mutableStateOf(true) }
|
||||
@@ -48,9 +50,9 @@ fun CenterControl(
|
||||
override fun onPlaybackStateChanged(playbackState: Int) {
|
||||
isBuffering =
|
||||
listOf(Player.STATE_BUFFERING, Player.STATE_IDLE).contains(playbackState)
|
||||
super.onPlaybackStateChanged(playbackState)
|
||||
}
|
||||
|
||||
|
||||
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
|
||||
onMediaChange()
|
||||
super.onMediaItemTransition(mediaItem, reason)
|
||||
@@ -59,22 +61,28 @@ fun CenterControl(
|
||||
|
||||
override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) {
|
||||
isPlaying = playWhenReady
|
||||
super.onPlayWhenReadyChanged(playWhenReady, reason)
|
||||
}
|
||||
}
|
||||
player.addListener(listener)
|
||||
|
||||
// 清理资源
|
||||
onDispose {
|
||||
player.removeListener(listener)
|
||||
player.release()
|
||||
}
|
||||
}
|
||||
AnimatedVisibility(isBuffering, modifier = modifier) {
|
||||
|
||||
AnimatedVisibility(
|
||||
isBuffering,
|
||||
modifier = modifier,
|
||||
enter = scaleIn(),
|
||||
exit = scaleOut(),
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
strokeWidth = 2.dp,
|
||||
modifier = Modifier.size(40.dp)
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = visible,
|
||||
enter = fadeIn(),
|
||||
@@ -86,6 +94,7 @@ fun CenterControl(
|
||||
modifier = Modifier.scale(1.5f),
|
||||
onClick = {
|
||||
player.seekBack()
|
||||
onClick()
|
||||
},
|
||||
) {
|
||||
Icon(
|
||||
@@ -103,10 +112,15 @@ fun CenterControl(
|
||||
} else {
|
||||
player.play()
|
||||
}
|
||||
onPause()
|
||||
onClick()
|
||||
},
|
||||
) {
|
||||
AnimatedVisibility(!isBuffering) {
|
||||
AnimatedVisibility(
|
||||
!isBuffering,
|
||||
modifier = Modifier,
|
||||
enter = scaleIn(),
|
||||
exit = scaleOut(),
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(100.dp),
|
||||
imageVector = if (isPlaying) Icons.Default.Pause else Icons.Default.PlayArrow,
|
||||
@@ -120,6 +134,7 @@ fun CenterControl(
|
||||
modifier = Modifier.scale(1.5f),
|
||||
onClick = {
|
||||
player.seekForward()
|
||||
onClick()
|
||||
},
|
||||
) {
|
||||
Icon(
|
||||
|
||||
@@ -6,7 +6,6 @@ import android.net.Uri
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
@@ -38,7 +37,6 @@ import com.donut.mixfile.util.showToast
|
||||
import kotlinx.coroutines.delay
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
fun formatTime(milliseconds: Long): String {
|
||||
val seconds = (milliseconds / 1000) % 60
|
||||
val minutes = (milliseconds / (1000 * 60)) % 60
|
||||
@@ -58,6 +56,19 @@ val playerColorScheme
|
||||
onSecondaryContainer = colorScheme.primary.copy(0.8f)
|
||||
)
|
||||
|
||||
|
||||
class ForceUpdateMutable<T>(value: T) {
|
||||
private var value by mutableStateOf(value)
|
||||
var inc by mutableLongStateOf(0)
|
||||
|
||||
val get get() = value
|
||||
|
||||
fun set(value: T) {
|
||||
this.value = value
|
||||
inc++
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("PrivateResource")
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@@ -87,15 +98,17 @@ fun VideoPlayerScreen(
|
||||
|
||||
var currentMediaItem by remember { mutableIntStateOf(player.currentMediaItemIndex) }
|
||||
|
||||
var controlsVisible by remember { mutableStateOf(true) }
|
||||
var controlsVisible = remember { ForceUpdateMutable(true) }
|
||||
|
||||
|
||||
// 控制栏自动隐藏
|
||||
LaunchedEffect(controlsVisible) {
|
||||
if (controlsVisible) {
|
||||
delay(3000) // 3秒后隐藏
|
||||
controlsVisible = false
|
||||
LaunchedEffect(controlsVisible.inc) {
|
||||
if (controlsVisible.get) {
|
||||
delay(3000)
|
||||
controlsVisible.set(false)
|
||||
}
|
||||
}
|
||||
|
||||
val lifecycleOwner =
|
||||
LocalLifecycleOwner.current
|
||||
|
||||
@@ -132,24 +145,20 @@ fun VideoPlayerScreen(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(Color.Black)
|
||||
.clickable(
|
||||
onClick = {
|
||||
if (System.currentTimeMillis() - lastClick < 300L) {
|
||||
if (player.isPlaying) {
|
||||
player.pause()
|
||||
controlsVisible = true
|
||||
} else {
|
||||
player.play()
|
||||
controlsVisible = false
|
||||
}
|
||||
return@clickable
|
||||
.clickable {
|
||||
if (System.currentTimeMillis() - lastClick < 300L) {
|
||||
if (player.isPlaying) {
|
||||
player.pause()
|
||||
controlsVisible.set(true)
|
||||
} else {
|
||||
player.play()
|
||||
controlsVisible.set(false)
|
||||
}
|
||||
lastClick = System.currentTimeMillis()
|
||||
controlsVisible = !controlsVisible
|
||||
},
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
)
|
||||
return@clickable
|
||||
}
|
||||
lastClick = System.currentTimeMillis()
|
||||
controlsVisible.set(!controlsVisible.get)
|
||||
}
|
||||
) {
|
||||
AndroidView(
|
||||
factory = {
|
||||
@@ -164,21 +173,26 @@ fun VideoPlayerScreen(
|
||||
|
||||
TopControl(
|
||||
title = if (videoUris.size > 1) "${currentMediaItem + 1} - ${currentMediaTitle}" else currentMediaTitle,
|
||||
visible = controlsVisible,
|
||||
visible = controlsVisible.get,
|
||||
modifier = Modifier.align(Alignment.TopCenter)
|
||||
)
|
||||
|
||||
|
||||
CenterControl(controlsVisible, Modifier.align(Alignment.Center), player, onPause = {
|
||||
controlsVisible = true
|
||||
}) {
|
||||
CenterControl(
|
||||
controlsVisible.get,
|
||||
Modifier.align(Alignment.Center),
|
||||
player,
|
||||
onClick = {
|
||||
controlsVisible.set(true)
|
||||
}
|
||||
) {
|
||||
currentMediaItem = player.currentMediaItemIndex
|
||||
controlsVisible = true
|
||||
controlsVisible.set(true)
|
||||
}
|
||||
|
||||
|
||||
BottomControl(
|
||||
visible = controlsVisible,
|
||||
visible = controlsVisible.get,
|
||||
modifier = Modifier.align(Alignment.BottomCenter),
|
||||
player = player,
|
||||
videos = videoUris,
|
||||
@@ -193,7 +207,7 @@ fun VideoPlayerScreen(
|
||||
}
|
||||
},
|
||||
onTrackTimeChange = {
|
||||
controlsVisible = true
|
||||
controlsVisible.set(true)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,10 +2,9 @@ package com.donut.mixfile.server.core.routes
|
||||
|
||||
import com.donut.mixfile.server.core.MixFileServer
|
||||
import com.donut.mixfile.server.core.routes.api.getAPIRoute
|
||||
import com.donut.mixfile.server.core.utils.decodedPath
|
||||
import com.donut.mixfile.server.core.utils.parseFileMimeType
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.http.decodeURLQueryComponent
|
||||
import io.ktor.server.request.path
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.response.respondBytesWriter
|
||||
import io.ktor.server.routing.Routing
|
||||
@@ -18,7 +17,7 @@ fun MixFileServer.getRoutes(): Routing.() -> Unit {
|
||||
|
||||
return {
|
||||
get("{param...}") {
|
||||
val file = call.request.path().decodeURLQueryComponent().substring(1).ifEmpty {
|
||||
val file = decodedPath.substring(1).ifEmpty {
|
||||
"index.html"
|
||||
}
|
||||
val fileStream =
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.donut.mixfile.server.core.routes.api.webdav.objects.WebDavFile
|
||||
import com.donut.mixfile.server.core.routes.api.webdav.objects.WebDavManager
|
||||
import com.donut.mixfile.server.core.routes.api.webdav.objects.normalizePath
|
||||
import com.donut.mixfile.server.core.routes.api.webdav.objects.toDavPath
|
||||
import com.donut.mixfile.server.core.utils.decodedPath
|
||||
import com.donut.mixfile.server.core.utils.decompressGzip
|
||||
import com.donut.mixfile.server.core.utils.getHeader
|
||||
import com.donut.mixfile.server.core.utils.mb
|
||||
@@ -24,7 +25,6 @@ import io.ktor.http.encodeURLParameter
|
||||
import io.ktor.http.withCharset
|
||||
import io.ktor.server.application.ApplicationCall
|
||||
import io.ktor.server.request.contentLength
|
||||
import io.ktor.server.request.path
|
||||
import io.ktor.server.request.receiveChannel
|
||||
import io.ktor.server.response.header
|
||||
import io.ktor.server.response.respond
|
||||
@@ -40,8 +40,6 @@ import kotlinx.io.readByteArray
|
||||
|
||||
const val API_PATH = "/api/webdav"
|
||||
|
||||
val RoutingContext.decodedPath: String get() = call.request.path().decodeURLQueryComponent()
|
||||
|
||||
val RoutingContext.davPath: String
|
||||
get() = normalizePath(decodedPath.substringAfter(API_PATH))
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.donut.mixfile.server.core.utils
|
||||
|
||||
import io.ktor.http.decodeURLQueryComponent
|
||||
import io.ktor.server.request.path
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
import java.nio.ByteBuffer
|
||||
import kotlin.streams.toList
|
||||
|
||||
@@ -75,9 +78,14 @@ fun Boolean?.toInt(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
val Long.mb get() = this * 1024 * 1024
|
||||
val Int.kb get() = this * 1024
|
||||
|
||||
val Long.kb get() = this * 1024
|
||||
|
||||
val Long.mb get() = this * 1024.kb
|
||||
|
||||
val Int.mb get() = this * 1024.kb
|
||||
|
||||
val Int.mb get() = this * 1024 * 1024
|
||||
|
||||
fun Int.negative(): Int {
|
||||
return -this
|
||||
@@ -165,3 +173,5 @@ fun ByteArray.toInt(): Int =
|
||||
|
||||
|
||||
infix fun <T> T?.default(value: T) = this ?: value
|
||||
|
||||
val RoutingContext.decodedPath: String get() = call.request.path().decodeURLQueryComponent()
|
||||
|
||||
@@ -29,10 +29,6 @@ import java.util.zip.GZIPInputStream
|
||||
import java.util.zip.GZIPOutputStream
|
||||
import kotlin.random.Random
|
||||
|
||||
fun String.getFileExtension(): String {
|
||||
return substringAfterLast(".", "")
|
||||
}
|
||||
|
||||
fun String.sanitizeFileName(): String {
|
||||
// 定义非法字符,包括控制字符、文件系统非法字符、路径遍历等
|
||||
val illegalChars = "[\\x00-\\x1F\\x7F/\\\\:*?\"<>|]".toRegex()
|
||||
@@ -47,13 +43,13 @@ fun String.sanitizeFileName(): String {
|
||||
var sanitized = this
|
||||
// 替换非法字符为下划线
|
||||
.replace(illegalChars, "_")
|
||||
// 移除路径遍历序列
|
||||
.replace("..", "_")
|
||||
.trim()
|
||||
|
||||
// 检查是否为 Windows 保留文件名
|
||||
val baseName = sanitized.substringBeforeLast(".").uppercase()
|
||||
if (baseName in reservedNames) {
|
||||
if (sanitized.all { it == '.' }) {
|
||||
sanitized = "unnamed_file"
|
||||
}
|
||||
|
||||
if (sanitized.uppercase() in reservedNames) {
|
||||
sanitized = "_$sanitized"
|
||||
}
|
||||
|
||||
|
||||
@@ -93,16 +93,16 @@ fun getAppVersion(context: Context): Pair<String, Long> {
|
||||
|
||||
|
||||
class CachedDelegate<T>(val getKeys: () -> Array<Any?>, private val initializer: () -> T) {
|
||||
private var cache: T? = null
|
||||
private var keys: Array<Any?> = arrayOf()
|
||||
private var cache: T = initializer()
|
||||
private var keys: Array<Any?> = getKeys()
|
||||
|
||||
operator fun getValue(thisRef: Any?, property: Any?): T {
|
||||
val newKeys = getKeys()
|
||||
if (cache == null || !keys.contentEquals(newKeys)) {
|
||||
if (!keys.contentEquals(newKeys)) {
|
||||
keys = newKeys
|
||||
cache = initializer()
|
||||
}
|
||||
return cache!!
|
||||
return cache
|
||||
}
|
||||
|
||||
operator fun setValue(thisRef: Any?, property: Any?, value: T) {
|
||||
@@ -110,7 +110,6 @@ class CachedDelegate<T>(val getKeys: () -> Array<Any?>, private val initializer:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline fun String.isUrl(block: (URL) -> Unit = {}): Boolean {
|
||||
val urlPattern =
|
||||
Regex("^https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)\$")
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.donut.mixfile.server.core.objects.FileDataLog
|
||||
import com.donut.mixfile.server.core.objects.isImage
|
||||
import com.donut.mixfile.server.core.objects.isVideo
|
||||
import com.donut.mixfile.server.core.utils.hashSHA256
|
||||
import com.donut.mixfile.server.core.utils.isTrue
|
||||
import com.donut.mixfile.server.core.utils.resolveMixShareInfo
|
||||
import com.donut.mixfile.server.core.utils.shareCode
|
||||
import com.donut.mixfile.server.core.utils.toHex
|
||||
@@ -33,6 +34,7 @@ import com.donut.mixfile.ui.routes.home.showDownloadTaskWindow
|
||||
import com.donut.mixfile.ui.routes.useShortCode
|
||||
import com.donut.mixfile.ui.routes.useSystemPlayer
|
||||
import com.donut.mixfile.ui.theme.colorScheme
|
||||
import com.donut.mixfile.util.CachedDelegate
|
||||
import com.donut.mixfile.util.copyToClipboard
|
||||
import com.donut.mixfile.util.formatFileSize
|
||||
import com.donut.mixfile.util.showToast
|
||||
@@ -43,12 +45,12 @@ fun showFileInfoDialog(
|
||||
dataLog: FileDataLog,
|
||||
onDismiss: () -> Unit = {}
|
||||
) {
|
||||
val log = if (favorites.contains(dataLog)) {
|
||||
dataLog
|
||||
} else {
|
||||
favorites.firstOrNull { it.isSimilar(dataLog) }
|
||||
?: dataLog
|
||||
var isFav = false
|
||||
|
||||
val log by CachedDelegate({ arrayOf(favorites) }) {
|
||||
favorites.firstOrNull { it.isSimilar(dataLog).isTrue { isFav = true } } ?: dataLog
|
||||
}
|
||||
|
||||
val shareInfo = resolveMixShareInfo(log.shareInfoData)
|
||||
if (shareInfo == null) {
|
||||
showToast("解析文件分享码失败")
|
||||
@@ -84,7 +86,7 @@ fun showFileInfoDialog(
|
||||
Text(text = "查看文件", color = colorScheme.primary)
|
||||
})
|
||||
}
|
||||
if (!favorites.any { it.isSimilar(log) }) {
|
||||
if (!isFav) {
|
||||
AssistChip(onClick = {
|
||||
addFavoriteLog(log)
|
||||
}, label = {
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.donut.mixfile.MainActivity
|
||||
import com.donut.mixfile.app
|
||||
import com.donut.mixfile.appScope
|
||||
import com.donut.mixfile.server.core.utils.StreamContent
|
||||
import com.donut.mixfile.server.core.utils.kb
|
||||
import com.donut.mixfile.server.core.utils.mb
|
||||
import com.donut.mixfile.server.core.utils.sanitizeFileName
|
||||
import com.donut.mixfile.server.mixFileServer
|
||||
@@ -244,9 +245,8 @@ suspend fun loadDataWithMaxSize(
|
||||
onDownload(progressContent.ktorListener)
|
||||
}.execute {
|
||||
if (!it.status.isSuccess()) {
|
||||
val text = if ((it.contentLength()
|
||||
?: (1024 * 1024)) < 1024 * 500
|
||||
) it.bodyAsText() else "未知错误"
|
||||
val text =
|
||||
if ((it.contentLength() ?: 1024L.kb) < 500L.kb) it.bodyAsText() else "未知错误"
|
||||
throw Exception("下载失败: ${text}")
|
||||
}
|
||||
if ((it.contentLength() ?: 0) > limit) {
|
||||
@@ -293,9 +293,8 @@ suspend fun saveFileToStorage(
|
||||
onDownload(progress.ktorListener)
|
||||
}.execute {
|
||||
if (!it.status.isSuccess()) {
|
||||
val text = if ((it.contentLength()
|
||||
?: (1024 * 1024)) < 1024 * 500
|
||||
) it.bodyAsText() else "未知错误"
|
||||
val text =
|
||||
if ((it.contentLength() ?: 1024L.kb) < 500L.kb) it.bodyAsText() else "未知错误"
|
||||
throw Exception("下载失败: ${text}")
|
||||
}
|
||||
resolver.openOutputStream(fileUri)?.use { output ->
|
||||
|
||||
@@ -1,26 +1,7 @@
|
||||
package com.donut.mixfile
|
||||
|
||||
import com.alibaba.fastjson2.JSONReader
|
||||
import com.alibaba.fastjson2.JSONWriter
|
||||
import com.alibaba.fastjson2.annotation.JSONType
|
||||
import com.alibaba.fastjson2.to
|
||||
import com.alibaba.fastjson2.toJSONString
|
||||
import com.donut.mixfile.server.core.objects.FileDataLog
|
||||
import com.donut.mixfile.server.core.utils.sanitizeFileName
|
||||
import org.junit.Test
|
||||
|
||||
//appScope.launch(Dispatchers.IO) {
|
||||
// repeat(100) {
|
||||
// favorites += List(1000) {
|
||||
// FileDataLog(
|
||||
// genRandomString(32),
|
||||
// "test-data",
|
||||
// 1,
|
||||
// category = "test"
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
@@ -30,7 +11,6 @@ import org.junit.Test
|
||||
class ExampleUnitTest {
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
fun main() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user