Add the ability to explicitely remove items from frequently used items

Close #113
This commit is contained in:
MM20 2022-09-19 22:57:57 +02:00
parent 91e68cd8d3
commit db7db74d2d
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
5 changed files with 90 additions and 18 deletions

View File

@ -160,4 +160,7 @@ interface SearchDao {
@Query("UPDATE Searchable SET `pinned` = 0") @Query("UPDATE Searchable SET `pinned` = 0")
fun unpinAll() fun unpinAll()
@Query("UPDATE Searchable Set `pinned` = 0, `launchCount` = 0 WHERE `key` = :key")
suspend fun resetPinStatusAndLaunchCounter(key: String)
} }

View File

@ -54,14 +54,23 @@ interface FavoritesRepository {
fun unhideItem(searchable: Searchable) fun unhideItem(searchable: Searchable)
fun incrementLaunchCounter(searchable: Searchable) fun incrementLaunchCounter(searchable: Searchable)
fun updateFavorites( fun updateFavorites(
manuallySorted: List<Searchable>, manuallySorted: List<Searchable>,
automaticallySorted: List<Searchable>, automaticallySorted: List<Searchable>,
) )
fun getHiddenItems(): Flow<List<Searchable>> fun getHiddenItems(): Flow<List<Searchable>>
fun getHiddenItemKeys(): Flow<List<String>> fun getHiddenItemKeys(): Flow<List<String>>
/**
* Remove this item from the Searchable database
*/
fun remove(searchable: Searchable) fun remove(searchable: Searchable)
/**
* Remove this item from favorites and reset launch counter
*/
fun removeFromFavorites(searchable: Searchable)
/** /**
* Ensure that this searchable exists in the Favorites table. * Ensure that this searchable exists in the Favorites table.
* If it doesn't exist, insert it with 0 launch count, not pinned and not hidden * If it doesn't exist, insert it with 0 launch count, not pinned and not hidden
@ -287,6 +296,12 @@ internal class FavoritesRepositoryImpl(
} }
} }
override fun removeFromFavorites(searchable: Searchable) {
scope.launch {
database.searchDao().resetPinStatusAndLaunchCounter(searchable.key)
}
}
override fun save(searchable: Searchable) { override fun save(searchable: Searchable) {
scope.launch { scope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
@ -322,17 +337,18 @@ internal class FavoritesRepositoryImpl(
entity.pinPosition = manuallySorted.size - index + 1 entity.pinPosition = manuallySorted.size - index + 1
entity entity
} }
val updatedAutomaticallySorted = automaticallySorted.mapIndexedNotNull { index, searchable -> val updatedAutomaticallySorted =
val entity = entities.find { searchable.key == it.key } ?: FavoritesItem( automaticallySorted.mapIndexedNotNull { index, searchable ->
key = searchable.key, val entity = entities.find { searchable.key == it.key } ?: FavoritesItem(
searchable = searchable, key = searchable.key,
launchCount = 0, searchable = searchable,
pinPosition = 0, launchCount = 0,
hidden = false, pinPosition = 0,
).toDatabaseEntity() ?: return@mapIndexedNotNull null hidden = false,
entity.pinPosition = 1 ).toDatabaseEntity() ?: return@mapIndexedNotNull null
entity entity.pinPosition = 1
} entity
}
database.runInTransaction { database.runInTransaction {
dao.unpinAll() dao.unpinAll()
dao.insertAllReplaceExisting(updatedManuallySorted) dao.insertAllReplaceExisting(updatedManuallySorted)
@ -439,7 +455,10 @@ internal class FavoritesRepositoryImpl(
if (item.searchable == null || item.searchable.key != item.key) { if (item.searchable == null || item.searchable.key != item.key) {
removeInvalidItem(item.key) removeInvalidItem(item.key)
removed++ removed++
Log.i("MM20", "SearchableDatabase cleanup: removed invalid item ${item.key}") Log.i(
"MM20",
"SearchableDatabase cleanup: removed invalid item ${item.key}"
)
} }
} }
page++ page++

View File

@ -31,6 +31,7 @@ import kotlin.coroutines.coroutineContext
fun rememberLazyDragAndDropGridState( fun rememberLazyDragAndDropGridState(
gridState: LazyGridState = rememberLazyGridState(), gridState: LazyGridState = rememberLazyGridState(),
onDragStart: (item: LazyGridItemInfo) -> Boolean = { true }, onDragStart: (item: LazyGridItemInfo) -> Boolean = { true },
onDrag: (item: LazyGridItemInfo, offset: Offset) -> Unit = {_, _ ->},
onDragEnd: (item: LazyGridItemInfo) -> Unit = {}, onDragEnd: (item: LazyGridItemInfo) -> Unit = {},
onDragCancel: (item: LazyGridItemInfo) -> Unit = {}, onDragCancel: (item: LazyGridItemInfo) -> Unit = {},
onItemMove: (from: LazyGridItemInfo, to: LazyGridItemInfo) -> Unit onItemMove: (from: LazyGridItemInfo, to: LazyGridItemInfo) -> Unit
@ -39,6 +40,7 @@ fun rememberLazyDragAndDropGridState(
LazyDragAndDropGridState( LazyDragAndDropGridState(
gridState, gridState,
onDragStart, onDragStart,
onDrag,
onDragEnd, onDragEnd,
onDragCancel, onDragCancel,
onItemMove onItemMove
@ -49,6 +51,7 @@ fun rememberLazyDragAndDropGridState(
data class LazyDragAndDropGridState( data class LazyDragAndDropGridState(
val gridState: LazyGridState, val gridState: LazyGridState,
val onDragStart: (item: LazyGridItemInfo) -> Boolean = { true }, val onDragStart: (item: LazyGridItemInfo) -> Boolean = { true },
val onDrag: (item: LazyGridItemInfo, offset: Offset) -> Unit = {_, _ ->},
val onDragEnd: (item: LazyGridItemInfo) -> Unit = {}, val onDragEnd: (item: LazyGridItemInfo) -> Unit = {},
val onDragCancel: (item: LazyGridItemInfo) -> Unit = {}, val onDragCancel: (item: LazyGridItemInfo) -> Unit = {},
val onItemMove: (from: LazyGridItemInfo, to: LazyGridItemInfo) -> Unit val onItemMove: (from: LazyGridItemInfo, to: LazyGridItemInfo) -> Unit
@ -259,7 +262,7 @@ fun Modifier.dragAndDrop(
).contains(draggedCenter) ).contains(draggedCenter)
} }
if (dragOver != null && dragOver.key != state.draggedItem?.key) { if (dragOver != null && dragOver.key != draggedItem.key) {
scope.launch { scope.launch {
state.attemptMove(dragOver) state.attemptMove(dragOver)
} }
@ -280,6 +283,8 @@ fun Modifier.dragAndDrop(
} else { } else {
state.endScrolling() state.endScrolling()
} }
state.draggedItemOffset?.let { state.onDrag(draggedItem, it) }
} }
}, },
onDragCancel = { onDragCancel = {

View File

@ -14,6 +14,7 @@ import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Add import androidx.compose.material.icons.rounded.Add
import androidx.compose.material.icons.rounded.Delete
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.livedata.observeAsState
@ -112,9 +113,23 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM) {
val items by viewModel.gridItems.observeAsState(emptyList()) val items by viewModel.gridItems.observeAsState(emptyList())
val columns = LocalGridColumns.current val columns = LocalGridColumns.current
var contextMenuItemKey by remember { mutableStateOf<String?>(null) }
val contextMenuCloseDistance = 8.dp.toPixels()
val state = rememberLazyDragAndDropGridState( val state = rememberLazyDragAndDropGridState(
onDragStart = { onDragStart = {
items.getOrNull(it.index) is FavoritesSheetGridItem.Favorite val item = items.getOrNull(it.index)
if (item !is FavoritesSheetGridItem.Favorite) return@rememberLazyDragAndDropGridState false
contextMenuItemKey = item.item.key
true
},
onDrag = { _, offset ->
if (offset.getDistanceSquared() > contextMenuCloseDistance) {
contextMenuItemKey = null
}
} }
) { from, to -> ) { from, to ->
viewModel.moveItem(from, to) viewModel.moveItem(from, to)
@ -163,6 +178,23 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM) {
icon = icon, icon = icon,
badge = badge badge = badge
) )
if (contextMenuItemKey == it.item.key) {
DropdownMenu(
expanded = true,
onDismissRequest = { contextMenuItemKey = null }) {
DropdownMenuItem(
leadingIcon = {
Icon(imageVector = Icons.Rounded.Delete, contentDescription = null)
},
text = {
Text("Remove")
}, onClick = {
contextMenuItemKey?.let { viewModel.remove(it) }
contextMenuItemKey = null
}
)
}
}
} }
} }
is FavoritesSheetGridItem.Divider -> { is FavoritesSheetGridItem.Divider -> {
@ -331,8 +363,11 @@ fun ShortcutPicker(viewModel: EditFavoritesSheetVM) {
.fillMaxWidth() .fillMaxWidth()
.padding(vertical = 4.dp), .padding(vertical = 4.dp),
onClick = { onClick = {
val launcherApps = context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps val launcherApps =
val sender = launcherApps.getShortcutConfigActivityIntent(it.launcherActivityInfo) ?: return@OutlinedCard context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
val sender =
launcherApps.getShortcutConfigActivityIntent(it.launcherActivityInfo)
?: return@OutlinedCard
activityLauncher.launch(IntentSenderRequest.Builder(sender).build(), null) activityLauncher.launch(IntentSenderRequest.Builder(sender).build(), null)
}) { }) {
Row( Row(

View File

@ -202,5 +202,15 @@ class EditFavoritesSheetVM : ViewModel(), KoinComponent {
createShortcutTarget.value = null createShortcutTarget.value = null
} }
fun remove(key: String) {
val gridItems = gridItems.value?.toMutableList() ?: return
val item = gridItems.find { it is FavoritesSheetGridItem.Favorite && it.item.key == key } as FavoritesSheetGridItem.Favorite?
if (item != null) {
repository.removeFromFavorites(item.item)
gridItems.remove(item)
this.gridItems.value = gridItems
}
}
} }