mirror of
https://github.com/AllanWang/Frost-for-Facebook.git
synced 2024-11-08 12:02:33 +01:00
Add data to draggable
This commit is contained in:
parent
5567957475
commit
a1bf575da1
@ -38,9 +38,9 @@ import com.pitchedapps.frost.ext.toIntOffset
|
||||
*/
|
||||
|
||||
@Composable
|
||||
fun DragContainer(
|
||||
fun <T> DragContainer(
|
||||
modifier: Modifier = Modifier,
|
||||
draggableState: DraggableState,
|
||||
draggableState: DraggableState<T>,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
@ -61,26 +61,28 @@ fun DragContainer(
|
||||
* dragged.
|
||||
*/
|
||||
@Composable
|
||||
fun DragTarget(
|
||||
fun <T> DragTarget(
|
||||
key: String = "",
|
||||
draggableState: DraggableState,
|
||||
content: @Composable (isDragging: Boolean) -> Unit
|
||||
data: T,
|
||||
draggableState: DraggableState<T>,
|
||||
content: DraggableComposeContent,
|
||||
) {
|
||||
|
||||
val dragTargetState =
|
||||
draggableState.rememberDragTarget(
|
||||
key = key,
|
||||
data = data,
|
||||
content = content,
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier.dragTarget(dragTargetState),
|
||||
) {
|
||||
content(false)
|
||||
content(isDragging = false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Modifier.dragTarget(dragTargetState: DragTargetState): Modifier {
|
||||
private fun <T> Modifier.dragTarget(dragTargetState: DragTargetState<T>): Modifier {
|
||||
return onGloballyPositioned {
|
||||
dragTargetState.windowPosition = it.positionInWindow()
|
||||
dragTargetState.size = it.size
|
||||
@ -111,7 +113,7 @@ private fun Modifier.dragTarget(dragTargetState: DragTargetState): Modifier {
|
||||
.alpha(if (dragTargetState.isDragging) 0f else 1f)
|
||||
}
|
||||
|
||||
fun Modifier.dropTarget(dropTargetState: DropTargetState): Modifier {
|
||||
fun <T> Modifier.dropTarget(dropTargetState: DropTargetState<T>): Modifier {
|
||||
return onGloballyPositioned { dropTargetState.bounds = it.boundsInWindow() }
|
||||
}
|
||||
|
||||
@ -125,14 +127,14 @@ fun Modifier.dropTarget(dropTargetState: DropTargetState): Modifier {
|
||||
* fillMaxWidth in a grid, but would have a full parent width here without the sizing constraints.
|
||||
*/
|
||||
@Composable
|
||||
private fun DraggingContents(draggableState: DraggableState) {
|
||||
private fun <T> DraggingContents(draggableState: DraggableState<T>) {
|
||||
for (target in draggableState.targets) {
|
||||
DraggingContent(target = target)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DraggingContent(target: DragTargetState) {
|
||||
private fun <T> DraggingContent(target: DragTargetState<T>) {
|
||||
val density = LocalDensity.current
|
||||
Box(
|
||||
modifier =
|
||||
|
@ -28,13 +28,15 @@ import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
|
||||
@Composable
|
||||
fun rememberDraggableState(): DraggableState {
|
||||
fun <T> rememberDraggableState(): DraggableState<T> {
|
||||
return remember { DraggableStateImpl() }
|
||||
}
|
||||
|
||||
interface DraggableState {
|
||||
typealias DraggableComposeContent = @Composable (isDragging: Boolean) -> Unit
|
||||
|
||||
val targets: Collection<DragTargetState>
|
||||
interface DraggableState<T> {
|
||||
|
||||
val targets: Collection<DragTargetState<T>>
|
||||
|
||||
/**
|
||||
* Being drag for target [key].
|
||||
@ -44,30 +46,27 @@ interface DraggableState {
|
||||
* Returns true if the request is accepted. It is the caller's responsibility to not propagate
|
||||
* drag events if the request is denied.
|
||||
*/
|
||||
fun onDragStart(key: String, dragTargetState: DragTargetState): Boolean
|
||||
fun onDragStart(key: String, dragTargetState: DragTargetState<T>): Boolean
|
||||
|
||||
fun onDrag(key: String, offset: Offset)
|
||||
|
||||
fun onDragEnd(key: String)
|
||||
|
||||
@Composable
|
||||
fun rememberDragTarget(
|
||||
key: String,
|
||||
content: @Composable (isDragging: Boolean) -> Unit
|
||||
): DragTargetState
|
||||
fun rememberDragTarget(key: String, data: T, content: DraggableComposeContent): DragTargetState<T>
|
||||
|
||||
@Composable fun rememberDropTarget(key: String): DropTargetState
|
||||
@Composable fun rememberDropTarget(key: String): DropTargetState<T>
|
||||
}
|
||||
|
||||
class DraggableStateImpl : DraggableState {
|
||||
private val activeDragTargets = mutableStateMapOf<String, DragTargetState>()
|
||||
class DraggableStateImpl<T> : DraggableState<T> {
|
||||
private val activeDragTargets = mutableStateMapOf<String, DragTargetState<T>>()
|
||||
|
||||
private val dropTargets = mutableStateMapOf<String, DropTargetState>()
|
||||
private val dropTargets = mutableStateMapOf<String, DropTargetState<T>>()
|
||||
|
||||
override val targets: Collection<DragTargetState>
|
||||
override val targets: Collection<DragTargetState<T>>
|
||||
get() = activeDragTargets.values
|
||||
|
||||
override fun onDragStart(key: String, dragTargetState: DragTargetState): Boolean {
|
||||
override fun onDragStart(key: String, dragTargetState: DragTargetState<T>): Boolean {
|
||||
if (key in activeDragTargets) return false
|
||||
activeDragTargets[key] = dragTargetState
|
||||
return true
|
||||
@ -93,18 +92,19 @@ class DraggableStateImpl : DraggableState {
|
||||
@Composable
|
||||
override fun rememberDragTarget(
|
||||
key: String,
|
||||
content: @Composable (isDragging: Boolean) -> Unit
|
||||
): DragTargetState {
|
||||
data: T,
|
||||
content: DraggableComposeContent,
|
||||
): DragTargetState<T> {
|
||||
val target =
|
||||
remember(key, content, this) {
|
||||
DragTargetState(key = key, draggableState = this, composable = content)
|
||||
remember(key, data, content, this) {
|
||||
DragTargetState(key = key, data = data, draggableState = this, composable = content)
|
||||
}
|
||||
DisposableEffect(target) { onDispose { activeDragTargets.remove(key) } }
|
||||
return target
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun rememberDropTarget(key: String): DropTargetState {
|
||||
override fun rememberDropTarget(key: String): DropTargetState<T> {
|
||||
val target = remember(key, this) { DropTargetState(key, this) }
|
||||
DisposableEffect(target) {
|
||||
dropTargets[key] = target
|
||||
@ -116,11 +116,14 @@ class DraggableStateImpl : DraggableState {
|
||||
|
||||
private fun setHover(dragKey: String?, dropKey: String) {
|
||||
val dropTarget = dropTargets[dropKey] ?: return
|
||||
dropTarget.hoverKey = dragKey
|
||||
// Safety check; we only want to register active keys
|
||||
val dragTarget = if (dragKey != null) activeDragTargets[dragKey] else null
|
||||
dropTarget.hoverKey = dragTarget?.key
|
||||
dropTarget.hoverData = dragTarget?.data
|
||||
}
|
||||
|
||||
/** Returns true if drag target exists and is within bounds */
|
||||
private fun DropTargetState.hasValidDragTarget(): Boolean {
|
||||
private fun DropTargetState<T>.hasValidDragTarget(): Boolean {
|
||||
val currentKey = hoverKey ?: return false // no target
|
||||
val dragTarget = activeDragTargets[currentKey] ?: return false // target not valid
|
||||
return dragTarget.within(bounds)
|
||||
@ -152,17 +155,18 @@ class DraggableStateImpl : DraggableState {
|
||||
}
|
||||
}
|
||||
|
||||
private fun DragTargetState?.within(bounds: Rect): Boolean {
|
||||
private fun DragTargetState<*>?.within(bounds: Rect): Boolean {
|
||||
if (this == null) return false
|
||||
val center = dragPosition + Offset(size.width * 0.5f, size.height * 0.5f)
|
||||
return bounds.contains(center)
|
||||
}
|
||||
|
||||
/** State for individual dragging target. */
|
||||
class DragTargetState(
|
||||
class DragTargetState<T>(
|
||||
val key: String,
|
||||
val draggableState: DraggableStateImpl,
|
||||
val composable: @Composable (isDragging: Boolean) -> Unit
|
||||
val data: T,
|
||||
val draggableState: DraggableStateImpl<T>,
|
||||
val composable: DraggableComposeContent,
|
||||
) {
|
||||
var isDragging by mutableStateOf(false)
|
||||
var windowPosition = Offset.Zero
|
||||
@ -170,12 +174,18 @@ class DragTargetState(
|
||||
var size: IntSize by mutableStateOf(IntSize.Zero)
|
||||
}
|
||||
|
||||
class DropTargetState(private val key: String, private val draggableState: DraggableStateImpl) {
|
||||
class DropTargetState<T>(
|
||||
private val key: String,
|
||||
private val draggableState: DraggableStateImpl<T>
|
||||
) {
|
||||
var hoverKey: String? by mutableStateOf(null)
|
||||
var hoverData: String? by mutableStateOf(null)
|
||||
var hoverData: T? by mutableStateOf(null)
|
||||
var bounds: Rect = Rect.Zero
|
||||
set(value) {
|
||||
field = value
|
||||
draggableState.checkForDrop(key)
|
||||
}
|
||||
|
||||
val isHovered
|
||||
get() = hoverKey != null
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ fun TabSelector(
|
||||
unselected: List<TabData>,
|
||||
onSelect: (List<TabData>) -> Unit
|
||||
) {
|
||||
val draggableState = rememberDraggableState()
|
||||
val draggableState = rememberDraggableState<TabData>()
|
||||
|
||||
DragContainer(modifier = modifier, draggableState = draggableState) {
|
||||
Column(modifier = Modifier.statusBarsPadding()) {
|
||||
@ -96,7 +96,7 @@ fun TabSelector(
|
||||
columns = GridCells.Fixed(4),
|
||||
) {
|
||||
items(unselected, key = { it.key }) {
|
||||
DragTarget(key = it.key, draggableState = draggableState) { isDragging ->
|
||||
DragTarget(key = it.key, data = it, draggableState = draggableState) { isDragging ->
|
||||
TabItem(
|
||||
modifier =
|
||||
Modifier.thenIf(!isDragging) {
|
||||
@ -124,7 +124,7 @@ fun TabSelector(
|
||||
@Composable
|
||||
fun TabBottomBar(
|
||||
modifier: Modifier = Modifier,
|
||||
draggableState: DraggableState,
|
||||
draggableState: DraggableState<TabData>,
|
||||
items: List<TabData>
|
||||
) {
|
||||
NavigationBar(modifier = modifier) {
|
||||
@ -133,7 +133,7 @@ fun TabBottomBar(
|
||||
|
||||
val alpha by
|
||||
animateFloatAsState(
|
||||
targetValue = if (dropTargetState.hoverKey == null) 1f else 0f,
|
||||
targetValue = if (!dropTargetState.isHovered) 1f else 0.3f,
|
||||
label = "Nav Item Alpha",
|
||||
)
|
||||
|
||||
@ -141,10 +141,13 @@ fun TabBottomBar(
|
||||
modifier = Modifier.dropTarget(dropTargetState),
|
||||
icon = {
|
||||
// println(dropTargetState.hoverKey)
|
||||
|
||||
val iconItem = dropTargetState.hoverData ?: item
|
||||
|
||||
Icon(
|
||||
modifier = Modifier.size(24.dp).alpha(alpha),
|
||||
imageVector = item.icon,
|
||||
contentDescription = item.title,
|
||||
imageVector = iconItem.icon,
|
||||
contentDescription = iconItem.title,
|
||||
)
|
||||
},
|
||||
selected = false,
|
||||
|
Loading…
Reference in New Issue
Block a user