[client] Highlight all dragged rows

This commit is contained in:
Abhishek Shroff
2024-09-05 22:43:29 +05:30
parent 6432abd2a9
commit d8f4b1a11e
3 changed files with 60 additions and 30 deletions

View File

@@ -120,6 +120,7 @@ class _FolderContentsViewState extends State<FolderContentsView> {
: SelectionMode.single;
if (context.read<FolderSelectionState>().isSelected(r.id) && mode == SelectionMode.single) {
deferHandling = true;
context.read<FolderSelectionManager>().update(focusId: r.id, focusIndex: index, showFocus: false);
} else {
deferHandling = false;
updateSelection(index, mode, false);

View File

@@ -5,8 +5,9 @@ class FolderSelectionState {
final String focusId;
final int focusIndex;
final bool showFocus;
final bool dragging;
FolderSelectionState({required this.selected, required this.focusId, required this.focusIndex, required this.showFocus});
FolderSelectionState({required this.selected, required this.focusId, required this.focusIndex, required this.showFocus, required this.dragging});
bool isSelected(String id) {
return selected.contains(id);
@@ -14,19 +15,20 @@ class FolderSelectionState {
}
class FolderSelectionManager extends StateNotifier<FolderSelectionState> {
FolderSelectionManager() : super(FolderSelectionState(selected: {}, focusId: "", focusIndex: -1, showFocus: false));
FolderSelectionManager() : super(FolderSelectionState(selected: {}, focusId: "", focusIndex: -1, showFocus: false, dragging: false));
void update({
Set<String>? selected,
String? focusId,
int? focusIndex,
bool? showFocus,
bool? dragging,
}) {
state = FolderSelectionState(
selected: selected ?? state.selected,
focusId: focusId ?? state.focusId,
focusIndex: focusIndex ?? state.focusIndex,
showFocus: showFocus ?? state.showFocus,
);
selected: selected ?? state.selected,
focusId: focusId ?? state.focusId,
focusIndex: focusIndex ?? state.focusIndex,
showFocus: showFocus ?? state.showFocus,
dragging: dragging ?? state.dragging);
}
}

View File

@@ -4,7 +4,7 @@ import 'package:phylum/ui/folder/folder_selection_manager.dart';
import 'package:phylum/ui/folder/resource_options_dialog.dart';
import 'package:provider/provider.dart';
class ResourceDetailsRow extends StatelessWidget {
class ResourceDetailsRow extends StatefulWidget {
final Resource r;
final Function(TapDownDetails)? onTapDown;
final Function()? onTap;
@@ -13,16 +13,26 @@ class ResourceDetailsRow extends StatelessWidget {
ResourceDetailsRow({required this.r, this.onTapDown, this.onTap, this.onDoubleTap, this.onSecondaryTap}) : super(key: ValueKey(r.id));
@override
State<ResourceDetailsRow> createState() => _ResourceDetailsRowState();
}
class _ResourceDetailsRowState extends State<ResourceDetailsRow> {
bool dropTargetActive = false;
@override
Widget build(BuildContext context) {
return r.dir
return widget.r.dir
? DragTarget(
builder: (context, candidate, rejected) => buildRow(context),
onWillAcceptWithDetails: (details) {
dropTargetActive = true;
return true;
},
onLeave: (data) {},
onLeave: (data) {
dropTargetActive = false;
},
onAcceptWithDetails: (details) {
dropTargetActive = false;
print(details.data);
},
)
@@ -30,14 +40,18 @@ class ResourceDetailsRow extends StatelessWidget {
}
Widget buildRow(BuildContext context) {
final focussed = context.select<FolderSelectionState, bool>((state) => state.focusId == r.id && state.showFocus);
final selected = context.select<FolderSelectionState, bool>((state) => state.isSelected(r.id));
return Draggable(
data: r,
data: widget.r,
dragAnchorStrategy: pointerDragAnchorStrategy,
feedback: Builder(builder: (context) {
onDragStarted: () {
context.read<FolderSelectionManager>().update(dragging: true);
},
onDragEnd: (details) {
context.read<FolderSelectionManager>().update(dragging: false);
},
feedback: Builder(builder: (ctx) {
final theme = Theme.of(context);
final count = context.read<FolderSelectionState>().selected.length;
return Card(
shape: RoundedRectangleBorder(side: BorderSide(color: theme.colorScheme.primary), borderRadius: BorderRadius.circular(4.0)),
elevation: 16.0,
@@ -46,32 +60,45 @@ class ResourceDetailsRow extends StatelessWidget {
width: 240,
height: 48,
child: ListTile(
leading: r.getIcon(),
title: Text(r.name),
leading: widget.r.getIcon(),
title: Text(widget.r.name),
trailing: count == 1 ? null : Badge(label: Text(count.toString(), style: const TextStyle(fontSize: 14))),
),
),
);
}),
child: GestureDetector(
onTapDown: onTapDown,
onTap: onTap,
onDoubleTap: onDoubleTap,
onSecondaryTap: onSecondaryTap,
child: buildListTile(context, focussed, selected),
onTapDown: widget.onTapDown,
onTap: widget.onTap,
onDoubleTap: widget.onDoubleTap,
onSecondaryTap: widget.onSecondaryTap,
child: buildListTile(context),
),
);
}
Widget buildListTile(BuildContext context, bool showBorder, bool highlight) {
Widget buildListTile(BuildContext context) {
final showBorder = context.select<FolderSelectionState, bool>((state) => state.focusId == widget.r.id && state.showFocus);
final highlight = context.select<FolderSelectionState, bool>((state) => state.isSelected(widget.r.id));
final dim = context.select<FolderSelectionState, bool>((state) => state.isSelected(widget.r.id) && state.dragging);
final theme = Theme.of(context);
final border = showBorder ? BorderSide(color: theme.colorScheme.primary, width: 2.0) : const BorderSide(color: Colors.transparent, width: 2.0);
final border = dropTargetActive
? BorderSide(color: theme.colorScheme.secondary, width: 2.0)
: showBorder
? BorderSide(color: theme.colorScheme.primary, width: 2.0)
: const BorderSide(color: Colors.transparent, width: 2.0);
return ListTile(
leading: r.getIcon(),
title: Text(r.name),
trailing: ResourceOptionsButton(r: r),
shape: RoundedRectangleBorder(side: border, borderRadius: BorderRadius.circular(4.0)),
selected: highlight,
return Opacity(
opacity: dim ? 0.6 : 1.0,
child: ListTile(
leading: widget.r.getIcon(),
title: Text(widget.r.name),
trailing: ResourceOptionsButton(r: widget.r),
shape: RoundedRectangleBorder(side: border, borderRadius: BorderRadius.circular(4.0)),
selected: highlight,
selectedTileColor: dim ? theme.colorScheme.surfaceDim : null,
tileColor: dropTargetActive ? theme.colorScheme.secondaryContainer : null,
),
);
}
}