nc-photos/app/lib/widget/draggable.dart

124 lines
3.7 KiB
Dart
Raw Normal View History

2021-07-08 10:57:20 +02:00
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
2022-12-16 16:01:04 +01:00
import 'package:np_codegen/np_codegen.dart';
2021-07-08 10:57:20 +02:00
2022-12-16 16:01:04 +01:00
part 'draggable.g.dart';
@npLog
2021-07-23 22:05:57 +02:00
class Draggable<T extends Object> extends StatelessWidget {
2021-09-15 08:58:06 +02:00
const Draggable({
2024-05-28 17:10:33 +02:00
super.key,
2021-07-23 22:05:57 +02:00
required this.data,
required this.child,
this.feedback,
2021-07-08 10:57:20 +02:00
this.onDropBefore,
this.onDropAfter,
this.onDragStarted,
this.onDragEndedAny,
2024-05-28 17:10:33 +02:00
});
2021-07-08 10:57:20 +02:00
@override
2024-10-26 13:41:03 +02:00
Widget build(BuildContext context) {
Widget buildIndicator(alignment, isActive) {
2021-07-08 10:57:20 +02:00
return Stack(
children: [
Container(),
Visibility(
visible: isActive,
child: Align(
alignment: alignment,
child: Container(
2021-09-15 08:58:06 +02:00
constraints: const BoxConstraints.tightFor(width: 2),
2021-07-08 10:57:20 +02:00
color: Theme.of(context).colorScheme.primary,
),
),
),
],
);
2021-09-15 08:58:06 +02:00
}
2021-07-08 10:57:20 +02:00
return Stack(
2024-10-26 13:41:03 +02:00
fit: StackFit.passthrough,
2021-07-08 10:57:20 +02:00
children: [
2024-10-20 12:36:32 +02:00
LongPressDraggable<T>(
data: data,
dragAnchorStrategy: pointerDragAnchorStrategy,
onDragStarted: onDragStarted,
onDragEnd: (_) => onDragEndedAny?.call(),
onDragCompleted: onDragEndedAny,
onDraggableCanceled: (v, o) => onDragEndedAny?.call(),
2024-10-26 13:41:03 +02:00
feedback: Material(
type: MaterialType.transparency,
child: FractionalTranslation(
translation: const Offset(-.5, -.5),
2024-10-20 12:36:32 +02:00
child: Opacity(
opacity: .5,
child: feedback ?? child,
2021-07-08 10:57:20 +02:00
),
),
2024-10-20 12:36:32 +02:00
),
childWhenDragging: Opacity(
opacity: .25,
2022-07-08 16:52:18 +02:00
child: child,
2021-07-08 10:57:20 +02:00
),
2024-10-20 12:36:32 +02:00
child: child,
2021-07-08 10:57:20 +02:00
),
if (onDropBefore != null || onDropAfter != null)
Positioned.fill(
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
if (onDropBefore != null)
Expanded(
child: DragTarget<T>(
builder: (context, candidateItems, rejectedItems) {
return buildIndicator(AlignmentDirectional.centerStart,
candidateItems.isNotEmpty);
},
2024-09-01 19:19:19 +02:00
onAcceptWithDetails: (details) {
_log.fine(
"[build] Dropping ${details.data} before $data");
onDropBefore!(details.data);
2021-07-08 10:57:20 +02:00
},
),
),
if (onDropAfter != null)
Expanded(
child: DragTarget<T>(
builder: (context, candidateItems, rejectedItems) {
return buildIndicator(AlignmentDirectional.centerEnd,
candidateItems.isNotEmpty);
},
2024-09-01 19:19:19 +02:00
onAcceptWithDetails: (details) {
_log.fine(
"[build] Dropping ${details.data} after $data");
onDropAfter!(details.data);
2021-07-08 10:57:20 +02:00
},
),
),
],
),
),
],
);
}
final T data;
final Widget child;
2021-07-23 22:05:57 +02:00
final Widget? feedback;
2021-07-08 10:57:20 +02:00
/// Called when some item dropped before this item
2021-07-23 22:05:57 +02:00
final DragTargetAccept<T>? onDropBefore;
2021-07-08 10:57:20 +02:00
/// Called when some item dropped after this item
2021-07-23 22:05:57 +02:00
final DragTargetAccept<T>? onDropAfter;
2021-07-08 10:57:20 +02:00
2021-07-23 22:05:57 +02:00
final VoidCallback? onDragStarted;
2021-07-08 10:57:20 +02:00
/// Called when either one of onDragEnd, onDragCompleted or
/// onDraggableCanceled is called.
///
/// The callback might be called multiple times per each drag event
2021-07-23 22:05:57 +02:00
final VoidCallback? onDragEndedAny;
2021-07-08 10:57:20 +02:00
}