Files
hstream/app/Livewire/PlaylistOverview.php
2026-08-04 15:29:39 +02:00

219 lines
5.4 KiB
PHP

<?php
namespace App\Livewire;
use App\Models\Episode;
use App\Models\Playlist;
use App\Models\PlaylistEpisode;
use App\Services\PlaylistService;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;
class PlaylistOverview extends Component
{
use WithPagination;
protected PlaylistService $playlistService;
#[Url(history: true)]
public string $search = '';
#[Url(history: true)]
public int $perPage = 25;
public Playlist $playlist;
public bool $editingName = false;
public string $editingPlaylistName = '';
public function boot(PlaylistService $playlistService)
{
$this->playlistService = $playlistService;
}
public function mount($playlist_id)
{
$this->playlist = Playlist::withCount('episodes')->with('user')->findOrFail($playlist_id);
$this->sanitizePerPage();
$this->repairNullPositions();
}
public function updatingSearch(): void
{
$this->resetPage();
}
public function updatingPerPage(): void
{
$this->resetPage();
}
public function getEpisodesProperty(): LengthAwarePaginator
{
$this->sanitizePerPage();
return PlaylistEpisode::query()
->where('playlist_id', $this->playlist->id)
->when($this->search !== '', fn ($query) => $query->whereHas('episode', fn ($episode) => $episode
->where('title', 'like', '%'.$this->search.'%')
->orWhere('title_jpn', 'like', '%'.$this->search.'%')))
->orderBy('position')
->with(['episode.gallery' => fn ($gallery) => $gallery->orderBy('id')->limit(1)])
->paginate($this->perPage);
}
public function getFirstEpisodeProperty(): ?Episode
{
return PlaylistEpisode::where('playlist_id', $this->playlist->id)
->orderBy('position')
->first()?->episode;
}
public function moveUp($episodeId)
{
if (! $this->isOwner()) {
return;
}
$episode = PlaylistEpisode::find($episodeId);
if (! $episode) {
return;
}
$above = PlaylistEpisode::where('playlist_id', $episode->playlist_id)
->where('position', '<', $episode->position)
->orderBy('position', 'desc')
->first();
if ($above) {
$this->playlistService->swapPositions($episode, $above);
}
}
public function moveDown($episodeId)
{
if (! $this->isOwner()) {
return;
}
$episode = PlaylistEpisode::find($episodeId);
if (! $episode) {
return;
}
$below = PlaylistEpisode::where('playlist_id', $episode->playlist_id)
->where('position', '>', $episode->position)
->orderBy('position')
->first();
if ($below) {
$this->playlistService->swapPositions($episode, $below);
}
}
public function remove($episodeId)
{
if (! $this->isOwner()) {
return;
}
PlaylistEpisode::find($episodeId)?->delete();
$this->playlistService->reorderPositions($this->playlist);
$this->playlist->loadCount('episodes');
$lastPage = max(1, (int) ceil(PlaylistEpisode::where('playlist_id', $this->playlist->id)->count() / $this->perPage));
if ($this->getPage() > $lastPage) {
$this->setPage($lastPage);
}
}
public function editName()
{
if (! $this->isOwner()) {
return;
}
$this->editingPlaylistName = $this->playlist->name;
$this->editingName = true;
}
public function cancelEditName()
{
$this->editingName = false;
$this->editingPlaylistName = '';
}
public function updateName()
{
if (! $this->isOwner()) {
return;
}
$this->validate([
'editingPlaylistName' => 'required|max:30',
]);
$this->playlist->update([
'name' => $this->editingPlaylistName,
]);
$this->editingName = false;
$this->editingPlaylistName = '';
}
public function toggleVisibility()
{
if (! $this->isOwner()) {
return;
}
$this->playlist->update([
'is_private' => ! $this->playlist->is_private,
]);
$this->playlist->loadCount('episodes');
}
public function render()
{
return view('livewire.playlist-overview', [
'episodes' => $this->episodes,
'firstEpisode' => $this->firstEpisode,
'isOwner' => $this->isOwner(),
]);
}
private function isOwner(): bool
{
return Auth::check() && Auth::user()->id === $this->playlist->user_id;
}
private function sanitizePerPage(): void
{
if (! in_array($this->perPage, [25, 50, 100], true)) {
$this->perPage = 25;
}
}
private function repairNullPositions(): void
{
if (! PlaylistEpisode::where('playlist_id', $this->playlist->id)->whereNull('position')->exists()) {
return;
}
PlaylistEpisode::where('playlist_id', $this->playlist->id)
->orderBy('position')->orderBy('id')
->get()
->each(fn ($playlistEpisode, $index) => $playlistEpisode->update(['position' => $index + 1]));
}
}