Skip to content

Commit 1851e7e

Browse files
committed
Add trash feature for media items
1 parent b0077bc commit 1851e7e

18 files changed

+283
-71
lines changed

app/src/main/java/com/ismartcoding/plain/ui/base/PIconTextSmallButton.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,16 @@ fun IconTextSmallButtonRestore(
155155
)
156156
}
157157

158+
@Composable
159+
fun IconTextSmallButtonTrash(
160+
click: () -> Unit,
161+
) {
162+
PIconTextSmallButton(
163+
R.drawable.trash_2,
164+
text = stringResource(R.string.trash),
165+
click = click
166+
)
167+
}
158168

159169
@Composable
160170
fun IconTrashButton(

app/src/main/java/com/ismartcoding/plain/ui/components/MediaFilesSelectModeBottomActions.kt

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,20 @@ import androidx.compose.runtime.setValue
1111
import androidx.compose.ui.platform.LocalContext
1212
import com.ismartcoding.plain.data.IData
1313
import com.ismartcoding.plain.db.DTag
14+
import com.ismartcoding.plain.enums.AppFeatureType
1415
import com.ismartcoding.plain.helpers.ShareHelper
1516
import com.ismartcoding.plain.ui.base.BottomActionButtons
1617
import com.ismartcoding.plain.ui.base.IconTextSmallButtonDelete
1718
import com.ismartcoding.plain.ui.base.IconTextSmallButtonLabel
1819
import com.ismartcoding.plain.ui.base.IconTextSmallButtonLabelOff
20+
import com.ismartcoding.plain.ui.base.IconTextSmallButtonRestore
1921
import com.ismartcoding.plain.ui.base.IconTextSmallButtonShare
22+
import com.ismartcoding.plain.ui.base.IconTextSmallButtonTrash
2023
import com.ismartcoding.plain.ui.base.PBottomAppBar
2124
import com.ismartcoding.plain.ui.base.dragselect.DragSelectState
2225
import com.ismartcoding.plain.ui.helpers.DialogHelper
2326
import com.ismartcoding.plain.ui.models.AudioViewModel
27+
import com.ismartcoding.plain.ui.models.BaseMediaViewModel
2428
import com.ismartcoding.plain.ui.models.ImagesViewModel
2529
import com.ismartcoding.plain.ui.models.TagsViewModel
2630
import com.ismartcoding.plain.ui.models.VideosViewModel
@@ -30,12 +34,13 @@ import com.ismartcoding.plain.ui.page.tags.BatchSelectTagsDialog
3034
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
3135
@Composable
3236
fun <T : IData> MediaFilesSelectModeBottomActions(
33-
viewModel: Any,
37+
vm: BaseMediaViewModel<T>,
3438
tagsVM: TagsViewModel,
3539
tagsState: List<DTag>,
3640
dragSelectState: DragSelectState,
3741
getItemUri: (String) -> android.net.Uri,
38-
getCollectableItems: @Composable () -> List<T>
42+
getCollectableItems: @Composable () -> List<T>,
43+
isInTrashMode: Boolean
3944
) {
4045
val context = LocalContext.current
4146
var showSelectTagsDialog by remember {
@@ -67,15 +72,50 @@ fun <T : IData> MediaFilesSelectModeBottomActions(
6772
IconTextSmallButtonShare {
6873
ShareHelper.shareUris(context, dragSelectState.selectedIds.map { getItemUri(it) })
6974
}
70-
IconTextSmallButtonDelete {
71-
DialogHelper.confirmToDelete {
72-
@Suppress("UNCHECKED_CAST")
73-
when (viewModel) {
74-
is ImagesViewModel -> viewModel.delete(context, tagsVM, dragSelectState.selectedIds.toSet())
75-
is VideosViewModel -> viewModel.delete(context, tagsVM, dragSelectState.selectedIds.toSet())
76-
is AudioViewModel -> viewModel.delete(context, tagsVM, dragSelectState.selectedIds.toSet())
75+
if (AppFeatureType.MEDIA_TRASH.has()) {
76+
if (isInTrashMode) {
77+
IconTextSmallButtonRestore {
78+
@Suppress("UNCHECKED_CAST")
79+
when (vm) {
80+
is ImagesViewModel -> vm.restore(context, tagsVM, dragSelectState.selectedIds.toSet())
81+
is VideosViewModel -> vm.restore(context, tagsVM, dragSelectState.selectedIds.toSet())
82+
is AudioViewModel -> vm.restore(context, tagsVM, dragSelectState.selectedIds.toSet())
83+
}
84+
dragSelectState.exitSelectMode()
85+
}
86+
IconTextSmallButtonDelete {
87+
DialogHelper.confirmToDelete {
88+
@Suppress("UNCHECKED_CAST")
89+
when (vm) {
90+
is ImagesViewModel -> vm.delete(context, tagsVM, dragSelectState.selectedIds.toSet())
91+
is VideosViewModel -> vm.delete(context, tagsVM, dragSelectState.selectedIds.toSet())
92+
is AudioViewModel -> vm.delete(context, tagsVM, dragSelectState.selectedIds.toSet())
93+
}
94+
dragSelectState.exitSelectMode()
95+
}
96+
}
97+
} else {
98+
IconTextSmallButtonTrash {
99+
@Suppress("UNCHECKED_CAST")
100+
when (vm) {
101+
is ImagesViewModel -> vm.trash(context, tagsVM, dragSelectState.selectedIds.toSet())
102+
is VideosViewModel -> vm.trash(context, tagsVM, dragSelectState.selectedIds.toSet())
103+
is AudioViewModel -> vm.trash(context, tagsVM, dragSelectState.selectedIds.toSet())
104+
}
105+
dragSelectState.exitSelectMode()
106+
}
107+
}
108+
} else {
109+
IconTextSmallButtonDelete {
110+
DialogHelper.confirmToDelete {
111+
@Suppress("UNCHECKED_CAST")
112+
when (vm) {
113+
is ImagesViewModel -> vm.delete(context, tagsVM, dragSelectState.selectedIds.toSet())
114+
is VideosViewModel -> vm.delete(context, tagsVM, dragSelectState.selectedIds.toSet())
115+
is AudioViewModel -> vm.delete(context, tagsVM, dragSelectState.selectedIds.toSet())
116+
}
117+
dragSelectState.exitSelectMode()
77118
}
78-
dragSelectState.exitSelectMode()
79119
}
80120
}
81121
}

app/src/main/java/com/ismartcoding/plain/ui/models/AudioViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class AudioViewModel : BaseMediaViewModel<DAudio>() {
2323
viewModelScope.launch(Dispatchers.IO) {
2424
DialogHelper.showLoading()
2525
TagHelper.deleteTagRelationByKeys(ids, dataType)
26-
AudioMediaStoreHelper.deleteRecordsAndFilesByIdsAsync(context, ids)
26+
AudioMediaStoreHelper.deleteRecordsAndFilesByIdsAsync(context, ids, trash.value)
2727
val pathes = itemsFlow.value.filter { ids.contains(it.id) }.map { it.path }.toSet()
2828
AudioPlaylistPreference.deleteAsync(context, pathes)
2929
loadAsync(context, tagsVM)

app/src/main/java/com/ismartcoding/plain/ui/models/BaseMediaViewModel.kt

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,21 +99,47 @@ abstract class BaseMediaViewModel<T : IData> : ISearchableViewModel<T>, ViewMode
9999
_itemsFlow.value = searchAsync(context, getQuery()).toMutableStateList()
100100
tagsViewModel.loadAsync(_itemsFlow.value.map { it.id }.toSet())
101101
total.intValue = countAsync(context, getTotalQuery())
102+
totalTrash.intValue = countAsync(context, getTrashQuery())
102103
noMore.value = _itemsFlow.value.size < limit.intValue
103104
showLoading.value = false
104105
}
105106

106-
fun trash(ids: Set<String>) {
107+
fun trash(context: Context, tagsVM: TagsViewModel, ids: Set<String>) {
107108
viewModelScope.launch(Dispatchers.IO) {
108109
DialogHelper.showLoading()
110+
TagHelper.deleteTagRelationByKeys(ids, dataType)
111+
when (dataType) {
112+
DataType.AUDIO -> AudioMediaStoreHelper.trashByIdsAsync(context, ids)
113+
DataType.IMAGE -> ImageMediaStoreHelper.trashByIdsAsync(context, ids)
114+
DataType.VIDEO -> VideoMediaStoreHelper.trashByIdsAsync(context, ids)
115+
else -> {}
116+
}
117+
loadAsync(context, tagsVM)
109118
DialogHelper.hideLoading()
119+
_itemsFlow.update {
120+
it.toMutableStateList().apply {
121+
removeIf { i -> ids.contains(i.id) }
122+
}
123+
}
110124
}
111125
}
112126

113-
fun restore(ids: Set<String>) {
127+
fun restore(context: Context, tagsVM: TagsViewModel, ids: Set<String>) {
114128
viewModelScope.launch(Dispatchers.IO) {
115129
DialogHelper.showLoading()
130+
when (dataType) {
131+
DataType.AUDIO -> AudioMediaStoreHelper.restoreByIdsAsync(context, ids)
132+
DataType.IMAGE -> ImageMediaStoreHelper.restoreByIdsAsync(context, ids)
133+
DataType.VIDEO -> VideoMediaStoreHelper.restoreByIdsAsync(context, ids)
134+
else -> {}
135+
}
136+
loadAsync(context, tagsVM)
116137
DialogHelper.hideLoading()
138+
_itemsFlow.update {
139+
it.toMutableStateList().apply {
140+
removeIf { i -> ids.contains(i.id) }
141+
}
142+
}
117143
}
118144
}
119145

app/src/main/java/com/ismartcoding/plain/ui/models/ImagesViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class ImagesViewModel : BaseMediaViewModel<DImage>() {
2222
viewModelScope.launch(Dispatchers.IO) {
2323
DialogHelper.showLoading()
2424
TagHelper.deleteTagRelationByKeys(ids, dataType)
25-
ImageMediaStoreHelper.deleteRecordsAndFilesByIdsAsync(context, ids)
25+
ImageMediaStoreHelper.deleteRecordsAndFilesByIdsAsync(context, ids, trash.value)
2626
loadAsync(context, tagsVM)
2727
DialogHelper.hideLoading()
2828
}

app/src/main/java/com/ismartcoding/plain/ui/models/VideosViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class VideosViewModel : BaseMediaViewModel<DVideo>() {
2424
viewModelScope.launch(Dispatchers.IO) {
2525
DialogHelper.showLoading()
2626
TagHelper.deleteTagRelationByKeys(ids, dataType)
27-
VideoMediaStoreHelper.deleteRecordsAndFilesByIdsAsync(context, ids)
27+
VideoMediaStoreHelper.deleteRecordsAndFilesByIdsAsync(context, ids, trash.value)
2828
loadAsync(context, tagsVM)
2929
DialogHelper.hideLoading()
3030
}

app/src/main/java/com/ismartcoding/plain/ui/page/audio/AudioPageState.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import com.ismartcoding.plain.data.DAudio
1414
import com.ismartcoding.plain.data.DMediaBucket
1515
import com.ismartcoding.plain.db.DTag
1616
import com.ismartcoding.plain.db.DTagRelation
17+
import com.ismartcoding.plain.enums.AppFeatureType
1718
import com.ismartcoding.plain.ui.base.dragselect.DragSelectState
1819
import com.ismartcoding.plain.ui.base.dragselect.rememberListDragSelectState
1920
import com.ismartcoding.plain.ui.models.AudioViewModel
@@ -42,7 +43,9 @@ data class AudioPageState(
4243
tagsVM.dataType.value = audioVM.dataType
4344
mediaFoldersVM.dataType.value = audioVM.dataType
4445
val tagsState by tagsVM.itemsFlow.collectAsState()
45-
val pagerState = rememberPagerState(pageCount = { tagsState.size + 1 })
46+
val pagerState = rememberPagerState(pageCount = {
47+
tagsState.size + if (AppFeatureType.MEDIA_TRASH.has()) 2 else 1
48+
})
4649
val itemsState by audioVM.itemsFlow.collectAsState()
4750
val scrollState = rememberLazyListState()
4851

app/src/main/java/com/ismartcoding/plain/ui/page/audio/components/AudioFilesSelectModeBottomActions.kt

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import androidx.compose.ui.platform.LocalContext
1212
import com.ismartcoding.lib.helpers.CoroutinesHelper.withIO
1313
import com.ismartcoding.plain.R
1414
import com.ismartcoding.plain.db.DTag
15+
import com.ismartcoding.plain.enums.AppFeatureType
1516
import com.ismartcoding.plain.features.media.AudioMediaStoreHelper
1617
import com.ismartcoding.plain.helpers.ShareHelper
1718
import com.ismartcoding.plain.ui.base.ActionButtons
@@ -20,7 +21,9 @@ import com.ismartcoding.plain.ui.base.IconTextSmallButtonDelete
2021
import com.ismartcoding.plain.ui.base.IconTextSmallButtonLabel
2122
import com.ismartcoding.plain.ui.base.IconTextSmallButtonLabelOff
2223
import com.ismartcoding.plain.ui.base.IconTextSmallButtonPlaylistAdd
24+
import com.ismartcoding.plain.ui.base.IconTextSmallButtonRestore
2325
import com.ismartcoding.plain.ui.base.IconTextSmallButtonShare
26+
import com.ismartcoding.plain.ui.base.IconTextSmallButtonTrash
2427
import com.ismartcoding.plain.ui.base.PBottomAppBar
2528
import com.ismartcoding.plain.ui.base.dragselect.DragSelectState
2629
import com.ismartcoding.plain.ui.helpers.DialogHelper
@@ -77,10 +80,30 @@ fun AudioFilesSelectModeBottomActions(
7780
IconTextSmallButtonShare {
7881
ShareHelper.shareUris(context, dragSelectState.selectedIds.map { AudioMediaStoreHelper.getItemUri(it) })
7982
}
80-
IconTextSmallButtonDelete {
81-
DialogHelper.confirmToDelete {
82-
audioVM.delete(context, tagsVM, dragSelectState.selectedIds.toSet())
83-
dragSelectState.exitSelectMode()
83+
if (AppFeatureType.MEDIA_TRASH.has()) {
84+
if (audioVM.trash.value) {
85+
IconTextSmallButtonRestore {
86+
audioVM.restore(context, tagsVM, dragSelectState.selectedIds.toSet())
87+
dragSelectState.exitSelectMode()
88+
}
89+
IconTextSmallButtonDelete {
90+
DialogHelper.confirmToDelete {
91+
audioVM.delete(context, tagsVM, dragSelectState.selectedIds.toSet())
92+
dragSelectState.exitSelectMode()
93+
}
94+
}
95+
} else {
96+
IconTextSmallButtonTrash {
97+
audioVM.trash(context, tagsVM, dragSelectState.selectedIds.toSet())
98+
dragSelectState.exitSelectMode()
99+
}
100+
}
101+
} else {
102+
IconTextSmallButtonDelete {
103+
DialogHelper.confirmToDelete {
104+
audioVM.delete(context, tagsVM, dragSelectState.selectedIds.toSet())
105+
dragSelectState.exitSelectMode()
106+
}
84107
}
85108
}
86109
}

app/src/main/java/com/ismartcoding/plain/ui/page/audio/components/ViewAudioBottomSheet.kt

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import com.ismartcoding.plain.R
1616
import com.ismartcoding.plain.clipboardManager
1717
import com.ismartcoding.plain.db.DTag
1818
import com.ismartcoding.plain.db.DTagRelation
19+
import com.ismartcoding.plain.enums.AppFeatureType
1920
import com.ismartcoding.plain.extensions.formatDateTime
2021
import com.ismartcoding.plain.features.locale.LocaleHelper
2122
import com.ismartcoding.plain.features.media.AudioMediaStoreHelper
@@ -25,8 +26,10 @@ import com.ismartcoding.plain.ui.base.BottomSpace
2526
import com.ismartcoding.plain.ui.base.IconTextDeleteButton
2627
import com.ismartcoding.plain.ui.base.IconTextOpenWithButton
2728
import com.ismartcoding.plain.ui.base.IconTextRenameButton
29+
import com.ismartcoding.plain.ui.base.IconTextRestoreButton
2830
import com.ismartcoding.plain.ui.base.IconTextSelectButton
2931
import com.ismartcoding.plain.ui.base.IconTextShareButton
32+
import com.ismartcoding.plain.ui.base.IconTextTrashButton
3033
import com.ismartcoding.plain.ui.base.PCard
3134
import com.ismartcoding.plain.ui.base.PIconButton
3235
import com.ismartcoding.plain.ui.base.PListItem
@@ -97,10 +100,30 @@ fun ViewAudioBottomSheet(
97100
IconTextRenameButton {
98101
audioVM.showRenameDialog.value = true
99102
}
100-
IconTextDeleteButton {
101-
DialogHelper.confirmToDelete {
102-
audioVM.delete(context, tagsVM, setOf(m.id))
103-
onDismiss()
103+
if (AppFeatureType.MEDIA_TRASH.has()) {
104+
if (audioVM.trash.value) {
105+
IconTextRestoreButton {
106+
audioVM.restore(context, tagsVM, setOf(m.id))
107+
onDismiss()
108+
}
109+
IconTextDeleteButton {
110+
DialogHelper.confirmToDelete {
111+
audioVM.delete(context, tagsVM, setOf(m.id))
112+
onDismiss()
113+
}
114+
}
115+
} else {
116+
IconTextTrashButton {
117+
audioVM.trash(context, tagsVM, setOf(m.id))
118+
onDismiss()
119+
}
120+
}
121+
} else {
122+
IconTextDeleteButton {
123+
DialogHelper.confirmToDelete {
124+
audioVM.delete(context, tagsVM, setOf(m.id))
125+
onDismiss()
126+
}
104127
}
105128
}
106129
}

app/src/main/java/com/ismartcoding/plain/ui/page/images/ImageFilesSelectModeBottomActions.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ fun ImageFilesSelectModeBottomActions(
1919
dragSelectState: DragSelectState,
2020
) {
2121
MediaFilesSelectModeBottomActions(
22-
viewModel = imagesVM,
22+
vm = imagesVM,
2323
tagsVM = tagsVM,
2424
tagsState = tagsState,
2525
dragSelectState = dragSelectState,
2626
getItemUri = { ImageMediaStoreHelper.getItemUri(it) },
27-
getCollectableItems = { imagesVM.itemsFlow.collectAsStateValue() }
27+
getCollectableItems = { imagesVM.itemsFlow.collectAsStateValue() },
28+
isInTrashMode = imagesVM.trash.value
2829
)
2930
}

0 commit comments

Comments
 (0)