Rating Overhaul (#2159)
* Switched Ratings to a float system. Allow rating something as 0%. Allow half step ratings. Added new css variable: --rating-star-color. By default, N/A will show for series that have no ratings. N/A ratings are not included in overall rating calculations. * Show extended entity properties on desktop for list view cards. * Refactored the code for series metadata detail to use a re-usable component to reduce the copy/paste for the Genres tags like sections. * List Item will show extended properties about a chapter/volume, like weblinks on Desktop viewports. * Refactored even further so all of series detail uses the same component code. Tweaked the spacing on the series detail area. List items will now show Characters and Tags which are helpful for more Hentai related content. * Fixed a bug with removing something from "OnDeckRemoval" table when something was read.
This commit is contained in:
parent
f5ad821cd9
commit
734e299f7f
29 changed files with 2760 additions and 405 deletions
2269
API/Data/Migrations/20230725133536_ChangeRatingScale.Designer.cs
generated
Normal file
2269
API/Data/Migrations/20230725133536_ChangeRatingScale.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
45
API/Data/Migrations/20230725133536_ChangeRatingScale.cs
Normal file
45
API/Data/Migrations/20230725133536_ChangeRatingScale.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace API.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class ChangeRatingScale : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<float>(
|
||||
name: "Rating",
|
||||
table: "AppUserRating",
|
||||
type: "REAL",
|
||||
nullable: false,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "INTEGER");
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "HasBeenRated",
|
||||
table: "AppUserRating",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "HasBeenRated",
|
||||
table: "AppUserRating");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "Rating",
|
||||
table: "AppUserRating",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
oldClrType: typeof(float),
|
||||
oldType: "REAL");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ namespace API.Data.Migrations
|
|||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "7.0.8");
|
||||
modelBuilder.HasAnnotation("ProductVersion", "7.0.9");
|
||||
|
||||
modelBuilder.Entity("API.Entities.AppRole", b =>
|
||||
{
|
||||
|
@ -180,7 +180,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("AppUserId");
|
||||
|
||||
b.ToTable("AppUserBookmark", (string)null);
|
||||
b.ToTable("AppUserBookmark");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.AppUserOnDeckRemoval", b =>
|
||||
|
@ -201,7 +201,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("SeriesId");
|
||||
|
||||
b.ToTable("AppUserOnDeckRemoval", (string)null);
|
||||
b.ToTable("AppUserOnDeckRemoval");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.AppUserPreferences", b =>
|
||||
|
@ -309,7 +309,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("ThemeId");
|
||||
|
||||
b.ToTable("AppUserPreferences", (string)null);
|
||||
b.ToTable("AppUserPreferences");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.AppUserProgress", b =>
|
||||
|
@ -359,7 +359,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("SeriesId");
|
||||
|
||||
b.ToTable("AppUserProgresses", (string)null);
|
||||
b.ToTable("AppUserProgresses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.AppUserRating", b =>
|
||||
|
@ -371,9 +371,12 @@ namespace API.Data.Migrations
|
|||
b.Property<int>("AppUserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Rating")
|
||||
b.Property<bool>("HasBeenRated")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<float>("Rating")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<string>("Review")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
|
@ -389,7 +392,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("SeriesId");
|
||||
|
||||
b.ToTable("AppUserRating", (string)null);
|
||||
b.ToTable("AppUserRating");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.AppUserRole", b =>
|
||||
|
@ -457,7 +460,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("SeriesId");
|
||||
|
||||
b.ToTable("AppUserTableOfContent", (string)null);
|
||||
b.ToTable("AppUserTableOfContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.Chapter", b =>
|
||||
|
@ -567,7 +570,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("VolumeId");
|
||||
|
||||
b.ToTable("Chapter", (string)null);
|
||||
b.ToTable("Chapter");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.CollectionTag", b =>
|
||||
|
@ -602,7 +605,7 @@ namespace API.Data.Migrations
|
|||
b.HasIndex("Id", "Promoted")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("CollectionTag", (string)null);
|
||||
b.ToTable("CollectionTag");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.Device", b =>
|
||||
|
@ -648,7 +651,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("AppUserId");
|
||||
|
||||
b.ToTable("Device", (string)null);
|
||||
b.ToTable("Device");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.FolderPath", b =>
|
||||
|
@ -670,7 +673,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("LibraryId");
|
||||
|
||||
b.ToTable("FolderPath", (string)null);
|
||||
b.ToTable("FolderPath");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.Genre", b =>
|
||||
|
@ -690,7 +693,7 @@ namespace API.Data.Migrations
|
|||
b.HasIndex("NormalizedTitle")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Genre", (string)null);
|
||||
b.ToTable("Genre");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.Library", b =>
|
||||
|
@ -748,7 +751,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Library", (string)null);
|
||||
b.ToTable("Library");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.MangaFile", b =>
|
||||
|
@ -797,7 +800,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("ChapterId");
|
||||
|
||||
b.ToTable("MangaFile", (string)null);
|
||||
b.ToTable("MangaFile");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.MediaError", b =>
|
||||
|
@ -832,7 +835,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("MediaError", (string)null);
|
||||
b.ToTable("MediaError");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b =>
|
||||
|
@ -933,7 +936,7 @@ namespace API.Data.Migrations
|
|||
b.HasIndex("Id", "SeriesId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("SeriesMetadata", (string)null);
|
||||
b.ToTable("SeriesMetadata");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.Metadata.SeriesRelation", b =>
|
||||
|
@ -957,7 +960,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("TargetSeriesId");
|
||||
|
||||
b.ToTable("SeriesRelation", (string)null);
|
||||
b.ToTable("SeriesRelation");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.Person", b =>
|
||||
|
@ -977,7 +980,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Person", (string)null);
|
||||
b.ToTable("Person");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.ReadingList", b =>
|
||||
|
@ -1040,7 +1043,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("AppUserId");
|
||||
|
||||
b.ToTable("ReadingList", (string)null);
|
||||
b.ToTable("ReadingList");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.ReadingListItem", b =>
|
||||
|
@ -1074,7 +1077,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("VolumeId");
|
||||
|
||||
b.ToTable("ReadingListItem", (string)null);
|
||||
b.ToTable("ReadingListItem");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.Scrobble.ScrobbleError", b =>
|
||||
|
@ -1119,7 +1122,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("SeriesId");
|
||||
|
||||
b.ToTable("ScrobbleError", (string)null);
|
||||
b.ToTable("ScrobbleError");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.Scrobble.ScrobbleEvent", b =>
|
||||
|
@ -1190,7 +1193,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("SeriesId");
|
||||
|
||||
b.ToTable("ScrobbleEvent", (string)null);
|
||||
b.ToTable("ScrobbleEvent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.Scrobble.ScrobbleHold", b =>
|
||||
|
@ -1223,7 +1226,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("SeriesId");
|
||||
|
||||
b.ToTable("ScrobbleHold", (string)null);
|
||||
b.ToTable("ScrobbleHold");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.Series", b =>
|
||||
|
@ -1319,7 +1322,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("LibraryId");
|
||||
|
||||
b.ToTable("Series", (string)null);
|
||||
b.ToTable("Series");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.ServerSetting", b =>
|
||||
|
@ -1336,7 +1339,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasKey("Key");
|
||||
|
||||
b.ToTable("ServerSetting", (string)null);
|
||||
b.ToTable("ServerSetting");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.ServerStatistics", b =>
|
||||
|
@ -1374,7 +1377,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ServerStatistics", (string)null);
|
||||
b.ToTable("ServerStatistics");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.SiteTheme", b =>
|
||||
|
@ -1412,7 +1415,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SiteTheme", (string)null);
|
||||
b.ToTable("SiteTheme");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.Tag", b =>
|
||||
|
@ -1432,7 +1435,7 @@ namespace API.Data.Migrations
|
|||
b.HasIndex("NormalizedTitle")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Tag", (string)null);
|
||||
b.ToTable("Tag");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.Volume", b =>
|
||||
|
@ -1484,7 +1487,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("SeriesId");
|
||||
|
||||
b.ToTable("Volume", (string)null);
|
||||
b.ToTable("Volume");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AppUserLibrary", b =>
|
||||
|
@ -1499,7 +1502,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("LibrariesId");
|
||||
|
||||
b.ToTable("AppUserLibrary", (string)null);
|
||||
b.ToTable("AppUserLibrary");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ChapterGenre", b =>
|
||||
|
@ -1514,7 +1517,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("GenresId");
|
||||
|
||||
b.ToTable("ChapterGenre", (string)null);
|
||||
b.ToTable("ChapterGenre");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ChapterPerson", b =>
|
||||
|
@ -1529,7 +1532,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("PeopleId");
|
||||
|
||||
b.ToTable("ChapterPerson", (string)null);
|
||||
b.ToTable("ChapterPerson");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ChapterTag", b =>
|
||||
|
@ -1544,7 +1547,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("TagsId");
|
||||
|
||||
b.ToTable("ChapterTag", (string)null);
|
||||
b.ToTable("ChapterTag");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CollectionTagSeriesMetadata", b =>
|
||||
|
@ -1559,7 +1562,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("SeriesMetadatasId");
|
||||
|
||||
b.ToTable("CollectionTagSeriesMetadata", (string)null);
|
||||
b.ToTable("CollectionTagSeriesMetadata");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GenreSeriesMetadata", b =>
|
||||
|
@ -1574,7 +1577,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("SeriesMetadatasId");
|
||||
|
||||
b.ToTable("GenreSeriesMetadata", (string)null);
|
||||
b.ToTable("GenreSeriesMetadata");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<int>", b =>
|
||||
|
@ -1673,7 +1676,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("SeriesMetadatasId");
|
||||
|
||||
b.ToTable("PersonSeriesMetadata", (string)null);
|
||||
b.ToTable("PersonSeriesMetadata");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SeriesMetadataTag", b =>
|
||||
|
@ -1688,7 +1691,7 @@ namespace API.Data.Migrations
|
|||
|
||||
b.HasIndex("TagsId");
|
||||
|
||||
b.ToTable("SeriesMetadataTag", (string)null);
|
||||
b.ToTable("SeriesMetadataTag");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Entities.AppUserBookmark", b =>
|
||||
|
|
|
@ -625,6 +625,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
if (rating != null)
|
||||
{
|
||||
s.UserRating = rating.Rating;
|
||||
s.HasUserRated = rating.HasBeenRated;
|
||||
}
|
||||
|
||||
if (userProgress.Count > 0)
|
||||
|
@ -1686,13 +1687,13 @@ public class SeriesRepository : ISeriesRepository
|
|||
{
|
||||
// If there is 0 or 1 rating and that rating is you, return 0 back
|
||||
var countOfRatingsThatAreUser = await _context.AppUserRating
|
||||
.Where(r => r.SeriesId == seriesId).CountAsync(u => u.AppUserId == userId);
|
||||
.Where(r => r.SeriesId == seriesId && r.HasBeenRated).CountAsync(u => u.AppUserId == userId);
|
||||
if (countOfRatingsThatAreUser == 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
var avg = (await _context.AppUserRating
|
||||
.Where(r => r.SeriesId == seriesId)
|
||||
.Where(r => r.SeriesId == seriesId && r.HasBeenRated)
|
||||
.AverageAsync(r => (int?) r.Rating));
|
||||
return avg.HasValue ? (int) (avg.Value * 20) : 0;
|
||||
}
|
||||
|
@ -1714,7 +1715,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
public async Task ClearOnDeckRemoval(int seriesId, int userId)
|
||||
{
|
||||
var existingEntry = await _context.AppUserOnDeckRemoval
|
||||
.Where(u => u.Id == userId && u.SeriesId == seriesId)
|
||||
.Where(u => u.AppUserId == userId && u.SeriesId == seriesId)
|
||||
.FirstOrDefaultAsync();
|
||||
if (existingEntry == null) return;
|
||||
_context.AppUserOnDeckRemoval.Remove(existingEntry);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue