Skip to content

Commit

Permalink
BaseGrid: Add support for a fixed layout
Browse files Browse the repository at this point in the history
Which allows an entry provider to use specific rows
for its entries.
  • Loading branch information
nilmerg committed Apr 26, 2024
1 parent ac8fee3 commit a64abe5
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 1 deletion.
103 changes: 102 additions & 1 deletion library/Notifications/Widget/Calendar/BaseGrid.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
use SplObjectStorage;
use Traversable;

use function ipl\Stdlib\iterable_value_first;

/**
* @phpstan-type GridArea array{0: int, 1: int, 2: int, 3: int}
* @phpstan-type GridContinuationType self::FROM_PREV_GRID | self::TO_NEXT_GRID | self::ACROSS_GRID
Expand Down Expand Up @@ -390,9 +392,108 @@ final protected function yieldFlowingEntries(Traversable $entries): Generator
}
}

/**
* Yield the entries to show on the grid and place them using a fixed layout
*
* Entry positions are expected to be registered on each individual entry and cannot span multiple rows.
* Collisions won't be prevented and the grid is expected to allow for an infinite number of sections.
*
* @param Traversable<int, Entry> $entries
*
* @return Generator<array{0: GridArea, 1: ?ContinuationType}, Entry>
*/
final protected function yieldFixedEntries(Traversable $entries): Generator
{
if ($this->getMaximumRowSpan() !== 1) {
throw new LogicException('Fixed layouts require a maximum row span of 1');
}

if ($this->getSectionsPerStep() !== self::INFINITE) {
throw new LogicException('Fixed layouts currently only work with an infinite number of sections');
}

$rowStartModifier = $this->getRowStartModifier();
$gridStartsAt = $this->getGridStart();
$gridEndsAt = $this->getGridEnd();
$amountOfDays = $gridStartsAt->diff($gridEndsAt)->days;
$gridBorderAt = $this->getNoOfVisuallyConnectedHours() * 2;

if ($amountOfDays !== $gridBorderAt / 48) {
throw new LogicException(
'The number of days in the grid must match the number'
. ' of visually connected hours, when a fixed layout is used.'
);
}

$lastRow = 1;
foreach ($entries as $entry) {
$position = $entry->getPosition();
if ($position === null) {
throw new LogicException('All entries must have a position set when using a fixed layout');
}

$rowStart = $position + $rowStartModifier;
if ($rowStart > $lastRow) {
$lastRow = $rowStart;
}

$actualStart = $this->roundToNearestThirtyMinute($entry->getStart());
if ($actualStart < $gridStartsAt) {
$colStart = 0;
} else {
$colStart = Util::diffHours($gridStartsAt, $actualStart) * 2;
}

$actualEnd = $this->roundToNearestThirtyMinute($entry->getEnd());
if ($actualEnd > $gridEndsAt) {
$colEnd = $gridBorderAt;
} else {
$colEnd = Util::diffHours($gridStartsAt, $actualEnd) * 2;
}

if ($colStart > $gridBorderAt) {
// TODO: Should this be here? Should this throw? It should definitely not happen!
continue;
}

$gridArea = $this->getGridArea(
$rowStart,
$rowStart + 1,
$colStart + 1,
$colEnd + 1
);

$fromPrevGrid = $gridStartsAt > $entry->getStart();
$toNextGrid = $gridEndsAt < $entry->getEnd();
if ($fromPrevGrid && $toNextGrid) {
$continuationType = self::ACROSS_GRID;
} elseif ($fromPrevGrid) {
$continuationType = self::FROM_PREV_GRID;
} elseif ($toNextGrid) {
$continuationType = self::TO_NEXT_GRID;
} else {
$continuationType = null;
}

yield [$gridArea, $continuationType] => $entry;
}

$this->style->addFor($this, [
'--primaryRows' => $lastRow === 1 ? 1 : $lastRow - $rowStartModifier + 1,
'--rowsPerStep' => 1
]);
}

protected function assembleGridOverlay(BaseHtmlElement $overlay): void
{
foreach ($this->yieldFlowingEntries($this->provider->getEntries()) as $data => $entry) {
$entries = $this->provider->getEntries();
if (iterable_value_first($entries)->getPosition() === null) {
$generator = $this->yieldFlowingEntries($entries);
} else {
$generator = $this->yieldFixedEntries($entries);
}

foreach ($generator as $data => $entry) {
[$gridArea, $continuationType] = $data;

$gradientClass = null;
Expand Down
27 changes: 27 additions & 0 deletions library/Notifications/Widget/Calendar/Entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ class Entry

protected $end;

/** @var ?int The 0-based position of the row where to place this entry on the grid */
protected $position;

protected $rrule;

/** @var Url */
Expand Down Expand Up @@ -73,6 +76,30 @@ public function getEnd(): ?DateTime
return $this->end;
}

/**
* Set the position of the row where to place this entry on the grid
*
* @param ?int $position The 0-based position of the row
*
* @return $this
*/
public function setPosition(?int $position): self
{
$this->position = $position;

return $this;
}

/**
* Get the position of the row where to place this entry on the grid
*
* @return ?int The 0-based position of the row
*/
public function getPosition(): ?int
{
return $this->position;
}

public function setRecurrencyRule(?string $rrule): self
{
$this->rrule = $rrule;
Expand Down

0 comments on commit a64abe5

Please sign in to comment.