diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/home/HomeViewModel.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/home/HomeViewModel.kt index 0b037bb..edb49a9 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/home/HomeViewModel.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/home/HomeViewModel.kt @@ -158,25 +158,26 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { Manifest.permission.WRITE_EXTERNAL_STORAGE ) == PackageManager.PERMISSION_GRANTED - Build.VERSION.SDK_INT <= Build.VERSION_CODES.S -> + Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2 -> ContextCompat.checkSelfPermission( getApplication(), Manifest.permission.READ_EXTERNAL_STORAGE - ) == PackageManager.PERMISSION_GRANTED && - ContextCompat.checkSelfPermission( - getApplication(), - Manifest.permission.WRITE_EXTERNAL_STORAGE - ) == PackageManager.PERMISSION_GRANTED + ) == PackageManager.PERMISSION_GRANTED else -> true } + val hasManageStoragePermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { Environment.isExternalStorageManager() } else { true } - val hasUsageStatsPermission = isAccessGranted() + val hasUsageStatsPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + isAccessGranted() + } else { + true + } val hasMediaPermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { ContextCompat.checkSelfPermission( diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerComposable.kt index 2fb429d..5005476 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerComposable.kt @@ -47,9 +47,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha @@ -67,17 +64,18 @@ import com.d4rk.cleaner.R import com.d4rk.cleaner.ui.memory.model.RamInfo import com.d4rk.cleaner.ui.memory.model.StorageInfo import com.d4rk.cleaner.utils.StorageProgressBar +import com.d4rk.cleaner.utils.Utils.formatSize import com.d4rk.cleaner.utils.bounceClick import kotlin.math.absoluteValue import kotlin.math.min val StorageIcons = mapOf( - "Installed Apps" to Icons.Outlined.Apps, - "System" to Icons.Outlined.Android, - "Music" to Icons.Outlined.MusicNote, - "Images" to Icons.Outlined.Image, - "Documents" to Icons.Outlined.FolderOpen, - "Downloads" to Icons.Outlined.Download, + "Installed Apps" to Icons.Outlined.Apps , + "System" to Icons.Outlined.Android , + "Music" to Icons.Outlined.MusicNote , + "Images" to Icons.Outlined.Image , + "Documents" to Icons.Outlined.FolderOpen , + "Downloads" to Icons.Outlined.Download , "Other Files" to Icons.Outlined.FolderOpen ) @@ -88,11 +86,10 @@ fun MemoryManagerComposable() { val storageInfo by viewModel.storageInfo.collectAsState() val ramInfo by viewModel.ramInfo.collectAsState() val isLoading by viewModel.isLoading.collectAsState() + val listExpanded by viewModel.listExpanded.collectAsState() val context = LocalContext.current - var listExpanded by remember { mutableStateOf(true) } - - val transition = updateTransition(targetState = !isLoading, label = "LoadingTransition") + val transition = updateTransition(targetState = ! isLoading , label = "LoadingTransition") val progressAlpha by transition.animateFloat(label = "Progress Alpha") { if (it) 0f else 1f @@ -110,22 +107,22 @@ fun MemoryManagerComposable() { if (isLoading) { Box( modifier = Modifier - .fillMaxSize() - .animateContentSize() - .alpha(progressAlpha), + .fillMaxSize() + .animateContentSize() + .alpha(progressAlpha) , contentAlignment = Alignment.Center ) { CircularProgressIndicator() } - } else { + } + else { Column( modifier = Modifier - .fillMaxSize() - .alpha(contentAlpha) + .fillMaxSize() + .alpha(contentAlpha) ) { CarouselLayout( - items = listOf(storageInfo, ramInfo), - peekPreviewWidth = 24.dp + items = listOf(storageInfo , ramInfo) , peekPreviewWidth = 24.dp ) { item -> when (item) { is StorageInfo -> StorageInfoCard(item) @@ -136,9 +133,9 @@ fun MemoryManagerComposable() { Spacer(modifier = Modifier.height(16.dp)) DotsIndicator( - modifier = Modifier.align(Alignment.CenterHorizontally), - totalDots = 2, - selectedIndex = pagerState.currentPage, + modifier = Modifier.align(Alignment.CenterHorizontally) , + totalDots = 2 , + selectedIndex = pagerState.currentPage , dotSize = 6.dp ) @@ -146,21 +143,23 @@ fun MemoryManagerComposable() { Row( modifier = Modifier - .fillMaxWidth() - .animateContentSize() - .padding(horizontal = 16.dp), + .fillMaxWidth() + .animateContentSize() + .padding(horizontal = 16.dp) , verticalAlignment = Alignment.CenterVertically ) { Text( - text = stringResource(id = R.string.categories), - modifier = Modifier.weight(1f), - style = MaterialTheme.typography.headlineSmall, + text = stringResource(id = R.string.categories) , + modifier = Modifier.weight(1f) , + style = MaterialTheme.typography.headlineSmall , ) Spacer(modifier = Modifier.width(8.dp)) - IconButton(modifier = Modifier.bounceClick(), onClick = { listExpanded = !listExpanded }) { + IconButton( + modifier = Modifier.bounceClick() , + onClick = { viewModel.toggleListExpanded() }) { Icon( - imageVector = if (listExpanded) Icons.Outlined.ArrowDropDown else Icons.AutoMirrored.Filled.ArrowLeft, + imageVector = if (listExpanded) Icons.Outlined.ArrowDropDown else Icons.AutoMirrored.Filled.ArrowLeft , contentDescription = if (listExpanded) "Collapse" else "Expand" ) } @@ -178,92 +177,84 @@ fun MemoryManagerComposable() { @OptIn(ExperimentalFoundationApi::class) @Composable fun CarouselLayout( - items: List, - peekPreviewWidth: Dp, - itemContent: @Composable (item: T) -> Unit + items : List , peekPreviewWidth : Dp , itemContent : @Composable (item : T) -> Unit ) { val pagerState = rememberPagerState(pageCount = { items.size }) HorizontalPager( - state = pagerState, - modifier = Modifier.fillMaxWidth(), + state = pagerState , + modifier = Modifier.fillMaxWidth() , contentPadding = PaddingValues(horizontal = peekPreviewWidth) ) { page -> val pageOffset = (pagerState.currentPage - page).toFloat().absoluteValue val scale by animateFloatAsState( targetValue = lerp( - start = 0.95f, - stop = 1f, - fraction = 1f - pageOffset.coerceIn(0f, 1f) - ), - animationSpec = tween(durationMillis = 250), - label = "" + start = 0.95f , stop = 1f , fraction = 1f - pageOffset.coerceIn(0f , 1f) + ) , animationSpec = tween(durationMillis = 250) , label = "" ) - val alpha = lerp(start = 0.5f, stop = 1f, fraction = 1f - pageOffset.coerceIn(0f, 1f)) + val alpha = lerp(start = 0.5f , stop = 1f , fraction = 1f - pageOffset.coerceIn(0f , 1f)) - Card( - modifier = Modifier + Card(modifier = Modifier .fillMaxWidth() .graphicsLayer { scaleX = scale scaleY = scale this.alpha = alpha - } - ) { + }) { itemContent(items[page]) } } } @Composable -fun StorageInfoCard(storageInfo: StorageInfo) { +fun StorageInfoCard(storageInfo : StorageInfo) { Column( modifier = Modifier - .padding(16.dp) - .animateContentSize() + .padding(16.dp) + .animateContentSize() ) { Text( - text = "Storage Information", - style = MaterialTheme.typography.headlineSmall, + text = "Storage Information" , + style = MaterialTheme.typography.headlineSmall , fontWeight = FontWeight.Bold ) Spacer(modifier = Modifier.height(8.dp)) LinearProgressIndicator( - progress = { storageInfo.usedStorage.toFloat() / storageInfo.totalStorage.toFloat() }, + progress = { storageInfo.usedStorage.toFloat() / storageInfo.totalStorage.toFloat() } , modifier = Modifier - .fillMaxWidth() - .height(8.dp), - color = MaterialTheme.colorScheme.primary, + .fillMaxWidth() + .height(8.dp) , + color = MaterialTheme.colorScheme.primary , ) Spacer(modifier = Modifier.height(8.dp)) - StorageInfoText(label = "Used:", size = storageInfo.usedStorage) - StorageInfoText(label = "Free:", size = storageInfo.freeStorage) - StorageInfoText(label = "Total:", size = storageInfo.totalStorage) + StorageInfoText(label = "Used:" , size = storageInfo.usedStorage) + StorageInfoText(label = "Free:" , size = storageInfo.freeStorage) + StorageInfoText(label = "Total:" , size = storageInfo.totalStorage) } } @Composable -fun StorageBreakdownGrid(storageBreakdown: Map) { +fun StorageBreakdownGrid(storageBreakdown : Map) { val items = storageBreakdown.entries.toList() val chunkSize = 2 LazyColumn( modifier = Modifier - .fillMaxWidth() - .animateContentSize() - .padding(horizontal = 16.dp) + .fillMaxWidth() + .animateContentSize() + .padding(horizontal = 16.dp) ) { items((items.size + chunkSize - 1) / chunkSize) { rowIndex -> Row( modifier = Modifier - .fillMaxWidth() - .animateContentSize() + .fillMaxWidth() + .animateContentSize() ) { - for (columnIndex in 0 until min(chunkSize, items.size - rowIndex * chunkSize)) { + for (columnIndex in 0 until min(chunkSize , items.size - rowIndex * chunkSize)) { val index = rowIndex * chunkSize + columnIndex - val (icon, size) = items[index] - StorageBreakdownItem(icon = icon, size = size, modifier = Modifier.weight(1f)) + val (icon , size) = items[index] + StorageBreakdownItem(icon = icon , size = size , modifier = Modifier.weight(1f)) } } } @@ -271,27 +262,27 @@ fun StorageBreakdownGrid(storageBreakdown: Map) { } @Composable -fun StorageBreakdownItem(icon: String, size: Long, modifier: Modifier = Modifier) { +fun StorageBreakdownItem(icon : String , size : Long , modifier : Modifier = Modifier) { Card( modifier = modifier - .padding(vertical = 4.dp, horizontal = 4.dp) - .animateContentSize() + .padding(vertical = 4.dp , horizontal = 4.dp) + .animateContentSize() ) { Row( modifier = Modifier - .fillMaxWidth() - .animateContentSize() - .padding(16.dp), + .fillMaxWidth() + .animateContentSize() + .padding(16.dp) , verticalAlignment = Alignment.CenterVertically ) { Card( - modifier = Modifier.size(48.dp), - colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primaryContainer), + modifier = Modifier.size(48.dp) , + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primaryContainer) , ) { - Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Box(modifier = Modifier.fillMaxSize() , contentAlignment = Alignment.Center) { Icon( - imageVector = StorageIcons[icon] ?: Icons.Filled.Info, - contentDescription = icon, + imageVector = StorageIcons[icon] ?: Icons.Filled.Info , + contentDescription = icon , tint = MaterialTheme.colorScheme.onPrimaryContainer ) } @@ -301,62 +292,62 @@ fun StorageBreakdownItem(icon: String, size: Long, modifier: Modifier = Modifier Column { Text( - text = icon, - style = MaterialTheme.typography.bodyMedium, + text = icon , + style = MaterialTheme.typography.bodyMedium , fontWeight = FontWeight.Bold ) - Text(text = formatSize(size), style = MaterialTheme.typography.bodySmall) + Text(text = formatSize(size) , style = MaterialTheme.typography.bodySmall) } } } } @Composable -fun StorageInfoText(label: String, size: Long) { - Text(text = "$label ${formatSize(size)}", style = MaterialTheme.typography.bodyMedium) +fun StorageInfoText(label : String , size : Long) { + Text(text = "$label ${formatSize(size)}" , style = MaterialTheme.typography.bodyMedium) } @Composable -fun RamInfoCard(ramInfo: RamInfo) { +fun RamInfoCard(ramInfo : RamInfo) { Column(modifier = Modifier.padding(16.dp)) { Text( - "RAM Information", - style = MaterialTheme.typography.headlineSmall, + "RAM Information" , + style = MaterialTheme.typography.headlineSmall , fontWeight = FontWeight.Bold ) Spacer(modifier = Modifier.height(8.dp)) StorageProgressBar( StorageInfo( - totalStorage = ramInfo.totalRam, - usedStorage = ramInfo.usedRam, + totalStorage = ramInfo.totalRam , + usedStorage = ramInfo.usedRam , freeStorage = ramInfo.availableRam ) ) Spacer(modifier = Modifier.height(8.dp)) - StorageInfoText(label = "Used RAM:", size = ramInfo.usedRam) - StorageInfoText(label = "Free RAM:", size = ramInfo.availableRam) - StorageInfoText(label = "Total RAM:", size = ramInfo.totalRam) + StorageInfoText(label = "Used RAM:" , size = ramInfo.usedRam) + StorageInfoText(label = "Free RAM:" , size = ramInfo.availableRam) + StorageInfoText(label = "Total RAM:" , size = ramInfo.totalRam) } } @Composable fun DotsIndicator( - modifier: Modifier = Modifier, - totalDots: Int, - selectedIndex: Int, - selectedColor: Color = MaterialTheme.colorScheme.primary, - unSelectedColor: Color = Color.Gray, - dotSize: Dp, + modifier : Modifier = Modifier , + totalDots : Int , + selectedIndex : Int , + selectedColor : Color = MaterialTheme.colorScheme.primary , + unSelectedColor : Color = Color.Gray , + dotSize : Dp , ) { LazyRow( modifier = modifier - .wrapContentWidth() - .wrapContentHeight() + .wrapContentWidth() + .wrapContentHeight() ) { items(totalDots) { index -> IndicatorDot( - color = if (index == selectedIndex) selectedColor else unSelectedColor, + color = if (index == selectedIndex) selectedColor else unSelectedColor , size = dotSize ) @@ -369,14 +360,14 @@ fun DotsIndicator( @Composable fun IndicatorDot( - modifier: Modifier = Modifier, - size: Dp, - color: Color, + modifier : Modifier = Modifier , + size : Dp , + color : Color , ) { Box( modifier = modifier - .size(size) - .clip(CircleShape) - .background(color) + .size(size) + .clip(CircleShape) + .background(color) ) } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerViewModel.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerViewModel.kt index 765eaa9..0273b29 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerViewModel.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerViewModel.kt @@ -18,30 +18,30 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File -import java.util.Locale import java.util.UUID -import kotlin.math.log10 -import kotlin.math.pow /** * ViewModel for managing and providing information about device memory (RAM and storage). */ class MemoryManagerViewModel : ViewModel() { private val _storageInfo = MutableStateFlow(StorageInfo()) - val storageInfo: StateFlow = _storageInfo.asStateFlow() + val storageInfo : StateFlow = _storageInfo.asStateFlow() private val _ramInfo = MutableStateFlow(RamInfo()) - val ramInfo: StateFlow = _ramInfo.asStateFlow() + val ramInfo : StateFlow = _ramInfo.asStateFlow() private val _isLoading = MutableStateFlow(true) - val isLoading: StateFlow = _isLoading.asStateFlow() + val isLoading : StateFlow = _isLoading.asStateFlow() + + private val _listExpanded = MutableStateFlow(true) + val listExpanded : StateFlow = _listExpanded.asStateFlow() /** * Updates the storage information by fetching the latest data from the device. * * @param context The application context. */ - fun updateStorageInfo(context: Context) { + fun updateStorageInfo(context : Context) { viewModelScope.launch { try { _storageInfo.value = getStorageInfo(context) @@ -56,7 +56,7 @@ class MemoryManagerViewModel : ViewModel() { * * @param context The application context. */ - fun updateRamInfo(context: Context) { + fun updateRamInfo(context : Context) { viewModelScope.launch { try { _ramInfo.value = getRamInfo(context) @@ -72,38 +72,38 @@ class MemoryManagerViewModel : ViewModel() { * @param context The application context. * @return A [StorageInfo] object containing details about total, free, and used storage. */ - private suspend fun getStorageInfo(context: Context): StorageInfo = - withContext(Dispatchers.IO) { - val storageManager = - context.getSystemService(Context.STORAGE_SERVICE) as StorageManager - val storageStatsManager = - context.getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager - val storageVolume = storageManager.primaryStorageVolume - val totalSize: Long - val usedSize: Long - val freeSize: Long - val uuidStr = storageVolume.uuid - val uuid: UUID = if (uuidStr == null) StorageManager.UUID_DEFAULT - else UUID.fromString(uuidStr) - totalSize = storageStatsManager.getTotalBytes(uuid) - freeSize = storageStatsManager.getFreeBytes(uuid) - usedSize = totalSize - freeSize - _isLoading.value = true - val storageBreakdown = getStorageBreakdown(context) - StorageInfo( - totalStorage = totalSize, - freeStorage = freeSize, - usedStorage = usedSize, - storageBreakdown = storageBreakdown - ) - } + private suspend fun getStorageInfo(context : Context) : StorageInfo = + withContext(Dispatchers.IO) { + val storageManager = + context.getSystemService(Context.STORAGE_SERVICE) as StorageManager + val storageStatsManager = + context.getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager + val storageVolume = storageManager.primaryStorageVolume + val totalSize : Long + val usedSize : Long + val freeSize : Long + val uuidStr = storageVolume.uuid + val uuid : UUID = if (uuidStr == null) StorageManager.UUID_DEFAULT + else UUID.fromString(uuidStr) + totalSize = storageStatsManager.getTotalBytes(uuid) + freeSize = storageStatsManager.getFreeBytes(uuid) + usedSize = totalSize - freeSize + _isLoading.value = true + val storageBreakdown = getStorageBreakdown(context) + StorageInfo( + totalStorage = totalSize , + freeStorage = freeSize , + usedStorage = usedSize , + storageBreakdown = storageBreakdown + ) + } /** * Retrieves information about the internal storage. * * @return An [InternalStorageInfo] object containing details about total, free, and used internal storage. */ - private fun getInternalStorageInfo(): InternalStorageInfo { + private fun getInternalStorageInfo() : InternalStorageInfo { val statFs = StatFs(Environment.getDataDirectory().path) val blockSizeBytes = statFs.blockSizeLong val totalBlocks = statFs.blockCountLong @@ -113,7 +113,7 @@ class MemoryManagerViewModel : ViewModel() { val freeStorage = availableBlocks * blockSizeBytes val usedStorage = totalStorage - freeStorage - return InternalStorageInfo(totalStorage, freeStorage, usedStorage) + return InternalStorageInfo(totalStorage , freeStorage , usedStorage) } /** @@ -122,17 +122,22 @@ class MemoryManagerViewModel : ViewModel() { * @param context The application context. * @return A map containing storage usage by category (e.g., "Installed Apps", "Music", etc.). */ - private fun getStorageBreakdown(context: Context): Map { - val breakdown = mutableMapOf() + private fun getStorageBreakdown(context : Context) : Map { + val breakdown = mutableMapOf() val externalStoragePath = Environment.getExternalStorageDirectory().absolutePath breakdown["Installed Apps"] = getInstalledAppsSize(context) breakdown["System"] = getDirectorySize(Environment.getRootDirectory()) - breakdown["Music"] = getDirectorySize(File(externalStoragePath, "Music")) - breakdown["Images"] = getDirectorySize(File(externalStoragePath, "DCIM")) + - getDirectorySize(File(externalStoragePath, "Pictures")) - breakdown["Documents"] = getDirectorySize(File(externalStoragePath, "Documents")) - breakdown["Downloads"] = getDirectorySize(File(externalStoragePath, "Download")) + breakdown["Music"] = getDirectorySize(File(externalStoragePath , "Music")) + breakdown["Images"] = + getDirectorySize(File(externalStoragePath , "DCIM")) + getDirectorySize( + File( + externalStoragePath , + "Pictures" + ) + ) + breakdown["Documents"] = getDirectorySize(File(externalStoragePath , "Documents")) + breakdown["Downloads"] = getDirectorySize(File(externalStoragePath , "Download")) breakdown["Other Files"] = getOtherFilesSize(breakdown) return breakdown @@ -144,12 +149,12 @@ class MemoryManagerViewModel : ViewModel() { * @param context The application context. * @return The total size of installed apps in bytes. */ - private fun getInstalledAppsSize(context: Context): Long { + private fun getInstalledAppsSize(context : Context) : Long { val packageManager = context.packageManager val installedApps = packageManager.getInstalledApplications(0) var installedAppsSize = 0L for (app in installedApps) { - installedAppsSize += getApkSize(context, app.packageName) + installedAppsSize += getApkSize(context , app.packageName) } return installedAppsSize } @@ -161,13 +166,12 @@ class MemoryManagerViewModel : ViewModel() { * @param packageName The package name of the app. * @return The size of the APK file in bytes. */ - private fun getApkSize(context: Context, packageName: String): Long { + private fun getApkSize(context : Context , packageName : String) : Long { return try { context.packageManager.getApplicationInfo( - packageName, - 0 + packageName , 0 ).sourceDir.let { File(it).length() } - } catch (e: Exception) { + } catch (e : Exception) { 0L } } @@ -178,15 +182,16 @@ class MemoryManagerViewModel : ViewModel() { * @param directory The directory to calculate the size for. * @return The size of the directory in bytes. */ - private fun getDirectorySize(directory: File?): Long { - if (directory == null || !directory.exists() || !directory.isDirectory) return 0 + private fun getDirectorySize(directory : File?) : Long { + if (directory == null || ! directory.exists() || ! directory.isDirectory) return 0 var size = 0L val files = directory.listFiles() if (files != null) { for (file in files) { size += if (file.isDirectory) { getDirectorySize(file) - } else { + } + else { file.length() } } @@ -201,7 +206,7 @@ class MemoryManagerViewModel : ViewModel() { * @param breakdown The current storage breakdown map. * @return The size of "other files" in bytes. */ - private fun getOtherFilesSize(breakdown: MutableMap): Long { + private fun getOtherFilesSize(breakdown : MutableMap) : Long { val totalUsedStorage = getInternalStorageInfo().usedStorage val calculatedSize = breakdown.values.sum() return totalUsedStorage - calculatedSize @@ -213,32 +218,21 @@ class MemoryManagerViewModel : ViewModel() { * @param context The application context. * @return A [RamInfo] object containing details about total, available, and used RAM. */ - private fun getRamInfo(context: Context): RamInfo { + private fun getRamInfo(context : Context) : RamInfo { val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val memoryInfo = ActivityManager.MemoryInfo() activityManager.getMemoryInfo(memoryInfo) return RamInfo( - totalRam = memoryInfo.totalMem, - availableRam = memoryInfo.availMem, + totalRam = memoryInfo.totalMem , + availableRam = memoryInfo.availMem , usedRam = memoryInfo.totalMem - memoryInfo.availMem ) } -} -/** - * Formats a file size in bytes to a human-readable string (e.g., "128 MB"). - * - * @param size The file size in bytes. - * @return A formatted string representing the file size. - */ -fun formatSize(size: Long): String { - if (size <= 0) return "0 B" - val units = arrayOf("B", "KB", "MB", "GB", "TB") - val digitGroups = (log10(size.toDouble()) / log10(1024.0)).toInt() - return String.format( - Locale.US, - "%.2f %s", - size / 1024.0.pow(digitGroups.toDouble()), - units[digitGroups] - ) + /** + * Toggles the expansion state of the storage breakdown list. + */ + fun toggleListExpanded() { + _listExpanded.value = ! _listExpanded.value + } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/utils/Utils.kt b/app/src/main/kotlin/com/d4rk/cleaner/utils/Utils.kt index 065fed6..9210f1e 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/utils/Utils.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/utils/Utils.kt @@ -5,6 +5,9 @@ import android.content.Intent import android.net.Uri import android.provider.Settings import com.d4rk.cleaner.R +import java.util.Locale +import kotlin.math.log10 +import kotlin.math.pow /** * A utility object for performing common operations such as opening URLs, activities, and app notification settings. @@ -114,4 +117,22 @@ object Utils { ) ) } + + /** + * Formats a file size in bytes to a human-readable string (e.g., "128 MB"). + * + * @param size The file size in bytes. + * @return A formatted string representing the file size. + */ + fun formatSize(size: Long): String { + if (size <= 0) return "0 B" + val units = arrayOf("B", "KB", "MB", "GB", "TB") + val digitGroups = (log10(size.toDouble()) / log10(1024.0)).toInt() + return String.format( + Locale.US , + "%.2f %s" , + size / 1024.0.pow(digitGroups.toDouble()) , + units[digitGroups] + ) + } } \ No newline at end of file