Skip to content

Commit

Permalink
Performed some documentation, code refactoring and app improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Mihai-Cristian Condrea committed Oct 17, 2024
1 parent 941f12f commit a6a0caa
Show file tree
Hide file tree
Showing 8 changed files with 295 additions and 138 deletions.
6 changes: 4 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
<activity
android:name=".ui.screens.main.MainActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@style/SplashScreenTheme">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
Expand Down Expand Up @@ -86,10 +87,11 @@
android:label="@string/image_optimizer"
android:parentActivityName=".ui.screens.imageoptimizer.imageoptimizer.ImageOptimizerActivity" />

<activity android:name=".ui.screens.trash.TrashActivity"
<activity
android:name=".ui.screens.trash.TrashActivity"
android:exported="false"
android:label="@string/trash"
android:parentActivityName=".ui.screens.main.MainActivity"/>
android:parentActivityName=".ui.screens.main.MainActivity" />

<activity
android:name=".ui.screens.settings.SettingsActivity"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.navDeepLink
import com.d4rk.cleaner.constants.ui.bottombar.BottomBarRoutes
import com.d4rk.cleaner.data.datastore.DataStore
import com.d4rk.cleaner.data.model.ui.navigation.BottomNavigationScreen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,11 @@ fun AnalyzeScreen(
viewModel : HomeViewModel ,
data : UiHomeModel ,
) {
val TAG = "TAG"

val coroutineScope : CoroutineScope = rememberCoroutineScope()
val enabled = data.analyzeState.selectedFilesCount > 0
val isLoading: Boolean by viewModel.isLoading.collectAsState()

val filesTypesTitles = data.analyzeState.fileTypesData.fileTypesTitles
val apkExtensions = data.analyzeState.fileTypesData.apkExtensions
Expand Down Expand Up @@ -143,11 +146,7 @@ fun AnalyzeScreen(
return@remember finalMap
}

if (groupedFiles.isEmpty()) {
Box(modifier = Modifier.fillMaxSize()) {
CircularProgressIndicator()
}
}
println("$TAG - Recomposing AnalyzeScreen")

Column(
modifier = Modifier
Expand All @@ -162,17 +161,20 @@ fun AnalyzeScreen(
.fillMaxWidth() ,
) {
when {
data.analyzeState.scannedFileList.isEmpty() -> {
isLoading -> {
println("$TAG - ScannedFileList is empty, showing CircularProgressIndicator") // Log empty state
Box(modifier = Modifier.fillMaxSize() , contentAlignment = Alignment.Center) {
CircularProgressIndicator()
}
}

groupedFiles.isEmpty() || data.analyzeState.isFileScanEmpty -> {
println("$TAG - GroupedFiles is empty or file scan is empty, showing NoFilesFoundScreen") // Log empty state
NoFilesFoundScreen(viewModel = viewModel)
}

else -> {
println("$TAG - Files found, displaying them in tabs") // Log files found state
val tabs = groupedFiles.keys.toList()
val pagerState : PagerState = rememberPagerState(pageCount = { tabs.size })

Expand Down Expand Up @@ -242,6 +244,7 @@ fun AnalyzeScreen(
}
}
if (data.analyzeState.scannedFileList.isNotEmpty()) {
println("$TAG - ScannedFileList is not empty, displaying selection controls") // Log selection controls state
Row(
modifier = Modifier.fillMaxWidth() ,
verticalAlignment = Alignment.CenterVertically ,
Expand Down Expand Up @@ -291,7 +294,7 @@ fun AnalyzeScreen(
onEndButtonText = R.string.delete_forever ,
view = view)

if (data.analyzeState.isMoveToTrashConfirmationDialogVisible) {
if (data.analyzeState.isDeleteForeverConfirmationDialogVisible) {
ConfirmationAlertDialog(confirmationTitle = stringResource(R.string.delete_forever_title) ,
confirmationMessage = stringResource(R.string.delete_forever_message) ,
confirmationConfirmButtonText = stringResource(android.R.string.ok) ,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import java.io.File

/**
* ViewModel for the home screen.
* Manages the UI state and interacts with the repository to perform file operations.
*
* @param application The application instance.
* @author Mihai-Cristian Condrea
*/
class HomeViewModel(application : Application) : BaseViewModel(application) {
private val repository = HomeRepository(DataStore(application) , application)
private val _uiState = MutableStateFlow(UiHomeModel())
Expand All @@ -22,11 +29,17 @@ class HomeViewModel(application : Application) : BaseViewModel(application) {
prepareScreenData()
}

/**
* Loads initial screen data, including storage info and file types data.
*/
private fun prepareScreenData() {
updateStorageInfo()
populateFileTypesData()
}

/**
* Updates the storage information in the UI state.
*/
private fun updateStorageInfo() {
viewModelScope.launch(coroutineExceptionHandler) {
repository.getStorageInfo { uiHomeModel ->
Expand All @@ -41,12 +54,14 @@ class HomeViewModel(application : Application) : BaseViewModel(application) {
}
}

/**
* Initiates file analysis and updates the UI state with the results.
*/
fun analyze() {
viewModelScope.launch(context = Dispatchers.Default + coroutineExceptionHandler) {
showLoading()
repository.analyzeFiles { result ->
val filteredFiles = result.first
val emptyFolders = result.second
val (filteredFiles , emptyFolders) = result
_uiState.update { currentUiState ->
currentUiState.copy(
analyzeState = currentUiState.analyzeState.copy(
Expand All @@ -62,9 +77,13 @@ class HomeViewModel(application : Application) : BaseViewModel(application) {
}
}

/**
* Rescans files and updates the UI state with the new results.
*/
fun rescanFiles() {
viewModelScope.launch(context = Dispatchers.Default + coroutineExceptionHandler) {
showLoading()
// Clear previous scan results before starting a new scan
_uiState.update { currentUiState ->
currentUiState.copy(
analyzeState = currentUiState.analyzeState.copy(
Expand All @@ -85,6 +104,9 @@ class HomeViewModel(application : Application) : BaseViewModel(application) {
}
}

/**
* Hides the analyze screen.
*/
fun onCloseAnalyzeComposable() {
viewModelScope.launch(coroutineExceptionHandler) {
_uiState.update { currentUiState ->
Expand All @@ -97,6 +119,12 @@ class HomeViewModel(application : Application) : BaseViewModel(application) {
}
}

/**
* Updates the file selection state and selected file count.
*
* @param file The file whose selection state has changed.
* @param isChecked True if the file is now selected, false otherwise.
*/
fun onFileSelectionChange(file : File , isChecked : Boolean) {
viewModelScope.launch(coroutineExceptionHandler) {
val updatedFileSelectionStates =
Expand All @@ -111,7 +139,7 @@ class HomeViewModel(application : Application) : BaseViewModel(application) {
areAllFilesSelected = when {
newSelectedCount == currentUiState.analyzeState.scannedFileList.size && newSelectedCount > 0 -> true
newSelectedCount == 0 -> false
isChecked -> currentUiState.analyzeState.areAllFilesSelected
isChecked -> currentUiState.analyzeState.areAllFilesSelected // Maintain 'select all' state if an item was checked and all were already checked
else -> false
}
)
Expand All @@ -120,6 +148,9 @@ class HomeViewModel(application : Application) : BaseViewModel(application) {
}
}

/**
* Toggles the "select all" state for files.
*/
fun toggleSelectAllFiles() {
viewModelScope.launch(context = Dispatchers.Default + coroutineExceptionHandler) {
val newState = ! _uiState.value.analyzeState.areAllFilesSelected
Expand All @@ -141,6 +172,9 @@ class HomeViewModel(application : Application) : BaseViewModel(application) {
}
}

/**
* Deletes selected files and updates the UI state.
*/
fun clean() {
viewModelScope.launch(context = Dispatchers.Default + coroutineExceptionHandler) {
val filesToDelete =
Expand All @@ -165,6 +199,9 @@ class HomeViewModel(application : Application) : BaseViewModel(application) {
}
}

/**
* Moves selected files to the trash and updates the UI state.
*/
fun moveToTrash() {
viewModelScope.launch(context = Dispatchers.Default + coroutineExceptionHandler) {
val filesToMove =
Expand All @@ -189,6 +226,9 @@ class HomeViewModel(application : Application) : BaseViewModel(application) {
}
}

/**
* Populates file types data in the UI state.
*/
private fun populateFileTypesData() {
viewModelScope.launch(coroutineExceptionHandler) {
repository.getFileTypesData { fileTypesData ->
Expand All @@ -203,13 +243,21 @@ class HomeViewModel(application : Application) : BaseViewModel(application) {
}
}

fun setDeleteForeverConfirmationDialogVisibility(isVisible: Boolean) {
/**
* Sets the visibility of the "delete forever" confirmation dialog.
* @param isVisible True to show the dialog, false to hide it.
*/
fun setDeleteForeverConfirmationDialogVisibility(isVisible : Boolean) {
_uiState.update {
it.copy(analyzeState = it.analyzeState.copy(isDeleteForeverConfirmationDialogVisible = isVisible))
}
}

fun setMoveToTrashConfirmationDialogVisibility(isVisible: Boolean) {
/**
* Sets the visibility of the "move to trash" confirmation dialog.
* @param isVisible True to show the dialog, false to hide it.
*/
fun setMoveToTrashConfirmationDialogVisibility(isVisible : Boolean) {
_uiState.update {
it.copy(analyzeState = it.analyzeState.copy(isMoveToTrashConfirmationDialogVisible = isVisible))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.d4rk.cleaner.ui.screens.home.repository

import android.app.Application
import android.os.Environment
import android.util.Log
import com.d4rk.cleaner.data.datastore.DataStore
import com.d4rk.cleaner.data.model.ui.screens.FileTypesData
import com.d4rk.cleaner.data.model.ui.screens.UiHomeModel
Expand All @@ -10,11 +11,22 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File

/**
* Repository class for handling home screen data and operations.
*
* @param dataStore The DataStore instance for accessing user preferences.
* @param application The application instance for accessing resources and external files directory.
* @author Mihai-Cristian Condrea
*/
class HomeRepository(
dataStore : DataStore , application : Application ,
) : HomeRepositoryImplementation(application , dataStore) {
private val fileScanner = FileScanner(dataStore , application)

/**
* Retrieves storage information.
* @param onSuccess Callback function to be invoked with the storage information.
*/
suspend fun getStorageInfo(onSuccess : (UiHomeModel) -> Unit) {
withContext(Dispatchers.IO) {
val storageInfo : UiHomeModel = getStorageInfo()
Expand All @@ -24,7 +36,11 @@ class HomeRepository(
}
}

suspend fun getFileTypesData(onSuccess: (FileTypesData) -> Unit) {
/**
* Retrieves file types data from resources.
* @param onSuccess Callback function to be invoked with the file types data.
*/
suspend fun getFileTypesData(onSuccess : (FileTypesData) -> Unit) {
withContext(Dispatchers.IO) {
val fileTypesData = getFileTypesDataFromResources()
withContext(Dispatchers.Main) {
Expand All @@ -33,16 +49,28 @@ class HomeRepository(
}
}

/**
* Analyzes files and retrieves filtered files and empty folders.
* @param onSuccess Callback function to be invoked with the filtered files and empty folders.
*/
suspend fun analyzeFiles(onSuccess : (Pair<List<File> , List<File>>) -> Unit) {
withContext(Dispatchers.IO) {
val (filteredFiles , emptyFolders) = fileScanner.getAllFiles()

fileScanner.startScanning()
val filteredFiles = fileScanner.getFilteredFiles()
val emptyFolders = fileScanner.getAllFiles().second.ifEmpty {
emptyList()
}
println("Cleaner for Android -> analyzeFiles() received filteredFiles size: ${filteredFiles.size}, emptyFolders size: ${emptyFolders.size}")
withContext(Dispatchers.Main) {
onSuccess(Pair(filteredFiles , emptyFolders))
}
}
}

/**
* Rescans files and retrieves filtered files.
* @param onSuccess Callback to receive the result of filtered files.
*/
suspend fun rescanFiles(onSuccess : (List<File>) -> Unit) {
withContext(Dispatchers.IO) {
fileScanner.reset()
Expand All @@ -54,6 +82,10 @@ class HomeRepository(
}
}

/**
* Retrieves files from the trash directory.
* @return A list of files in the trash directory.
*/
suspend fun getTrashFiles() : List<File> {
return withContext(Dispatchers.IO) {
val trashDir = File(
Expand All @@ -69,6 +101,11 @@ class HomeRepository(
}
}

/**
* Deletes the specified files.
* @param filesToDelete The set of files to delete.
* @param onSuccess Callback function to be invoked after successful deletion.
*/
suspend fun deleteFiles(filesToDelete : Set<File> , onSuccess : () -> Unit) {
withContext(Dispatchers.IO) {
deleteFiles(filesToDelete)
Expand All @@ -78,6 +115,11 @@ class HomeRepository(
}
}

/**
* Moves the specified files to the trash directory.
* @param filesToMove The list of files to move to trash.
* @param onSuccess Callback function to be invoked after successful move.
*/
suspend fun moveToTrash(filesToMove : List<File> , onSuccess : () -> Unit) {
withContext(Dispatchers.IO) {
moveToTrash(filesToMove)
Expand All @@ -87,6 +129,11 @@ class HomeRepository(
}
}

/**
* Restores the specified files from the trash directory.
* @param filesToRestore The set of files to restore from trash.
* @param onSuccess Callback function to be invoked after successful restore.
*/
suspend fun restoreFromTrash(filesToRestore : Set<File> , onSuccess : () -> Unit) {
withContext(Dispatchers.IO) {
restoreFromTrash(filesToRestore)
Expand Down
Loading

0 comments on commit a6a0caa

Please sign in to comment.