增加收藏分类以及文件列表分享功能

This commit is contained in:
1
2024-09-19 18:40:16 +08:00
parent 44ff2bb022
commit a22ea1a20a
14 changed files with 445 additions and 115 deletions

View File

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

View File

@@ -6,7 +6,7 @@
<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-9BLoK6H2.js"></script>
<script type="module" crossorigin src="/assets/index-DVXpF9eB.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BuZ9x1Ok.css">
</head>
<body>

View File

@@ -1,5 +1,6 @@
package com.donut.mixfile.ui.component.common
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -163,6 +164,7 @@ fun SingleSelectItemList(
)
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun <T> SingleSelectItemList(
items: List<T>,
@@ -182,6 +184,7 @@ fun <T> SingleSelectItemList(
onClick = {
onSelect(currentItem)
},
selected = selected,
leadingIcon = if (selected) {
{

View File

@@ -95,6 +95,7 @@ fun NavComponent() {
}
}
Scaffold(
floatingActionButton = currentFloatingButtons,
topBar = {
TopAppBar(
modifier = Modifier.clickable {

View File

@@ -17,6 +17,8 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
@@ -33,6 +35,9 @@ import com.donut.mixfile.util.genRandomString
import com.donut.mixfile.util.isNotNull
import java.lang.ref.WeakReference
var currentFloatingButtons: @Composable () -> Unit by mutableStateOf({})
@Suppress("MemberVisibilityCanBePrivate")
class MixNavPage(
val name: String = genRandomString(),
@@ -40,6 +45,7 @@ class MixNavPage(
val modifier: Modifier = Modifier,
val useTransition: Boolean = false,
val horizontalAlignment: Alignment.Horizontal = Alignment.Start,
val floatingButton: @Composable () -> Unit = {},
val content: @Composable (NavBackStackEntry) -> Unit,
) {
@@ -63,6 +69,7 @@ class MixNavPage(
horizontalAlignment = horizontalAlignment
) {
content(it)
currentFloatingButtons = floatingButton
}
}
}

View File

@@ -2,12 +2,19 @@ package com.donut.mixfile.ui.routes
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.Button
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.LaunchedEffect
@@ -20,14 +27,199 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.donut.mixfile.server.localClient
import com.donut.mixfile.ui.component.common.MixDialogBuilder
import com.donut.mixfile.ui.component.common.SingleSelectItemList
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.decompressGzip
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.objects.ProgressContent
import com.donut.mixfile.util.showToast
import com.donut.mixfile.util.toJsonString
import com.google.gson.Gson
import io.ktor.client.plugins.onDownload
import io.ktor.client.plugins.timeout
import io.ktor.client.request.prepareGet
import io.ktor.client.request.url
import io.ktor.client.statement.bodyAsChannel
import io.ktor.client.statement.bodyAsText
import io.ktor.http.contentLength
import io.ktor.http.isSuccess
import io.ktor.utils.io.core.readBytes
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
fun openCategorySelect(default: String = "", onSelect: (String) -> Unit) {
MixDialogBuilder("收藏分类").apply {
setContent {
SingleSelectItemList(favCategories.toList(), default) {
onSelect(it)
closeDialog()
}
}
setPositiveButton("添加分类") {
createCategory()
}
if (default.isNotEmpty()) {
setNegativeButton("删除分类") {
if (default.contentEquals("默认")) {
showToast("不能删除默认分类")
}
deleteCategory(default)
}
}
show()
}
}
fun deleteCategory(name: String) {
MixDialogBuilder("确定删除分类?").apply {
setContent {
Text(text = "分类: ${name}")
Text(text = "删除后将会移除此分类下所有文件!")
}
setDefaultNegative()
setPositiveButton("确定") {
favCategories -= name
favorites = favorites.filter {
it.category != name
}
showToast("删除分类成功")
closeDialog()
}
show()
}
}
fun createCategory() {
MixDialogBuilder("新建分类").apply {
var name by mutableStateOf("")
setContent {
OutlinedTextField(value = name, onValueChange = {
name = it.substring(0, minOf(it.length, 20)).trim()
}, modifier = Modifier.fillMaxWidth())
}
setPositiveButton("确认") {
favCategories += name
showToast("添加分类成功")
closeDialog()
}
setDefaultNegative()
show()
}
}
fun exportFileList(fileList: List<FileDataLog>) {
val strData = fileList.toJsonString()
val compressedData = compressGzip(strData)
doUploadFile(compressedData, "__mixfile_list")
}
fun showFileList(fileList: List<FileDataLog>) {
MixDialogBuilder("文件列表").apply {
setContent {
Column(
verticalArrangement = Arrangement.spacedBy(10.dp),
modifier = Modifier.padding(0.dp)
) {
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.heightIn(0.dp, 1000.dp),
verticalArrangement = Arrangement.spacedBy(0.dp)
) {
items(fileList.size) { index ->
FileCard(fileList[index]) {
}
}
}
}
}
setPositiveButton("导入文件") {
val prevSize = favorites.size
fileList.forEach {
favCategories += it.category
}
favorites += fileList
favorites = favorites.distinct()
showToast("导入了 ${favorites.size - prevSize} 个文件")
closeDialog()
}
show()
}
}
fun importFileList(url: String) {
val progress = ProgressContent()
MixDialogBuilder("解析中").apply {
setContent {
UseEffect {
val fileList = loadFileList(url, progress)
if (fileList == null) {
showToast("解析分享列表失败!")
closeDialog()
return@UseEffect
}
withContext(Dispatchers.Main) {
showFileList(fileList.toList())
closeDialog()
}
}
progress.LoadingContent()
}
setDefaultNegative()
show()
}
}
suspend fun loadFileList(url: String, progressContent: ProgressContent): Array<FileDataLog>? {
return ignoreError {
localClient.prepareGet {
timeout {
requestTimeoutMillis = 1000 * 60 * 60 * 24 * 30L
}
url(url)
onDownload(progressContent.ktorListener)
}.execute {
if (!it.status.isSuccess()) {
val text = if ((it.contentLength()
?: (1024 * 1024)) < 1024 * 500
) it.bodyAsText() else "未知错误"
throw Exception("下载失败: ${text}")
}
if ((it.contentLength() ?: 0) > 1024 * 1024 * 50) {
throw Exception("文件过大")
}
val data = it.bodyAsChannel().readRemaining(1024 * 1024 * 50).readBytes()
val extractedData = decompressGzip(data)
return@execute Gson().fromJson(extractedData, Array<FileDataLog>::class.java)
}
}
}
var currentCategory: String by mutableStateOf("")
val Favorites = MixNavPage(
gap = 10.dp,
horizontalAlignment = Alignment.CenterHorizontally
horizontalAlignment = Alignment.CenterHorizontally,
floatingButton = {
FloatingActionButton(onClick = {
selectAndUploadFile()
}, modifier = Modifier.padding(10.dp, 50.dp)) {
Icon(Icons.Filled.Add, "Upload File")
}
}
) {
var searchVal by remember {
@@ -38,16 +230,6 @@ val Favorites = MixNavPage(
mutableStateOf(favorites.reversed())
}
LaunchedEffect(key1 = searchVal) {
if (searchVal.trim().isNotEmpty()) {
result = favorites.filter {
it.name.contains(searchVal)
}.reversed()
} else {
result = favorites.reversed()
}
}
if (favorites.isEmpty()) {
Text(
text = "暂未收藏文件",
@@ -62,6 +244,67 @@ val Favorites = MixNavPage(
searchVal = it
}, label = { Text(text = "搜索") }, modifier = Modifier.fillMaxWidth())
LaunchedEffect(key1 = searchVal, currentCategory, favorites) {
result = if (searchVal.trim().isNotEmpty()) {
favorites.filter {
it.name.contains(searchVal)
}.reversed()
} else {
favorites.reversed()
}
result = result.filter {
currentCategory.isEmpty() || it.category == currentCategory
}
}
Row {
OutlinedButton(
onClick = {
openCategorySelect(currentCategory) {
currentCategory = if (it.contentEquals(currentCategory)) {
""
} else {
it
}
}
}, modifier = Modifier
.weight(1.0f)
.padding(10.dp, 0.dp)
) {
Text(text = "筛选分类: ${currentCategory.ifEmpty { "全部" }}")
}
Button(
onClick = {
MixDialogBuilder("确定导出?").apply {
setContent {
Text(text = "将会导出当前筛选的文件列表上传为一键分享链接")
}
setDefaultNegative()
setPositiveButton("确定") {
exportFileList(result)
closeDialog()
}
show()
}
},
modifier = Modifier
.weight(1.0f)
.padding(10.dp, 0.dp),
) {
Text(text = "导出文件")
}
}
if (result.isEmpty()) {
Text(
text = "没有搜索到文件",
modifier = Modifier.fillMaxWidth(),
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = colorScheme.primary
)
return@MixNavPage
}
ElevatedCard(
modifier = Modifier.fillMaxSize(),
) {

View File

@@ -15,11 +15,13 @@ import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedButton
@@ -51,14 +53,23 @@ import com.donut.mixfile.util.file.uploadLogs
import com.donut.mixfile.util.formatFileSize
import com.donut.mixfile.util.formatTime
import com.donut.mixfile.util.getIpAddressInLocalNetwork
import com.donut.mixfile.util.isFalse
import com.donut.mixfile.util.readClipBoardText
import com.donut.mixfile.util.showToast
var serverAddress by mutableStateOf("http://${getIpAddressInLocalNetwork()}:${serverPort}")
@OptIn(ExperimentalLayoutApi::class, ExperimentalFoundationApi::class)
val Home = MixNavPage(
gap = 10.dp,
horizontalAlignment = Alignment.CenterHorizontally
horizontalAlignment = Alignment.CenterHorizontally,
floatingButton = {
FloatingActionButton(onClick = {
selectAndUploadFile()
}, modifier = Modifier.padding(10.dp, 50.dp)) {
Icon(Icons.Filled.Add, "Upload File")
}
}
) {
var text by remember {
mutableStateOf("")
@@ -120,13 +131,15 @@ val Home = MixNavPage(
}
Button(
onClick = {
selectAndUploadFile()
tryResolveFile(text.trim()).isFalse {
showToast("解析失败!")
}
},
modifier = Modifier
.weight(1.0f)
.padding(10.dp, 0.dp),
) {
Text(text = "上传文件")
Text(text = "解析文件")
}
}
@@ -168,7 +181,11 @@ val Home = MixNavPage(
@OptIn(ExperimentalFoundationApi::class, ExperimentalLayoutApi::class)
@Composable
fun FileCard(fileDataLog: FileDataLog, showDate: Boolean = true, longClick: () -> Unit = {}) {
fun FileCard(
fileDataLog: FileDataLog,
showDate: Boolean = true,
longClick: () -> Unit = {},
) {
HorizontalDivider()
Card(
colors = CardDefaults.cardColors(

View File

@@ -50,6 +50,7 @@ import com.donut.mixfile.util.showToast
var useShortCode by cachedMutableOf(true, "use_short_code")
var autoAddFavorite by cachedMutableOf(true, "auto_add_favorite")
@OptIn(ExperimentalLayoutApi::class)
@Composable
@@ -145,6 +146,9 @@ val MixSettings = MixNavPage(
CommonSwitch(checked = useShortCode, text = "使用短分享码(空白字符编码信息):") {
useShortCode = it
}
CommonSwitch(checked = autoAddFavorite, text = "上传后自动添加文件到默认收藏:") {
autoAddFavorite = it
}
HorizontalDivider()
ElevatedButton(onClick = {
MixDialogBuilder("确定清除记录?").apply {

View File

@@ -19,7 +19,7 @@ val LightColorScheme = lightColorScheme(
secondary = Color(0xFF625b71),
tertiary = Color(0xFF7D5260),
// tertiaryContainer = Color(0xFFF0004E),
// primaryContainer = Color(0xFFF0004E),
primaryContainer = Color(0xFF99CEFC),
secondaryContainer = Color(0x3662B5E8),
background = Color(0xFFE6DFEB),
surface = Color(0xFFE6DFEB),

View File

@@ -5,7 +5,8 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.donut.mixfile.kv
import kotlinx.parcelize.Parcelize
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
fun <T> constructCachedMutableValue(
value: T,
@@ -52,21 +53,19 @@ fun cachedMutableOf(value: Parcelable, key: String) =
{ kv.encode(key, it) },
{ kv.decodeParcelable(key, value.javaClass) })
@Parcelize
data class ParcelableItemList<T : Parcelable>(
val items: List<T>,
) : Parcelable
inline fun <reified T : Parcelable> cachedMutableOf(value: List<T>, key: String) =
inline fun <reified T> cachedMutableOf(value: List<T>, key: String) =
constructCachedMutableValue(
value,
key,
{ kv.encode(key, ParcelableItemList(it)) },
{ kv.encode(key, it.toJsonString()) },
getter@{
val data =
kv.decodeParcelable(key, ParcelableItemList::class.java) ?: return@getter value
@Suppress("UNCHECKED_CAST")
return@getter data.items as List<T>
var result = listOf<T>()
val type = object : TypeToken<List<T>>() {}.type
ignoreError {
val json: List<T> = Gson().fromJson(kv.decodeString(key), type)
result = json
}
return@getter result
}
)

View File

@@ -26,7 +26,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@@ -114,7 +113,7 @@ fun TipText(content: String, onClick: () -> Unit = {}) {
@Composable
fun OnResume(block: () -> Unit) {
val lifecycleOwner = LocalLifecycleOwner.current
val lifecycleOwner = androidx.lifecycle.compose.LocalLifecycleOwner.current
val lifecycleObserver = remember {
LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_RESUME) {

View File

@@ -1,26 +1,42 @@
package com.donut.mixfile.util.file
import android.os.Parcelable
import androidx.compose.material3.Text
import com.donut.mixfile.server.utils.bean.MixShareInfo
import com.donut.mixfile.ui.component.common.MixDialogBuilder
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 kotlinx.parcelize.Parcelize
import java.util.Date
@Parcelize
data class FileDataLog(
val shareInfoData: String,
val name: String,
val size: Long,
val time: Date = Date(),
) : Parcelable {
var category: String = "默认",
) {
init {
//限制category长度
if (category.length > 20) {
category = category.substring(0, 20)
}
category = category.trim()
}
override fun hashCode(): Int {
return shareInfoData.hashCode()
}
fun updateCategory(category: String) {
favorites = favorites.toMutableList().apply {
remove(this@FileDataLog)
}
this.category = category
favorites = favorites + this.copy()
}
override fun equals(other: Any?): Boolean {
if (other !is FileDataLog) return false
return shareInfoData.contentEquals(other.shareInfoData)
@@ -31,20 +47,29 @@ var uploadLogs by cachedMutableOf(listOf<FileDataLog>(), "upload_file_logs")
var favorites by cachedMutableOf(listOf<FileDataLog>(), "favorite_file_logs")
var favCategories by cachedMutableOf(setOf("默认"), "fav_categories")
fun isFavorite(shareInfo: MixShareInfo): Boolean {
return favorites.contains(shareInfo.toDataLog())
}
fun addFavoriteLog(shareInfo: MixShareInfo) {
fun addFavoriteLog(
shareInfo: MixShareInfo,
category: String = currentCategory.ifEmpty { "默认" },
): Boolean {
if (favorites.size > 10000) {
showToast("收藏已达到限制!")
return false
}
val favoriteLog = shareInfo.toDataLog()
favoriteLog.category = category
favCategories += category
if (favorites.any { it == favoriteLog }) {
favorites = favorites.filter { it != favoriteLog } + favoriteLog
return
}
if (favorites.size > 1000) {
favorites = favorites.drop(1)
return true
}
favorites = favorites + favoriteLog
return true
}
fun MixShareInfo.toDataLog(): FileDataLog {
@@ -56,6 +81,9 @@ fun MixShareInfo.toDataLog(): FileDataLog {
}
fun addUploadLog(shareInfo: MixShareInfo) {
if (autoAddFavorite) {
addFavoriteLog(shareInfo)
}
val uploadLog = shareInfo.toDataLog()
if (uploadLogs.size > 1000) {
uploadLogs = uploadLogs.drop(1)

View File

@@ -33,6 +33,8 @@ import com.donut.mixfile.server.localClient
import com.donut.mixfile.server.utils.bean.MixShareInfo
import com.donut.mixfile.ui.component.common.MixDialogBuilder
import com.donut.mixfile.ui.routes.getLocalServerAddress
import com.donut.mixfile.ui.routes.importFileList
import com.donut.mixfile.ui.routes.openCategorySelect
import com.donut.mixfile.ui.routes.tryResolveFile
import com.donut.mixfile.ui.theme.colorScheme
import com.donut.mixfile.util.UseEffect
@@ -62,64 +64,68 @@ import kotlin.coroutines.cancellation.CancellationException
import kotlin.coroutines.coroutineContext
fun doUploadFile(data: Any?, name: String) {
MixDialogBuilder(
"上传中", properties = DialogProperties(
dismissOnClickOutside = false,
dismissOnBackPress = false
)
).apply {
setContent {
val progressContent = remember {
ProgressContent("上传中")
}
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
progressContent.LoadingContent()
}
UseEffect {
errorDialog("上传失败") {
val response = localClient.put {
timeout {
requestTimeoutMillis = 1000 * 60 * 60 * 24 * 30L
}
url("${getLocalServerAddress()}/api/upload")
onUpload(progressContent.ktorListener)
parameter("name", name)
setBody(data)
}
val message = response.bodyAsText()
if (!response.status.isSuccess()) {
throw Exception("上传失败: $message")
}
withContext(Dispatchers.Main) {
tryResolveFile(message)
}
showToast("上传成功!")
}
closeDialog()
}
}
setNegativeButton("取消") {
showToast("上传已取消")
closeDialog()
}
show()
}
}
@SuppressLint("Recycle")
fun selectAndUploadFile() {
MainActivity.mixFileSelector.openSelect { uri ->
MixDialogBuilder(
"上传中", properties = DialogProperties(
dismissOnClickOutside = false,
dismissOnBackPress = false
)
).apply {
setContent {
val progressContent = remember {
ProgressContent("上传中")
}
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
progressContent.LoadingContent()
}
UseEffect {
val resolver = app.contentResolver
val fileDescriptor: AssetFileDescriptor? =
resolver.openAssetFileDescriptor(uri, "r")
val fileSize = fileDescriptor?.length ?: 0
errorDialog("上传失败") {
val response = localClient.put {
timeout {
requestTimeoutMillis = 1000 * 60 * 60 * 24 * 30L
}
url("${getLocalServerAddress()}/api/upload")
onUpload(progressContent.ktorListener)
val fileStream = resolver.openInputStream(uri)
if (fileStream == null) {
showToast("打开文件失败")
return@put
}
parameter("name", uri.getFileName())
setBody(StreamContent(fileStream, fileSize))
}
val message = response.bodyAsText()
if (!response.status.isSuccess()) {
throw Exception("上传失败: $message")
}
withContext(Dispatchers.Main) {
tryResolveFile(message)
}
showToast("上传成功!")
}
closeDialog()
}
}
setNegativeButton("取消") {
showToast("上传已取消")
closeDialog()
}
show()
val resolver = app.contentResolver
val fileDescriptor: AssetFileDescriptor? =
resolver.openAssetFileDescriptor(uri, "r")
val fileSize = fileDescriptor?.length ?: 0
val fileStream = resolver.openInputStream(uri)
if (fileStream == null) {
showToast("打开文件失败")
return@openSelect
}
doUploadFile(StreamContent(fileStream, fileSize), uri.getFileName())
}
}
@@ -195,6 +201,13 @@ fun showFileShareDialog(shareInfo: MixShareInfo, onDismiss: () -> Unit = {}) {
}, label = {
Text(text = "复制分享码", color = colorScheme.primary)
})
if (shareInfo.fileName.contentEquals("__mixfile_list")) {
AssistChip(onClick = {
importFileList(shareInfo.downloadUrl)
}, label = {
Text(text = "文件列表", color = colorScheme.primary)
})
}
if (!isFavorite(shareInfo)) {
AssistChip(onClick = {
addFavoriteLog(shareInfo)
@@ -202,11 +215,24 @@ fun showFileShareDialog(shareInfo: MixShareInfo, onDismiss: () -> Unit = {}) {
Text(text = "收藏", color = colorScheme.primary)
})
} else {
val dataLog = remember(shareInfo) {
favorites.firstOrNull { it == shareInfo.toDataLog() }
}
AssistChip(onClick = {
deleteFavoriteLog(shareInfo.toDataLog())
}, label = {
Text(text = "取消收藏", color = colorScheme.primary)
})
AssistChip(onClick = {
openCategorySelect(dataLog?.category ?: "默认") {
dataLog?.updateCategory(it)
}
}, label = {
Text(
text = "分类: ${dataLog?.category}",
color = colorScheme.primary
)
})
}
if (shareInfo.contentType().startsWith("video/")) {