Compare commits
13 Commits
d0f91fd0e1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 594541a103 | |||
| ee7bcc1eae | |||
| 4fe354add0 | |||
| c6355d47df | |||
| 97a92269ad | |||
| 66468a1f8b | |||
| e48e8b6394 | |||
| 5f39417109 | |||
| 76e8e8daa6 | |||
| 6db2bca50b | |||
| 46491dd987 | |||
| 8edf749e23 | |||
| 3cc4fd8240 |
@@ -159,7 +159,7 @@
|
|||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
GlobalEntities = await CouchLogDB.GlobalEntities.OrderByDescending(Entity => Entity.Title).ToListAsync();
|
GlobalEntities = await CouchLogDB.GlobalEntities.OrderByDescending(Entity => Entity.CreationTime).ToListAsync();
|
||||||
MediaTypes = await CouchLogDB.MediaType.OrderBy(Type => Type.Id).ToListAsync();
|
MediaTypes = await CouchLogDB.MediaType.OrderBy(Type => Type.Id).ToListAsync();
|
||||||
Genres = await CouchLogDB.Genres.OrderBy(Genre => Genre.Name).ToListAsync();
|
Genres = await CouchLogDB.Genres.OrderBy(Genre => Genre.Name).ToListAsync();
|
||||||
|
|
||||||
|
|||||||
@@ -16,139 +16,41 @@
|
|||||||
<PageTitle>Private List</PageTitle>
|
<PageTitle>Private List</PageTitle>
|
||||||
|
|
||||||
<div class="container-fluid mt-4 px-4">
|
<div class="container-fluid mt-4 px-4">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
||||||
<h2>Private List</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Grid-Layout -->
|
<!-- Active Watching Section -->
|
||||||
<div class="row g-4">
|
@if (ActiveWatchingEntities.Any())
|
||||||
@foreach (var Entity in PrivateEntities)
|
{
|
||||||
{
|
<div class="mb-5">
|
||||||
<div class="col-12 col-lg-6 col-xxl-4">
|
<h2 class="mb-4">Aktiv am Schauen</h2>
|
||||||
|
<div class="row g-4">
|
||||||
<div class="card shadow-sm border-0 overflow-hidden private-entity-card">
|
@foreach (var entity in ActiveWatchingEntities)
|
||||||
<div class="row g-0 h-100">
|
{
|
||||||
|
@RenderEntityCard(entity)
|
||||||
<!-- Feste Breite für das Bild, kein Umbruch -->
|
}
|
||||||
<div class="col-auto" style="flex: 0 0 auto; min-width: 120px; max-width: 150px;">
|
|
||||||
@if (!string.IsNullOrEmpty(Entity.GlobalEntity?.PicturePath))
|
|
||||||
{
|
|
||||||
<img src="/@Entity.GlobalEntity.PicturePath"
|
|
||||||
class="entity-img w-100 h-100"
|
|
||||||
style="object-fit: cover;"
|
|
||||||
alt="@Entity.GlobalEntity.Title">
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<div class="d-flex align-items-center justify-content-center h-100 bg-light text-muted small">
|
|
||||||
Kein Bild
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Der Rest nimmt den verbleibenden Platz -->
|
|
||||||
<div class="col" style="min-width: 0;">
|
|
||||||
<div class="card-body d-flex flex-column h-100 py-2 px-3">
|
|
||||||
|
|
||||||
<!-- Header mit besserer Text-Behandlung -->
|
|
||||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
|
||||||
<div style="min-width: 0; flex: 1;">
|
|
||||||
<h5 class="card-title fw-bold mb-0" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
|
||||||
@Entity.GlobalEntity?.Title
|
|
||||||
</h5>
|
|
||||||
<small class="text-muted meta-text">
|
|
||||||
@Entity.CreationTime.ToShortDateString()
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="dropdown ms-2" style="flex-shrink: 0;">
|
|
||||||
<button class="btn btn-link menu-btn" type="button" data-bs-toggle="modal" data-bs-target="#modal-@Entity.Id">
|
|
||||||
⋮
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<select class="form-select"
|
|
||||||
value="@Entity.UserWatchStatusId"
|
|
||||||
@onchange="@(e => UpdateWatchStatus(Entity, e.Value))">
|
|
||||||
|
|
||||||
@foreach (var status in userWatchStatuses)
|
|
||||||
{
|
|
||||||
<option value="@status.Id">@status.Name</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
@if (Entity.GlobalEntity?.MediaType.Name == "Series" || Entity.GlobalEntity?.MediaType.Name == "Anime")
|
|
||||||
{
|
|
||||||
<select class="form-select" value="@Entity.Season" @onchange="@(e => UpdateSeason(Entity, e.Value))">
|
|
||||||
@{
|
|
||||||
int currentSeason = Entity.Season ?? 1;
|
|
||||||
|
|
||||||
int startOffsetSeason = currentSeason > 1 ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@for (int i = startOffsetSeason; i <= 5; i++)
|
|
||||||
{
|
|
||||||
int season = currentSeason + i;
|
|
||||||
|
|
||||||
<option value="@season">
|
|
||||||
Staffel @season
|
|
||||||
</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<select class="form-select" value="@Entity.Episode" @onchange="@(e => UpdateEpisode(Entity, e.Value))">
|
|
||||||
@{
|
|
||||||
int currentEpisode = Entity.Episode ?? 1;
|
|
||||||
|
|
||||||
int startOffsetEpisode = currentEpisode > 1 ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@for (int i = startOffsetEpisode; i <= 5; i++)
|
|
||||||
{
|
|
||||||
int episode = currentEpisode + i;
|
|
||||||
|
|
||||||
<option value="@episode">
|
|
||||||
Episode @episode
|
|
||||||
</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
}
|
|
||||||
|
|
||||||
<!-- Beschreibung -->
|
|
||||||
<!--<p class="card-text text-truncate-multiline flex-grow-1 text-muted small mt-1 mb-2">
|
|
||||||
@(!string.IsNullOrWhiteSpace(Entity.Description)
|
|
||||||
? Entity.Description
|
|
||||||
: (Entity.Description ?? "Keine Beschreibung."))
|
|
||||||
</p>
|
|
||||||
-->
|
|
||||||
<!-- Footer Button -->
|
|
||||||
<div class="mt-auto d-flex justify-content-end">
|
|
||||||
<button class="btn btn-outline-secondary btn-sm btn-details" type="button">Details</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modal (unverändert) -->
|
|
||||||
<div class="modal fade" id="modal-@Entity.Id" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">Optionen</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">Optionen...</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
</div>
|
||||||
</div>
|
}
|
||||||
|
|
||||||
|
<!-- Library / Completed Section -->
|
||||||
|
@if (LibraryEntities.Any())
|
||||||
|
{
|
||||||
|
<div class="mb-5">
|
||||||
|
<h2 class="mb-4">Bibliothek</h2>
|
||||||
|
<div class="row g-4">
|
||||||
|
@foreach (var entity in LibraryEntities)
|
||||||
|
{
|
||||||
|
@RenderEntityCard(entity)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (!PrivateEntities.Any())
|
||||||
|
{
|
||||||
|
<div class="text-center text-muted py-5">
|
||||||
|
<p>Keine Einträge vorhanden.</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code
|
@code
|
||||||
@@ -157,6 +59,9 @@
|
|||||||
private List<UserWatchStatus> userWatchStatuses = new List<UserWatchStatus>();
|
private List<UserWatchStatus> userWatchStatuses = new List<UserWatchStatus>();
|
||||||
ApplicationUser? AppUser = new();
|
ApplicationUser? AppUser = new();
|
||||||
|
|
||||||
|
private List<PrivateEntity> ActiveWatchingEntities => PrivateEntities.Where(x => x.UserWatchStatus?.Name == "Watching").ToList();
|
||||||
|
private List<PrivateEntity> LibraryEntities => PrivateEntities.Where(x => x.UserWatchStatus?.Name != "Watching").ToList();
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
var AuthState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
var AuthState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||||
@@ -176,29 +81,142 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RenderFragment RenderEntityCard(PrivateEntity Entity) => __builder =>
|
||||||
|
{
|
||||||
|
<div class="col-12 col-lg-6 col-xxl-4">
|
||||||
|
<div class="card shadow-sm border-0 overflow-hidden private-entity-card">
|
||||||
|
<div class="row g-0 h-100">
|
||||||
|
|
||||||
|
<div class="col-auto" style="flex: 0 0 auto; min-width: 120px; max-width: 150px;">
|
||||||
|
@if (!string.IsNullOrEmpty(Entity.GlobalEntity?.PicturePath))
|
||||||
|
{
|
||||||
|
<img src="/@Entity.GlobalEntity.PicturePath"
|
||||||
|
class="entity-img w-100 h-100"
|
||||||
|
style="object-fit: cover;"
|
||||||
|
alt="@Entity.GlobalEntity.Title">
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="d-flex align-items-center justify-content-center h-100 bg-light text-muted small">
|
||||||
|
Kein Bild
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
|
<div class="col" style="min-width: 0;">
|
||||||
|
<div class="card-body d-flex flex-column h-100 py-2 px-3">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||||
|
<div style="min-width: 0; flex: 1;">
|
||||||
|
<h5 class="card-title fw-bold mb-0" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||||
|
@Entity.GlobalEntity?.Title
|
||||||
|
</h5>
|
||||||
|
<small class="text-muted meta-text">
|
||||||
|
@Entity.CreationTime.ToShortDateString()
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dropdown ms-2" style="flex-shrink: 0;">
|
||||||
|
<button class="btn btn-link menu-btn" type="button" data-bs-toggle="modal" data-bs-target="#modal-@Entity.Id">
|
||||||
|
⋮
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Watch Status Dropdown -->
|
||||||
|
<select class="form-select"
|
||||||
|
value="@Entity.UserWatchStatusId"
|
||||||
|
@onchange="@(e => UpdateWatchStatus(Entity, e.Value))">
|
||||||
|
@foreach (var status in userWatchStatuses)
|
||||||
|
{
|
||||||
|
<option value="@status.Id">@status.Name</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
@if (Entity.GlobalEntity?.MediaType.Name == "Series" || Entity.GlobalEntity?.MediaType.Name == "Anime")
|
||||||
|
{
|
||||||
|
<select class="form-select" value="@Entity.Season" @onchange="@(e => UpdateSeason(Entity, e.Value))">
|
||||||
|
@{
|
||||||
|
int currentSeason = Entity.Season ?? 1;
|
||||||
|
int startOffsetSeason = currentSeason > 1 ? -1 : 0;
|
||||||
|
}
|
||||||
|
@for (int i = startOffsetSeason; i <= 5; i++)
|
||||||
|
{
|
||||||
|
int season = currentSeason + i;
|
||||||
|
<option value="@season">Staffel @season</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select class="form-select" value="@Entity.Episode" @onchange="@(e => UpdateEpisode(Entity, e.Value))">
|
||||||
|
@{
|
||||||
|
int currentEpisode = Entity.Episode ?? 1;
|
||||||
|
int startOffsetEpisode = currentEpisode > 1 ? -1 : 0;
|
||||||
|
}
|
||||||
|
@for (int i = startOffsetEpisode; i <= 5; i++)
|
||||||
|
{
|
||||||
|
int episode = currentEpisode + i;
|
||||||
|
<option value="@episode">Episode @episode</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Footer Button -->
|
||||||
|
<div class="mt-auto d-flex justify-content-end">
|
||||||
|
<button class="btn btn-outline-secondary btn-sm btn-details" type="button">Details</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal -->
|
||||||
|
<div class="modal fade" id="modal-@Entity.Id" tabindex="-1" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Optionen</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<button type="button" class="btn btn-danger" @onclick="@(e => RemoveEntityFromPrivateList(Entity))" data-bs-dismiss="modal">Aus PrivateList entfernen</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
};
|
||||||
|
|
||||||
|
private async Task RemoveEntityFromPrivateList(PrivateEntity entity)
|
||||||
|
{
|
||||||
|
//Delete DB
|
||||||
|
CouchLogDB.PrivateEntities.Remove(entity);
|
||||||
|
await CouchLogDB.SaveChangesAsync();
|
||||||
|
|
||||||
|
//Delete Memory List
|
||||||
|
PrivateEntities.Remove(entity);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task UpdateWatchStatus(PrivateEntity entity, object? newValue)
|
private async Task UpdateWatchStatus(PrivateEntity entity, object? newValue)
|
||||||
{
|
{
|
||||||
// Wir holen uns die gewählte ID aus dem Dropdown
|
|
||||||
if (int.TryParse(newValue?.ToString(), out int newId))
|
if (int.TryParse(newValue?.ToString(), out int newId))
|
||||||
{
|
{
|
||||||
// 1. ID im Objekt aktualisieren
|
|
||||||
entity.UserWatchStatusId = newId;
|
entity.UserWatchStatusId = newId;
|
||||||
|
|
||||||
// 2. Navigation Property aktualisieren (damit die UI nicht flackert)
|
|
||||||
// Wir suchen das passende Objekt aus der geladenen Liste
|
|
||||||
entity.UserWatchStatus = userWatchStatuses.FirstOrDefault(s => s.Id == newId);
|
entity.UserWatchStatus = userWatchStatuses.FirstOrDefault(s => s.Id == newId);
|
||||||
|
|
||||||
// 3. Ab in die Datenbank
|
|
||||||
await CouchLogDB.SaveChangesAsync();
|
await CouchLogDB.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateSeason(PrivateEntity entity, object? newSeasonValue)
|
private async Task UpdateSeason(PrivateEntity entity, object? newSeasonValue)
|
||||||
{
|
{
|
||||||
if(int.TryParse(newSeasonValue?.ToString(), out int newSeason))
|
if (int.TryParse(newSeasonValue?.ToString(), out int newSeason))
|
||||||
{
|
{
|
||||||
entity.Season = newSeason;
|
entity.Season = newSeason;
|
||||||
|
entity.Episode = 1;
|
||||||
await CouchLogDB.SaveChangesAsync();
|
await CouchLogDB.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,7 +226,6 @@
|
|||||||
if (int.TryParse(newEpisodeValue?.ToString(), out int newEpisode))
|
if (int.TryParse(newEpisodeValue?.ToString(), out int newEpisode))
|
||||||
{
|
{
|
||||||
entity.Episode = newEpisode;
|
entity.Episode = newEpisode;
|
||||||
|
|
||||||
await CouchLogDB.SaveChangesAsync();
|
await CouchLogDB.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ namespace CouchLog
|
|||||||
List<UserWatchStatus> UserWatchStatuses =
|
List<UserWatchStatus> UserWatchStatuses =
|
||||||
[
|
[
|
||||||
new() { Name = "Not watched", CreationTime = DateTime.Now },
|
new() { Name = "Not watched", CreationTime = DateTime.Now },
|
||||||
new() { Name = "Started", CreationTime = DateTime.Now },
|
new() { Name = "Watching", CreationTime = DateTime.Now },
|
||||||
new() { Name = "Finished", CreationTime = DateTime.Now },
|
new() { Name = "Finished", CreationTime = DateTime.Now },
|
||||||
new() { Name = "Paused", CreationTime = DateTime.Now },
|
new() { Name = "Paused", CreationTime = DateTime.Now },
|
||||||
new() { Name = "Aborted", CreationTime= DateTime.Now },
|
new() { Name = "Aborted", CreationTime= DateTime.Now },
|
||||||
@@ -152,6 +152,24 @@ namespace CouchLog
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#################################################
|
||||||
|
//###### Old-Things that need to be deleted #######
|
||||||
|
//#################################################
|
||||||
|
List<UserWatchStatus> oldUserWatchStatuses =
|
||||||
|
[
|
||||||
|
new() { Name = "Started" , CreationTime = DateTime.Now },
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach(UserWatchStatus oldUserWatchStatus in oldUserWatchStatuses)
|
||||||
|
{
|
||||||
|
UserWatchStatus? toDeletedUserWatchStatus = await CouchLogDB.UserWatchStatuses.FirstOrDefaultAsync(m => m.Name == oldUserWatchStatus.Name);
|
||||||
|
|
||||||
|
if(toDeletedUserWatchStatus != null)
|
||||||
|
{
|
||||||
|
CouchLogDB.UserWatchStatuses.Remove(toDeletedUserWatchStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await CouchLogDB.SaveChangesAsync();
|
await CouchLogDB.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user