Update playlist design

This commit is contained in:
2026-08-04 15:29:39 +02:00
parent 7553b9f895
commit 7f9573fe0f
13 changed files with 632 additions and 132 deletions
+87 -41
View File
@@ -2,10 +2,11 @@
namespace App\Livewire;
use App\Models\Episode;
use App\Models\Playlist;
use App\Models\PlaylistEpisode;
use App\Services\PlaylistService;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Url;
use Livewire\Component;
@@ -18,14 +19,13 @@ class PlaylistOverview extends Component
protected PlaylistService $playlistService;
#[Url(history: true)]
public $search;
public string $search = '';
public int $pagination = 25;
#[Url(history: true)]
public int $perPage = 25;
public Playlist $playlist;
public Collection $playlistEpisodes;
public bool $editingName = false;
public string $editingPlaylistName = '';
@@ -37,35 +37,56 @@ class PlaylistOverview extends Component
public function mount($playlist_id)
{
$this->playlist = Playlist::with(['episodes.episode'])->findOrFail($playlist_id);
$this->playlist = Playlist::withCount('episodes')->with('user')->findOrFail($playlist_id);
// Set position if null
$this->playlist->episodes->each(function ($item, $index) {
if ($item->position === null) {
$item->position = $index + 1;
$item->save();
}
});
$this->sanitizePerPage();
$this->refreshEpisodes();
$this->repairNullPositions();
}
public function refreshEpisodes()
public function updatingSearch(): void
{
$this->playlistEpisodes = $this->playlist->episodes()->orderBy('position')->with('episode')->get();
$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 (! Auth::check()) {
return;
}
if (Auth::user()->id !== $this->playlist->user->id) {
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')
@@ -74,21 +95,20 @@ class PlaylistOverview extends Component
if ($above) {
$this->playlistService->swapPositions($episode, $above);
}
$this->refreshEpisodes();
}
public function moveDown($episodeId)
{
if (! Auth::check()) {
return;
}
if (Auth::user()->id !== $this->playlist->user->id) {
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')
@@ -97,28 +117,28 @@ class PlaylistOverview extends Component
if ($below) {
$this->playlistService->swapPositions($episode, $below);
}
$this->refreshEpisodes();
}
public function remove($episodeId)
{
if (! Auth::check()) {
return;
}
if (Auth::user()->id !== $this->playlist->user->id) {
if (! $this->isOwner()) {
return;
}
PlaylistEpisode::find($episodeId)?->delete();
$this->playlistService->reorderPositions($this->playlist);
$this->refreshEpisodes();
$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 (! Auth::check() || Auth::user()->id !== $this->playlist->user->id) {
if (! $this->isOwner()) {
return;
}
@@ -134,7 +154,7 @@ class PlaylistOverview extends Component
public function updateName()
{
if (! Auth::check() || Auth::user()->id !== $this->playlist->user->id) {
if (! $this->isOwner()) {
return;
}
@@ -152,7 +172,7 @@ class PlaylistOverview extends Component
public function toggleVisibility()
{
if (! Auth::check() || Auth::user()->id !== $this->playlist->user->id) {
if (! $this->isOwner()) {
return;
}
@@ -160,13 +180,39 @@ class PlaylistOverview extends Component
'is_private' => ! $this->playlist->is_private,
]);
$this->playlist->refresh();
$this->playlist->loadCount('episodes');
}
public function render()
{
return view('livewire.playlist-overview', [
'query' => $this->search,
'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]));
}
}
+10
View File
@@ -2,12 +2,22 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Gallery extends Model
{
use HasFactory;
public $table = 'gallery';
/**
* The attributes that aren't mass assignable.
*
* @var array<int, string>
*/
protected $guarded = [];
/**
* Belongs To Episode.
*/
+3
View File
@@ -2,11 +2,14 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Playlist extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
+3
View File
@@ -2,11 +2,14 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class PlaylistEpisode extends Model
{
use HasFactory;
/**
* Indicates If The Model Should Be Timestamped.
*