From 776ae8744ce648af79c0e9d8a72d837bb82a5289 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Sun, 15 Jun 2025 19:27:26 +0800 Subject: [PATCH] manager: add folder size labels for module items to optimize the display of module information --- .../java/com/sukisu/ultra/ui/screen/Module.kt | 43 ++++++++++++ .../ultra/ui/viewmodel/ModuleViewModel.kt | 67 +++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt index a28c06fa..a5272ad0 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt @@ -897,6 +897,9 @@ fun ModuleItem( val interactionSource = remember { MutableInteractionSource() } val indication = LocalIndication.current val viewModel = viewModel() + val moduleSize by remember(module.dirId) { + mutableStateOf(viewModel.getModuleSize(module.dirId)) + } Column( modifier = Modifier @@ -981,6 +984,46 @@ fun ModuleItem( textDecoration = textDecoration, ) + Spacer(modifier = Modifier.height(12.dp)) + + // 标签行 + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp), + modifier = Modifier.fillMaxWidth() + ) { + // 文件夹名称标签 + Surface( + shape = RoundedCornerShape(4.dp), + color = MaterialTheme.colorScheme.primary, + modifier = Modifier + ) { + Text( + text = module.dirId, + style = MaterialTheme.typography.labelSmall, + modifier = Modifier.padding(horizontal = 4.dp, vertical = 1.dp), + color = MaterialTheme.colorScheme.onPrimary, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + + // 大小标签 + Surface( + shape = RoundedCornerShape(4.dp), + color = MaterialTheme.colorScheme.secondaryContainer, + modifier = Modifier + ) { + Text( + text = moduleSize, + style = MaterialTheme.typography.labelSmall, + modifier = Modifier.padding(horizontal = 4.dp, vertical = 1.dp), + color = MaterialTheme.colorScheme.onSecondaryContainer, + maxLines = 1 + ) + } + } + Spacer(modifier = Modifier.height(16.dp)) HorizontalDivider(thickness = Dp.Hairline) diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt index 3107f780..16cd81ff 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt @@ -17,9 +17,15 @@ import com.sukisu.ultra.ui.util.listModules import kotlinx.coroutines.withContext import org.json.JSONArray import org.json.JSONObject +import java.io.BufferedReader +import java.io.File +import java.io.InputStreamReader import java.text.Collator +import java.text.DecimalFormat import java.util.Locale import java.util.concurrent.TimeUnit +import kotlin.math.log10 +import kotlin.math.pow /** * @author ShirkNeko @@ -33,6 +39,11 @@ class ModuleViewModel : ViewModel() { private const val CUSTOM_USER_AGENT = "SukiSU-Ultra/2.0" } + fun getModuleSize(dirId: String): String { + val size = getModuleFolderSize(dirId) + return formatFileSize(size) + } + class ModuleInfo( val id: String, val name: String, @@ -220,4 +231,60 @@ class ModuleViewModel : ViewModel() { return Triple(zipUrl, version, changelog) } +} + +/** + * 格式化文件大小的工具函数 + */ +fun formatFileSize(bytes: Long): String { + if (bytes <= 0) return "0 KB" + + val units = arrayOf("B", "KB", "MB", "GB", "TB") + val digitGroups = (log10(bytes.toDouble()) / log10(1024.0)).toInt() + + return DecimalFormat("#,##0.#").format( + bytes / 1024.0.pow(digitGroups.toDouble()) + ) + " " + units[digitGroups] +} + +/** + * 使用 su 权限调用 du 命令获取模块文件夹大小 + */ +fun getModuleFolderSize(dirId: String): Long { + return try { + val process = Runtime.getRuntime().exec(arrayOf("su", "-c", "du -sb /data/adb/modules/$dirId")) + val reader = BufferedReader(InputStreamReader(process.inputStream)) + val output = reader.readLine() + process.waitFor() + reader.close() + + if (output != null) { + val sizeStr = output.split("\t").firstOrNull() + sizeStr?.toLongOrNull() ?: 0L + } else { + 0L + } + } catch (e: Exception) { + Log.e("ModuleItem", "Error calculating module size with su for $dirId: ${e.message}") + 0L + } +} + +/** + * 递归计算目录大小(备用) + */ +private fun calculateDirectorySize(directory: File): Long { + var size = 0L + try { + directory.listFiles()?.forEach { file -> + size += if (file.isDirectory) { + calculateDirectorySize(file) + } else { + file.length() + } + } + } catch (e: Exception) { + Log.e("ModuleItem", "Error calculating directory size: ${e.message}") + } + return size } \ No newline at end of file