fix: pack visually colliding timeline cards
This commit is contained in:
parent
acee1da264
commit
dd6552e68d
2 changed files with 50 additions and 15 deletions
|
|
@ -73,7 +73,10 @@ class _TimelineViewState extends State<TimelineView> {
|
|||
minCardHeight: 88,
|
||||
);
|
||||
final contentHeight = geometry.totalHeight + 24;
|
||||
final placements = _TimelineCardPlacement.pack(widget.cards);
|
||||
final placements = _TimelineCardPlacement.pack(
|
||||
widget.cards,
|
||||
geometry: geometry,
|
||||
);
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
_scheduleInitialScroll(geometry, constraints.maxHeight);
|
||||
|
|
@ -195,7 +198,10 @@ class _TimelineCardPlacement {
|
|||
final int lane;
|
||||
final int laneCount;
|
||||
|
||||
static List<_TimelineCardPlacement> pack(List<TimelineCardModel> cards) {
|
||||
static List<_TimelineCardPlacement> pack(
|
||||
List<TimelineCardModel> cards, {
|
||||
required TimelineGeometry geometry,
|
||||
}) {
|
||||
if (cards.isEmpty) {
|
||||
return const [];
|
||||
}
|
||||
|
|
@ -213,41 +219,50 @@ class _TimelineCardPlacement {
|
|||
});
|
||||
final placements = <_TimelineCardPlacement>[];
|
||||
var groupStart = 0;
|
||||
var groupEnd = sorted.first.endMinutes;
|
||||
var groupEnd = _visualEnd(sorted.first, geometry);
|
||||
for (var index = 1; index < sorted.length; index += 1) {
|
||||
final card = sorted[index];
|
||||
if (card.startMinutes < groupEnd) {
|
||||
if (card.endMinutes > groupEnd) {
|
||||
groupEnd = card.endMinutes;
|
||||
final cardStart = _visualStart(card, geometry);
|
||||
final cardEnd = _visualEnd(card, geometry);
|
||||
if (cardStart < groupEnd) {
|
||||
if (cardEnd > groupEnd) {
|
||||
groupEnd = cardEnd;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
placements.addAll(_packGroup(sorted.sublist(groupStart, index)));
|
||||
placements.addAll(
|
||||
_packGroup(sorted.sublist(groupStart, index), geometry: geometry),
|
||||
);
|
||||
groupStart = index;
|
||||
groupEnd = card.endMinutes;
|
||||
groupEnd = cardEnd;
|
||||
}
|
||||
placements.addAll(_packGroup(sorted.sublist(groupStart)));
|
||||
placements.addAll(
|
||||
_packGroup(sorted.sublist(groupStart), geometry: geometry),
|
||||
);
|
||||
return placements;
|
||||
}
|
||||
|
||||
static List<_TimelineCardPlacement> _packGroup(
|
||||
List<TimelineCardModel> group,
|
||||
) {
|
||||
final laneEnds = <int>[];
|
||||
List<TimelineCardModel> group, {
|
||||
required TimelineGeometry geometry,
|
||||
}) {
|
||||
final laneEnds = <double>[];
|
||||
final laneByCard = <TimelineCardModel, int>{};
|
||||
for (final card in group) {
|
||||
final cardStart = _visualStart(card, geometry);
|
||||
final cardEnd = _visualEnd(card, geometry);
|
||||
var assignedLane = -1;
|
||||
for (var lane = 0; lane < laneEnds.length; lane += 1) {
|
||||
if (laneEnds[lane] <= card.startMinutes) {
|
||||
if (laneEnds[lane] <= cardStart) {
|
||||
assignedLane = lane;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (assignedLane == -1) {
|
||||
assignedLane = laneEnds.length;
|
||||
laneEnds.add(card.endMinutes);
|
||||
laneEnds.add(cardEnd);
|
||||
} else {
|
||||
laneEnds[assignedLane] = card.endMinutes;
|
||||
laneEnds[assignedLane] = cardEnd;
|
||||
}
|
||||
laneByCard[card] = assignedLane;
|
||||
}
|
||||
|
|
@ -262,6 +277,18 @@ class _TimelineCardPlacement {
|
|||
];
|
||||
}
|
||||
|
||||
static double _visualStart(
|
||||
TimelineCardModel card,
|
||||
TimelineGeometry geometry,
|
||||
) {
|
||||
return geometry.yForMinutesSinceMidnight(card.startMinutes);
|
||||
}
|
||||
|
||||
static double _visualEnd(TimelineCardModel card, TimelineGeometry geometry) {
|
||||
final duration = card.endMinutes - card.startMinutes;
|
||||
return _visualStart(card, geometry) + geometry.heightForDuration(duration);
|
||||
}
|
||||
|
||||
double left(double trackWidth) {
|
||||
final laneWidth = _laneWidth(trackWidth);
|
||||
final laneGap = _laneGapForWidth(trackWidth);
|
||||
|
|
|
|||
|
|
@ -242,6 +242,12 @@ void main() {
|
|||
final waterPlants = tester.getRect(
|
||||
find.byKey(const ValueKey('water-plants')),
|
||||
);
|
||||
final cleanCoffee = tester.getRect(
|
||||
find.byKey(const ValueKey('clean-coffee-maker')),
|
||||
);
|
||||
final cleanedKitchenEarly = tester.getRect(
|
||||
find.byKey(const ValueKey('cleaned-kitchen-counter-early')),
|
||||
);
|
||||
|
||||
expect(startLaundry.left, greaterThan(sortMail.left));
|
||||
expect(waterPlants.left, closeTo(sortMail.left, 1));
|
||||
|
|
@ -249,6 +255,8 @@ void main() {
|
|||
expect(waterPlants.width, closeTo(sortMail.width, 1));
|
||||
expect(sortMail.right, lessThan(startLaundry.left));
|
||||
expect(waterPlants.right, lessThan(startLaundry.left));
|
||||
expect(cleanedKitchenEarly.left, greaterThan(cleanCoffee.left));
|
||||
expect(cleanCoffee.right, lessThan(cleanedKitchenEarly.left));
|
||||
});
|
||||
|
||||
testWidgets('top bar controls scale inside a compact header width', (
|
||||
|
|
|
|||
Loading…
Reference in a new issue