Skip to content

Commit

Permalink
Condense multiple online viewers to one row
Browse files Browse the repository at this point in the history
  • Loading branch information
danon committed Oct 8, 2024
1 parent d749fc9 commit 1a2f53b
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 39 deletions.
2 changes: 1 addition & 1 deletion app/Domain/Online/FakeSessionRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function sessionsIn(string $prefixPath): SessionsSnapshot
return new SessionsSnapshot(
users:[
...$this->id(User::query()->whereNotNull('group_name')->limit(1)),
...$this->id(User::query()->inRandomOrder()->limit(\rand(5, 7))),
...$this->id(User::query()->inRandomOrder()->limit(\rand(3, 20))),
],
guestsCount:\rand(5, 90),
);
Expand Down
35 changes: 35 additions & 0 deletions app/Domain/Online/Viewers.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php
namespace Coyote\Domain\Online;

use function count;

readonly class Viewers
{
/**
Expand All @@ -12,4 +14,37 @@ public function __construct(
)
{
}

public function usersLeading(int $limit): array
{
return \array_slice($this->usersWithoutGroup(), 0, $limit);
}

public function usersSuperfluous(int $limit): int
{
return \max(0, \count($this->usersWithoutGroup()) - $limit);
}

public function totalCount(): int
{
return count($this->users) + $this->guestsCount;
}

/**
* @return ViewerUser[]
*/
public function usersWithGroup(): array
{
return $this->usersFiltered(fn(ViewerUser $user) => $user->groupName);
}

private function usersWithoutGroup(): array
{
return $this->usersFiltered(fn(ViewerUser $user) => !$user->groupName);
}

private function usersFiltered(callable $predicate): array
{
return \array_values(\array_filter($this->users, $predicate));
}
}
32 changes: 19 additions & 13 deletions app/Services/Session/Renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
namespace Coyote\Services\Session;

use Coyote\Domain\Online\FakeSessionRepository;
use Coyote\Domain\Online\Viewers;
use Coyote\Domain\Online\ViewersStore;
use Illuminate\Http\Request;
use Illuminate\View\View;
Expand All @@ -17,26 +18,31 @@ public function __construct(
}

public function render(string $requestUri, bool $local): View
{
$viewers = $this->sessionViewers($requestUri);
$limit = 8;
return view('components.viewers', [
'local' => $local,
'guestsCount' => $viewers->guestsCount,
'usersCount' => \count($viewers->users),
'title' => $local
? 'Aktualnie na tej stronie'
: "{$viewers->totalCount()} użytkowników online",
'usersWithGroup' => $viewers->usersWithGroup(),
'usersWithoutGroup' => $viewers->usersLeading($limit),
'superfluousCount' => $viewers->usersSuperfluous($limit),
]);
}

private function sessionViewers(string $requestUri): Viewers
{
$sessions = $this->session->sessionsIn($requestUri);
if ($this->isUserLogged()) {
$sessions = $sessions->coalesceUser($this->loggedUserId());
} else {
$sessions = $sessions->coalesceGuest();
}
$viewers = $this->store->viewers($sessions);

$viewersCount = $viewers->guestsCount + \count($viewers->users);
return view('components.viewers', [
'local' => $local,
'showAvatars' => $local,
'guestsCount' => $viewers->guestsCount,
'usersCount' => \count($viewers->users),
'title' => $local
? 'Aktualnie na tej stronie'
: "$viewersCount użytkowników online",
'users' => $viewers->users,
]);
return $this->store->viewers($sessions);
}

private function isUserLogged(): bool
Expand Down
15 changes: 13 additions & 2 deletions resources/feature/viewersOnline/viewers-online.scss
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,22 @@
border-radius: 32px;
overflow: hidden;
margin-right: -12px;
@include dark {
border: 1px solid #444;
width: 32px;

&.viewers-superfluous {
height: 32px;
text-align: center;
line-height: 32px;
font-size: 0.8em;
}

@include light {
border: 1px solid #dedede;
background: white;
}
@include dark {
border: 1px solid #444;
background: #2e2e2e;
}
}
}
Expand Down
45 changes: 22 additions & 23 deletions resources/views/components/viewers.twig
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,29 @@
</p>
</div>
<div class="mb-2 viewers-users-group">
{% for user in users %}
{% if user.groupName %}
<div class="viewer-pill d-inline-flex mb-1" title="Online: {{ user.name }}">
<div class="d-inline-block" style="width:32px; border-radius:16px; overflow:hidden;">
{{ user_avatar(user.avatarUrl, user.name) }}
</div>
<span class="viewer-pill-title">
<b>{{ user.name }}</b>
<br>
<small>{{ user.groupName }}</small>
</span>
{% for user in usersWithGroup %}
<div class="viewer-pill d-inline-flex mb-1" title="Online: {{ user.name }}">
<div class="d-inline-block" style="width:32px; border-radius:16px; overflow:hidden;">
{{ user_avatar(user.avatarUrl, user.name) }}
</div>
{% endif %}
<span class="viewer-pill-title">
<b>{{ user.name }}</b>
<br>
<small>{{ user.groupName }}</small>
</span>
</div>
{% endfor %}
</div>
{% if showAvatars %}
<div class="viewers-users">
{% for user in users %}
{% if not user.groupName %}
<div class="viewers-user d-inline-block mb-1" style="width:32px;" title="Online: {{ user.name }}">
{{ user_avatar(user.avatarUrl, user.name) }}
</div>
{% endif %}
{% endfor %}
</div>
{% endif %}
<div class="viewers-users">
{% for user in usersWithoutGroup %}
<div class="viewers-user d-inline-block mb-1" title="{{ user.name }} (Online)">
{{ user_avatar(user.avatarUrl, user.name) }}
</div>
{% endfor %}
{% if superfluousCount > 0 %}
<div class="viewers-user viewers-superfluous d-inline-block mb-1" title="Jeszcze {{ superfluousCount }} użytkowników online">
+{{ superfluousCount }}
</div>
{% endif %}
</div>
</div>
91 changes: 91 additions & 0 deletions tests/Unit/OnlineUsers/ViewersTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php
namespace Tests\Unit\OnlineUsers;

use Coyote\Domain\Online\Viewers;
use Coyote\Domain\Online\ViewerUser;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

class ViewersTest extends TestCase
{
#[Test]
public function totalCount(): void
{
$viewers = new Viewers($this->usersOfSize(2), 3);
$this->assertSame(5, $viewers->totalCount());
}

#[Test]
public function leadingUsers(): void
{
$viewers = new Viewers([$this->user('Mark')], 0);
[$leading] = $viewers->usersLeading(2);
$this->assertSame('Mark', $leading->name);
}

#[Test]
public function leadingUsersUpToLimit(): void
{
$viewers = new Viewers($this->usersOfSize(5), 0);
$this->assertCount(2, $viewers->usersLeading(2));
}

#[Test]
public function countSuperfluousUsers(): void
{
$viewers = new Viewers($this->usersOfSize(5), 0);
$this->assertSame(3, $viewers->usersSuperfluous(2));
}

#[Test]
public function withLimitBiggerThanUsers_returnEmptySuperfluous(): void
{
$viewers = new Viewers($this->usersOfSize(3), 0);
$this->assertSame(0, $viewers->usersSuperfluous(5));
}

#[Test]
public function usersWithGroup(): void
{
$viewers = new Viewers([
$this->user(name:'Tom'),
$this->user(name:'Mark', group:'Blue'),
], 0);
$users = $viewers->usersWithGroup();
$this->assertCount(1, $users);
$this->assertSame('Mark', $users[0]->name);
}

#[Test]
public function leadingUsers_areWithoutGroups(): void
{
$viewers = new Viewers([
$this->user(name:'Mark', group:'Blue'),
$this->user(name:'Tom'),
], 0);
$leading = $viewers->usersLeading(2);
$this->assertCount(1, $leading);
$this->assertSame('Tom', $leading[0]->name);
}

#[Test]
public function superfluousUsers_areWithoutGroups(): void
{
$viewers = new Viewers([
$this->user(name:'Mark', group:'Blue'),
$this->user(name:'Mark', group:'Blue'),
$this->user(name:'Tom'),
], 0);
$this->assertSame(1, $viewers->usersSuperfluous(0));
}

private function usersOfSize(int $size): array
{
return \array_fill(0, $size, $this->user());
}

private function user(string $name = null, string $group = null): ViewerUser
{
return new ViewerUser($name ?? '', $group, null);
}
}

0 comments on commit 1a2f53b

Please sign in to comment.