Drop items on tags in edit favorites sheet to tag them

This commit is contained in:
MM20 2022-09-24 23:01:04 +02:00
parent 2c307693f2
commit 60990e767c
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
5 changed files with 99 additions and 8 deletions

View File

@ -32,6 +32,7 @@ interface CustomAttributesRepository {
suspend fun getAllTags(startsWith: String? = null): List<String> suspend fun getAllTags(startsWith: String? = null): List<String>
fun getItemsForTag(tag: String): Flow<List<Searchable>> fun getItemsForTag(tag: String): Flow<List<Searchable>>
fun addTag(item: Searchable, tag: String)
} }
internal class CustomAttributesRepositoryImpl( internal class CustomAttributesRepositoryImpl(
@ -122,6 +123,13 @@ internal class CustomAttributesRepositoryImpl(
} }
} }
override fun addTag(item: Searchable, tag: String) {
val dao = appDatabase.customAttrsDao()
scope.launch {
dao.addTag(item.key, tag)
}
}
override suspend fun search(query: String): Flow<List<Searchable>> { override suspend fun search(query: String): Flow<List<Searchable>> {
if (query.isBlank()) { if (query.isBlank()) {
return flow { return flow {

View File

@ -41,4 +41,17 @@ interface CustomAttrsDao {
@Query("SELECT key FROM CustomAttributes WHERE type = 'tag' AND value = :tag") @Query("SELECT key FROM CustomAttributes WHERE type = 'tag' AND value = :tag")
fun getItemsWithTag(tag: String): Flow<List<String>> fun getItemsWithTag(tag: String): Flow<List<String>>
@Transaction
suspend fun addTag(key: String, tag: String) {
removeTag(key, tag)
insertTag(key, tag)
}
@Query("DELETE FROM CustomAttributes WHERE type = 'tag' AND key = :key AND value = :tag")
suspend fun removeTag(key: String, tag: String)
@Query("INSERT INTO CustomAttributes (key, value, type) VALUES (:key, :tag, 'tag')")
suspend fun insertTag(key: String, tag: String)
} }

View File

@ -31,7 +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 = {_, _ ->}, onDrag: (item: LazyGridItemInfo, offset: Offset, position: 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
@ -51,7 +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 onDrag: (item: LazyGridItemInfo, offset: Offset, position: 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
@ -284,7 +284,7 @@ fun Modifier.dragAndDrop(
state.endScrolling() state.endScrolling()
} }
state.draggedItemOffset?.let { state.onDrag(draggedItem, it) } state.draggedItemOffset?.let { state.onDrag(draggedItem, it, absPosition) }
} }
}, },
onDragCancel = { onDragCancel = {

View File

@ -9,11 +9,17 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.* import androidx.compose.material.icons.rounded.*
import androidx.compose.material3.* import androidx.compose.material3.*
@ -22,9 +28,11 @@ import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.PathEffect import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.drawOutline import androidx.compose.ui.graphics.drawOutline
import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -32,6 +40,8 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toOffset
import androidx.compose.ui.unit.toSize
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.badges.Badge import de.mm20.launcher2.badges.Badge
import de.mm20.launcher2.icons.LauncherIcon import de.mm20.launcher2.icons.LauncherIcon
@ -43,6 +53,8 @@ import de.mm20.launcher2.ui.component.ShapedLauncherIcon
import de.mm20.launcher2.ui.ktx.toPixels import de.mm20.launcher2.ui.ktx.toPixels
import de.mm20.launcher2.ui.launcher.helper.* import de.mm20.launcher2.ui.launcher.helper.*
import de.mm20.launcher2.ui.locals.LocalGridColumns import de.mm20.launcher2.ui.locals.LocalGridColumns
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.isActive
import kotlin.math.roundToInt import kotlin.math.roundToInt
@Composable @Composable
@ -119,19 +131,55 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM) {
val contextMenuCloseDistance = 8.dp.toPixels() val contextMenuCloseDistance = 8.dp.toPixels()
var draggedItemKey by remember { mutableStateOf<String?>(null) }
var hoveredTag by remember { mutableStateOf<String?>(null) }
val gridState = rememberLazyGridState()
val tagsListState = rememberLazyListState()
val tagsTitleSize = 48.dp.toPixels()
val state = rememberLazyDragAndDropGridState( val state = rememberLazyDragAndDropGridState(
gridState = gridState,
onDragStart = { onDragStart = {
val item = items.getOrNull(it.index) val item = items.getOrNull(it.index)
if (item !is FavoritesSheetGridItem.Favorite) return@rememberLazyDragAndDropGridState false if (item !is FavoritesSheetGridItem.Favorite) return@rememberLazyDragAndDropGridState false
draggedItemKey = item.item.key
contextMenuItemKey = item.item.key contextMenuItemKey = item.item.key
true true
}, },
onDrag = { _, offset -> onDrag = { item, offset, position ->
if (offset.getDistanceSquared() > contextMenuCloseDistance) { if (offset.getDistanceSquared() > contextMenuCloseDistance) {
contextMenuItemKey = null contextMenuItemKey = null
} }
val draggedCenter = Rect(position, item.size.toSize()).center
val hoveredItem = gridState.layoutInfo.visibleItemsInfo.find {
Rect(
it.offset.toOffset(),
it.size.toSize()
).contains(draggedCenter)
}
if (hoveredItem != null
&& items[hoveredItem.index] is FavoritesSheetGridItem.Tags
&& hoveredItem.offset.y + tagsTitleSize < position.y
) {
val scroll = tagsListState.layoutInfo.viewportStartOffset
val tag = tagsListState.layoutInfo.visibleItemsInfo.find {
position.x + scroll > it.offset && position.x + scroll < it.offset + it.size
}
hoveredTag = tag?.index?.let { pinnedTags[it].tag }
} else {
hoveredTag = null
}
},
onDragEnd = {
viewModel.addTag(draggedItemKey, hoveredTag)
draggedItemKey = null
hoveredTag = null
},
onDragCancel = {
draggedItemKey = null
hoveredTag = null
} }
) { from, to -> ) { from, to ->
viewModel.moveItem(from, to) viewModel.moveItem(from, to)
@ -428,10 +476,15 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM) {
} }
if (pinnedTags.isNotEmpty()) { if (pinnedTags.isNotEmpty()) {
val rowState = rememberLazyDragAndDropListState { from, to -> val rowState = rememberLazyDragAndDropListState(
listState = tagsListState,
) { from, to ->
viewModel.moveTag(from, to) viewModel.moveTag(from, to)
} }
LazyDragAndDropRow(state = rowState) { LazyDragAndDropRow(
modifier = Modifier.fillMaxWidth(),
state = rowState
) {
items( items(
pinnedTags, pinnedTags,
key = { it.key } key = { it.key }
@ -439,8 +492,15 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM) {
DraggableItem(state = rowState, key = tag.key) { dragged -> DraggableItem(state = rowState, key = tag.key) { dragged ->
FilterChip( FilterChip(
modifier = Modifier.padding(end = 12.dp), modifier = Modifier
selected = false, .padding(end = 12.dp)
.pointerInput(null) {
val coroutineContext =
currentCoroutineContext()
}
,
selected = tag.tag == hoveredTag,
onClick = {}, onClick = {},
label = { Text(tag.label) }, label = { Text(tag.label) },
leadingIcon = { leadingIcon = {

View File

@ -296,4 +296,14 @@ class EditFavoritesSheetVM : ViewModel(), KoinComponent {
save() save()
} }
fun addTag(key: String?, tag: String?) {
val gridItems = gridItems.value?.toMutableList() ?: return
if (key == null || tag == null) return
val item =
gridItems.find { it is FavoritesSheetGridItem.Favorite && it.item.key == key } as FavoritesSheetGridItem.Favorite?
if (item != null) {
customAttributesRepository.addTag(item.item, tag)
}
}
} }