Merge pull request #248 from amir1376/fix/always-remove-unfinished-downloads-from-disk

always remove unfinished downloads and improve delete prompt
This commit is contained in:
AmirHossein Abdolmotallebi 2024-12-02 06:39:36 +03:30 committed by GitHub
commit 9cdb1f3844
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 103 additions and 32 deletions

View File

@ -61,6 +61,8 @@ sealed interface HomeEffects {
data class DeleteItems(
val list: List<Long>,
val finishedCount: Int,
val unfinishedCount: Int,
) : HomeEffects
data class DeleteCategory(
@ -460,7 +462,27 @@ class HomeComponent(
private fun requestDelete(
downloadList: List<Long>,
) {
sendEffect(HomeEffects.DeleteItems(downloadList))
if (downloadList.isEmpty()) {
// nothing to delete!
return
}
scope.launch {
val unfinished = downloadSystem.getUnfinishedDownloadIds()
.count {
it in downloadList
}
val finished = downloadSystem.getFinishedDownloadIds()
.count {
it in downloadList
}
sendEffect(
HomeEffects.DeleteItems(
list = downloadList,
unfinishedCount = unfinished,
finishedCount = finished,
)
)
}
}
fun onConfirmDeleteCategory(promptState: CategoryDeletePromptState) {

View File

@ -45,13 +45,13 @@ import androidx.compose.ui.window.Dialog
import com.abdownloadmanager.desktop.ui.customwindow.*
import com.abdownloadmanager.desktop.ui.widget.menu.ShowOptionsInDropDown
import com.abdownloadmanager.resources.Res
import com.abdownloadmanager.resources.*
import com.abdownloadmanager.utils.category.Category
import com.abdownloadmanager.utils.category.rememberIconPainter
import ir.amirab.util.compose.resources.myStringResource
import ir.amirab.util.compose.StringSource
import ir.amirab.util.compose.action.MenuItem
import ir.amirab.util.compose.asStringSource
import ir.amirab.util.compose.asStringSourceWithARgs
import ir.amirab.util.compose.localizationmanager.WithLanguageDirection
import java.awt.datatransfer.DataFlavor
import java.io.File
@ -79,7 +79,11 @@ fun HomePage(component: HomeComponent) {
when (it) {
is HomeEffects.DeleteItems -> {
if (it.list.isNotEmpty()) {
showDeletePromptState = DeletePromptState(it.list)
showDeletePromptState = DeletePromptState(
downloadList = it.list,
finishedCount = it.finishedCount,
unfinishedCount = it.unfinishedCount,
)
}
}
@ -353,35 +357,59 @@ private fun ShowDeletePrompts(
color = myColors.onBackground,
)
Spacer(Modifier.height(12.dp))
val finishedCount = deletePromptState.finishedCount
val unfinishedCount = deletePromptState.unfinishedCount
Text(
myStringResource(
Res.string.confirm_delete_download_items_description,
Res.string.confirm_delete_download_items_description_createArgs(
count = deletePromptState.downloadList.size.toString()
),
),
when {
deletePromptState.hasBothFinishedAndUnfinished() -> {
Res.string.confirm_delete_download_finished_and_unfinished_items_description.asStringSourceWithARgs(
Res.string.confirm_delete_download_finished_and_unfinished_items_description_createArgs(
finishedCount = finishedCount.toString(),
unfinishedCount = unfinishedCount.toString(),
)
)
}
deletePromptState.hasUnfinishedDownloads -> {
Res.string.confirm_delete_download_unfinished_items_description.asStringSourceWithARgs(
Res.string.confirm_delete_download_unfinished_items_description_createArgs(
count = unfinishedCount.toString(),
)
)
}
else -> {
Res.string.confirm_delete_download_items_description.asStringSourceWithARgs(
Res.string.confirm_delete_download_items_description_createArgs(
count = finishedCount.toString()
),
)
}
}.rememberString(),
fontSize = myTextSizes.base,
color = myColors.onBackground,
)
Spacer(Modifier.height(12.dp))
Row(
Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null
if (deletePromptState.hasFinishedDownloads) {
Spacer(Modifier.height(12.dp))
Row(
Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null
) {
deletePromptState.alsoDeleteFile = !deletePromptState.alsoDeleteFile
},
verticalAlignment = Alignment.CenterVertically,
) {
deletePromptState.alsoDeleteFile = !deletePromptState.alsoDeleteFile
},
verticalAlignment = Alignment.CenterVertically,
) {
CheckBox(deletePromptState.alsoDeleteFile, {
deletePromptState.alsoDeleteFile = it
})
Spacer(Modifier.width(8.dp))
Text(
myStringResource(Res.string.also_delete_file_from_disk),
fontSize = myTextSizes.base,
color = myColors.onBackground,
)
CheckBox(deletePromptState.alsoDeleteFile, {
deletePromptState.alsoDeleteFile = it
})
Spacer(Modifier.width(8.dp))
Text(
myStringResource(Res.string.also_delete_file_from_disk),
fontSize = myTextSizes.base,
color = myColors.onBackground,
)
}
}
Spacer(Modifier.height(12.dp))
Row(
@ -530,8 +558,16 @@ private fun ShowDeleteCategoryPrompt(
@Stable
class DeletePromptState(
val downloadList: List<Long>,
val finishedCount: Int,
val unfinishedCount: Int,
) {
val hasFinishedDownloads = finishedCount > 0
var hasUnfinishedDownloads = unfinishedCount > 0
var alsoDeleteFile by mutableStateOf(false)
fun hasBothFinishedAndUnfinished(): Boolean {
return hasFinishedDownloads && hasUnfinishedDownloads
}
}
@Immutable

View File

@ -12,7 +12,6 @@ import ir.amirab.downloader.downloaditem.contexts.StoppedBy
import ir.amirab.downloader.downloaditem.contexts.User
import ir.amirab.downloader.monitor.IDownloadMonitor
import ir.amirab.downloader.monitor.isDownloadActiveFlow
import ir.amirab.downloader.monitor.statusOrFinished
import ir.amirab.downloader.queue.QueueManager
import ir.amirab.downloader.utils.OnDuplicateStrategy
import kotlinx.coroutines.CoroutineScope
@ -110,7 +109,14 @@ class DownloadSystem(
}
suspend fun removeDownload(id: Long, alsoRemoveFile: Boolean) {
downloadManager.deleteDownload(id, alsoRemoveFile, RemovedBy(User))
downloadManager.deleteDownload(id, {
if (it.status == DownloadStatus.Completed) {
alsoRemoveFile
} else {
// always remove file if download is not finished!
true
}
}, RemovedBy(User))
categoryManager.removeItemInCategories(listOf(id))
}
@ -222,6 +228,7 @@ class DownloadSystem(
it.id
}
}
fun getAllRegisteredDownloadFiles(): List<File> {
return downloadMonitor.run {
activeDownloadListFlow.value + completedDownloadListFlow.value

View File

@ -93,7 +93,7 @@ class DownloadManager(
OverrideDownload -> {
foundItems.forEach {
deleteDownload(it.id, true,RemovedBy(DuplicateRemoval))
deleteDownload(it.id, { true }, RemovedBy(DuplicateRemoval))
}
removedItems=foundItems
}
@ -142,7 +142,11 @@ class DownloadManager(
return job
}
suspend fun deleteDownload(id: Long, alsoRemoveFile: Boolean,context: DownloadItemContext=EmptyContext) {
suspend fun deleteDownload(
id: Long,
alsoRemoveFile: (DownloadItem) -> Boolean,
context: DownloadItemContext = EmptyContext,
) {
kotlin.runCatching { pause(id) }
val itemToDelete = dlListDb.getById(id) ?: return
contextContainer.updateContext(id){ it+context }
@ -153,7 +157,7 @@ class DownloadManager(
DownloadManagerEvents.OnJobRemoved(itemToDelete, contextContainer.getContext(id))
)
contextContainer.removeContext(id)
if (alsoRemoveFile) {
if (alsoRemoveFile(itemToDelete)) {
val fileToDelete = calculateOutputFile(itemToDelete)
if (fileToDelete.isFile) {
fileToDelete.delete()

View File

@ -5,6 +5,8 @@ confirm_reset_to_default_categories_title=Reset to Default Categories
confirm_reset_to_default_categories_description=this will REMOVE all categories and brings backs default categories!
confirm_delete_download_items_title=Confirm Delete
confirm_delete_download_items_description=Are you sure you want to delete {{count}} items?
confirm_delete_download_unfinished_items_description=Are you sure you want to delete {{count}} unfinished downloads?
confirm_delete_download_finished_and_unfinished_items_description=Are you sure you want to delete {{finishedCount}} finished and {{unfinishedCount}} unfinished downloads?
also_delete_file_from_disk=Also delete file from disk
confirm_delete_category_item_title=Removing {{name}} category
confirm_delete_category_item_description=Are you sure you want to delete "{{value}}" Category?