mirror of
https://github.com/rmcrackan/Libation.git
synced 2026-01-02 02:48:17 -05:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15ad753fa1 | ||
|
|
75b984bdb2 | ||
|
|
f586d1d59f | ||
|
|
cb91a591f0 | ||
|
|
0c0c556c6a | ||
|
|
ff63b73c09 | ||
|
|
c1d56adbd2 | ||
|
|
bcd99fd208 | ||
|
|
d1df10d060 | ||
|
|
1fa415628f | ||
|
|
a83fe9e532 | ||
|
|
f85462ffec | ||
|
|
156349c293 | ||
|
|
5976706e40 | ||
|
|
1e40180f0c | ||
|
|
7d09728e6b | ||
|
|
4899ef3007 | ||
|
|
296c2b43eb | ||
|
|
932472cb91 | ||
|
|
1bf86b05ec | ||
|
|
5d5e3a6671 |
@@ -118,11 +118,7 @@ namespace AaxDecrypter
|
||||
public abstract Task CancelAsync();
|
||||
protected abstract Task<bool> Step_DownloadAndDecryptAudiobookAsync();
|
||||
|
||||
public virtual void SetCoverArt(byte[] coverArt)
|
||||
{
|
||||
if (coverArt is not null)
|
||||
OnRetrievedCoverArt(coverArt);
|
||||
}
|
||||
public virtual void SetCoverArt(byte[] coverArt) { }
|
||||
|
||||
protected void OnRetrievedTitle(string title)
|
||||
=> RetrievedTitle?.Invoke(this, title);
|
||||
|
||||
@@ -127,6 +127,8 @@ namespace AaxDecrypter
|
||||
{
|
||||
ArgumentValidator.EnsureNotNullOrWhiteSpace(uriToSameFile?.AbsoluteUri, nameof(uriToSameFile));
|
||||
|
||||
if (Path.GetFileName(uriToSameFile.LocalPath) != Path.GetFileName(Uri.LocalPath))
|
||||
throw new ArgumentException($"New uri to the same file must have the same file name.");
|
||||
if (uriToSameFile.Host != Uri.Host)
|
||||
throw new ArgumentException($"New uri to the same file must have the same host.\r\n Old Host :{Uri.Host}\r\nNew Host: {uriToSameFile.Host}");
|
||||
if (DownloadTask is not null)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Version>10.5.2.1</Version>
|
||||
<Version>10.6.2.1</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Octokit" Version="6.0.0" />
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
||||
<PackageReference Include="NPOI" Version="2.6.0" />
|
||||
<PackageReference Include="NPOI" Version="2.6.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AudibleApi" Version="8.4.1.1" />
|
||||
<PackageReference Include="AudibleApi" Version="8.4.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dinah.Core" Version="7.2.2.1" />
|
||||
<PackageReference Include="Dinah.Core" Version="7.2.3.1" />
|
||||
<PackageReference Include="Dinah.EntityFrameworkCore" Version="7.1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using AaxDecrypter;
|
||||
using ApplicationServices;
|
||||
using AudibleApi.Common;
|
||||
using DataLayer;
|
||||
using Dinah.Core;
|
||||
using Dinah.Core.ErrorHandling;
|
||||
@@ -124,12 +125,12 @@ namespace FileLiberator
|
||||
var quality = (AudibleApi.DownloadQuality)config.FileDownloadQuality;
|
||||
var api = await libraryBook.GetApiAsync();
|
||||
var contentLic = await api.GetDownloadLicenseAsync(libraryBook.Book.AudibleProductId, quality);
|
||||
using var dlOptions = BuildDownloadOptions(libraryBook, config, contentLic);
|
||||
using var dlOptions = BuildDownloadOptions(libraryBook, config, contentLic);
|
||||
|
||||
var outFileName = AudibleFileStorage.Audio.GetInProgressFilename(libraryBook, dlOptions.OutputFormat.ToString().ToLower());
|
||||
var cacheDir = AudibleFileStorage.DownloadsInProgressDirectory;
|
||||
|
||||
if (contentLic.DrmType != AudibleApi.Common.DrmType.Adrm)
|
||||
if (contentLic.DrmType != DrmType.Adrm)
|
||||
abDownloader = new UnencryptedAudiobookDownloader(outFileName, cacheDir, dlOptions);
|
||||
else
|
||||
{
|
||||
@@ -152,16 +153,34 @@ namespace FileLiberator
|
||||
abDownloader.RetrievedCoverArt += AaxcDownloader_RetrievedCoverArt;
|
||||
abDownloader.FileCreated += (_, path) => OnFileCreated(libraryBook, path);
|
||||
|
||||
// REAL WORK DONE HERE
|
||||
return await abDownloader.RunAsync();
|
||||
// REAL WORK DONE HERE
|
||||
var success = await abDownloader.RunAsync();
|
||||
|
||||
if (success && config.SaveMetadataToFile)
|
||||
{
|
||||
var metadataFile = Templates.File.GetFilename(dlOptions.LibraryBookDto, Path.GetDirectoryName(outFileName), ".metadata.json");
|
||||
|
||||
saveMetadata(libraryBook, contentLic.ContentMetadata, metadataFile);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
private DownloadOptions BuildDownloadOptions(LibraryBook libraryBook, Configuration config, AudibleApi.Common.ContentLicense contentLic)
|
||||
private void saveMetadata(LibraryBook libraryBook, ContentMetadata contentMetadata, string fileName)
|
||||
{
|
||||
var export = Newtonsoft.Json.Linq.JObject.FromObject(LibToDtos.ToDtos(new[] { libraryBook })[0]);
|
||||
export.Add(nameof(contentMetadata.ChapterInfo), Newtonsoft.Json.Linq.JObject.FromObject(contentMetadata.ChapterInfo));
|
||||
export.Add(nameof(contentMetadata.ContentReference), Newtonsoft.Json.Linq.JObject.FromObject(contentMetadata.ContentReference));
|
||||
|
||||
File.WriteAllText(fileName, export.ToString());
|
||||
OnFileCreated(libraryBook, fileName);
|
||||
}
|
||||
|
||||
private DownloadOptions BuildDownloadOptions(LibraryBook libraryBook, Configuration config, ContentLicense contentLic)
|
||||
{
|
||||
//If DrmType != Adrm the delivered file is an unencrypted mp3.
|
||||
|
||||
var outputFormat
|
||||
= contentLic.DrmType != AudibleApi.Common.DrmType.Adrm || (config.AllowLibationFixup && config.DecryptToLossy)
|
||||
= contentLic.DrmType != DrmType.Adrm || (config.AllowLibationFixup && config.DecryptToLossy)
|
||||
? OutputFormat.Mp3
|
||||
: OutputFormat.M4b;
|
||||
|
||||
@@ -183,7 +202,11 @@ namespace FileLiberator
|
||||
RuntimeLength = TimeSpan.FromMilliseconds(contentLic?.ContentMetadata?.ChapterInfo?.RuntimeLengthMs ?? 0),
|
||||
};
|
||||
|
||||
var chapters = flattenChapters(contentLic.ContentMetadata.ChapterInfo.Chapters).OrderBy(c => c.StartOffsetMs).ToList();
|
||||
var titleConcat = config.CombineNestedChapterTitles ? ": " : null;
|
||||
var chapters
|
||||
= flattenChapters(contentLic.ContentMetadata.ChapterInfo.Chapters, titleConcat)
|
||||
.OrderBy(c => c.StartOffsetMs)
|
||||
.ToList();
|
||||
|
||||
if (config.MergeOpeningAndEndCredits)
|
||||
combineCredits(chapters);
|
||||
@@ -280,14 +303,19 @@ namespace FileLiberator
|
||||
|
||||
*/
|
||||
|
||||
public static List<AudibleApi.Common.Chapter> flattenChapters(IList<AudibleApi.Common.Chapter> chapters, string titleConcat = ": ")
|
||||
public static List<Chapter> flattenChapters(IList<Chapter> chapters, string titleConcat = ": ")
|
||||
{
|
||||
List<AudibleApi.Common.Chapter> chaps = new();
|
||||
List<Chapter> chaps = new();
|
||||
|
||||
foreach (var c in chapters)
|
||||
{
|
||||
if (c.Chapters is null)
|
||||
chaps.Add(c);
|
||||
else if (titleConcat is null)
|
||||
{
|
||||
chaps.Add(c);
|
||||
chaps.AddRange(flattenChapters(c.Chapters));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c.LengthMs < 10000)
|
||||
@@ -305,13 +333,12 @@ namespace FileLiberator
|
||||
child.Title = $"{c.Title}{titleConcat}{child.Title}";
|
||||
|
||||
chaps.AddRange(children);
|
||||
c.Chapters = null;
|
||||
}
|
||||
}
|
||||
return chaps;
|
||||
}
|
||||
|
||||
public static void combineCredits(IList<AudibleApi.Common.Chapter> chapters)
|
||||
public static void combineCredits(IList<Chapter> chapters)
|
||||
{
|
||||
if (chapters.Count > 1 && chapters[0].Title == "Opening Credits")
|
||||
{
|
||||
@@ -351,11 +378,15 @@ namespace FileLiberator
|
||||
|
||||
private void AaxcDownloader_RetrievedCoverArt(object _, byte[] e)
|
||||
{
|
||||
if (Configuration.Instance.AllowLibationFixup)
|
||||
{
|
||||
e = OnRequestCoverArt();
|
||||
abDownloader.SetCoverArt(e);
|
||||
}
|
||||
|
||||
if (e is not null)
|
||||
OnCoverImageDiscovered(e);
|
||||
else if (Configuration.Instance.AllowLibationFixup)
|
||||
abDownloader.SetCoverArt(OnRequestCoverArt());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Move new files to 'Books' directory</summary>
|
||||
/// <returns>Return directory if audiobook file(s) were successfully created and can be located on disk. Else null.</returns>
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dinah.Core" Version="7.2.2.1" />
|
||||
<PackageReference Include="Polly" Version="7.2.3" />
|
||||
<PackageReference Include="Dinah.Core" Version="7.2.3.1" />
|
||||
<PackageReference Include="Polly" Version="7.2.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
||||
@@ -131,6 +131,35 @@ namespace FileManager
|
||||
writeFile(propertyName, parsedNewValue);
|
||||
}
|
||||
|
||||
public bool RemoveProperty(string propertyName)
|
||||
{
|
||||
if (IsReadOnly)
|
||||
return false;
|
||||
|
||||
var success = false;
|
||||
try
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
var jObject = readFile();
|
||||
|
||||
if (!jObject.ContainsKey(propertyName))
|
||||
return false;
|
||||
|
||||
jObject.Remove(propertyName);
|
||||
|
||||
var endContents = JsonConvert.SerializeObject(jObject, Formatting.Indented);
|
||||
|
||||
File.WriteAllText(Filepath, endContents);
|
||||
success = true;
|
||||
}
|
||||
Serilog.Log.Logger.Information("Removed property. {@DebugInfo}", propertyName);
|
||||
}
|
||||
catch { }
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private void writeFile(string propertyName, JToken newValue)
|
||||
{
|
||||
if (IsReadOnly)
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
<Panel Background="Transparent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<Grid Name="ratingsGrid" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="3,0,0,0" ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto,Auto">
|
||||
<Grid.Styles>
|
||||
<Style Selector="TextBlock">
|
||||
<Setter Property="FontSize" Value="11" />
|
||||
</Style>
|
||||
<Style Selector="StackPanel > TextBlock">
|
||||
<Setter Property="Padding" Value="0,0,-2,0" />
|
||||
</Style>
|
||||
|
||||
@@ -73,7 +73,15 @@
|
||||
<TextBlock Text="{CompiledBinding MergeOpeningEndCreditsText}" />
|
||||
</CheckBox>
|
||||
|
||||
<CheckBox IsChecked="{CompiledBinding AllowLibationFixup, Mode=TwoWay}">
|
||||
<CheckBox
|
||||
ToolTip.Tip="{CompiledBinding CombineNestedChapterTitlesTip}"
|
||||
IsChecked="{CompiledBinding CombineNestedChapterTitles, Mode=TwoWay}">
|
||||
<TextBlock Text="{CompiledBinding CombineNestedChapterTitlesText}" />
|
||||
</CheckBox>
|
||||
|
||||
<CheckBox
|
||||
ToolTip.Tip="{CompiledBinding AllowLibationFixupTip}"
|
||||
IsChecked="{CompiledBinding AllowLibationFixup, Mode=TwoWay}">
|
||||
<TextBlock Text="{CompiledBinding AllowLibationFixupText}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
|
||||
@@ -165,18 +165,32 @@
|
||||
</StackPanel>
|
||||
</controls:GroupBox>
|
||||
|
||||
<CheckBox
|
||||
<StackPanel
|
||||
Grid.Row="3"
|
||||
Margin="5"
|
||||
VerticalAlignment="Top"
|
||||
IsVisible="{CompiledBinding !Config.IsLinux}"
|
||||
IsChecked="{CompiledBinding UseCoverAsFolderIcon, Mode=TwoWay}">
|
||||
Orientation="Horizontal">
|
||||
|
||||
<TextBlock
|
||||
TextWrapping="Wrap"
|
||||
Text="{CompiledBinding UseCoverAsFolderIconText}" />
|
||||
<CheckBox
|
||||
Margin="5"
|
||||
VerticalAlignment="Top"
|
||||
IsVisible="{CompiledBinding !Config.IsLinux}"
|
||||
IsChecked="{CompiledBinding UseCoverAsFolderIcon, Mode=TwoWay}">
|
||||
|
||||
</CheckBox>
|
||||
<TextBlock
|
||||
TextWrapping="Wrap"
|
||||
Text="{CompiledBinding UseCoverAsFolderIconText}" />
|
||||
|
||||
</CheckBox>
|
||||
|
||||
<CheckBox
|
||||
Margin="5"
|
||||
VerticalAlignment="Top"
|
||||
IsChecked="{CompiledBinding SaveMetadataToFile, Mode=TwoWay}">
|
||||
|
||||
<TextBlock
|
||||
TextWrapping="Wrap"
|
||||
Text="{CompiledBinding SaveMetadataToFileText}" />
|
||||
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="450"
|
||||
mc:Ignorable="d" d:DesignWidth="700" d:DesignHeight="600"
|
||||
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
|
||||
xmlns:vm="clr-namespace:LibationAvalonia.ViewModels.Settings"
|
||||
x:DataType="vm:ImportantSettingsVM"
|
||||
x:Class="LibationAvalonia.Controls.Settings.Important">
|
||||
|
||||
<Grid RowDefinitions="Auto,Auto,*">
|
||||
<Grid RowDefinitions="Auto,Auto,Auto,*">
|
||||
<controls:GroupBox
|
||||
Grid.Row="0"
|
||||
Margin="5"
|
||||
Label="Books Location">
|
||||
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Margin="5"
|
||||
@@ -35,7 +35,7 @@
|
||||
<Grid
|
||||
RowDefinitions="Auto,Auto"
|
||||
ColumnDefinitions="Auto,*">
|
||||
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,0,10,0"
|
||||
@@ -95,8 +95,63 @@
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<Grid
|
||||
<controls:GroupBox
|
||||
Grid.Row="2"
|
||||
Margin="5"
|
||||
Label="Display Settings">
|
||||
<Grid
|
||||
RowDefinitions="Auto,Auto"
|
||||
ColumnDefinitions="Auto,Auto,*">
|
||||
|
||||
<TextBlock
|
||||
Margin="0,0,10,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{CompiledBinding GridScaleFactorText}"/>
|
||||
|
||||
<Slider
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Value="{CompiledBinding GridScaleFactor, Mode=TwoWay}"
|
||||
VerticalAlignment="Center"
|
||||
Minimum="-100"
|
||||
Maximum="100"
|
||||
IsSnapToTickEnabled="False"
|
||||
TickFrequency="25"
|
||||
TickPlacement="BottomRight">
|
||||
</Slider>
|
||||
|
||||
<TextBlock
|
||||
Margin="0,0,10,0"
|
||||
Grid.Row="1"
|
||||
VerticalAlignment="Center"
|
||||
Text="{CompiledBinding GridFontScaleFactorText}"/>
|
||||
|
||||
<Slider
|
||||
Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Width="200"
|
||||
Value="{CompiledBinding GridFontScaleFactor, Mode=TwoWay}"
|
||||
VerticalAlignment="Center"
|
||||
Minimum="-100"
|
||||
Maximum="100"
|
||||
IsSnapToTickEnabled="False"
|
||||
TickFrequency="25"
|
||||
TickPlacement="BottomRight">
|
||||
</Slider>
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,5"
|
||||
Padding="20,0"
|
||||
VerticalAlignment="Stretch"
|
||||
Content="Apply Display Settings"
|
||||
Command="{CompiledBinding ApplyDisplaySettings}"/>
|
||||
</Grid>
|
||||
</controls:GroupBox>
|
||||
|
||||
<Grid
|
||||
Grid.Row="3"
|
||||
ColumnDefinitions="Auto,Auto,*"
|
||||
Margin="10"
|
||||
VerticalAlignment="Bottom">
|
||||
@@ -111,7 +166,7 @@
|
||||
MinWidth="80"
|
||||
SelectedItem="{CompiledBinding ThemeVariant, Mode=TwoWay}"
|
||||
ItemsSource="{CompiledBinding Themes}"/>
|
||||
|
||||
|
||||
<TextBlock
|
||||
Grid.Column="2"
|
||||
FontSize="16"
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace LibationAvalonia
|
||||
}
|
||||
AppDomain.CurrentDomain.UnhandledException += (o, e) => LogError(e.ExceptionObject);
|
||||
|
||||
bool loggingEnabled = false;
|
||||
//***********************************************//
|
||||
// //
|
||||
// do not use Configuration before this line //
|
||||
@@ -55,6 +56,7 @@ namespace LibationAvalonia
|
||||
// most migrations go in here
|
||||
LibationScaffolding.RunPostConfigMigrations(config);
|
||||
LibationScaffolding.RunPostMigrationScaffolding(Variety.Chardonnay, config);
|
||||
loggingEnabled = true;
|
||||
|
||||
//Start loading the library before loading the main form
|
||||
App.LibraryTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true));
|
||||
@@ -64,9 +66,12 @@ namespace LibationAvalonia
|
||||
|
||||
classicLifetimeTask.Result.Start(null);
|
||||
}
|
||||
catch(Exception e)
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogError(e);
|
||||
if (loggingEnabled)
|
||||
Serilog.Log.Logger.Error(ex, "CRASH");
|
||||
else
|
||||
LogError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using ApplicationServices;
|
||||
using Avalonia.Threading;
|
||||
using DataLayer;
|
||||
using LibationFileManager;
|
||||
using ReactiveUI;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibationAvalonia.ViewModels
|
||||
@@ -41,16 +44,17 @@ namespace LibationAvalonia.ViewModels
|
||||
|
||||
private void Configure_BackupCounts()
|
||||
{
|
||||
MainWindow.Loaded += setBackupCounts;
|
||||
LibraryCommands.LibrarySizeChanged += setBackupCounts;
|
||||
LibraryCommands.BookUserDefinedItemCommitted += setBackupCounts;
|
||||
MainWindow.LibraryLoaded += (_, e) => setBackupCounts(e.Where(l => !l.Book.IsEpisodeParent()));
|
||||
LibraryCommands.LibrarySizeChanged += (_,_) => setBackupCounts();
|
||||
LibraryCommands.BookUserDefinedItemCommitted += (_, _) => setBackupCounts();
|
||||
}
|
||||
|
||||
private async void setBackupCounts(object _, object __)
|
||||
private async void setBackupCounts(IEnumerable<LibraryBook> libraryBooks = null)
|
||||
{
|
||||
if (updateCountsTask?.IsCompleted ?? true)
|
||||
{
|
||||
updateCountsTask = Task.Run(() => LibraryCommands.GetCounts());
|
||||
libraryBooks ??= DbContexts.GetLibrary_Flat_NoTracking();
|
||||
updateCountsTask = Task.Run(() => LibraryCommands.GetCounts(libraryBooks));
|
||||
var stats = await updateCountsTask;
|
||||
await Dispatcher.UIThread.InvokeAsync(() => LibraryStats = stats);
|
||||
|
||||
|
||||
@@ -264,9 +264,12 @@ namespace LibationAvalonia.ViewModels
|
||||
|
||||
private byte[] AudioDecodable_RequestCoverArt(object sender, EventArgs e)
|
||||
{
|
||||
byte[] coverData = PictureStorage
|
||||
.GetPictureSynchronously(
|
||||
new PictureDefinition(LibraryBook.Book.PictureId, PictureSize._500x500));
|
||||
var quality
|
||||
= Configuration.Instance.FileDownloadQuality == Configuration.DownloadQuality.High
|
||||
? new PictureDefinition(LibraryBook.Book.PictureLarge, PictureSize.Native)
|
||||
: new PictureDefinition(LibraryBook.Book.PictureId, PictureSize._500x500);
|
||||
|
||||
byte[] coverData = PictureStorage.GetPictureSynchronously(quality);
|
||||
|
||||
AudioDecodable_CoverImageDiscovered(this, coverData);
|
||||
return coverData;
|
||||
|
||||
@@ -91,37 +91,21 @@ namespace LibationAvalonia.ViewModels
|
||||
|
||||
#region Display Functions
|
||||
|
||||
internal void BindToGrid(List<LibraryBook> dbBooks)
|
||||
internal async Task BindToGridAsync(List<LibraryBook> dbBooks)
|
||||
{
|
||||
GridEntries = new(SOURCE) { Filter = CollectionFilter };
|
||||
|
||||
var geList = dbBooks
|
||||
.Where(lb => lb.Book.IsProduct())
|
||||
.Select(b => new LibraryBookEntry<AvaloniaEntryStatus>(b))
|
||||
.ToList<IGridEntry>();
|
||||
var geList = await LibraryBookEntry<AvaloniaEntryStatus>.GetAllProductsAsync(dbBooks);
|
||||
|
||||
var episodes = dbBooks.Where(lb => lb.Book.IsEpisodeChild()).ToList();
|
||||
|
||||
var seriesBooks = dbBooks.Where(lb => lb.Book.IsEpisodeParent()).ToList();
|
||||
|
||||
foreach (var parent in seriesBooks)
|
||||
{
|
||||
var seriesEpisodes = episodes.FindChildren(parent);
|
||||
|
||||
if (!seriesEpisodes.Any()) continue;
|
||||
|
||||
var seriesEntry = new SeriesEntry<AvaloniaEntryStatus>(parent, seriesEpisodes);
|
||||
seriesEntry.Liberate.Expanded = false;
|
||||
|
||||
geList.Add(seriesEntry);
|
||||
}
|
||||
var seriesEntries = await SeriesEntry<AvaloniaEntryStatus>.GetAllSeriesEntriesAsync(dbBooks);
|
||||
|
||||
//Create the filtered-in list before adding entries to avoid a refresh
|
||||
FilteredInGridEntries = geList.Union(geList.OfType<ISeriesEntry>().SelectMany(s => s.Children)).FilterEntries(FilterString);
|
||||
SOURCE.AddRange(geList.OrderDescending(new RowComparer(null)));
|
||||
FilteredInGridEntries = geList.Union(seriesEntries.SelectMany(s => s.Children)).FilterEntries(FilterString);
|
||||
//Adding entries to the Source list will invoke CollectionFilter
|
||||
SOURCE.AddRange(geList.Concat(seriesEntries).OrderDescending(new RowComparer(null)));
|
||||
|
||||
//Add all children beneath their parent
|
||||
foreach (var series in SOURCE.OfType<ISeriesEntry>().ToList())
|
||||
foreach (var series in seriesEntries)
|
||||
{
|
||||
var seriesIndex = SOURCE.IndexOf(series);
|
||||
foreach (var child in series.Children)
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
public void LoadSettings(Configuration config)
|
||||
{
|
||||
CreateCueSheet = config.CreateCueSheet;
|
||||
CombineNestedChapterTitles = config.CombineNestedChapterTitles;
|
||||
AllowLibationFixup = config.AllowLibationFixup;
|
||||
DownloadCoverArt = config.DownloadCoverArt;
|
||||
RetainAaxFile = config.RetainAaxFile;
|
||||
@@ -71,6 +72,7 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
public void SaveSettings(Configuration config)
|
||||
{
|
||||
config.CreateCueSheet = CreateCueSheet;
|
||||
config.CombineNestedChapterTitles = CombineNestedChapterTitles;
|
||||
config.AllowLibationFixup = AllowLibationFixup;
|
||||
config.DownloadCoverArt = DownloadCoverArt;
|
||||
config.RetainAaxFile = RetainAaxFile;
|
||||
@@ -99,7 +101,10 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
public AvaloniaList<Configuration.ClipBookmarkFormat> ClipBookmarkFormats { get; } = new(Enum<Configuration.ClipBookmarkFormat>.GetValues());
|
||||
public string FileDownloadQualityText { get; } = Configuration.GetDescription(nameof(Configuration.FileDownloadQuality));
|
||||
public string CreateCueSheetText { get; } = Configuration.GetDescription(nameof(Configuration.CreateCueSheet));
|
||||
public string CombineNestedChapterTitlesText { get; } = Configuration.GetDescription(nameof(Configuration.CombineNestedChapterTitles));
|
||||
public string CombineNestedChapterTitlesTip => Configuration.GetHelpText(nameof(CombineNestedChapterTitles));
|
||||
public string AllowLibationFixupText { get; } = Configuration.GetDescription(nameof(Configuration.AllowLibationFixup));
|
||||
public string AllowLibationFixupTip => Configuration.GetHelpText(nameof(AllowLibationFixup));
|
||||
public string DownloadCoverArtText { get; } = Configuration.GetDescription(nameof(Configuration.DownloadCoverArt));
|
||||
public string RetainAaxFileText { get; } = Configuration.GetDescription(nameof(Configuration.RetainAaxFile));
|
||||
public string SplitFilesByChapterText { get; } = Configuration.GetDescription(nameof(Configuration.SplitFilesByChapter));
|
||||
@@ -110,6 +115,7 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
public string MoveMoovToBeginningText { get; } = Configuration.GetDescription(nameof(Configuration.MoveMoovToBeginning));
|
||||
|
||||
public bool CreateCueSheet { get; set; }
|
||||
public bool CombineNestedChapterTitles { get; set; }
|
||||
public bool DownloadCoverArt { get; set; }
|
||||
public bool RetainAaxFile { get; set; }
|
||||
public bool DownloadClipsBookmarks { get => _downloadClipsBookmarks; set => this.RaiseAndSetIfChanged(ref _downloadClipsBookmarks, value); }
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
ChapterFileTemplate = config.ChapterFileTemplate;
|
||||
InProgressDirectory = config.InProgress;
|
||||
UseCoverAsFolderIcon = config.UseCoverAsFolderIcon;
|
||||
SaveMetadataToFile = config.SaveMetadataToFile;
|
||||
}
|
||||
|
||||
public void SaveSettings(Configuration config)
|
||||
@@ -54,9 +55,11 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
config.InProgress = InProgressDirectory;
|
||||
|
||||
config.UseCoverAsFolderIcon = UseCoverAsFolderIcon;
|
||||
config.SaveMetadataToFile = SaveMetadataToFile;
|
||||
}
|
||||
|
||||
public string UseCoverAsFolderIconText { get; } = Configuration.GetDescription(nameof(Configuration.UseCoverAsFolderIcon));
|
||||
public string SaveMetadataToFileText { get; } = Configuration.GetDescription(nameof(Configuration.SaveMetadataToFile));
|
||||
public string BadBookGroupboxText { get; } = Configuration.GetDescription(nameof(Configuration.BadBook));
|
||||
public string BadBookAskText { get; } = Configuration.BadBookAction.Ask.GetDescription();
|
||||
public string BadBookAbortText { get; } = Configuration.BadBookAction.Abort.GetDescription();
|
||||
@@ -72,6 +75,7 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
public string FileTemplate { get => _fileTemplate; set { this.RaiseAndSetIfChanged(ref _fileTemplate, value); } }
|
||||
public string ChapterFileTemplate { get => _chapterFileTemplate; set { this.RaiseAndSetIfChanged(ref _chapterFileTemplate, value); } }
|
||||
public bool UseCoverAsFolderIcon { get; set; }
|
||||
public bool SaveMetadataToFile { get; set; }
|
||||
|
||||
public bool BadBookAsk { get; set; }
|
||||
public bool BadBookAbort { get; set; }
|
||||
|
||||
@@ -13,9 +13,11 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
{
|
||||
private string themeVariant;
|
||||
private string initialThemeVariant;
|
||||
private readonly Configuration config;
|
||||
|
||||
public ImportantSettingsVM(Configuration config)
|
||||
{
|
||||
this.config = config;
|
||||
LoadSettings(config);
|
||||
}
|
||||
|
||||
@@ -27,6 +29,8 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
CreationTime = DateTimeSources.SingleOrDefault(v => v.Value == config.CreationTime) ?? DateTimeSources[0];
|
||||
LastWriteTime = DateTimeSources.SingleOrDefault(v => v.Value == config.LastWriteTime) ?? DateTimeSources[0];
|
||||
LoggingLevel = config.LogLevel;
|
||||
GridScaleFactor = scaleFactorToLinearRange(config.GridScaleFactor);
|
||||
GridFontScaleFactor = scaleFactorToLinearRange(config.GridFontScaleFactor);
|
||||
ThemeVariant = initialThemeVariant
|
||||
= Configuration.Instance.GetString(propertyName: nameof(ThemeVariant)) is nameof(Avalonia.Styling.ThemeVariant.Dark)
|
||||
? nameof(Avalonia.Styling.ThemeVariant.Dark)
|
||||
@@ -47,6 +51,16 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
Configuration.Instance.SetString(ThemeVariant, nameof(ThemeVariant));
|
||||
}
|
||||
|
||||
private static float scaleFactorToLinearRange(float scaleFactor)
|
||||
=> float.Round(100 * MathF.Log2(scaleFactor));
|
||||
private static float linearRangeToScaleFactor(float value)
|
||||
=> MathF.Pow(2, value / 100f);
|
||||
|
||||
public void ApplyDisplaySettings()
|
||||
{
|
||||
config.GridFontScaleFactor = linearRangeToScaleFactor(GridFontScaleFactor);
|
||||
config.GridScaleFactor = linearRangeToScaleFactor(GridScaleFactor);
|
||||
}
|
||||
public void OpenLogFolderButton() => Go.To.Folder(((LongPath)Configuration.Instance.LibationFiles).ShortPathName);
|
||||
|
||||
public List<Configuration.KnownDirectories> KnownDirectories { get; } = new()
|
||||
@@ -66,12 +80,16 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
.Select(v => new EnumDiaplay<Configuration.DateTimeSource>(v))
|
||||
.ToArray();
|
||||
public Serilog.Events.LogEventLevel[] LoggingLevels { get; } = Enum.GetValues<Serilog.Events.LogEventLevel>();
|
||||
public string GridScaleFactorText { get; } = Configuration.GetDescription(nameof(Configuration.GridScaleFactor));
|
||||
public string GridFontScaleFactorText { get; } = Configuration.GetDescription(nameof(Configuration.GridFontScaleFactor));
|
||||
public string BetaOptInText { get; } = Configuration.GetDescription(nameof(Configuration.BetaOptIn));
|
||||
public string[] Themes { get; } = { nameof(Avalonia.Styling.ThemeVariant.Light), nameof(Avalonia.Styling.ThemeVariant.Dark) };
|
||||
|
||||
public string BooksDirectory { get; set; }
|
||||
public bool SavePodcastsToParentFolder { get; set; }
|
||||
public bool OverwriteExisting { get; set; }
|
||||
public float GridScaleFactor { get; set; }
|
||||
public float GridFontScaleFactor { get; set; }
|
||||
public EnumDiaplay<Configuration.DateTimeSource> CreationTime { get; set; }
|
||||
public EnumDiaplay<Configuration.DateTimeSource> LastWriteTime { get; set; }
|
||||
public Serilog.Events.LogEventLevel LoggingLevel { get; set; }
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="clr-namespace:LibationAvalonia.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="200" d:DesignHeight="200" MinWidth="64" MinHeight="64"
|
||||
mc:Ignorable="d" d:DesignWidth="200" d:DesignHeight="200" MinWidth="37" MinHeight="40"
|
||||
Background="Transparent"
|
||||
x:DataType="vm:LiberateStatusButtonViewModel"
|
||||
x:Class="LibationAvalonia.Views.LiberateStatusButton">
|
||||
@@ -35,48 +35,51 @@
|
||||
Name="button"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
IsEnabled="{CompiledBinding IsButtonEnabled}" Padding="0" Click="Button_Click" >
|
||||
<Panel>
|
||||
|
||||
<Panel
|
||||
Width="64" Height="64"
|
||||
IsVisible="{CompiledBinding !IsError}">
|
||||
Padding="0"
|
||||
IsEnabled="{CompiledBinding IsButtonEnabled}" Click="Button_Click" >
|
||||
|
||||
<Panel IsVisible="{CompiledBinding IsSeries}">
|
||||
<Path IsVisible="{CompiledBinding Expanded}" Data="{StaticResource CollapseIcon}" />
|
||||
<Path IsVisible="{CompiledBinding !Expanded}" Data="{StaticResource ExpandIcon}" />
|
||||
<Grid RowDefinitions="*,8*,*">
|
||||
<Viewbox
|
||||
Grid.Row="1"
|
||||
Stretch="Uniform"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<Panel>
|
||||
<Panel IsVisible="{CompiledBinding !IsError}">
|
||||
|
||||
<Panel IsVisible="{CompiledBinding IsSeries}">
|
||||
<Path IsVisible="{CompiledBinding Expanded}" Data="{StaticResource CollapseIcon}" />
|
||||
<Path IsVisible="{CompiledBinding !Expanded}" Data="{StaticResource ExpandIcon}" />
|
||||
</Panel>
|
||||
|
||||
<Grid
|
||||
IsVisible="{CompiledBinding !IsSeries}"
|
||||
HorizontalAlignment="Center"
|
||||
ColumnDefinitions="Auto,Auto">
|
||||
<Canvas Width="29.44" Height="64">
|
||||
<Rectangle Canvas.Left="5" Canvas.Top="5" IsVisible="{CompiledBinding RedVisible}" Fill="{DynamicResource StoplightRed}" />
|
||||
<Rectangle Canvas.Left="5" Canvas.Top="23" IsVisible="{CompiledBinding YellowVisible}" Fill="{DynamicResource StoplightYellow}" />
|
||||
<Rectangle Canvas.Left="5" Canvas.Top="42" IsVisible="{CompiledBinding GreenVisible}" Fill="{DynamicResource StoplightGreen}" />
|
||||
<Path Height="64" Stretch="Uniform" Data="{StaticResource StoplightBodyIcon}"/>
|
||||
</Canvas>
|
||||
<Path Grid.Column="1" IsVisible="{CompiledBinding PdfDownloadedVisible}" Data="{StaticResource PdfDownloadedIcon}"/>
|
||||
<Path Grid.Column="1" IsVisible="{CompiledBinding PdfNotDownloadedVisible}" Data="{StaticResource PdfNotDownloadedIcon}"/>
|
||||
</Grid>
|
||||
</Panel>
|
||||
|
||||
<Path
|
||||
Stretch="None" Width="64"
|
||||
IsVisible="{CompiledBinding IsError}"
|
||||
Fill="{DynamicResource CancelRed}"
|
||||
Data="{StaticResource BookErrorIcon}" />
|
||||
|
||||
<Path
|
||||
Stretch="Fill"
|
||||
IsVisible="{CompiledBinding !IsButtonEnabled}"
|
||||
Fill="{DynamicResource DisabledGrayBrush}"
|
||||
Data="M0,0 H1 V1 H0" />
|
||||
</Panel>
|
||||
|
||||
<Grid
|
||||
IsVisible="{CompiledBinding !IsSeries}"
|
||||
HorizontalAlignment="Center"
|
||||
ColumnDefinitions="Auto,Auto">
|
||||
|
||||
<Canvas Width="29.44" Height="64">
|
||||
<Rectangle Canvas.Left="5" Canvas.Top="5" IsVisible="{CompiledBinding RedVisible}" Fill="{DynamicResource StoplightRed}" />
|
||||
<Rectangle Canvas.Left="5" Canvas.Top="23" IsVisible="{CompiledBinding YellowVisible}" Fill="{DynamicResource StoplightYellow}" />
|
||||
<Rectangle Canvas.Left="5" Canvas.Top="42" IsVisible="{CompiledBinding GreenVisible}" Fill="{DynamicResource StoplightGreen}" />
|
||||
<Path Height="64" Stretch="Uniform" Data="{StaticResource StoplightBodyIcon}"/>
|
||||
</Canvas>
|
||||
|
||||
<Path Grid.Column="1" IsVisible="{CompiledBinding PdfDownloadedVisible}" Data="{StaticResource PdfDownloadedIcon}"/>
|
||||
<Path Grid.Column="1" IsVisible="{CompiledBinding PdfNotDownloadedVisible}" Data="{StaticResource PdfNotDownloadedIcon}"/>
|
||||
</Grid>
|
||||
|
||||
</Panel>
|
||||
|
||||
<Path
|
||||
Stretch="None" Width="64"
|
||||
IsVisible="{CompiledBinding IsError}"
|
||||
Fill="{DynamicResource CancelRed}"
|
||||
Data="{StaticResource BookErrorIcon}" />
|
||||
|
||||
<Path
|
||||
Stretch="Fill"
|
||||
IsVisible="{CompiledBinding !IsButtonEnabled}"
|
||||
Fill="{DynamicResource DisabledGrayBrush}"
|
||||
Data="M0,0 H1 V1 H0" />
|
||||
</Panel>
|
||||
</Viewbox>
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
</UserControl>
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace LibationAvalonia.Views
|
||||
if (QuickFilters.UseDefault)
|
||||
await ViewModel.PerformFilter(QuickFilters.Filters.FirstOrDefault());
|
||||
|
||||
ViewModel.ProductsDisplay.BindToGrid(dbBooks);
|
||||
await ViewModel.ProductsDisplay.BindToGridAsync(dbBooks);
|
||||
}
|
||||
|
||||
private void selectAndFocusSearchBox()
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
CanUserReorderColumns="True">
|
||||
|
||||
<DataGrid.Styles>
|
||||
<Style Selector="DataGridCell">
|
||||
<Setter Property="Height" Value="80"/>
|
||||
</Style>
|
||||
<Style Selector="DataGridCell > Panel">
|
||||
<Setter Property="VerticalAlignment" Value="Stretch"/>
|
||||
</Style>
|
||||
@@ -31,7 +28,6 @@
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="TextWrapping" Value="Wrap"/>
|
||||
<Setter Property="Padding" Value="4"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
</Style>
|
||||
<Style Selector="DataGridCell Path">
|
||||
<Setter Property="Stretch" Value="Uniform" />
|
||||
@@ -69,7 +65,7 @@
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<controls:DataGridTemplateColumnExt CanUserSort="True" Width="75" Header="Liberate" SortMemberPath="Liberate" ClipboardContentBinding="{Binding Liberate.ToolTip}">
|
||||
<controls:DataGridTemplateColumnExt CanUserSort="True" Header="Liberate" SortMemberPath="Liberate" ClipboardContentBinding="{Binding Liberate.ToolTip}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<views:LiberateStatusButton
|
||||
@@ -84,19 +80,19 @@
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</controls:DataGridTemplateColumnExt>
|
||||
|
||||
<DataGridTemplateColumn CanUserSort="False" Width="80" Header="Cover" SortMemberPath="Cover" ClipboardContentBinding="{Binding LibraryBook.Book.PictureLarge}">
|
||||
<controls:DataGridTemplateColumnExt CanUserSort="False" Header="Cover" SortMemberPath="Cover" ClipboardContentBinding="{Binding LibraryBook.Book.PictureLarge}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<Image Opacity="{CompiledBinding Liberate.Opacity}" Tapped="Cover_Click" Height="80" Source="{CompiledBinding Cover}" ToolTip.Tip="Click to see full size" />
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<Image Opacity="{CompiledBinding Liberate.Opacity}" Tapped="Cover_Click" Source="{CompiledBinding Cover}" ToolTip.Tip="Click to see full size" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</controls:DataGridTemplateColumnExt>
|
||||
|
||||
<controls:DataGridTemplateColumnExt MinWidth="150" Width="2*" Header="Title" CanUserSort="True" SortMemberPath="Title" ClipboardContentBinding="{Binding Title}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
||||
<TextBlock FontSize="14" Text="{CompiledBinding Title}" />
|
||||
<TextBlock Classes="h1" Text="{CompiledBinding Title}" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
@@ -156,7 +152,7 @@
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}" Tapped="Description_Click" ToolTip.Tip="Click to see full description" >
|
||||
<TextBlock Text="{CompiledBinding Description}" FontSize="11" VerticalAlignment="Top" />
|
||||
<TextBlock Text="{CompiledBinding Description}" VerticalAlignment="Top" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
@@ -208,7 +204,7 @@
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
||||
<TextBlock Text="{CompiledBinding Misc}" TextWrapping="WrapWithOverflow" FontSize="10" />
|
||||
<TextBlock Text="{CompiledBinding Misc}" TextWrapping="WrapWithOverflow" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
@@ -218,7 +214,7 @@
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}" ToolTip.Tip="{CompiledBinding LastDownload.ToolTipText}" DoubleTapped="Version_DoubleClick">
|
||||
<TextBlock Text="{CompiledBinding LastDownload}" TextWrapping="WrapWithOverflow" FontSize="10" />
|
||||
<TextBlock Text="{CompiledBinding LastDownload}" TextWrapping="WrapWithOverflow" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
@@ -227,13 +223,30 @@
|
||||
<controls:DataGridTemplateColumnExt CanUserSort="True" Width="100" Header="Tags" SortMemberPath="BookTags" ClipboardContentBinding="{Binding BookTags}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<Button IsVisible="{CompiledBinding !Liberate.IsSeries}" Width="100" Height="80" Click="OnTagsButtonClick" ToolTip.Tip="Click to edit tags" >
|
||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}">
|
||||
<Panel Width="24" Height="24" IsVisible="{CompiledBinding BookTags, Converter={x:Static StringConverters.IsNullOrEmpty}}">
|
||||
<Path Stretch="Uniform" Fill="{DynamicResource IconFill}" Data="{StaticResource EditTagsIcon}" />
|
||||
</Panel>
|
||||
<TextBlock IsVisible="{CompiledBinding BookTags, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" FontSize="12" TextWrapping="WrapWithOverflow" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{CompiledBinding BookTags}"/>
|
||||
</Panel>
|
||||
<Button
|
||||
IsVisible="{CompiledBinding !Liberate.IsSeries}"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Click="OnTagsButtonClick"
|
||||
ToolTip.Tip="Click to edit tags">
|
||||
<Grid
|
||||
RowDefinitions="*,*,*"
|
||||
Opacity="{CompiledBinding Liberate.Opacity}">
|
||||
<Viewbox
|
||||
Grid.Row="1"
|
||||
Stretch="Uniform"
|
||||
IsVisible="{CompiledBinding BookTags, Converter={x:Static StringConverters.IsNullOrEmpty}}">
|
||||
|
||||
<Path Fill="{DynamicResource IconFill}" Data="{StaticResource EditTagsIcon}" />
|
||||
</Viewbox>
|
||||
<TextBlock
|
||||
Classes="h2"
|
||||
Grid.RowSpan="3"
|
||||
IsVisible="{CompiledBinding BookTags, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" TextWrapping="WrapWithOverflow" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{CompiledBinding BookTags}"/>
|
||||
|
||||
</Grid>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
|
||||
@@ -2,7 +2,9 @@ using ApplicationServices;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Avalonia.Styling;
|
||||
using DataLayer;
|
||||
using Dinah.Core;
|
||||
using FileLiberator;
|
||||
using LibationAvalonia.Controls;
|
||||
using LibationAvalonia.Dialogs;
|
||||
@@ -30,6 +32,25 @@ namespace LibationAvalonia.Views
|
||||
InitializeComponent();
|
||||
DataGridContextMenus.CellContextMenuStripNeeded += ProductsGrid_CellContextMenuStripNeeded;
|
||||
|
||||
var cellSelector = Selectors.Is<DataGridCell>(null);
|
||||
rowHeightStyle = new Style(_ => cellSelector);
|
||||
rowHeightStyle.Setters.Add(rowHeightSetter);
|
||||
|
||||
var tboxSelector = cellSelector.Descendant().Is<TextBlock>();
|
||||
fontSizeStyle = new Style(_ => tboxSelector);
|
||||
fontSizeStyle.Setters.Add(fontSizeSetter);
|
||||
|
||||
var tboxH1Selector = cellSelector.Child().Is<Panel>().Child().Is<TextBlock>().Class("h1");
|
||||
fontSizeH1Style = new Style(_ => tboxH1Selector);
|
||||
fontSizeH1Style.Setters.Add(fontSizeH1Setter);
|
||||
|
||||
var tboxH2Selector = cellSelector.Child().Is<Panel>().Child().Is<TextBlock>().Class("h2");
|
||||
fontSizeH2Style = new Style(_ => tboxH2Selector);
|
||||
fontSizeH2Style.Setters.Add(fontSizeH2Setter);
|
||||
|
||||
Configuration.Instance.PropertyChanged += Configuration_GridScaleChanged;
|
||||
Configuration.Instance.PropertyChanged += Configuration_FontChanged;
|
||||
|
||||
if (Design.IsDesignMode)
|
||||
{
|
||||
using var context = DbContexts.GetContext();
|
||||
@@ -51,12 +72,16 @@ namespace LibationAvalonia.Views
|
||||
catch { sampleEntries = new(); }
|
||||
|
||||
var pdvm = new ProductsDisplayViewModel();
|
||||
pdvm.BindToGrid(sampleEntries);
|
||||
_ = pdvm.BindToGridAsync(sampleEntries);
|
||||
DataContext = pdvm;
|
||||
|
||||
setGridScale(1);
|
||||
setFontScale(1);
|
||||
return;
|
||||
}
|
||||
|
||||
setGridScale(Configuration.Instance.GridScaleFactor);
|
||||
setFontScale(Configuration.Instance.GridFontScaleFactor);
|
||||
Configure_ColumnCustomization();
|
||||
|
||||
foreach (var column in productsGrid.Columns)
|
||||
@@ -67,174 +92,257 @@ namespace LibationAvalonia.Views
|
||||
|
||||
private void RemoveColumn_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)
|
||||
{
|
||||
if (sender is DataGridColumn col && e.Property.Name == nameof(DataGridColumn.IsVisible))
|
||||
if (sender is DataGridColumn col && e.Property == DataGridColumn.IsVisibleProperty)
|
||||
{
|
||||
col.DisplayIndex = 0;
|
||||
col.CanUserReorder = false;
|
||||
}
|
||||
}
|
||||
|
||||
#region Scaling
|
||||
|
||||
[PropertyChangeFilter(nameof(Configuration.GridScaleFactor))]
|
||||
private void Configuration_GridScaleChanged(object sender, Dinah.Core.PropertyChangedEventArgsEx e)
|
||||
{
|
||||
setGridScale((float)e.NewValue);
|
||||
}
|
||||
|
||||
[PropertyChangeFilter(nameof(Configuration.GridFontScaleFactor))]
|
||||
private void Configuration_FontChanged(object sender, Dinah.Core.PropertyChangedEventArgsEx e)
|
||||
{
|
||||
setFontScale((float)e.NewValue);
|
||||
}
|
||||
|
||||
private readonly Style rowHeightStyle;
|
||||
private readonly Setter rowHeightSetter = new() { Property = DataGridCell.HeightProperty };
|
||||
|
||||
private readonly Style fontSizeStyle;
|
||||
private readonly Setter fontSizeSetter = new() { Property = TextBlock.FontSizeProperty };
|
||||
|
||||
private readonly Style fontSizeH1Style;
|
||||
private readonly Setter fontSizeH1Setter = new() { Property = TextBlock.FontSizeProperty };
|
||||
|
||||
private readonly Style fontSizeH2Style;
|
||||
private readonly Setter fontSizeH2Setter = new() { Property = TextBlock.FontSizeProperty };
|
||||
|
||||
private void setFontScale(double scaleFactor)
|
||||
{
|
||||
const double TextBlockFontSize = 11;
|
||||
const double H1FontSize = 14;
|
||||
const double H2FontSize = 12;
|
||||
|
||||
fontSizeSetter.Value = TextBlockFontSize * scaleFactor;
|
||||
fontSizeH1Setter.Value = H1FontSize * scaleFactor;
|
||||
fontSizeH2Setter.Value = H2FontSize * scaleFactor;
|
||||
|
||||
productsGrid.Styles.Remove(fontSizeStyle);
|
||||
productsGrid.Styles.Remove(fontSizeH1Style);
|
||||
productsGrid.Styles.Remove(fontSizeH2Style);
|
||||
productsGrid.Styles.Add(fontSizeStyle);
|
||||
productsGrid.Styles.Add(fontSizeH1Style);
|
||||
productsGrid.Styles.Add(fontSizeH2Style);
|
||||
}
|
||||
|
||||
private void setGridScale(double scaleFactor)
|
||||
{
|
||||
const float BaseRowHeight = 80;
|
||||
const float BaseLiberateWidth = 75;
|
||||
const float BaseCoverWidth = 80;
|
||||
|
||||
foreach (var column in productsGrid.Columns)
|
||||
{
|
||||
switch (column.SortMemberPath)
|
||||
{
|
||||
case nameof(IGridEntry.Liberate):
|
||||
column.Width = new DataGridLength(BaseLiberateWidth * scaleFactor);
|
||||
break;
|
||||
case nameof(IGridEntry.Cover):
|
||||
column.Width = new DataGridLength(BaseCoverWidth * scaleFactor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
rowHeightSetter.Value = BaseRowHeight * scaleFactor;
|
||||
productsGrid.Styles.Remove(rowHeightStyle);
|
||||
productsGrid.Styles.Add(rowHeightStyle);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cell Context Menu
|
||||
|
||||
public void ProductsGrid_CellContextMenuStripNeeded(object sender, DataGridCellContextMenuStripNeededEventArgs args)
|
||||
{
|
||||
// stop light
|
||||
if (args.Column.SortMemberPath == "Liberate")
|
||||
if (args.Column.SortMemberPath is not "Liberate" and not "Cover")
|
||||
{
|
||||
var entry = args.GridEntry;
|
||||
|
||||
#region Liberate all Episodes
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
{
|
||||
var liberateEpisodesMenuItem = new MenuItem()
|
||||
{
|
||||
Header = "_Liberate All Episodes",
|
||||
IsEnabled = ((ISeriesEntry)entry).Children.Any(c => c.Liberate.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload)
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Add(liberateEpisodesMenuItem);
|
||||
|
||||
liberateEpisodesMenuItem.Click += (_, _) => LiberateSeriesClicked?.Invoke(this, ((ISeriesEntry)entry));
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region Set Download status to Downloaded
|
||||
|
||||
var setDownloadMenuItem = new MenuItem()
|
||||
{
|
||||
Header = "Set Download status to '_Downloaded'",
|
||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated || entry.Liberate.IsSeries
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Add(setDownloadMenuItem);
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
setDownloadMenuItem.Click += (_, __) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.Liberated);
|
||||
else
|
||||
setDownloadMenuItem.Click += (_, __) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.Liberated);
|
||||
|
||||
#endregion
|
||||
#region Set Download status to Not Downloaded
|
||||
|
||||
var setNotDownloadMenuItem = new MenuItem()
|
||||
{
|
||||
Header = "Set Download status to '_Not Downloaded'",
|
||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated || entry.Liberate.IsSeries
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Add(setNotDownloadMenuItem);
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
setNotDownloadMenuItem.Click += (_, __) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.NotLiberated);
|
||||
else
|
||||
setNotDownloadMenuItem.Click += (_, __) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.NotLiberated);
|
||||
|
||||
#endregion
|
||||
#region Remove from library
|
||||
|
||||
var removeMenuItem = new MenuItem() { Header = "_Remove from library" };
|
||||
|
||||
args.ContextMenuItems.Add(removeMenuItem);
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
removeMenuItem.Click += async (_, __) => await ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).RemoveBooksAsync();
|
||||
else
|
||||
removeMenuItem.Click += async (_, __) => await Task.Run(entry.LibraryBook.RemoveBook);
|
||||
|
||||
#endregion
|
||||
|
||||
if (!entry.Liberate.IsSeries)
|
||||
{
|
||||
#region Locate file
|
||||
var locateFileMenuItem = new MenuItem() { Header = "_Locate file..." };
|
||||
|
||||
args.ContextMenuItems.Add(locateFileMenuItem);
|
||||
|
||||
locateFileMenuItem.Click += async (_, __) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var window = this.GetParentWindow();
|
||||
|
||||
var openFileDialogOptions = new FilePickerOpenOptions
|
||||
{
|
||||
Title = $"Locate the audio file for '{entry.Book.TitleWithSubtitle}'",
|
||||
AllowMultiple = false,
|
||||
SuggestedStartLocation = await window.StorageProvider.TryGetFolderFromPathAsync(Configuration.Instance.Books.PathWithoutPrefix),
|
||||
FileTypeFilter = new FilePickerFileType[]
|
||||
{
|
||||
new("All files (*.*)") { Patterns = new[] { "*" } },
|
||||
}
|
||||
};
|
||||
|
||||
var selectedFiles = await window.StorageProvider.OpenFilePickerAsync(openFileDialogOptions);
|
||||
var selectedFile = selectedFiles.SingleOrDefault()?.TryGetLocalPath();
|
||||
|
||||
if (selectedFile is not null)
|
||||
FilePathCache.Insert(entry.AudibleProductId, selectedFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var msg = "Error saving book's location";
|
||||
await MessageBox.ShowAdminAlert(null, msg, msg, ex);
|
||||
}
|
||||
};
|
||||
|
||||
#endregion
|
||||
#region Convert to Mp3
|
||||
var convertToMp3MenuItem = new MenuItem
|
||||
{
|
||||
Header = "_Convert to Mp3",
|
||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
||||
};
|
||||
args.ContextMenuItems.Add(convertToMp3MenuItem);
|
||||
|
||||
convertToMp3MenuItem.Click += (_, _) => ConvertToMp3Clicked?.Invoke(this, entry.LibraryBook);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
args.ContextMenuItems.Add(new Separator());
|
||||
|
||||
#region View Bookmarks/Clips
|
||||
|
||||
if (!entry.Liberate.IsSeries)
|
||||
{
|
||||
|
||||
var bookRecordMenuItem = new MenuItem { Header = "View _Bookmarks/Clips" };
|
||||
|
||||
args.ContextMenuItems.Add(bookRecordMenuItem);
|
||||
|
||||
bookRecordMenuItem.Click += async (_, _) => await new BookRecordsDialog(entry.LibraryBook).ShowDialog(VisualRoot as Window);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region View All Series
|
||||
|
||||
if (entry.Book.SeriesLink.Any())
|
||||
{
|
||||
var header = entry.Liberate.IsSeries ? "View All Episodes in Series" : "View All Books in Series";
|
||||
var viewSeriesMenuItem = new MenuItem { Header = header };
|
||||
|
||||
args.ContextMenuItems.Add(viewSeriesMenuItem);
|
||||
|
||||
viewSeriesMenuItem.Click += (_, _) => new SeriesViewDialog(entry.LibraryBook).Show();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
else
|
||||
{
|
||||
// any non-stop light column
|
||||
// (except for the Cover column which does not have a context menu)
|
||||
var menuItem = new MenuItem { Header = "_Copy Cell Contents" };
|
||||
|
||||
menuItem.Click += async (s, e)
|
||||
=> await App.MainWindow.Clipboard.SetTextAsync(args.CellClipboardContents);
|
||||
|
||||
args.ContextMenuItems.Add(menuItem);
|
||||
args.ContextMenuItems.Add(new Separator());
|
||||
}
|
||||
var entry = args.GridEntry;
|
||||
|
||||
#region Liberate all Episodes
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
{
|
||||
var liberateEpisodesMenuItem = new MenuItem()
|
||||
{
|
||||
Header = "_Liberate All Episodes",
|
||||
IsEnabled = ((ISeriesEntry)entry).Children.Any(c => c.Liberate.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload)
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Add(liberateEpisodesMenuItem);
|
||||
|
||||
liberateEpisodesMenuItem.Click += (_, _) => LiberateSeriesClicked?.Invoke(this, ((ISeriesEntry)entry));
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region Set Download status to Downloaded
|
||||
|
||||
var setDownloadMenuItem = new MenuItem()
|
||||
{
|
||||
Header = "Set Download status to '_Downloaded'",
|
||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated || entry.Liberate.IsSeries
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Add(setDownloadMenuItem);
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
setDownloadMenuItem.Click += (_, __) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.Liberated);
|
||||
else
|
||||
setDownloadMenuItem.Click += (_, __) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.Liberated);
|
||||
|
||||
#endregion
|
||||
#region Set Download status to Not Downloaded
|
||||
|
||||
var setNotDownloadMenuItem = new MenuItem()
|
||||
{
|
||||
Header = "Set Download status to '_Not Downloaded'",
|
||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated || entry.Liberate.IsSeries
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Add(setNotDownloadMenuItem);
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
setNotDownloadMenuItem.Click += (_, __) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.NotLiberated);
|
||||
else
|
||||
setNotDownloadMenuItem.Click += (_, __) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.NotLiberated);
|
||||
|
||||
#endregion
|
||||
#region Remove from library
|
||||
|
||||
var removeMenuItem = new MenuItem() { Header = "_Remove from library" };
|
||||
|
||||
args.ContextMenuItems.Add(removeMenuItem);
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
removeMenuItem.Click += async (_, __) => await ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).RemoveBooksAsync();
|
||||
else
|
||||
removeMenuItem.Click += async (_, __) => await Task.Run(entry.LibraryBook.RemoveBook);
|
||||
|
||||
#endregion
|
||||
|
||||
if (!entry.Liberate.IsSeries)
|
||||
{
|
||||
#region Locate file
|
||||
var locateFileMenuItem = new MenuItem() { Header = "_Locate file..." };
|
||||
|
||||
args.ContextMenuItems.Add(locateFileMenuItem);
|
||||
|
||||
locateFileMenuItem.Click += async (_, __) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var window = this.GetParentWindow();
|
||||
|
||||
var openFileDialogOptions = new FilePickerOpenOptions
|
||||
{
|
||||
Title = $"Locate the audio file for '{entry.Book.TitleWithSubtitle}'",
|
||||
AllowMultiple = false,
|
||||
SuggestedStartLocation = await window.StorageProvider.TryGetFolderFromPathAsync(Configuration.Instance.Books.PathWithoutPrefix),
|
||||
FileTypeFilter = new FilePickerFileType[]
|
||||
{
|
||||
new("All files (*.*)") { Patterns = new[] { "*" } },
|
||||
}
|
||||
};
|
||||
|
||||
var selectedFiles = await window.StorageProvider.OpenFilePickerAsync(openFileDialogOptions);
|
||||
var selectedFile = selectedFiles.SingleOrDefault()?.TryGetLocalPath();
|
||||
|
||||
if (selectedFile is not null)
|
||||
FilePathCache.Insert(entry.AudibleProductId, selectedFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var msg = "Error saving book's location";
|
||||
await MessageBox.ShowAdminAlert(null, msg, msg, ex);
|
||||
}
|
||||
};
|
||||
|
||||
#endregion
|
||||
#region Convert to Mp3
|
||||
var convertToMp3MenuItem = new MenuItem
|
||||
{
|
||||
Header = "_Convert to Mp3",
|
||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
||||
};
|
||||
args.ContextMenuItems.Add(convertToMp3MenuItem);
|
||||
|
||||
convertToMp3MenuItem.Click += (_, _) => ConvertToMp3Clicked?.Invoke(this, entry.LibraryBook);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region Force Re-Download
|
||||
if (!entry.Liberate.IsSeries)
|
||||
{
|
||||
var reDownloadMenuItem = new MenuItem()
|
||||
{
|
||||
Header = "Re-download this audiobook",
|
||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Add(reDownloadMenuItem);
|
||||
reDownloadMenuItem.Click += (s, _) =>
|
||||
{
|
||||
//No need to persist this change. It only needs to last long for the file to start downloading
|
||||
entry.Book.UserDefinedItem.BookStatus = LiberatedStatus.NotLiberated;
|
||||
LiberateClicked?.Invoke(s, entry.LibraryBook);
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
args.ContextMenuItems.Add(new Separator());
|
||||
|
||||
#region View Bookmarks/Clips
|
||||
|
||||
if (!entry.Liberate.IsSeries)
|
||||
{
|
||||
|
||||
var bookRecordMenuItem = new MenuItem { Header = "View _Bookmarks/Clips" };
|
||||
|
||||
args.ContextMenuItems.Add(bookRecordMenuItem);
|
||||
|
||||
bookRecordMenuItem.Click += async (_, _) => await new BookRecordsDialog(entry.LibraryBook).ShowDialog(VisualRoot as Window);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region View All Series
|
||||
|
||||
if (entry.Book.SeriesLink.Any())
|
||||
{
|
||||
var header = entry.Liberate.IsSeries ? "View All Episodes in Series" : "View All Books in Series";
|
||||
var viewSeriesMenuItem = new MenuItem { Header = header };
|
||||
|
||||
args.ContextMenuItems.Add(viewSeriesMenuItem);
|
||||
|
||||
viewSeriesMenuItem.Click += (_, _) => new SeriesViewDialog(entry.LibraryBook).Show();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
36
Source/LibationFileManager/Configuration.HelpText.cs
Normal file
36
Source/LibationFileManager/Configuration.HelpText.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace LibationFileManager
|
||||
{
|
||||
public partial class Configuration
|
||||
{
|
||||
public static ReadOnlyDictionary<string, string> HelpText { get; } = new Dictionary<string, string>
|
||||
{
|
||||
{ nameof(CombineNestedChapterTitles),"""
|
||||
If the book has nested chapters, e.g. a chapter named "Part 1"
|
||||
that contains chapters "Chapter 1" and "Chapter 2", then combine
|
||||
the chapter titles like the following example:
|
||||
|
||||
Part 1: Chapter 1
|
||||
Part 1: Chapter 2
|
||||
"""},
|
||||
{nameof(AllowLibationFixup), """
|
||||
In addition to the options that are enabled if you allow
|
||||
"fixing up" the audiobook, it does the following:
|
||||
|
||||
* Sets the ©gen metadata tag for the genres.
|
||||
* Adds the TCOM (@wrt in M4B files) metadata tag for the narrators.
|
||||
* Unescapes the copyright symbol (replace © with ©)
|
||||
* Replaces the recording copyright (P) string with ℗
|
||||
* Adds various other metadata tags recognized by AudiobookShelf
|
||||
* Sets the embedded cover art image with cover art retrieved from Audible
|
||||
""" },
|
||||
}
|
||||
.AsReadOnly();
|
||||
|
||||
public static string GetHelpText(string settingName)
|
||||
=> HelpText.TryGetValue(settingName, out var value) ? value : null;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,8 @@ namespace LibationFileManager
|
||||
|
||||
private PersistentDictionary persistentDictionary;
|
||||
|
||||
public bool RemoveProperty(string propertyName) => persistentDictionary.RemoveProperty(propertyName);
|
||||
|
||||
public T GetNonString<T>(T defaultValue, [CallerMemberName] string propertyName = "") => persistentDictionary.GetNonString(propertyName, defaultValue);
|
||||
public object GetObject([CallerMemberName] string propertyName = "") => persistentDictionary.GetObject(propertyName);
|
||||
public string GetString(string defaultValue = null, [CallerMemberName] string propertyName = "") => persistentDictionary.GetString(propertyName, defaultValue);
|
||||
@@ -73,9 +75,18 @@ namespace LibationFileManager
|
||||
|
||||
public bool Exists(string propertyName) => persistentDictionary.Exists(propertyName);
|
||||
|
||||
[Description("Set cover art as the folder's icon. (Windows and macOS only)")]
|
||||
[Description("Set cover art as the folder's icon.")]
|
||||
public bool UseCoverAsFolderIcon { get => GetNonString(defaultValue: false); set => SetNonString(value); }
|
||||
|
||||
[Description("Save audiobook metadata to metadata.json")]
|
||||
public bool SaveMetadataToFile { get => GetNonString(defaultValue: false); set => SetNonString(value); }
|
||||
|
||||
[Description("Book display grid size")]
|
||||
public float GridScaleFactor { get => float.Min(2, float.Max(0.5f, GetNonString(defaultValue: 1f))); set => SetNonString(value); }
|
||||
|
||||
[Description("Book display font size")]
|
||||
public float GridFontScaleFactor { get => float.Min(2, float.Max(0.5f, GetNonString(defaultValue: 1f))); set => SetNonString(value); }
|
||||
|
||||
[Description("Use the beta version of Libation\r\nNew and experimental features, but probably buggy.\r\n(requires restart to take effect)")]
|
||||
public bool BetaOptIn { get => GetNonString(defaultValue: false); set => SetNonString(value); }
|
||||
|
||||
@@ -164,6 +175,9 @@ namespace LibationFileManager
|
||||
[Description("Save cover image alongside audiobook?")]
|
||||
public bool DownloadCoverArt { get => GetNonString(defaultValue: false); set => SetNonString(value); }
|
||||
|
||||
[Description("Combine nested chapter titles")]
|
||||
public bool CombineNestedChapterTitles { get => GetNonString(defaultValue: false); set => SetNonString(value); }
|
||||
|
||||
[Description("Download clips and bookmarks?")]
|
||||
public bool DownloadClipsBookmarks { get => GetNonString(defaultValue: false); set => SetNonString(value); }
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace LibationUiBase.GridView
|
||||
Misc = GetMiscDisplay(libraryBook);
|
||||
LastDownload = new(Book.UserDefinedItem);
|
||||
LongDescription = GetDescriptionDisplay(Book);
|
||||
Description = TrimTextToWord(LongDescription, 62);
|
||||
Description = LongDescription;// TrimTextToWord(LongDescription, 62);
|
||||
SeriesIndex = Book.SeriesLink.FirstOrDefault()?.Index ?? 0;
|
||||
BookTags = GetBookTags();
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
using DataLayer;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibationUiBase.GridView
|
||||
{
|
||||
@@ -29,6 +33,41 @@ namespace LibationUiBase.GridView
|
||||
LoadCover();
|
||||
}
|
||||
|
||||
|
||||
public static async Task<List<IGridEntry>> GetAllProductsAsync(IEnumerable<LibraryBook> libraryBooks)
|
||||
{
|
||||
var products = libraryBooks.Where(lb => lb.Book.IsProduct()).ToArray();
|
||||
|
||||
int parallelism = int.Max(1, Environment.ProcessorCount - 1);
|
||||
|
||||
(int numPer, int rem) = int.DivRem(products.Length, parallelism);
|
||||
if (rem != 0) numPer++;
|
||||
|
||||
var tasks = new Task<IGridEntry[]>[parallelism];
|
||||
var syncContext = SynchronizationContext.Current;
|
||||
|
||||
for (int i = 0; i < parallelism; i++)
|
||||
{
|
||||
int start = i * numPer;
|
||||
tasks[i] = Task.Run(() =>
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(syncContext);
|
||||
|
||||
int length = int.Min(numPer, products.Length - start);
|
||||
if (length < 1) return Array.Empty<IGridEntry>();
|
||||
|
||||
var result = new IGridEntry[length];
|
||||
|
||||
for (int j = 0; j < length; j++)
|
||||
result[j] = new LibraryBookEntry<TStatus>(products[start + j]);
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
return (await Task.WhenAll(tasks)).SelectMany(a => a).ToList();
|
||||
}
|
||||
|
||||
protected override string GetBookTags() => string.Join("\r\n", Book.UserDefinedItem.TagsEnumerated);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using DataLayer;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibationUiBase.GridView
|
||||
{
|
||||
@@ -54,6 +57,60 @@ namespace LibationUiBase.GridView
|
||||
LoadCover();
|
||||
}
|
||||
|
||||
public static async Task<List<ISeriesEntry>> GetAllSeriesEntriesAsync(IEnumerable<LibraryBook> libraryBooks)
|
||||
{
|
||||
var seriesBooks = libraryBooks.Where(lb => lb.Book.IsEpisodeParent()).ToArray();
|
||||
var allEpisodes = libraryBooks.Where(lb => lb.Book.IsEpisodeChild()).ToArray();
|
||||
|
||||
int parallelism = int.Max(1, Environment.ProcessorCount - 1);
|
||||
|
||||
var tasks = new Task[parallelism];
|
||||
var syncContext = SynchronizationContext.Current;
|
||||
|
||||
var q = new BlockingCollection<(int, LibraryBook episode)>();
|
||||
|
||||
var seriesEntries = new ISeriesEntry[seriesBooks.Length];
|
||||
var seriesEpisodes = new ConcurrentBag<ILibraryBookEntry>[seriesBooks.Length];
|
||||
|
||||
for (int i = 0; i < parallelism; i++)
|
||||
{
|
||||
tasks[i] = Task.Run(() =>
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(syncContext);
|
||||
|
||||
while (q.TryTake(out var entry, -1))
|
||||
{
|
||||
var parent = seriesEntries[entry.Item1];
|
||||
var episodeBag = seriesEpisodes[entry.Item1];
|
||||
episodeBag.Add(new LibraryBookEntry<TStatus>(entry.episode, parent));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i <seriesBooks.Length; i++)
|
||||
{
|
||||
var series = seriesBooks[i];
|
||||
seriesEntries[i] = new SeriesEntry<TStatus>(series, Enumerable.Empty<LibraryBook>());
|
||||
seriesEpisodes[i] = new ConcurrentBag<ILibraryBookEntry>();
|
||||
|
||||
foreach (var ep in allEpisodes.FindChildren(series))
|
||||
q.Add((i, ep));
|
||||
}
|
||||
|
||||
q.CompleteAdding();
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
for (int i = 0; i < seriesBooks.Length; i++)
|
||||
{
|
||||
var series = seriesEntries[i];
|
||||
series.Children.AddRange(seriesEpisodes[i].OrderByDescending(c => c.SeriesOrder));
|
||||
series.UpdateLibraryBook(series.LibraryBook);
|
||||
}
|
||||
|
||||
return seriesEntries.Where(s => s.Children.Count != 0).ToList();
|
||||
}
|
||||
|
||||
public void RemoveChild(ILibraryBookEntry lbe)
|
||||
{
|
||||
Children.Remove(lbe);
|
||||
|
||||
73
Source/LibationWinForms/ClearableTextBox.Designer.cs
generated
Normal file
73
Source/LibationWinForms/ClearableTextBox.Designer.cs
generated
Normal file
@@ -0,0 +1,73 @@
|
||||
namespace LibationWinForms
|
||||
{
|
||||
partial class ClearableTextBox
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
textBox1 = new System.Windows.Forms.TextBox();
|
||||
button1 = new System.Windows.Forms.Button();
|
||||
SuspendLayout();
|
||||
//
|
||||
// textBox1
|
||||
//
|
||||
textBox1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
textBox1.Location = new System.Drawing.Point(0, 0);
|
||||
textBox1.Margin = new System.Windows.Forms.Padding(0);
|
||||
textBox1.Name = "textBox1";
|
||||
textBox1.Size = new System.Drawing.Size(625, 23);
|
||||
textBox1.TabIndex = 0;
|
||||
//
|
||||
// button1
|
||||
//
|
||||
button1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
|
||||
button1.Location = new System.Drawing.Point(623, 0);
|
||||
button1.Margin = new System.Windows.Forms.Padding(0);
|
||||
button1.Name = "button1";
|
||||
button1.Size = new System.Drawing.Size(20, 20);
|
||||
button1.TabIndex = 1;
|
||||
button1.Text = "X";
|
||||
button1.UseVisualStyleBackColor = true;
|
||||
button1.Click += button1_Click;
|
||||
//
|
||||
// ClearableTextBox
|
||||
//
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
Controls.Add(button1);
|
||||
Controls.Add(textBox1);
|
||||
Name = "ClearableTextBox";
|
||||
Size = new System.Drawing.Size(642, 20);
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TextBox textBox1;
|
||||
private System.Windows.Forms.Button button1;
|
||||
}
|
||||
}
|
||||
44
Source/LibationWinForms/ClearableTextBox.cs
Normal file
44
Source/LibationWinForms/ClearableTextBox.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace LibationWinForms
|
||||
{
|
||||
public partial class ClearableTextBox : UserControl
|
||||
{
|
||||
public event EventHandler TextCleared;
|
||||
public override string Text { get => textBox1.Text; set => textBox1.Text = value; }
|
||||
public override Font Font
|
||||
{
|
||||
get => textBox1.Font;
|
||||
set
|
||||
{
|
||||
base.Font = textBox1.Font = button1.Font = value;
|
||||
OnSizeChanged(EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public ClearableTextBox()
|
||||
{
|
||||
InitializeComponent();
|
||||
textBox1.KeyDown += (_, e) => OnKeyDown(e);
|
||||
textBox1.KeyUp += (_, e) => OnKeyUp(e);
|
||||
textBox1.KeyPress += (_, e) => OnKeyPress(e);
|
||||
textBox1.TextChanged += (_, e) => OnTextChanged(e);
|
||||
}
|
||||
|
||||
protected override void OnSizeChanged(EventArgs e)
|
||||
{
|
||||
base.OnSizeChanged(e);
|
||||
Height = button1.Width = button1.Height = textBox1.Height;
|
||||
textBox1.Width = Width - button1.Width;
|
||||
button1.Location = new Point(textBox1.Width, 0);
|
||||
}
|
||||
|
||||
private void button1_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
textBox1.Clear();
|
||||
TextCleared?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
120
Source/LibationWinForms/ClearableTextBox.resx
Normal file
120
Source/LibationWinForms/ClearableTextBox.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing"">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -39,10 +39,9 @@ namespace LibationWinForms.Dialogs
|
||||
// knownDirectoryRb
|
||||
//
|
||||
knownDirectoryRb.AutoSize = true;
|
||||
knownDirectoryRb.Location = new System.Drawing.Point(6, 6);
|
||||
knownDirectoryRb.Margin = new System.Windows.Forms.Padding(6);
|
||||
knownDirectoryRb.Location = new System.Drawing.Point(3, 3);
|
||||
knownDirectoryRb.Name = "knownDirectoryRb";
|
||||
knownDirectoryRb.Size = new System.Drawing.Size(27, 26);
|
||||
knownDirectoryRb.Size = new System.Drawing.Size(14, 13);
|
||||
knownDirectoryRb.TabIndex = 0;
|
||||
knownDirectoryRb.UseVisualStyleBackColor = true;
|
||||
knownDirectoryRb.CheckedChanged += radioButton_CheckedChanged;
|
||||
@@ -50,10 +49,9 @@ namespace LibationWinForms.Dialogs
|
||||
// customDirectoryRb
|
||||
//
|
||||
customDirectoryRb.AutoSize = true;
|
||||
customDirectoryRb.Location = new System.Drawing.Point(4, 124);
|
||||
customDirectoryRb.Margin = new System.Windows.Forms.Padding(6);
|
||||
customDirectoryRb.Location = new System.Drawing.Point(2, 62);
|
||||
customDirectoryRb.Name = "customDirectoryRb";
|
||||
customDirectoryRb.Size = new System.Drawing.Size(27, 26);
|
||||
customDirectoryRb.Size = new System.Drawing.Size(14, 13);
|
||||
customDirectoryRb.TabIndex = 2;
|
||||
customDirectoryRb.UseVisualStyleBackColor = true;
|
||||
customDirectoryRb.CheckedChanged += radioButton_CheckedChanged;
|
||||
@@ -61,19 +59,17 @@ namespace LibationWinForms.Dialogs
|
||||
// customTb
|
||||
//
|
||||
customTb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
customTb.Location = new System.Drawing.Point(44, 116);
|
||||
customTb.Margin = new System.Windows.Forms.Padding(6);
|
||||
customTb.Location = new System.Drawing.Point(22, 58);
|
||||
customTb.Name = "customTb";
|
||||
customTb.Size = new System.Drawing.Size(1172, 39);
|
||||
customTb.Size = new System.Drawing.Size(588, 23);
|
||||
customTb.TabIndex = 3;
|
||||
//
|
||||
// customBtn
|
||||
//
|
||||
customBtn.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
|
||||
customBtn.Location = new System.Drawing.Point(1232, 116);
|
||||
customBtn.Margin = new System.Windows.Forms.Padding(6);
|
||||
customBtn.Location = new System.Drawing.Point(616, 58);
|
||||
customBtn.Name = "customBtn";
|
||||
customBtn.Size = new System.Drawing.Size(82, 54);
|
||||
customBtn.Size = new System.Drawing.Size(41, 27);
|
||||
customBtn.TabIndex = 4;
|
||||
customBtn.Text = "...";
|
||||
customBtn.UseVisualStyleBackColor = true;
|
||||
@@ -83,24 +79,23 @@ namespace LibationWinForms.Dialogs
|
||||
//
|
||||
directorySelectControl.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
directorySelectControl.AutoSize = true;
|
||||
directorySelectControl.Location = new System.Drawing.Point(46, 0);
|
||||
directorySelectControl.Margin = new System.Windows.Forms.Padding(12);
|
||||
directorySelectControl.Location = new System.Drawing.Point(23, 0);
|
||||
directorySelectControl.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6);
|
||||
directorySelectControl.Name = "directorySelectControl";
|
||||
directorySelectControl.Size = new System.Drawing.Size(1270, 104);
|
||||
directorySelectControl.Size = new System.Drawing.Size(635, 55);
|
||||
directorySelectControl.TabIndex = 5;
|
||||
//
|
||||
// DirectoryOrCustomSelectControl
|
||||
//
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(192F, 192F);
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
Controls.Add(directorySelectControl);
|
||||
Controls.Add(customBtn);
|
||||
Controls.Add(customTb);
|
||||
Controls.Add(customDirectoryRb);
|
||||
Controls.Add(knownDirectoryRb);
|
||||
Margin = new System.Windows.Forms.Padding(6);
|
||||
Name = "DirectoryOrCustomSelectControl";
|
||||
Size = new System.Drawing.Size(1320, 176);
|
||||
Size = new System.Drawing.Size(660, 88);
|
||||
Load += DirectoryOrCustomSelectControl_Load;
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
|
||||
@@ -37,6 +37,12 @@ namespace LibationWinForms.Dialogs
|
||||
if (directory != Configuration.KnownDirectories.None)
|
||||
selectDir(directory, null);
|
||||
}
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
//For some reason anchors don't work when the parent form scales up, even with AutoScale
|
||||
directorySelectControl.Width = customTb.Width = Width;
|
||||
}
|
||||
|
||||
/// <summary>set selection</summary>
|
||||
public void SelectDirectory(string directory)
|
||||
|
||||
@@ -39,32 +39,29 @@ namespace LibationWinForms.Dialogs
|
||||
directoryComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
directoryComboBox.FormattingEnabled = true;
|
||||
directoryComboBox.Location = new System.Drawing.Point(0, 0);
|
||||
directoryComboBox.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6);
|
||||
directoryComboBox.Name = "directoryComboBox";
|
||||
directoryComboBox.Size = new System.Drawing.Size(810, 40);
|
||||
directoryComboBox.Size = new System.Drawing.Size(814, 23);
|
||||
directoryComboBox.TabIndex = 0;
|
||||
directoryComboBox.SelectedIndexChanged += directoryComboBox_SelectedIndexChanged;
|
||||
//
|
||||
// textBox1
|
||||
//
|
||||
textBox1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
textBox1.Location = new System.Drawing.Point(0, 58);
|
||||
textBox1.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6);
|
||||
textBox1.Location = new System.Drawing.Point(0, 29);
|
||||
textBox1.Name = "textBox1";
|
||||
textBox1.ReadOnly = true;
|
||||
textBox1.Size = new System.Drawing.Size(810, 39);
|
||||
textBox1.Size = new System.Drawing.Size(814, 23);
|
||||
textBox1.TabIndex = 1;
|
||||
//
|
||||
// DirectorySelectControl
|
||||
//
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(192F, 192F);
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
AutoSize = true;
|
||||
Controls.Add(textBox1);
|
||||
Controls.Add(directoryComboBox);
|
||||
Margin = new System.Windows.Forms.Padding(6, 6, 6, 6);
|
||||
Name = "DirectorySelectControl";
|
||||
Size = new System.Drawing.Size(814, 104);
|
||||
Size = new System.Drawing.Size(814, 55);
|
||||
Load += DirectorySelectControl_Load;
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
|
||||
@@ -50,6 +50,12 @@ namespace LibationWinForms.Dialogs
|
||||
|
||||
return path;
|
||||
}
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
//For some reason anchors don't work when the parent form scales up, even with AutoScale
|
||||
directoryComboBox.Width = textBox1.Width = Width;
|
||||
}
|
||||
|
||||
private DirectoryComboBoxItem selectedItem => (DirectoryComboBoxItem)this.directoryComboBox.SelectedItem;
|
||||
|
||||
|
||||
@@ -37,10 +37,10 @@
|
||||
// libationFilesDescLbl
|
||||
//
|
||||
libationFilesDescLbl.AutoSize = true;
|
||||
libationFilesDescLbl.Location = new System.Drawing.Point(28, 20);
|
||||
libationFilesDescLbl.Margin = new System.Windows.Forms.Padding(8, 0, 8, 0);
|
||||
libationFilesDescLbl.Location = new System.Drawing.Point(14, 10);
|
||||
libationFilesDescLbl.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
libationFilesDescLbl.Name = "libationFilesDescLbl";
|
||||
libationFilesDescLbl.Size = new System.Drawing.Size(76, 32);
|
||||
libationFilesDescLbl.Size = new System.Drawing.Size(39, 15);
|
||||
libationFilesDescLbl.TabIndex = 0;
|
||||
libationFilesDescLbl.Text = "[desc]";
|
||||
//
|
||||
@@ -48,10 +48,10 @@
|
||||
//
|
||||
cancelBtn.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
|
||||
cancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
cancelBtn.Location = new System.Drawing.Point(1664, 236);
|
||||
cancelBtn.Margin = new System.Windows.Forms.Padding(8, 6, 8, 6);
|
||||
cancelBtn.Location = new System.Drawing.Point(832, 118);
|
||||
cancelBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
cancelBtn.Name = "cancelBtn";
|
||||
cancelBtn.Size = new System.Drawing.Size(176, 54);
|
||||
cancelBtn.Size = new System.Drawing.Size(88, 27);
|
||||
cancelBtn.TabIndex = 3;
|
||||
cancelBtn.Text = "Cancel";
|
||||
cancelBtn.UseVisualStyleBackColor = true;
|
||||
@@ -60,10 +60,10 @@
|
||||
// saveBtn
|
||||
//
|
||||
saveBtn.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
|
||||
saveBtn.Location = new System.Drawing.Point(1428, 236);
|
||||
saveBtn.Margin = new System.Windows.Forms.Padding(8, 6, 8, 6);
|
||||
saveBtn.Location = new System.Drawing.Point(714, 118);
|
||||
saveBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
saveBtn.Name = "saveBtn";
|
||||
saveBtn.Size = new System.Drawing.Size(176, 54);
|
||||
saveBtn.Size = new System.Drawing.Size(88, 27);
|
||||
saveBtn.TabIndex = 2;
|
||||
saveBtn.Text = "Save";
|
||||
saveBtn.UseVisualStyleBackColor = true;
|
||||
@@ -72,24 +72,24 @@
|
||||
// libationFilesSelectControl
|
||||
//
|
||||
libationFilesSelectControl.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
libationFilesSelectControl.Location = new System.Drawing.Point(28, 56);
|
||||
libationFilesSelectControl.Margin = new System.Windows.Forms.Padding(12);
|
||||
libationFilesSelectControl.Location = new System.Drawing.Point(14, 28);
|
||||
libationFilesSelectControl.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6);
|
||||
libationFilesSelectControl.Name = "libationFilesSelectControl";
|
||||
libationFilesSelectControl.Size = new System.Drawing.Size(1818, 176);
|
||||
libationFilesSelectControl.Size = new System.Drawing.Size(906, 88);
|
||||
libationFilesSelectControl.TabIndex = 1;
|
||||
//
|
||||
// LibationFilesDialog
|
||||
//
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(192F, 192F);
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
AutoSize = true;
|
||||
ClientSize = new System.Drawing.Size(1866, 328);
|
||||
ClientSize = new System.Drawing.Size(933, 164);
|
||||
Controls.Add(libationFilesSelectControl);
|
||||
Controls.Add(cancelBtn);
|
||||
Controls.Add(saveBtn);
|
||||
Controls.Add(libationFilesDescLbl);
|
||||
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||
Margin = new System.Windows.Forms.Padding(8, 6, 8, 6);
|
||||
Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
Name = "LibationFilesDialog";
|
||||
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
Text = "Libation Files location";
|
||||
|
||||
@@ -14,12 +14,16 @@ namespace LibationWinForms.Dialogs
|
||||
this.createCueSheetCbox.Text = desc(nameof(config.CreateCueSheet));
|
||||
this.downloadCoverArtCbox.Text = desc(nameof(config.DownloadCoverArt));
|
||||
this.retainAaxFileCbox.Text = desc(nameof(config.RetainAaxFile));
|
||||
this.combineNestedChapterTitlesCbox.Text = desc(nameof(config.CombineNestedChapterTitles));
|
||||
this.splitFilesByChapterCbox.Text = desc(nameof(config.SplitFilesByChapter));
|
||||
this.mergeOpeningEndCreditsCbox.Text = desc(nameof(config.MergeOpeningAndEndCredits));
|
||||
this.stripAudibleBrandingCbox.Text = desc(nameof(config.StripAudibleBrandAudio));
|
||||
this.stripUnabridgedCbox.Text = desc(nameof(config.StripUnabridged));
|
||||
this.moveMoovAtomCbox.Text = desc(nameof(config.MoveMoovToBeginning));
|
||||
|
||||
toolTip.SetToolTip(combineNestedChapterTitlesCbox, Configuration.GetHelpText(nameof(config.CombineNestedChapterTitles)));
|
||||
toolTip.SetToolTip(allowLibationFixupCbox, Configuration.GetHelpText(nameof(config.AllowLibationFixup)));
|
||||
|
||||
fileDownloadQualityCb.Items.AddRange(
|
||||
new object[]
|
||||
{
|
||||
@@ -55,6 +59,7 @@ namespace LibationWinForms.Dialogs
|
||||
fileDownloadQualityCb.SelectedItem = config.FileDownloadQuality;
|
||||
clipsBookmarksFormatCb.SelectedItem = config.ClipsBookmarksFileFormat;
|
||||
retainAaxFileCbox.Checked = config.RetainAaxFile;
|
||||
combineNestedChapterTitlesCbox.Checked = config.CombineNestedChapterTitles;
|
||||
splitFilesByChapterCbox.Checked = config.SplitFilesByChapter;
|
||||
mergeOpeningEndCreditsCbox.Checked = config.MergeOpeningAndEndCredits;
|
||||
stripUnabridgedCbox.Checked = config.StripUnabridged;
|
||||
@@ -99,6 +104,7 @@ namespace LibationWinForms.Dialogs
|
||||
config.FileDownloadQuality = (Configuration.DownloadQuality)fileDownloadQualityCb.SelectedItem;
|
||||
config.ClipsBookmarksFileFormat = (Configuration.ClipBookmarkFormat)clipsBookmarksFormatCb.SelectedItem;
|
||||
config.RetainAaxFile = retainAaxFileCbox.Checked;
|
||||
config.CombineNestedChapterTitles = combineNestedChapterTitlesCbox.Checked;
|
||||
config.SplitFilesByChapter = splitFilesByChapterCbox.Checked;
|
||||
config.MergeOpeningAndEndCredits = mergeOpeningEndCreditsCbox.Checked;
|
||||
config.StripUnabridged = stripUnabridgedCbox.Checked;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,7 @@ namespace LibationWinForms.Dialogs
|
||||
badBookRetryRb.Text = Configuration.BadBookAction.Retry.GetDescription();
|
||||
badBookIgnoreRb.Text = Configuration.BadBookAction.Ignore.GetDescription();
|
||||
useCoverAsFolderIconCb.Text = desc(nameof(config.UseCoverAsFolderIcon));
|
||||
saveMetadataToFileCbox.Text = desc(nameof(config.SaveMetadataToFile));
|
||||
|
||||
inProgressSelectControl.SetDirectoryItems(new()
|
||||
{
|
||||
@@ -60,6 +61,7 @@ namespace LibationWinForms.Dialogs
|
||||
fileTemplateTb.Text = config.FileTemplate;
|
||||
chapterFileTemplateTb.Text = config.ChapterFileTemplate;
|
||||
useCoverAsFolderIconCb.Checked = config.UseCoverAsFolderIcon;
|
||||
saveMetadataToFileCbox.Checked = config.SaveMetadataToFile;
|
||||
}
|
||||
|
||||
private void Save_DownloadDecrypt(Configuration config)
|
||||
@@ -77,6 +79,7 @@ namespace LibationWinForms.Dialogs
|
||||
config.FileTemplate = fileTemplateTb.Text;
|
||||
config.ChapterFileTemplate = chapterFileTemplateTb.Text;
|
||||
config.UseCoverAsFolderIcon = useCoverAsFolderIconCb.Checked;
|
||||
config.SaveMetadataToFile = saveMetadataToFileCbox.Checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,12 @@ namespace LibationWinForms.Dialogs
|
||||
}
|
||||
|
||||
booksLocationDescLbl.Text = desc(nameof(config.Books));
|
||||
betaOptInCbox.Text = desc(nameof(config.BetaOptIn));
|
||||
saveEpisodesToSeriesFolderCbox.Text = desc(nameof(config.SavePodcastsToParentFolder));
|
||||
overwriteExistingCbox.Text = desc(nameof(config.OverwriteExisting));
|
||||
creationTimeLbl.Text = desc(nameof(config.CreationTime));
|
||||
lastWriteTimeLbl.Text = desc(nameof(config.LastWriteTime));
|
||||
gridScaleFactorLbl.Text = desc(nameof(config.GridScaleFactor));
|
||||
gridFontScaleFactorLbl.Text = desc(nameof(config.GridFontScaleFactor));
|
||||
|
||||
var dateTimeSources = Enum.GetValues<Configuration.DateTimeSource>().Select(v => new EnumDiaplay<Configuration.DateTimeSource>(v)).ToArray();
|
||||
creationTimeCb.Items.AddRange(dateTimeSources);
|
||||
@@ -51,11 +52,8 @@ namespace LibationWinForms.Dialogs
|
||||
|
||||
saveEpisodesToSeriesFolderCbox.Checked = config.SavePodcastsToParentFolder;
|
||||
overwriteExistingCbox.Checked = config.OverwriteExisting;
|
||||
|
||||
betaOptInCbox.Checked = config.BetaOptIn;
|
||||
|
||||
if (!betaOptInCbox.Checked)
|
||||
betaOptInCbox.CheckedChanged += betaOptInCbox_CheckedChanged;
|
||||
gridScaleFactorTbar.Value = scaleFactorToLinearRange(config.GridScaleFactor);
|
||||
gridFontScaleFactorTbar.Value = scaleFactorToLinearRange(config.GridFontScaleFactor);
|
||||
}
|
||||
|
||||
private void Save_Important(Configuration config)
|
||||
@@ -92,39 +90,20 @@ namespace LibationWinForms.Dialogs
|
||||
config.SavePodcastsToParentFolder = saveEpisodesToSeriesFolderCbox.Checked;
|
||||
config.OverwriteExisting = overwriteExistingCbox.Checked;
|
||||
|
||||
config.BetaOptIn = betaOptInCbox.Checked;
|
||||
|
||||
|
||||
config.CreationTime = ((EnumDiaplay<Configuration.DateTimeSource>)creationTimeCb.SelectedItem).Value;
|
||||
config.LastWriteTime = ((EnumDiaplay<Configuration.DateTimeSource>)lastWriteTimeCb.SelectedItem).Value;
|
||||
|
||||
}
|
||||
|
||||
private static int scaleFactorToLinearRange(float scaleFactor)
|
||||
=> (int)float.Round(100 * MathF.Log2(scaleFactor));
|
||||
private static float linearRangeToScaleFactor(int value)
|
||||
=> MathF.Pow(2, value / 100f);
|
||||
|
||||
private void betaOptInCbox_CheckedChanged(object sender, EventArgs e)
|
||||
private void applyDisplaySettingsBtn_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!betaOptInCbox.Checked)
|
||||
return;
|
||||
|
||||
var result = MessageBox.Show(this, @"
|
||||
|
||||
|
||||
You've chosen to opt-in to Libation's beta releases. Thank you! We need all the testers we can get.
|
||||
|
||||
These features are works in progress and potentially very buggy. Libation may crash unexpectedly, and your library database may even be corruted. We suggest you back up your LibationContext.db file before proceding.
|
||||
|
||||
If bad/weird things happen, please report them at getlibation.com.
|
||||
|
||||
".Trim(), "A word of warning...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);
|
||||
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
betaOptInCbox.CheckedChanged -= betaOptInCbox_CheckedChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
betaOptInCbox.Checked = false;
|
||||
}
|
||||
config.GridFontScaleFactor = linearRangeToScaleFactor(gridFontScaleFactorTbar.Value);
|
||||
config.GridScaleFactor = linearRangeToScaleFactor(gridScaleFactorTbar.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,12 @@ namespace LibationWinForms.Dialogs
|
||||
{
|
||||
private Configuration config { get; } = Configuration.Instance;
|
||||
private Func<string, string> desc { get; } = Configuration.GetDescription;
|
||||
private readonly ToolTip toolTip = new ToolTip
|
||||
{
|
||||
InitialDelay = 300,
|
||||
AutoPopDelay = 10000,
|
||||
ReshowDelay = 0
|
||||
};
|
||||
|
||||
public SettingsDialog()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using ApplicationServices;
|
||||
using DataLayer;
|
||||
using Dinah.Core;
|
||||
using Dinah.Core.Threading;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace LibationWinForms
|
||||
{
|
||||
@@ -14,7 +16,6 @@ namespace LibationWinForms
|
||||
beginBookBackupsToolStripMenuItem.Format(0);
|
||||
beginPdfBackupsToolStripMenuItem.Format(0);
|
||||
|
||||
Load += setBackupCounts;
|
||||
LibraryCommands.LibrarySizeChanged += setBackupCounts;
|
||||
LibraryCommands.BookUserDefinedItemCommitted += setBackupCounts;
|
||||
|
||||
@@ -40,7 +41,11 @@ namespace LibationWinForms
|
||||
while (runBackupCountsAgain)
|
||||
{
|
||||
runBackupCountsAgain = false;
|
||||
e.Result = LibraryCommands.GetCounts();
|
||||
|
||||
if (e.Argument is not IEnumerable<LibraryBook> lbs)
|
||||
lbs = DbContexts.GetLibrary_Flat_NoTracking();
|
||||
|
||||
e.Result = LibraryCommands.GetCounts(lbs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
13
Source/LibationWinForms/Form1.Designer.cs
generated
13
Source/LibationWinForms/Form1.Designer.cs
generated
@@ -31,7 +31,7 @@
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
|
||||
this.filterHelpBtn = new System.Windows.Forms.Button();
|
||||
this.filterBtn = new System.Windows.Forms.Button();
|
||||
this.filterSearchTb = new System.Windows.Forms.TextBox();
|
||||
this.filterSearchTb = new ClearableTextBox();
|
||||
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
|
||||
this.importToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.autoScanLibraryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -129,10 +129,11 @@
|
||||
this.filterSearchTb.Size = new System.Drawing.Size(681, 25);
|
||||
this.filterSearchTb.TabIndex = 1;
|
||||
this.filterSearchTb.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.filterSearchTb_KeyPress);
|
||||
//
|
||||
// menuStrip1
|
||||
//
|
||||
this.menuStrip1.ImageScalingSize = new System.Drawing.Size(40, 40);
|
||||
this.filterSearchTb.TextCleared += filterSearchTb_TextCleared;
|
||||
//
|
||||
// menuStrip1
|
||||
//
|
||||
this.menuStrip1.ImageScalingSize = new System.Drawing.Size(40, 40);
|
||||
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.importToolStripMenuItem,
|
||||
this.liberateToolStripMenuItem,
|
||||
@@ -651,7 +652,7 @@
|
||||
private System.Windows.Forms.ToolStripStatusLabel backupsCountsLbl;
|
||||
private LibationWinForms.FormattableToolStripMenuItem beginBookBackupsToolStripMenuItem;
|
||||
private LibationWinForms.FormattableToolStripMenuItem beginPdfBackupsToolStripMenuItem;
|
||||
public System.Windows.Forms.TextBox filterSearchTb;
|
||||
public ClearableTextBox filterSearchTb;
|
||||
public System.Windows.Forms.Button filterBtn;
|
||||
public System.Windows.Forms.Button filterHelpBtn;
|
||||
public System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem;
|
||||
|
||||
@@ -10,6 +10,10 @@ namespace LibationWinForms
|
||||
|
||||
private void filterHelpBtn_Click(object sender, EventArgs e) => new SearchSyntaxDialog().ShowDialog();
|
||||
|
||||
private void filterSearchTb_TextCleared(object sender, EventArgs e)
|
||||
{
|
||||
performFilter(string.Empty);
|
||||
}
|
||||
private void filterSearchTb_KeyPress(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
if (e.KeyChar == (char)Keys.Return)
|
||||
|
||||
@@ -4,7 +4,6 @@ using LibationFileManager;
|
||||
using LibationUiBase.GridView;
|
||||
using LibationWinForms.ProcessQueue;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
@@ -12,15 +11,14 @@ namespace LibationWinForms
|
||||
{
|
||||
public partial class Form1
|
||||
{
|
||||
|
||||
int WidthChange = 0;
|
||||
private void Configure_ProcessQueue()
|
||||
{
|
||||
processBookQueue1.popoutBtn.Click += ProcessBookQueue1_PopOut;
|
||||
splitContainer1.Panel2MinSize = this.DpiScale(350);
|
||||
var coppalseState = Configuration.Instance.GetNonString(defaultValue: false, nameof(splitContainer1.Panel2Collapsed));
|
||||
|
||||
WidthChange = splitContainer1.Panel2.Width + splitContainer1.SplitterWidth;
|
||||
int width = this.Width;
|
||||
var coppalseState = Configuration.Instance.GetNonString(defaultValue: false, nameof(splitContainer1.Panel2Collapsed));
|
||||
SetQueueCollapseState(coppalseState);
|
||||
this.Width = width;
|
||||
}
|
||||
|
||||
@@ -4,10 +4,8 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using ApplicationServices;
|
||||
using Dinah.Core;
|
||||
using Dinah.Core.Threading;
|
||||
using DataLayer;
|
||||
using LibationFileManager;
|
||||
using LibationWinForms.Dialogs;
|
||||
|
||||
namespace LibationWinForms
|
||||
{
|
||||
@@ -16,11 +14,8 @@ namespace LibationWinForms
|
||||
public Form1()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Pre-requisite:
|
||||
// Before calling anything else, including subscribing to events, ensure database exists. If we wait and let it happen lazily, race conditions and errors are likely during new installs
|
||||
using var _ = DbContexts.GetContext();
|
||||
|
||||
//Set this size before restoring form size and position
|
||||
splitContainer1.Panel2MinSize = this.DpiScale(350);
|
||||
this.RestoreSizeAndLocation(Configuration.Instance);
|
||||
this.FormClosing += (_, _) => this.SaveSizeAndLocation(Configuration.Instance);
|
||||
|
||||
@@ -57,8 +52,7 @@ namespace LibationWinForms
|
||||
|
||||
// Configure_Grid(); // since it's just this, can keep here. If it needs more, then give grid it's own 'partial class Form1'
|
||||
{
|
||||
this.Load += (_, __) => productsDisplay.Display();
|
||||
LibraryCommands.LibrarySizeChanged += (_, __) => this.UIThreadAsync(() => productsDisplay.Display());
|
||||
LibraryCommands.LibrarySizeChanged += (_, __) => Invoke(() => productsDisplay.DisplayAsync());
|
||||
}
|
||||
Shown += Form1_Shown;
|
||||
}
|
||||
@@ -78,6 +72,13 @@ namespace LibationWinForms
|
||||
}
|
||||
}
|
||||
|
||||
public async Task InitLibraryAsync(List<LibraryBook> libraryBooks)
|
||||
{
|
||||
runBackupCountsAgain = true;
|
||||
updateCountsBw.RunWorkerAsync(libraryBooks.Where(b => !b.Book.IsEpisodeParent()));
|
||||
await productsDisplay.DisplayAsync(libraryBooks);
|
||||
}
|
||||
|
||||
private void Form1_Load(object sender, EventArgs e)
|
||||
{
|
||||
if (this.DesignMode)
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
internal class CoverGridViewColumn : DataGridViewImageColumn
|
||||
{
|
||||
public CoverGridViewColumn()
|
||||
{
|
||||
CellTemplate = new CoverGridViewCell();
|
||||
}
|
||||
}
|
||||
|
||||
public class CoverGridViewCell : DataGridViewImageCell
|
||||
{
|
||||
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
|
||||
{
|
||||
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, paintParts);
|
||||
|
||||
if (value is Image image)
|
||||
{
|
||||
var w = graphics.ScaleX(image.Width);
|
||||
var h = graphics.ScaleY(image.Height);
|
||||
var x = cellBounds.Left + (cellBounds.Width - w) / 2;
|
||||
var y = cellBounds.Top + (cellBounds.Height - h) / 2;
|
||||
|
||||
graphics.DrawImage(image, new Rectangle(x, y, w, h));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,10 @@ namespace LibationWinForms.GridView
|
||||
{
|
||||
protected void DrawButtonImage(Graphics graphics, Image image, Rectangle cellBounds)
|
||||
{
|
||||
var w = graphics.ScaleX(image.Width);
|
||||
var h = graphics.ScaleY(image.Height);
|
||||
var scaleFactor = OwningColumn is IDataGridScaleColumn scCol ? scCol.ScaleFactor : 1f;
|
||||
|
||||
var w = (int)float.Round(graphics.ScaleX(image.Width) * scaleFactor);
|
||||
var h = (int)float.Round(graphics.ScaleY(image.Height) * scaleFactor);
|
||||
var x = cellBounds.Left + (cellBounds.Width - w) / 2;
|
||||
var y = cellBounds.Top + (cellBounds.Height - h) / 2;
|
||||
|
||||
|
||||
@@ -5,12 +5,18 @@ using LibationUiBase.GridView;
|
||||
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
public class EditTagsDataGridViewImageButtonColumn : DataGridViewButtonColumn
|
||||
public interface IDataGridScaleColumn
|
||||
{
|
||||
float ScaleFactor { get; set; }
|
||||
}
|
||||
public class EditTagsDataGridViewImageButtonColumn : DataGridViewButtonColumn, IDataGridScaleColumn
|
||||
{
|
||||
public EditTagsDataGridViewImageButtonColumn()
|
||||
{
|
||||
CellTemplate = new EditTagsDataGridViewImageButtonCell();
|
||||
}
|
||||
|
||||
public float ScaleFactor { get; set; }
|
||||
}
|
||||
|
||||
internal class EditTagsDataGridViewImageButtonCell : DataGridViewImageButtonCell
|
||||
|
||||
@@ -30,7 +30,6 @@ namespace LibationWinForms.GridView
|
||||
{
|
||||
SearchEngineCommands.SearchEngineUpdated += SearchEngineCommands_SearchEngineUpdated;
|
||||
ListChanged += GridEntryBindingList_ListChanged;
|
||||
refreshEntries();
|
||||
}
|
||||
|
||||
/// <returns>All items in the list, including those filtered out.</returns>
|
||||
|
||||
@@ -4,12 +4,14 @@ using System.Windows.Forms;
|
||||
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
public class LiberateDataGridViewImageButtonColumn : DataGridViewButtonColumn
|
||||
public class LiberateDataGridViewImageButtonColumn : DataGridViewButtonColumn, IDataGridScaleColumn
|
||||
{
|
||||
public LiberateDataGridViewImageButtonColumn()
|
||||
{
|
||||
CellTemplate = new LiberateDataGridViewImageButtonCell();
|
||||
}
|
||||
|
||||
public float ScaleFactor { get; set; }
|
||||
}
|
||||
|
||||
internal class LiberateDataGridViewImageButtonCell : DataGridViewImageButtonCell
|
||||
|
||||
@@ -69,7 +69,6 @@
|
||||
//
|
||||
this.lblPerform.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblPerform.AutoSize = true;
|
||||
this.lblPerform.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.lblPerform.Location = new System.Drawing.Point(0, 16);
|
||||
this.lblPerform.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.lblPerform.Name = "lblPerform";
|
||||
@@ -103,7 +102,6 @@
|
||||
//
|
||||
// noBorderLabel1
|
||||
//
|
||||
this.noBorderLabel1.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel1.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.noBorderLabel1.Name = "noBorderLabel1";
|
||||
@@ -116,7 +114,6 @@
|
||||
//
|
||||
// noBorderLabel2
|
||||
//
|
||||
this.noBorderLabel2.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel2.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel2.Location = new System.Drawing.Point(10, 0);
|
||||
this.noBorderLabel2.Name = "noBorderLabel2";
|
||||
@@ -129,7 +126,6 @@
|
||||
//
|
||||
// noBorderLabel3
|
||||
//
|
||||
this.noBorderLabel3.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel3.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel3.Location = new System.Drawing.Point(20, 0);
|
||||
this.noBorderLabel3.Name = "noBorderLabel3";
|
||||
@@ -142,7 +138,6 @@
|
||||
//
|
||||
// noBorderLabel4
|
||||
//
|
||||
this.noBorderLabel4.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel4.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel4.Location = new System.Drawing.Point(30, 0);
|
||||
this.noBorderLabel4.Name = "noBorderLabel4";
|
||||
@@ -155,7 +150,6 @@
|
||||
//
|
||||
// noBorderLabel5
|
||||
//
|
||||
this.noBorderLabel5.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel5.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel5.Location = new System.Drawing.Point(40, 0);
|
||||
this.noBorderLabel5.Name = "noBorderLabel5";
|
||||
@@ -181,7 +175,6 @@
|
||||
//
|
||||
// noBorderLabel6
|
||||
//
|
||||
this.noBorderLabel6.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel6.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel6.Location = new System.Drawing.Point(0, 0);
|
||||
this.noBorderLabel6.Name = "noBorderLabel6";
|
||||
@@ -194,7 +187,6 @@
|
||||
//
|
||||
// noBorderLabel7
|
||||
//
|
||||
this.noBorderLabel7.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel7.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel7.Location = new System.Drawing.Point(10, 0);
|
||||
this.noBorderLabel7.Name = "noBorderLabel7";
|
||||
@@ -207,7 +199,6 @@
|
||||
//
|
||||
// noBorderLabel8
|
||||
//
|
||||
this.noBorderLabel8.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel8.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel8.Location = new System.Drawing.Point(20, 0);
|
||||
this.noBorderLabel8.Name = "noBorderLabel8";
|
||||
@@ -220,7 +211,6 @@
|
||||
//
|
||||
// noBorderLabel9
|
||||
//
|
||||
this.noBorderLabel9.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel9.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel9.Location = new System.Drawing.Point(30, 0);
|
||||
this.noBorderLabel9.Name = "noBorderLabel9";
|
||||
@@ -233,7 +223,6 @@
|
||||
//
|
||||
// noBorderLabel10
|
||||
//
|
||||
this.noBorderLabel10.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel10.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel10.Location = new System.Drawing.Point(40, 0);
|
||||
this.noBorderLabel10.Name = "noBorderLabel10";
|
||||
@@ -259,7 +248,6 @@
|
||||
//
|
||||
// noBorderLabel11
|
||||
//
|
||||
this.noBorderLabel11.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel11.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel11.Location = new System.Drawing.Point(0, 0);
|
||||
this.noBorderLabel11.Name = "noBorderLabel11";
|
||||
@@ -272,7 +260,6 @@
|
||||
//
|
||||
// noBorderLabel12
|
||||
//
|
||||
this.noBorderLabel12.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel12.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel12.Location = new System.Drawing.Point(10, 0);
|
||||
this.noBorderLabel12.Name = "noBorderLabel12";
|
||||
@@ -285,7 +272,6 @@
|
||||
//
|
||||
// noBorderLabel13
|
||||
//
|
||||
this.noBorderLabel13.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel13.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel13.Location = new System.Drawing.Point(20, 0);
|
||||
this.noBorderLabel13.Name = "noBorderLabel13";
|
||||
@@ -298,7 +284,6 @@
|
||||
//
|
||||
// noBorderLabel14
|
||||
//
|
||||
this.noBorderLabel14.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel14.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel14.Location = new System.Drawing.Point(30, 0);
|
||||
this.noBorderLabel14.Name = "noBorderLabel14";
|
||||
@@ -311,7 +296,6 @@
|
||||
//
|
||||
// noBorderLabel15
|
||||
//
|
||||
this.noBorderLabel15.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.noBorderLabel15.LabelOffset = new System.Drawing.Point(-3, -3);
|
||||
this.noBorderLabel15.Location = new System.Drawing.Point(40, 0);
|
||||
this.noBorderLabel15.Name = "noBorderLabel15";
|
||||
|
||||
@@ -37,6 +37,13 @@ namespace LibationWinForms.GridView
|
||||
public MyRatingCellEditor()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.FontChanged += MyRatingCellEditor_FontChanged;
|
||||
}
|
||||
|
||||
private void MyRatingCellEditor_FontChanged(object sender, EventArgs e)
|
||||
{
|
||||
var scale = Font.Size / 9;
|
||||
Scale(new SizeF(scale, scale));
|
||||
}
|
||||
|
||||
private void Star_MouseEnter(object sender, EventArgs e)
|
||||
|
||||
@@ -206,6 +206,25 @@ namespace LibationWinForms.GridView
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region Force Re-Download
|
||||
if (!entry.Liberate.IsSeries)
|
||||
{
|
||||
var reDownloadMenuItem = new ToolStripMenuItem()
|
||||
{
|
||||
Text = "Re-download this audiobook",
|
||||
Enabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
||||
};
|
||||
|
||||
ctxMenu.Items.Add(reDownloadMenuItem);
|
||||
reDownloadMenuItem.Click += (s, _) =>
|
||||
{
|
||||
//No need to persist this change. It only needs to last long for the file to start downloading
|
||||
entry.Book.UserDefinedItem.BookStatus = LiberatedStatus.NotLiberated;
|
||||
LiberateClicked?.Invoke(s, entry.LibraryBook);
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
ctxMenu.Items.Add(new ToolStripSeparator());
|
||||
|
||||
#region View Bookmarks/Clips
|
||||
@@ -306,22 +325,22 @@ namespace LibationWinForms.GridView
|
||||
|
||||
#region UI display functions
|
||||
|
||||
public void Display()
|
||||
public async Task DisplayAsync(List<LibraryBook> libraryBooks = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// don't return early if lib size == 0. this will not update correctly if all books are removed
|
||||
var lib = DbContexts.GetLibrary_Flat_NoTracking(includeParents: true);
|
||||
libraryBooks ??= DbContexts.GetLibrary_Flat_NoTracking(includeParents: true);
|
||||
|
||||
if (!hasBeenDisplayed)
|
||||
{
|
||||
// bind
|
||||
productsGrid.BindToGrid(lib);
|
||||
await productsGrid.BindToGridAsync(libraryBooks);
|
||||
hasBeenDisplayed = true;
|
||||
InitialLoaded?.Invoke(this, new());
|
||||
}
|
||||
else
|
||||
productsGrid.UpdateGrid(lib);
|
||||
productsGrid.UpdateGrid(libraryBooks);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
partial class ProductsGrid
|
||||
partial class ProductsGrid
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
@@ -30,254 +30,260 @@ namespace LibationWinForms.GridView
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
components = new System.ComponentModel.Container();
|
||||
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
|
||||
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
|
||||
this.gridEntryDataGridView = new System.Windows.Forms.DataGridView();
|
||||
this.removeGVColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn();
|
||||
this.liberateGVColumn = new LibationWinForms.GridView.LiberateDataGridViewImageButtonColumn();
|
||||
this.coverGVColumn = new CoverGridViewColumn();
|
||||
this.titleGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.authorsGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.narratorsGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.lengthGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.seriesGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.seriesOrderGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.descriptionGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.categoryGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.productRatingGVColumn = new LibationWinForms.GridView.MyRatingGridViewColumn();
|
||||
this.purchaseDateGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.myRatingGVColumn = new LibationWinForms.GridView.MyRatingGridViewColumn();
|
||||
this.miscGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.lastDownloadedGVColumn = new LastDownloadedGridViewColumn();
|
||||
this.tagAndDetailsGVColumn = new LibationWinForms.GridView.EditTagsDataGridViewImageButtonColumn();
|
||||
this.showHideColumnsContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.syncBindingSource = new LibationWinForms.GridView.SyncBindingSource(this.components);
|
||||
((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
gridEntryDataGridView = new System.Windows.Forms.DataGridView();
|
||||
removeGVColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn();
|
||||
liberateGVColumn = new LiberateDataGridViewImageButtonColumn();
|
||||
coverGVColumn = new System.Windows.Forms.DataGridViewImageColumn();
|
||||
titleGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
authorsGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
narratorsGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
lengthGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
seriesGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
seriesOrderGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
descriptionGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
categoryGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
productRatingGVColumn = new MyRatingGridViewColumn();
|
||||
purchaseDateGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
myRatingGVColumn = new MyRatingGridViewColumn();
|
||||
miscGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
lastDownloadedGVColumn = new LastDownloadedGridViewColumn();
|
||||
tagAndDetailsGVColumn = new EditTagsDataGridViewImageButtonColumn();
|
||||
showHideColumnsContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(components);
|
||||
syncBindingSource = new SyncBindingSource(components);
|
||||
((System.ComponentModel.ISupportInitialize)gridEntryDataGridView).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)syncBindingSource).BeginInit();
|
||||
SuspendLayout();
|
||||
//
|
||||
// gridEntryDataGridView
|
||||
//
|
||||
this.gridEntryDataGridView.AllowUserToAddRows = false;
|
||||
this.gridEntryDataGridView.AllowUserToDeleteRows = false;
|
||||
this.gridEntryDataGridView.AllowUserToOrderColumns = true;
|
||||
this.gridEntryDataGridView.AllowUserToResizeRows = false;
|
||||
this.gridEntryDataGridView.AutoGenerateColumns = false;
|
||||
this.gridEntryDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.gridEntryDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
||||
this.removeGVColumn,
|
||||
this.liberateGVColumn,
|
||||
this.coverGVColumn,
|
||||
this.titleGVColumn,
|
||||
this.authorsGVColumn,
|
||||
this.narratorsGVColumn,
|
||||
this.lengthGVColumn,
|
||||
this.seriesGVColumn,
|
||||
this.seriesOrderGVColumn,
|
||||
this.descriptionGVColumn,
|
||||
this.categoryGVColumn,
|
||||
this.productRatingGVColumn,
|
||||
this.purchaseDateGVColumn,
|
||||
this.myRatingGVColumn,
|
||||
this.miscGVColumn,
|
||||
this.lastDownloadedGVColumn,
|
||||
this.tagAndDetailsGVColumn});
|
||||
this.gridEntryDataGridView.ContextMenuStrip = this.showHideColumnsContextMenuStrip;
|
||||
this.gridEntryDataGridView.DataSource = this.syncBindingSource;
|
||||
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
|
||||
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Window;
|
||||
dataGridViewCellStyle1.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.ControlText;
|
||||
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
|
||||
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
|
||||
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
|
||||
this.gridEntryDataGridView.DefaultCellStyle = dataGridViewCellStyle1;
|
||||
this.gridEntryDataGridView.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.gridEntryDataGridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnEnter;
|
||||
this.gridEntryDataGridView.Location = new System.Drawing.Point(0, 0);
|
||||
this.gridEntryDataGridView.Name = "gridEntryDataGridView";
|
||||
this.gridEntryDataGridView.RowHeadersVisible = false;
|
||||
this.gridEntryDataGridView.RowTemplate.Height = 82;
|
||||
this.gridEntryDataGridView.Size = new System.Drawing.Size(1570, 380);
|
||||
this.gridEntryDataGridView.TabIndex = 0;
|
||||
this.gridEntryDataGridView.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.DataGridView_CellContentClick);
|
||||
this.gridEntryDataGridView.CellToolTipTextNeeded += new System.Windows.Forms.DataGridViewCellToolTipTextNeededEventHandler(this.gridEntryDataGridView_CellToolTipTextNeeded);
|
||||
gridEntryDataGridView.AllowUserToAddRows = false;
|
||||
gridEntryDataGridView.AllowUserToDeleteRows = false;
|
||||
gridEntryDataGridView.AllowUserToOrderColumns = true;
|
||||
gridEntryDataGridView.AllowUserToResizeRows = false;
|
||||
gridEntryDataGridView.AutoGenerateColumns = false;
|
||||
gridEntryDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
gridEntryDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { removeGVColumn, liberateGVColumn, coverGVColumn, titleGVColumn, authorsGVColumn, narratorsGVColumn, lengthGVColumn, seriesGVColumn, seriesOrderGVColumn, descriptionGVColumn, categoryGVColumn, productRatingGVColumn, purchaseDateGVColumn, myRatingGVColumn, miscGVColumn, lastDownloadedGVColumn, tagAndDetailsGVColumn });
|
||||
gridEntryDataGridView.ContextMenuStrip = showHideColumnsContextMenuStrip;
|
||||
gridEntryDataGridView.DataSource = syncBindingSource;
|
||||
dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
|
||||
dataGridViewCellStyle2.BackColor = System.Drawing.SystemColors.Window;
|
||||
dataGridViewCellStyle2.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
dataGridViewCellStyle2.ForeColor = System.Drawing.SystemColors.ControlText;
|
||||
dataGridViewCellStyle2.SelectionBackColor = System.Drawing.SystemColors.Highlight;
|
||||
dataGridViewCellStyle2.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
|
||||
dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
|
||||
gridEntryDataGridView.DefaultCellStyle = dataGridViewCellStyle2;
|
||||
gridEntryDataGridView.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
gridEntryDataGridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnEnter;
|
||||
gridEntryDataGridView.Location = new System.Drawing.Point(0, 0);
|
||||
gridEntryDataGridView.Margin = new System.Windows.Forms.Padding(6);
|
||||
gridEntryDataGridView.Name = "gridEntryDataGridView";
|
||||
gridEntryDataGridView.RowHeadersVisible = false;
|
||||
gridEntryDataGridView.RowHeadersWidth = 82;
|
||||
gridEntryDataGridView.RowTemplate.Height = 82;
|
||||
gridEntryDataGridView.Size = new System.Drawing.Size(3140, 760);
|
||||
gridEntryDataGridView.TabIndex = 0;
|
||||
gridEntryDataGridView.CellContentClick += DataGridView_CellContentClick;
|
||||
gridEntryDataGridView.CellToolTipTextNeeded += gridEntryDataGridView_CellToolTipTextNeeded;
|
||||
//
|
||||
// removeGVColumn
|
||||
//
|
||||
this.removeGVColumn.DataPropertyName = "Remove";
|
||||
this.removeGVColumn.FalseValue = "";
|
||||
this.removeGVColumn.Frozen = true;
|
||||
this.removeGVColumn.HeaderText = "Remove";
|
||||
this.removeGVColumn.IndeterminateValue = "";
|
||||
this.removeGVColumn.MinimumWidth = 60;
|
||||
this.removeGVColumn.Name = "removeGVColumn";
|
||||
this.removeGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
||||
this.removeGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||
this.removeGVColumn.ThreeState = true;
|
||||
this.removeGVColumn.TrueValue = "";
|
||||
this.removeGVColumn.Width = 60;
|
||||
removeGVColumn.DataPropertyName = "Remove";
|
||||
removeGVColumn.FalseValue = "";
|
||||
removeGVColumn.Frozen = true;
|
||||
removeGVColumn.HeaderText = "Remove";
|
||||
removeGVColumn.IndeterminateValue = "";
|
||||
removeGVColumn.MinimumWidth = 60;
|
||||
removeGVColumn.Name = "removeGVColumn";
|
||||
removeGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
||||
removeGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||
removeGVColumn.ThreeState = true;
|
||||
removeGVColumn.TrueValue = "";
|
||||
removeGVColumn.Width = 60;
|
||||
//
|
||||
// liberateGVColumn
|
||||
//
|
||||
this.liberateGVColumn.DataPropertyName = "Liberate";
|
||||
this.liberateGVColumn.HeaderText = "Liberate";
|
||||
this.liberateGVColumn.Name = "liberateGVColumn";
|
||||
this.liberateGVColumn.ReadOnly = true;
|
||||
this.liberateGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
||||
this.liberateGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||
this.liberateGVColumn.Width = 75;
|
||||
liberateGVColumn.DataPropertyName = "Liberate";
|
||||
liberateGVColumn.HeaderText = "Liberate";
|
||||
liberateGVColumn.MinimumWidth = 10;
|
||||
liberateGVColumn.Name = "liberateGVColumn";
|
||||
liberateGVColumn.ReadOnly = true;
|
||||
liberateGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
||||
liberateGVColumn.ScaleFactor = 0F;
|
||||
liberateGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||
liberateGVColumn.Width = 75;
|
||||
//
|
||||
// coverGVColumn
|
||||
//
|
||||
this.coverGVColumn.DataPropertyName = "Cover";
|
||||
this.coverGVColumn.HeaderText = "Cover";
|
||||
this.coverGVColumn.Name = "coverGVColumn";
|
||||
this.coverGVColumn.ReadOnly = true;
|
||||
this.coverGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
||||
this.coverGVColumn.ToolTipText = "Cover Art";
|
||||
this.coverGVColumn.Width = 80;
|
||||
coverGVColumn.DataPropertyName = "Cover";
|
||||
coverGVColumn.HeaderText = "Cover";
|
||||
coverGVColumn.ImageLayout = System.Windows.Forms.DataGridViewImageCellLayout.Zoom;
|
||||
coverGVColumn.MinimumWidth = 10;
|
||||
coverGVColumn.Name = "coverGVColumn";
|
||||
coverGVColumn.ReadOnly = true;
|
||||
coverGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
||||
coverGVColumn.ToolTipText = "Cover Art";
|
||||
coverGVColumn.Width = 80;
|
||||
//
|
||||
// titleGVColumn
|
||||
//
|
||||
this.titleGVColumn.DataPropertyName = "Title";
|
||||
this.titleGVColumn.HeaderText = "Title";
|
||||
this.titleGVColumn.Name = "titleGVColumn";
|
||||
this.titleGVColumn.ReadOnly = true;
|
||||
this.titleGVColumn.Width = 200;
|
||||
titleGVColumn.DataPropertyName = "Title";
|
||||
titleGVColumn.HeaderText = "Title";
|
||||
titleGVColumn.MinimumWidth = 10;
|
||||
titleGVColumn.Name = "titleGVColumn";
|
||||
titleGVColumn.ReadOnly = true;
|
||||
titleGVColumn.Width = 200;
|
||||
//
|
||||
// authorsGVColumn
|
||||
//
|
||||
this.authorsGVColumn.DataPropertyName = "Authors";
|
||||
this.authorsGVColumn.HeaderText = "Authors";
|
||||
this.authorsGVColumn.Name = "authorsGVColumn";
|
||||
this.authorsGVColumn.ReadOnly = true;
|
||||
this.authorsGVColumn.Width = 100;
|
||||
authorsGVColumn.DataPropertyName = "Authors";
|
||||
authorsGVColumn.HeaderText = "Authors";
|
||||
authorsGVColumn.MinimumWidth = 10;
|
||||
authorsGVColumn.Name = "authorsGVColumn";
|
||||
authorsGVColumn.ReadOnly = true;
|
||||
authorsGVColumn.Width = 100;
|
||||
//
|
||||
// narratorsGVColumn
|
||||
//
|
||||
this.narratorsGVColumn.DataPropertyName = "Narrators";
|
||||
this.narratorsGVColumn.HeaderText = "Narrators";
|
||||
this.narratorsGVColumn.Name = "narratorsGVColumn";
|
||||
this.narratorsGVColumn.ReadOnly = true;
|
||||
this.narratorsGVColumn.Width = 100;
|
||||
narratorsGVColumn.DataPropertyName = "Narrators";
|
||||
narratorsGVColumn.HeaderText = "Narrators";
|
||||
narratorsGVColumn.MinimumWidth = 10;
|
||||
narratorsGVColumn.Name = "narratorsGVColumn";
|
||||
narratorsGVColumn.ReadOnly = true;
|
||||
narratorsGVColumn.Width = 100;
|
||||
//
|
||||
// lengthGVColumn
|
||||
//
|
||||
this.lengthGVColumn.DataPropertyName = "Length";
|
||||
this.lengthGVColumn.HeaderText = "Length";
|
||||
this.lengthGVColumn.Name = "lengthGVColumn";
|
||||
this.lengthGVColumn.ReadOnly = true;
|
||||
this.lengthGVColumn.Width = 100;
|
||||
this.lengthGVColumn.ToolTipText = "Recording Length";
|
||||
lengthGVColumn.DataPropertyName = "Length";
|
||||
lengthGVColumn.HeaderText = "Length";
|
||||
lengthGVColumn.MinimumWidth = 10;
|
||||
lengthGVColumn.Name = "lengthGVColumn";
|
||||
lengthGVColumn.ReadOnly = true;
|
||||
lengthGVColumn.ToolTipText = "Recording Length";
|
||||
lengthGVColumn.Width = 100;
|
||||
//
|
||||
// seriesGVColumn
|
||||
//
|
||||
this.seriesGVColumn.DataPropertyName = "Series";
|
||||
this.seriesGVColumn.HeaderText = "Series";
|
||||
this.seriesGVColumn.Name = "seriesGVColumn";
|
||||
this.seriesGVColumn.ReadOnly = true;
|
||||
this.seriesGVColumn.Width = 100;
|
||||
seriesGVColumn.DataPropertyName = "Series";
|
||||
seriesGVColumn.HeaderText = "Series";
|
||||
seriesGVColumn.MinimumWidth = 10;
|
||||
seriesGVColumn.Name = "seriesGVColumn";
|
||||
seriesGVColumn.ReadOnly = true;
|
||||
seriesGVColumn.Width = 100;
|
||||
//
|
||||
// seriesOrderGVColumn
|
||||
//
|
||||
this.seriesOrderGVColumn.DataPropertyName = "SeriesOrder";
|
||||
this.seriesOrderGVColumn.HeaderText = "Series\r\nOrder";
|
||||
this.seriesOrderGVColumn.Name = "seriesOrderGVColumn";
|
||||
this.seriesOrderGVColumn.Width = 60;
|
||||
this.seriesOrderGVColumn.ReadOnly = true;
|
||||
this.seriesOrderGVColumn.DefaultCellStyle.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
|
||||
seriesOrderGVColumn.DataPropertyName = "SeriesOrder";
|
||||
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
|
||||
seriesOrderGVColumn.DefaultCellStyle = dataGridViewCellStyle1;
|
||||
seriesOrderGVColumn.HeaderText = "Series\r\nOrder";
|
||||
seriesOrderGVColumn.MinimumWidth = 10;
|
||||
seriesOrderGVColumn.Name = "seriesOrderGVColumn";
|
||||
seriesOrderGVColumn.ReadOnly = true;
|
||||
seriesOrderGVColumn.Width = 60;
|
||||
//
|
||||
// descriptionGVColumn
|
||||
//
|
||||
this.descriptionGVColumn.DataPropertyName = "Description";
|
||||
this.descriptionGVColumn.HeaderText = "Description";
|
||||
this.descriptionGVColumn.Name = "descriptionGVColumn";
|
||||
this.descriptionGVColumn.ReadOnly = true;
|
||||
this.descriptionGVColumn.Width = 100;
|
||||
this.descriptionGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
||||
descriptionGVColumn.DataPropertyName = "Description";
|
||||
descriptionGVColumn.HeaderText = "Description";
|
||||
descriptionGVColumn.MinimumWidth = 10;
|
||||
descriptionGVColumn.Name = "descriptionGVColumn";
|
||||
descriptionGVColumn.ReadOnly = true;
|
||||
descriptionGVColumn.Width = 100;
|
||||
//
|
||||
// categoryGVColumn
|
||||
//
|
||||
this.categoryGVColumn.DataPropertyName = "Category";
|
||||
this.categoryGVColumn.HeaderText = "Category";
|
||||
this.categoryGVColumn.Name = "categoryGVColumn";
|
||||
this.categoryGVColumn.ReadOnly = true;
|
||||
this.categoryGVColumn.Width = 100;
|
||||
categoryGVColumn.DataPropertyName = "Category";
|
||||
categoryGVColumn.HeaderText = "Category";
|
||||
categoryGVColumn.MinimumWidth = 10;
|
||||
categoryGVColumn.Name = "categoryGVColumn";
|
||||
categoryGVColumn.ReadOnly = true;
|
||||
categoryGVColumn.Width = 100;
|
||||
//
|
||||
// productRatingGVColumn
|
||||
//
|
||||
this.productRatingGVColumn.DataPropertyName = "ProductRating";
|
||||
this.productRatingGVColumn.HeaderText = "Product Rating";
|
||||
this.productRatingGVColumn.Name = "productRatingGVColumn";
|
||||
this.productRatingGVColumn.ReadOnly = true;
|
||||
this.productRatingGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||
this.productRatingGVColumn.Width = 112;
|
||||
productRatingGVColumn.DataPropertyName = "ProductRating";
|
||||
productRatingGVColumn.HeaderText = "Product Rating";
|
||||
productRatingGVColumn.MinimumWidth = 10;
|
||||
productRatingGVColumn.Name = "productRatingGVColumn";
|
||||
productRatingGVColumn.ReadOnly = true;
|
||||
productRatingGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||
productRatingGVColumn.Width = 112;
|
||||
//
|
||||
// purchaseDateGVColumn
|
||||
//
|
||||
this.purchaseDateGVColumn.DataPropertyName = "PurchaseDate";
|
||||
this.purchaseDateGVColumn.HeaderText = "Purchase Date";
|
||||
this.purchaseDateGVColumn.Name = "purchaseDateGVColumn";
|
||||
this.purchaseDateGVColumn.ReadOnly = true;
|
||||
this.purchaseDateGVColumn.Width = 100;
|
||||
purchaseDateGVColumn.DataPropertyName = "PurchaseDate";
|
||||
purchaseDateGVColumn.HeaderText = "Purchase Date";
|
||||
purchaseDateGVColumn.MinimumWidth = 10;
|
||||
purchaseDateGVColumn.Name = "purchaseDateGVColumn";
|
||||
purchaseDateGVColumn.ReadOnly = true;
|
||||
purchaseDateGVColumn.Width = 100;
|
||||
//
|
||||
// myRatingGVColumn
|
||||
//
|
||||
this.myRatingGVColumn.DataPropertyName = "MyRating";
|
||||
this.myRatingGVColumn.HeaderText = "My Rating";
|
||||
this.myRatingGVColumn.Name = "myRatingGVColumn";
|
||||
this.myRatingGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||
this.myRatingGVColumn.Width = 112;
|
||||
myRatingGVColumn.DataPropertyName = "MyRating";
|
||||
myRatingGVColumn.HeaderText = "My Rating";
|
||||
myRatingGVColumn.MinimumWidth = 10;
|
||||
myRatingGVColumn.Name = "myRatingGVColumn";
|
||||
myRatingGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||
myRatingGVColumn.Width = 112;
|
||||
//
|
||||
// miscGVColumn
|
||||
//
|
||||
this.miscGVColumn.DataPropertyName = "Misc";
|
||||
this.miscGVColumn.HeaderText = "Misc";
|
||||
this.miscGVColumn.Name = "miscGVColumn";
|
||||
this.miscGVColumn.ReadOnly = true;
|
||||
this.miscGVColumn.Width = 140;
|
||||
miscGVColumn.DataPropertyName = "Misc";
|
||||
miscGVColumn.HeaderText = "Misc";
|
||||
miscGVColumn.MinimumWidth = 10;
|
||||
miscGVColumn.Name = "miscGVColumn";
|
||||
miscGVColumn.ReadOnly = true;
|
||||
miscGVColumn.Width = 140;
|
||||
//
|
||||
// lastDownloadedGVColumn
|
||||
//
|
||||
this.lastDownloadedGVColumn.DataPropertyName = "LastDownload";
|
||||
this.lastDownloadedGVColumn.HeaderText = "Last Download";
|
||||
this.lastDownloadedGVColumn.Name = "lastDownloadedGVColumn";
|
||||
this.lastDownloadedGVColumn.ReadOnly = true;
|
||||
this.lastDownloadedGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||
this.lastDownloadedGVColumn.Width = 108;
|
||||
lastDownloadedGVColumn.DataPropertyName = "LastDownload";
|
||||
lastDownloadedGVColumn.HeaderText = "Last Download";
|
||||
lastDownloadedGVColumn.MinimumWidth = 10;
|
||||
lastDownloadedGVColumn.Name = "lastDownloadedGVColumn";
|
||||
lastDownloadedGVColumn.ReadOnly = true;
|
||||
lastDownloadedGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||
lastDownloadedGVColumn.Width = 108;
|
||||
//
|
||||
// tagAndDetailsGVColumn
|
||||
//
|
||||
this.tagAndDetailsGVColumn.DataPropertyName = "BookTags";
|
||||
this.tagAndDetailsGVColumn.HeaderText = "Tags and Details";
|
||||
this.tagAndDetailsGVColumn.Name = "tagAndDetailsGVColumn";
|
||||
this.tagAndDetailsGVColumn.ReadOnly = true;
|
||||
this.tagAndDetailsGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
||||
this.tagAndDetailsGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||
this.tagAndDetailsGVColumn.Width = 100;
|
||||
tagAndDetailsGVColumn.DataPropertyName = "BookTags";
|
||||
tagAndDetailsGVColumn.HeaderText = "Tags and Details";
|
||||
tagAndDetailsGVColumn.MinimumWidth = 10;
|
||||
tagAndDetailsGVColumn.Name = "tagAndDetailsGVColumn";
|
||||
tagAndDetailsGVColumn.ReadOnly = true;
|
||||
tagAndDetailsGVColumn.ScaleFactor = 0F;
|
||||
tagAndDetailsGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||
tagAndDetailsGVColumn.Width = 100;
|
||||
//
|
||||
// showHideColumnsContextMenuStrip
|
||||
//
|
||||
this.showHideColumnsContextMenuStrip.Name = "contextMenuStrip1";
|
||||
this.showHideColumnsContextMenuStrip.Size = new System.Drawing.Size(61, 4);
|
||||
showHideColumnsContextMenuStrip.ImageScalingSize = new System.Drawing.Size(32, 32);
|
||||
showHideColumnsContextMenuStrip.Name = "contextMenuStrip1";
|
||||
showHideColumnsContextMenuStrip.ShowCheckMargin = true;
|
||||
showHideColumnsContextMenuStrip.Size = new System.Drawing.Size(83, 4);
|
||||
//
|
||||
// syncBindingSource
|
||||
//
|
||||
this.syncBindingSource.DataSource = typeof(IGridEntry);
|
||||
syncBindingSource.DataSource = typeof(IGridEntry);
|
||||
//
|
||||
// ProductsGrid
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.AutoScroll = true;
|
||||
this.Controls.Add(this.gridEntryDataGridView);
|
||||
this.Name = "ProductsGrid";
|
||||
this.Size = new System.Drawing.Size(1570, 380);
|
||||
this.Load += new System.EventHandler(this.ProductsGrid_Load);
|
||||
((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
AutoScroll = true;
|
||||
Controls.Add(gridEntryDataGridView);
|
||||
Name = "ProductsGrid";
|
||||
Size = new System.Drawing.Size(1570, 380);
|
||||
Load += new System.EventHandler(ProductsGrid_Load);
|
||||
((System.ComponentModel.ISupportInitialize)(gridEntryDataGridView)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(syncBindingSource)).EndInit();
|
||||
ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
@@ -288,7 +294,7 @@ namespace LibationWinForms.GridView
|
||||
private SyncBindingSource syncBindingSource;
|
||||
private System.Windows.Forms.DataGridViewCheckBoxColumn removeGVColumn;
|
||||
private LiberateDataGridViewImageButtonColumn liberateGVColumn;
|
||||
private CoverGridViewColumn coverGVColumn;
|
||||
private System.Windows.Forms.DataGridViewImageColumn coverGVColumn;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn titleGVColumn;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn authorsGVColumn;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn narratorsGVColumn;
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
using DataLayer;
|
||||
using Dinah.Core;
|
||||
using Dinah.Core.WindowsDesktop.Forms;
|
||||
using LibationFileManager;
|
||||
using LibationUiBase.GridView;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace LibationWinForms.GridView
|
||||
@@ -44,24 +47,76 @@ namespace LibationWinForms.GridView
|
||||
gridEntryDataGridView.CellContextMenuStripNeeded += GridEntryDataGridView_CellContextMenuStripNeeded;
|
||||
removeGVColumn.Frozen = false;
|
||||
|
||||
gridEntryDataGridView.RowTemplate.Height = this.DpiScale(gridEntryDataGridView.RowTemplate.Height);
|
||||
defaultFont = gridEntryDataGridView.DefaultCellStyle.Font;
|
||||
setGridFontScale(Configuration.Instance.GridFontScaleFactor);
|
||||
setGridScale(Configuration.Instance.GridScaleFactor);
|
||||
Configuration.Instance.PropertyChanged += Configuration_ScaleChanged;
|
||||
Configuration.Instance.PropertyChanged += Configuration_FontScaleChanged;
|
||||
|
||||
gridEntryDataGridView.Disposed += (_, _) =>
|
||||
{
|
||||
Configuration.Instance.PropertyChanged -= Configuration_ScaleChanged;
|
||||
Configuration.Instance.PropertyChanged -= Configuration_FontScaleChanged;
|
||||
};
|
||||
}
|
||||
|
||||
#region Scaling
|
||||
|
||||
[PropertyChangeFilter(nameof(Configuration.GridFontScaleFactor))]
|
||||
private void Configuration_FontScaleChanged(object sender, PropertyChangedEventArgsEx e)
|
||||
=> setGridFontScale((float)e.NewValue);
|
||||
|
||||
[PropertyChangeFilter(nameof(Configuration.GridScaleFactor))]
|
||||
private void Configuration_ScaleChanged(object sender, PropertyChangedEventArgsEx e)
|
||||
=> setGridScale((float)e.NewValue);
|
||||
|
||||
/// <summary>
|
||||
/// Keep track of the original dimensions for rescaling
|
||||
/// </summary>
|
||||
private static readonly Dictionary<DataGridViewElement, int> originalDims = new();
|
||||
private readonly Font defaultFont;
|
||||
private void setGridScale(float scale)
|
||||
{
|
||||
foreach (var col in gridEntryDataGridView.Columns.Cast<DataGridViewColumn>())
|
||||
{
|
||||
//Only resize fixed-width columns. The rest can be adjusted by users.
|
||||
if (col.Resizable is DataGridViewTriState.False)
|
||||
{
|
||||
if (!originalDims.ContainsKey(col))
|
||||
originalDims[col] = col.Width;
|
||||
|
||||
col.Width = this.DpiScale(originalDims[col], scale);
|
||||
}
|
||||
|
||||
if (col is IDataGridScaleColumn scCol)
|
||||
scCol.ScaleFactor = scale;
|
||||
}
|
||||
|
||||
if (!originalDims.ContainsKey(gridEntryDataGridView.RowTemplate))
|
||||
originalDims[gridEntryDataGridView.RowTemplate] = gridEntryDataGridView.RowTemplate.Height;
|
||||
|
||||
var height = gridEntryDataGridView.RowTemplate.Height = this.DpiScale(originalDims[gridEntryDataGridView.RowTemplate], scale);
|
||||
|
||||
foreach (var row in gridEntryDataGridView.Rows.Cast<DataGridViewRow>())
|
||||
row.Height = height;
|
||||
}
|
||||
|
||||
private void setGridFontScale(float scale)
|
||||
=> gridEntryDataGridView.DefaultCellStyle.Font = new Font(defaultFont.FontFamily, defaultFont.Size * scale);
|
||||
|
||||
#endregion
|
||||
|
||||
private void GridEntryDataGridView_CellContextMenuStripNeeded(object sender, DataGridViewCellContextMenuStripNeededEventArgs e)
|
||||
{
|
||||
// header
|
||||
if (e.RowIndex < 0)
|
||||
return;
|
||||
|
||||
// cover
|
||||
else if (e.ColumnIndex == coverGVColumn.Index)
|
||||
return;
|
||||
|
||||
e.ContextMenuStrip = new ContextMenuStrip();
|
||||
// any non-stop light
|
||||
if (e.ColumnIndex != liberateGVColumn.Index)
|
||||
// any column except cover & stop light
|
||||
if (e.ColumnIndex != liberateGVColumn.Index && e.ColumnIndex != coverGVColumn.Index)
|
||||
{
|
||||
e.ContextMenuStrip.Items.Add("Copy", null, (_, __) =>
|
||||
e.ContextMenuStrip.Items.Add("Copy Cell Contents", null, (_, __) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -70,14 +125,13 @@ namespace LibationWinForms.GridView
|
||||
Clipboard.SetDataObject(text, false, 5, 150);
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var entry = getGridEntry(e.RowIndex);
|
||||
var name = gridEntryDataGridView.Columns[e.ColumnIndex].DataPropertyName;
|
||||
LiberateContextMenuStripNeeded?.Invoke(entry, e.ContextMenuStrip);
|
||||
});
|
||||
e.ContextMenuStrip.Items.Add(new ToolStripSeparator());
|
||||
}
|
||||
|
||||
var entry = getGridEntry(e.RowIndex);
|
||||
var name = gridEntryDataGridView.Columns[e.ColumnIndex].DataPropertyName;
|
||||
LiberateContextMenuStripNeeded?.Invoke(entry, e.ContextMenuStrip);
|
||||
}
|
||||
|
||||
private void EnableDoubleBuffering()
|
||||
@@ -160,27 +214,23 @@ namespace LibationWinForms.GridView
|
||||
}
|
||||
}
|
||||
|
||||
internal void BindToGrid(List<LibraryBook> dbBooks)
|
||||
internal async Task BindToGridAsync(List<LibraryBook> dbBooks)
|
||||
{
|
||||
var geList = dbBooks
|
||||
.Where(lb => lb.Book.IsProduct())
|
||||
.Select(b => new LibraryBookEntry<WinFormsEntryStatus>(b))
|
||||
.ToList<IGridEntry>();
|
||||
var geList = await LibraryBookEntry<WinFormsEntryStatus>.GetAllProductsAsync(dbBooks);
|
||||
|
||||
var episodes = dbBooks.Where(lb => lb.Book.IsEpisodeChild());
|
||||
var seriesEntries = await SeriesEntry<WinFormsEntryStatus>.GetAllSeriesEntriesAsync(dbBooks);
|
||||
|
||||
var seriesBooks = dbBooks.Where(lb => lb.Book.IsEpisodeParent()).ToList();
|
||||
geList.AddRange(seriesEntries);
|
||||
//Sort descending by date (default sort property)
|
||||
var comparer = new RowComparer();
|
||||
geList.Sort((a, b) => comparer.Compare(b, a));
|
||||
|
||||
foreach (var parent in seriesBooks)
|
||||
//Add all children beneath their parent
|
||||
foreach (var series in seriesEntries)
|
||||
{
|
||||
var seriesEpisodes = episodes.FindChildren(parent);
|
||||
|
||||
if (!seriesEpisodes.Any()) continue;
|
||||
|
||||
var seriesEntry = new SeriesEntry<WinFormsEntryStatus>(parent, seriesEpisodes);
|
||||
|
||||
geList.Add(seriesEntry);
|
||||
geList.AddRange(seriesEntry.Children);
|
||||
var seriesIndex = geList.IndexOf(series);
|
||||
foreach (var child in series.Children)
|
||||
geList.Insert(++seriesIndex, child);
|
||||
}
|
||||
|
||||
bindingList = new GridEntryBindingList(geList);
|
||||
@@ -307,7 +357,7 @@ namespace LibationWinForms.GridView
|
||||
//Series exists. Create and add episode child then update the SeriesEntry
|
||||
episodeEntry = new LibraryBookEntry<WinFormsEntryStatus>(episodeBook, seriesEntry);
|
||||
seriesEntry.Children.Add(episodeEntry);
|
||||
seriesEntry.Children.Sort((c1,c2) => c1.SeriesIndex.CompareTo(c2.SeriesIndex));
|
||||
seriesEntry.Children.Sort((c1, c2) => c1.SeriesIndex.CompareTo(c2.SeriesIndex));
|
||||
var seriesBook = dbBooks.Single(lb => lb.Book.AudibleProductId == seriesEntry.LibraryBook.Book.AudibleProductId);
|
||||
seriesEntry.UpdateLibraryBook(seriesBook);
|
||||
}
|
||||
@@ -332,6 +382,8 @@ namespace LibationWinForms.GridView
|
||||
|
||||
public void Filter(string searchString)
|
||||
{
|
||||
if (bindingList is null) return;
|
||||
|
||||
int visibleCount = bindingList.Count;
|
||||
|
||||
if (string.IsNullOrEmpty(searchString))
|
||||
@@ -371,16 +423,19 @@ namespace LibationWinForms.GridView
|
||||
var itemName = column.DataPropertyName;
|
||||
var visible = gridColumnsVisibilities.GetValueOrDefault(itemName, true);
|
||||
|
||||
var menuItem = new ToolStripMenuItem()
|
||||
var menuItem = new ToolStripMenuItem(column.HeaderText)
|
||||
{
|
||||
Text = column.HeaderText,
|
||||
Checked = visible,
|
||||
Tag = itemName
|
||||
};
|
||||
menuItem.Click += HideMenuItem_Click;
|
||||
showHideColumnsContextMenuStrip.Items.Add(menuItem);
|
||||
|
||||
column.Width = gridColumnsWidths.GetValueOrDefault(itemName, this.DpiScale(column.Width));
|
||||
//Only set column widths for user resizable columns.
|
||||
//Fixed column widths are set by setGridScale()
|
||||
if (column.Resizable is not DataGridViewTriState.False)
|
||||
column.Width = gridColumnsWidths.GetValueOrDefault(itemName, this.DpiScale(column.Width));
|
||||
|
||||
column.MinimumWidth = 10;
|
||||
column.HeaderCell.ContextMenuStrip = showHideColumnsContextMenuStrip;
|
||||
column.Visible = visible;
|
||||
@@ -459,6 +514,7 @@ namespace LibationWinForms.GridView
|
||||
|
||||
var dictionary = config.GridColumnsWidths;
|
||||
dictionary[e.Column.DataPropertyName] = e.Column.Width;
|
||||
config.GridColumnsWidths = dictionary;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,4 +1,64 @@
|
||||
<root>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing"">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dinah.Core.WindowsDesktop" Version="7.2.2.1" />
|
||||
<PackageReference Include="Dinah.Core.WindowsDesktop" Version="7.2.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -249,9 +249,12 @@ namespace LibationWinForms.ProcessQueue
|
||||
|
||||
private byte[] AudioDecodable_RequestCoverArt(object sender, EventArgs e)
|
||||
{
|
||||
byte[] coverData = PictureStorage
|
||||
.GetPictureSynchronously(
|
||||
new PictureDefinition(LibraryBook.Book.PictureId, PictureSize._500x500));
|
||||
var quality
|
||||
= Configuration.Instance.FileDownloadQuality == Configuration.DownloadQuality.High
|
||||
? new PictureDefinition(LibraryBook.Book.PictureLarge, PictureSize.Native)
|
||||
: new PictureDefinition(LibraryBook.Book.PictureId, PictureSize._500x500);
|
||||
|
||||
byte[] coverData = PictureStorage.GetPictureSynchronously(quality);
|
||||
|
||||
AudioDecodable_CoverImageDiscovered(this, coverData);
|
||||
return coverData;
|
||||
|
||||
@@ -2,12 +2,13 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using ApplicationServices;
|
||||
using AppScaffolding;
|
||||
using Dinah.Core;
|
||||
using DataLayer;
|
||||
using LibationFileManager;
|
||||
using LibationWinForms.Dialogs;
|
||||
using Serilog;
|
||||
|
||||
namespace LibationWinForms
|
||||
{
|
||||
@@ -20,6 +21,7 @@ namespace LibationWinForms
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Task<List<LibraryBook>> libraryLoadTask;
|
||||
try
|
||||
{
|
||||
//// Uncomment to see Console. Must be called before anything writes to Console.
|
||||
@@ -48,6 +50,17 @@ namespace LibationWinForms
|
||||
// migrations which require Forms or are long-running
|
||||
RunWindowsOnlyMigrations(config);
|
||||
|
||||
//*******************************************************************//
|
||||
// //
|
||||
// Start loading the library as soon as possible //
|
||||
// //
|
||||
// Before calling anything else, including subscribing to events, //
|
||||
// to ensure database exists. If we wait and let it happen lazily, //
|
||||
// race conditions and errors are likely during new installs //
|
||||
// //
|
||||
//*******************************************************************//
|
||||
libraryLoadTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true));
|
||||
|
||||
MessageBoxLib.VerboseLoggingWarning_ShowIfTrue();
|
||||
|
||||
// logging is init'd here
|
||||
@@ -71,7 +84,9 @@ namespace LibationWinForms
|
||||
// global exception handling (ShowAdminAlert) attempts to use logging. only call it after logging has been init'd
|
||||
postLoggingGlobalExceptionHandling();
|
||||
|
||||
Application.Run(new Form1());
|
||||
var form1 = new Form1();
|
||||
form1.Load += async (_, _) => await form1.InitLibraryAsync(await libraryLoadTask);
|
||||
Application.Run(form1);
|
||||
}
|
||||
|
||||
private static void RunInstaller(Configuration config)
|
||||
@@ -153,6 +168,17 @@ namespace LibationWinForms
|
||||
// examples:
|
||||
// - only supported in winforms. don't move to app scaffolding
|
||||
// - long running. won't get a chance to finish in cli. don't move to app scaffolding
|
||||
|
||||
const string hasMigratedKey = "hasMigratedToHighDPI";
|
||||
if (!config.GetNonString(defaultValue: false, hasMigratedKey))
|
||||
{
|
||||
config.RemoveProperty(nameof(config.GridColumnsWidths));
|
||||
|
||||
foreach (var form in typeof(Program).Assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(Form))))
|
||||
config.RemoveProperty(form.Name);
|
||||
|
||||
config.SetNonString(true, hasMigratedKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static void postLoggingGlobalExceptionHandling()
|
||||
|
||||
@@ -23,15 +23,15 @@ namespace LibationWinForms
|
||||
}
|
||||
}
|
||||
|
||||
public static int DpiScale(this Control control, int value)
|
||||
=> (int)(control.DeviceDpi / BaseDpi * value);
|
||||
public static int DpiScale(this Control control, int value, float additionalScaleFactor = 1)
|
||||
=> (int)float.Round(control.DeviceDpi / BaseDpi * value * additionalScaleFactor);
|
||||
|
||||
public static int DpiUnscale(this Control control, int value)
|
||||
=> (int)(BaseDpi / control.DeviceDpi * value);
|
||||
=> (int)float.Round(BaseDpi / control.DeviceDpi * value);
|
||||
|
||||
public static int ScaleX(this Graphics control, int value)
|
||||
=> (int)(control.DpiX / BaseDpi * value);
|
||||
=> (int)float.Round(control.DpiX / BaseDpi * value);
|
||||
public static int ScaleY(this Graphics control, int value)
|
||||
=> (int)(control.DpiY / BaseDpi * value);
|
||||
=> (int)float.Round(control.DpiY / BaseDpi * value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dinah.Core" Version="7.2.2.1" />
|
||||
<PackageReference Include="Dinah.Core" Version="7.2.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
||||
<PackageReference Include="Moq" Version="4.18.4" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -540,7 +540,6 @@ namespace FileLiberator.Tests
|
||||
value[i].StartOffsetMs.Should().Be(expected[i].StartOffsetMs);
|
||||
value[i].StartOffsetSec.Should().Be(expected[i].StartOffsetSec);
|
||||
value[i].LengthMs.Should().Be(expected[i].LengthMs);
|
||||
value[i].Chapters.Should().BeNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
||||
<PackageReference Include="Moq" Version="4.18.4" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
Reference in New Issue
Block a user