First iteration of the UI
- Migrate current preferences over - Set defaults in db
This commit is contained in:
parent
5741a92bb2
commit
5656fb2148
26 changed files with 1246 additions and 728 deletions
|
|
@ -257,6 +257,19 @@ public sealed class DataContext : IdentityDbContext<AppUser, AppRole, int,
|
|||
builder.Entity<MetadataSettings>()
|
||||
.Property(b => b.EnableCoverImage)
|
||||
.HasDefaultValue(true);
|
||||
|
||||
builder.Entity<AppUserReadingProfile>()
|
||||
.Property(b => b.BookThemeName)
|
||||
.HasDefaultValue("Dark");
|
||||
builder.Entity<AppUserReadingProfile>()
|
||||
.Property(b => b.BackgroundColor)
|
||||
.HasDefaultValue("#000000");
|
||||
builder.Entity<AppUserReadingProfile>()
|
||||
.Property(b => b.BookReaderWritingStyle)
|
||||
.HasDefaultValue(WritingStyle.Horizontal);
|
||||
builder.Entity<AppUserReadingProfile>()
|
||||
.Property(b => b.AllowAutomaticWebtoonReaderDetection)
|
||||
.HasDefaultValue(true);
|
||||
}
|
||||
|
||||
#nullable enable
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using API.Entities;
|
||||
using API.Entities.History;
|
||||
using API.Extensions;
|
||||
using API.Helpers.Builders;
|
||||
using Kavita.Common.EnvironmentInfo;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace API.Data.ManualMigrations.v0._8._7;
|
||||
namespace API.Data.ManualMigrations;
|
||||
|
||||
public class ManualMigrateReadingProfiles
|
||||
public static class ManualMigrateReadingProfiles
|
||||
{
|
||||
public static async Task Migrate(DataContext context, ILogger<Program> logger)
|
||||
{
|
||||
|
|
@ -18,62 +21,55 @@ public class ManualMigrateReadingProfiles
|
|||
|
||||
logger.LogCritical("Running ManualMigrateReadingProfiles migration - Please be patient, this may take some time. This is not an error");
|
||||
|
||||
await context.Database.ExecuteSqlRawAsync(@"
|
||||
INSERT INTO AppUserReadingProfiles (
|
||||
AppUserId,
|
||||
ReadingDirection,
|
||||
ScalingOption,
|
||||
PageSplitOption,
|
||||
ReaderMode,
|
||||
AutoCloseMenu,
|
||||
ShowScreenHints,
|
||||
EmulateBook,
|
||||
LayoutMode,
|
||||
BackgroundColor,
|
||||
SwipeToPaginate,
|
||||
AllowAutomaticWebtoonReaderDetection,
|
||||
BookReaderMargin,
|
||||
BookReaderLineSpacing,
|
||||
BookReaderFontSize,
|
||||
BookReaderFontFamily,
|
||||
BookReaderTapToPaginate,
|
||||
BookReaderReadingDirection,
|
||||
BookReaderWritingStyle,
|
||||
BookThemeName,
|
||||
BookReaderLayoutMode,
|
||||
BookReaderImmersiveMode,
|
||||
PdfTheme,
|
||||
PdfScrollMode,
|
||||
PdfSpreadMode
|
||||
)
|
||||
SELECT
|
||||
AppUserId,
|
||||
ReadingDirection,
|
||||
ScalingOption,
|
||||
PageSplitOption,
|
||||
ReaderMode,
|
||||
AutoCloseMenu,
|
||||
ShowScreenHints,
|
||||
EmulateBook,
|
||||
LayoutMode,
|
||||
BackgroundColor,
|
||||
SwipeToPaginate,
|
||||
AllowAutomaticWebtoonReaderDetection,
|
||||
BookReaderMargin,
|
||||
BookReaderLineSpacing,
|
||||
BookReaderFontSize,
|
||||
BookReaderFontFamily,
|
||||
BookReaderTapToPaginate,
|
||||
BookReaderReadingDirection,
|
||||
BookReaderWritingStyle,
|
||||
BookThemeName,
|
||||
BookReaderLayoutMode,
|
||||
BookReaderImmersiveMode,
|
||||
PdfTheme,
|
||||
PdfScrollMode,
|
||||
PdfSpreadMode
|
||||
FROM AppUserPreferences
|
||||
");
|
||||
var users = await context.AppUser
|
||||
.Include(u => u.UserPreferences)
|
||||
.Include(u => u.UserPreferences.ReadingProfiles)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var user in users)
|
||||
{
|
||||
var readingProfile = new AppUserReadingProfile
|
||||
{
|
||||
Name = "Default",
|
||||
NormalizedName = "Default".ToNormalized(),
|
||||
BackgroundColor = user.UserPreferences.BackgroundColor,
|
||||
EmulateBook = user.UserPreferences.EmulateBook,
|
||||
User = user,
|
||||
PdfTheme = user.UserPreferences.PdfTheme,
|
||||
ReaderMode = user.UserPreferences.ReaderMode,
|
||||
ReadingDirection = user.UserPreferences.ReadingDirection,
|
||||
ScalingOption = user.UserPreferences.ScalingOption,
|
||||
LayoutMode = user.UserPreferences.LayoutMode,
|
||||
WidthOverride = null,
|
||||
UserId = user.Id,
|
||||
AutoCloseMenu = user.UserPreferences.AutoCloseMenu,
|
||||
BookReaderMargin = user.UserPreferences.BookReaderMargin,
|
||||
PageSplitOption = user.UserPreferences.PageSplitOption,
|
||||
BookThemeName = user.UserPreferences.BookThemeName,
|
||||
PdfSpreadMode = user.UserPreferences.PdfSpreadMode,
|
||||
PdfScrollMode = user.UserPreferences.PdfScrollMode,
|
||||
SwipeToPaginate = user.UserPreferences.SwipeToPaginate,
|
||||
BookReaderFontFamily = user.UserPreferences.BookReaderFontFamily,
|
||||
BookReaderFontSize = user.UserPreferences.BookReaderFontSize,
|
||||
BookReaderImmersiveMode = user.UserPreferences.BookReaderImmersiveMode,
|
||||
BookReaderLayoutMode = user.UserPreferences.BookReaderLayoutMode,
|
||||
BookReaderLineSpacing = user.UserPreferences.BookReaderLineSpacing,
|
||||
BookReaderReadingDirection = user.UserPreferences.BookReaderReadingDirection,
|
||||
BookReaderWritingStyle = user.UserPreferences.BookReaderWritingStyle,
|
||||
AllowAutomaticWebtoonReaderDetection = user.UserPreferences.AllowAutomaticWebtoonReaderDetection,
|
||||
BookReaderTapToPaginate = user.UserPreferences.BookReaderTapToPaginate,
|
||||
ShowScreenHints = user.UserPreferences.ShowScreenHints,
|
||||
};
|
||||
user.UserPreferences.ReadingProfiles.Add(readingProfile);
|
||||
}
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
foreach (var user in users)
|
||||
{
|
||||
user.UserPreferences.DefaultReadingProfileId =
|
||||
(await context.AppUserReadingProfile
|
||||
.FirstAsync(rp => rp.UserId == user.Id)).Id;
|
||||
}
|
||||
|
||||
context.ManualMigrationHistory.Add(new ManualMigrationHistory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|||
namespace API.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(DataContext))]
|
||||
[Migration("20250515215234_AppUserReadingProfiles")]
|
||||
[Migration("20250517195000_AppUserReadingProfiles")]
|
||||
partial class AppUserReadingProfiles
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
|
@ -622,7 +622,9 @@ namespace API.Data.Migrations
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("AllowAutomaticWebtoonReaderDetection")
|
||||
.HasColumnType("INTEGER");
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue(true);
|
||||
|
||||
b.Property<int?>("AppUserPreferencesId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
|
@ -631,7 +633,9 @@ namespace API.Data.Migrations
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("BackgroundColor")
|
||||
.HasColumnType("TEXT");
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValue("#000000");
|
||||
|
||||
b.Property<string>("BookReaderFontFamily")
|
||||
.HasColumnType("TEXT");
|
||||
|
|
@ -658,10 +662,14 @@ namespace API.Data.Migrations
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("BookReaderWritingStyle")
|
||||
.HasColumnType("INTEGER");
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue(0);
|
||||
|
||||
b.Property<string>("BookThemeName")
|
||||
.HasColumnType("TEXT");
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValue("Dark");
|
||||
|
||||
b.Property<bool>("EmulateBook")
|
||||
.HasColumnType("INTEGER");
|
||||
|
|
@ -34,9 +34,9 @@ namespace API.Data.Migrations
|
|||
ShowScreenHints = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
EmulateBook = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
LayoutMode = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
BackgroundColor = table.Column<string>(type: "TEXT", nullable: true),
|
||||
BackgroundColor = table.Column<string>(type: "TEXT", nullable: true, defaultValue: "#000000"),
|
||||
SwipeToPaginate = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
AllowAutomaticWebtoonReaderDetection = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
AllowAutomaticWebtoonReaderDetection = table.Column<bool>(type: "INTEGER", nullable: false, defaultValue: true),
|
||||
WidthOverride = table.Column<int>(type: "INTEGER", nullable: true),
|
||||
BookReaderMargin = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
BookReaderLineSpacing = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
|
|
@ -44,8 +44,8 @@ namespace API.Data.Migrations
|
|||
BookReaderFontFamily = table.Column<string>(type: "TEXT", nullable: true),
|
||||
BookReaderTapToPaginate = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
BookReaderReadingDirection = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
BookReaderWritingStyle = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
BookThemeName = table.Column<string>(type: "TEXT", nullable: true),
|
||||
BookReaderWritingStyle = table.Column<int>(type: "INTEGER", nullable: false, defaultValue: 0),
|
||||
BookThemeName = table.Column<string>(type: "TEXT", nullable: true, defaultValue: "Dark"),
|
||||
BookReaderLayoutMode = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
BookReaderImmersiveMode = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
PdfTheme = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
|
|
@ -619,7 +619,9 @@ namespace API.Data.Migrations
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("AllowAutomaticWebtoonReaderDetection")
|
||||
.HasColumnType("INTEGER");
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue(true);
|
||||
|
||||
b.Property<int?>("AppUserPreferencesId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
|
@ -628,7 +630,9 @@ namespace API.Data.Migrations
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("BackgroundColor")
|
||||
.HasColumnType("TEXT");
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValue("#000000");
|
||||
|
||||
b.Property<string>("BookReaderFontFamily")
|
||||
.HasColumnType("TEXT");
|
||||
|
|
@ -655,10 +659,14 @@ namespace API.Data.Migrations
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("BookReaderWritingStyle")
|
||||
.HasColumnType("INTEGER");
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue(0);
|
||||
|
||||
b.Property<string>("BookThemeName")
|
||||
.HasColumnType("TEXT");
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValue("Dark");
|
||||
|
||||
b.Property<bool>("EmulateBook")
|
||||
.HasColumnType("INTEGER");
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using API.DTOs;
|
||||
using API.Entities;
|
||||
using API.Extensions;
|
||||
using API.Extensions.QueryExtensions;
|
||||
using AutoMapper;
|
||||
using AutoMapper.QueryableExtensions;
|
||||
|
|
@ -22,13 +23,14 @@ public enum ReadingProfileIncludes
|
|||
|
||||
public interface IAppUserReadingProfileRepository
|
||||
{
|
||||
Task<IList<AppUserReadingProfile>> GetProfilesForUser(int userId);
|
||||
Task<AppUserReadingProfile?> GetProfileForSeries(int userId, int seriesId);
|
||||
Task<IList<AppUserReadingProfile>> GetProfilesForUser(int userId, bool nonImplicitOnly, ReadingProfileIncludes includes = ReadingProfileIncludes.None);
|
||||
Task<AppUserReadingProfile?> GetProfileForSeries(int userId, int seriesId, ReadingProfileIncludes includes = ReadingProfileIncludes.None);
|
||||
Task<UserReadingProfileDto?> GetProfileDtoForSeries(int userId, int seriesId);
|
||||
Task<AppUserReadingProfile?> GetProfileForLibrary(int userId, int libraryId);
|
||||
Task<AppUserReadingProfile?> GetProfileForLibrary(int userId, int libraryId, ReadingProfileIncludes includes = ReadingProfileIncludes.None);
|
||||
Task<UserReadingProfileDto?> GetProfileDtoForLibrary(int userId, int libraryId);
|
||||
Task<AppUserReadingProfile?> GetProfile(int profileId, ReadingProfileIncludes includes = ReadingProfileIncludes.None);
|
||||
Task<UserReadingProfileDto?> GetProfileDto(int profileId);
|
||||
Task<AppUserReadingProfile?> GetProfileByName(int userId, string name);
|
||||
|
||||
void Add(AppUserReadingProfile readingProfile);
|
||||
void Update(AppUserReadingProfile readingProfile);
|
||||
|
|
@ -38,17 +40,20 @@ public interface IAppUserReadingProfileRepository
|
|||
public class AppUserReadingProfileRepository(DataContext context, IMapper mapper): IAppUserReadingProfileRepository
|
||||
{
|
||||
|
||||
public async Task<IList<AppUserReadingProfile>> GetProfilesForUser(int userId)
|
||||
public async Task<IList<AppUserReadingProfile>> GetProfilesForUser(int userId, bool nonImplicitOnly, ReadingProfileIncludes includes = ReadingProfileIncludes.None)
|
||||
{
|
||||
return await context.AppUserReadingProfile
|
||||
.Where(rp => rp.UserId == userId)
|
||||
.Where(rp => rp.UserId == userId && !(nonImplicitOnly && rp.Implicit))
|
||||
.Includes(includes)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<AppUserReadingProfile?> GetProfileForSeries(int userId, int seriesId)
|
||||
public async Task<AppUserReadingProfile?> GetProfileForSeries(int userId, int seriesId, ReadingProfileIncludes includes = ReadingProfileIncludes.None)
|
||||
{
|
||||
return await context.AppUserReadingProfile
|
||||
.Where(rp => rp.UserId == userId && rp.Series.Any(s => s.Id == seriesId))
|
||||
.Includes(includes)
|
||||
.OrderByDescending(rp => rp.Implicit) // Get implicit profiles first
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
|
|
@ -56,14 +61,16 @@ public class AppUserReadingProfileRepository(DataContext context, IMapper mapper
|
|||
{
|
||||
return await context.AppUserReadingProfile
|
||||
.Where(rp => rp.UserId == userId && rp.Series.Any(s => s.Id == seriesId))
|
||||
.OrderByDescending(rp => rp.Implicit) // Get implicit profiles first
|
||||
.ProjectTo<UserReadingProfileDto>(mapper.ConfigurationProvider)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<AppUserReadingProfile?> GetProfileForLibrary(int userId, int libraryId)
|
||||
public async Task<AppUserReadingProfile?> GetProfileForLibrary(int userId, int libraryId, ReadingProfileIncludes includes = ReadingProfileIncludes.None)
|
||||
{
|
||||
return await context.AppUserReadingProfile
|
||||
.Where(rp => rp.UserId == userId && rp.Libraries.Any(s => s.Id == libraryId))
|
||||
.Includes(includes)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
|
|
@ -90,6 +97,15 @@ public class AppUserReadingProfileRepository(DataContext context, IMapper mapper
|
|||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<AppUserReadingProfile?> GetProfileByName(int userId, string name)
|
||||
{
|
||||
var normalizedName = name.ToNormalized();
|
||||
|
||||
return await context.AppUserReadingProfile
|
||||
.Where(rp => rp.NormalizedName == normalizedName && rp.UserId == userId)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public void Add(AppUserReadingProfile readingProfile)
|
||||
{
|
||||
context.AppUserReadingProfile.Add(readingProfile);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue