Merge pull request #432 from Mbucari/master
Add ability for users to edit book ratings from the main grid
This commit is contained in:
commit
f4189bf409
@ -13,7 +13,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AAXClean.Codecs" Version="0.2.14" />
|
<PackageReference Include="AAXClean.Codecs" Version="0.2.15" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -32,6 +32,9 @@ namespace AaxDecrypter
|
|||||||
AaxFile.AppleTags.Album = AaxFile.AppleTags.Album?.Replace(" (Unabridged)", "");
|
AaxFile.AppleTags.Album = AaxFile.AppleTags.Album?.Replace(" (Unabridged)", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (DownloadOptions.FixupFile)
|
||||||
|
AaxFile.AppleTags.AppleListBox.EditOrAddTag("TCOM", AaxFile.AppleTags.Narrator);
|
||||||
|
|
||||||
//Finishing configuring lame encoder.
|
//Finishing configuring lame encoder.
|
||||||
if (DownloadOptions.OutputFormat == OutputFormat.Mp3)
|
if (DownloadOptions.OutputFormat == OutputFormat.Mp3)
|
||||||
MpegUtil.ConfigureLameOptions(
|
MpegUtil.ConfigureLameOptions(
|
||||||
|
|||||||
@ -81,7 +81,6 @@ namespace AppScaffolding
|
|||||||
//
|
//
|
||||||
|
|
||||||
Migrations.migrate_to_v6_6_9(config);
|
Migrations.migrate_to_v6_6_9(config);
|
||||||
Migrations.migrate_from_7_10_1(config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void PopulateMissingConfigValues(Configuration config)
|
public static void PopulateMissingConfigValues(Configuration config)
|
||||||
@ -457,74 +456,5 @@ namespace AppScaffolding
|
|||||||
UNSAFE_MigrationHelper.Settings_AddUniqueToArray("Serilog.Enrich", "WithExceptionDetails");
|
UNSAFE_MigrationHelper.Settings_AddUniqueToArray("Serilog.Enrich", "WithExceptionDetails");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void migrate_from_7_10_1(Configuration config)
|
|
||||||
{
|
|
||||||
var lastMigrationThrew = config.GetNonString<bool>($"{nameof(migrate_from_7_10_1)}_ThrewError");
|
|
||||||
|
|
||||||
if (lastMigrationThrew) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
//https://github.com/rmcrackan/Libation/issues/270#issuecomment-1152863629
|
|
||||||
//This migration helps fix databases contaminated with the 7.10.1 hack workaround
|
|
||||||
//and those with improperly identified or missing series. This does not solve cases
|
|
||||||
//where individual episodes are in the db with a valid series link, but said series'
|
|
||||||
//parents have not been imported into the database. For those cases, Libation will
|
|
||||||
//attempt fixup by retrieving parents from the catalog endpoint
|
|
||||||
|
|
||||||
using var context = DbContexts.GetContext();
|
|
||||||
|
|
||||||
//This migration removes books and series with SERIES_ prefix that were created
|
|
||||||
//as a hack workaround in 7.10.1. Said workaround was removed in 7.10.2
|
|
||||||
string removeHackSeries = "delete " +
|
|
||||||
"from series " +
|
|
||||||
"where AudibleSeriesId like 'SERIES%'";
|
|
||||||
|
|
||||||
string removeHackBooks = "delete " +
|
|
||||||
"from books " +
|
|
||||||
"where AudibleProductId like 'SERIES%'";
|
|
||||||
|
|
||||||
//Detect series parents that were added to the database as books with ContentType.Episode,
|
|
||||||
//and change them to ContentType.Parent
|
|
||||||
string updateContentType =
|
|
||||||
"UPDATE books " +
|
|
||||||
"SET contenttype = 4 " +
|
|
||||||
"WHERE audibleproductid IN (SELECT books.audibleproductid " +
|
|
||||||
"FROM books " +
|
|
||||||
"INNER JOIN series " +
|
|
||||||
"ON ( books.audibleproductid = " +
|
|
||||||
"series.audibleseriesid) " +
|
|
||||||
"WHERE books.contenttype = 2)";
|
|
||||||
|
|
||||||
//Then detect series parents that were added to the database as books with ContentType.Parent
|
|
||||||
//but are missing a series link, and add the link (don't know how this happened)
|
|
||||||
string addMissingSeriesLink =
|
|
||||||
"INSERT INTO seriesbook " +
|
|
||||||
"SELECT series.seriesid, " +
|
|
||||||
"books.bookid, " +
|
|
||||||
"'- 1' " +
|
|
||||||
"FROM books " +
|
|
||||||
"LEFT OUTER JOIN seriesbook " +
|
|
||||||
"ON books.bookid = seriesbook.bookid " +
|
|
||||||
"INNER JOIN series " +
|
|
||||||
"ON books.audibleproductid = series.audibleseriesid " +
|
|
||||||
"WHERE books.contenttype = 4 " +
|
|
||||||
"AND seriesbook.seriesid IS NULL";
|
|
||||||
|
|
||||||
context.Database.ExecuteSqlRaw(removeHackSeries);
|
|
||||||
context.Database.ExecuteSqlRaw(removeHackBooks);
|
|
||||||
context.Database.ExecuteSqlRaw(updateContentType);
|
|
||||||
context.Database.ExecuteSqlRaw(addMissingSeriesLink);
|
|
||||||
|
|
||||||
LibraryCommands.SaveContext(context);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Serilog.Log.Logger.Error(ex, "An error occurred while running database migrations in {0}", nameof(migrate_from_7_10_1));
|
|
||||||
config.SetObject($"{nameof(migrate_from_7_10_1)}_ThrewError", true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -126,22 +126,6 @@ namespace ApplicationServices
|
|||||||
if (totalCount == 0)
|
if (totalCount == 0)
|
||||||
return default;
|
return default;
|
||||||
|
|
||||||
|
|
||||||
Log.Logger.Information("Begin scan for orphaned episode parents");
|
|
||||||
var newParents = await findAndAddMissingParents(accounts);
|
|
||||||
Log.Logger.Information($"Orphan episode scan complete. New parents count {newParents}");
|
|
||||||
|
|
||||||
if (newParents >= 0)
|
|
||||||
{
|
|
||||||
//If any episodes are still orphaned, their series have been
|
|
||||||
//removed from the catalog and we'll never be able to find them.
|
|
||||||
|
|
||||||
//only do this if findAndAddMissingParents returned >= 0. If it
|
|
||||||
//returned < 0, an error happened and there's still a chance that
|
|
||||||
//a future successful run will find missing parents.
|
|
||||||
removedOrphanedEpisodes();
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.Logger.Information("Begin long-running import");
|
Log.Logger.Information("Begin long-running import");
|
||||||
logTime($"pre {nameof(importIntoDbAsync)}");
|
logTime($"pre {nameof(importIntoDbAsync)}");
|
||||||
var newCount = await importIntoDbAsync(importItems);
|
var newCount = await importIntoDbAsync(importItems);
|
||||||
@ -235,84 +219,6 @@ namespace ApplicationServices
|
|||||||
return newCount;
|
return newCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void removedOrphanedEpisodes()
|
|
||||||
{
|
|
||||||
using var context = DbContexts.GetContext();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var orphanedEpisodes =
|
|
||||||
context
|
|
||||||
.GetLibrary_Flat_NoTracking(includeParents: true)
|
|
||||||
.FindOrphanedEpisodes();
|
|
||||||
|
|
||||||
context.LibraryBooks.RemoveRange(orphanedEpisodes);
|
|
||||||
context.Books.RemoveRange(orphanedEpisodes.Select(lb => lb.Book));
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Serilog.Log.Logger.Error(ex, "An error occurred while trying to remove orphaned episodes from the database");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static async Task<int> findAndAddMissingParents(Account[] accounts)
|
|
||||||
{
|
|
||||||
using var context = DbContexts.GetContext();
|
|
||||||
|
|
||||||
var library = context.GetLibrary_Flat_NoTracking(includeParents: true);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var orphanedEpisodes = library.FindOrphanedEpisodes().ToList();
|
|
||||||
|
|
||||||
if (!orphanedEpisodes.Any())
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
var orphanedSeries =
|
|
||||||
orphanedEpisodes
|
|
||||||
.SelectMany(lb => lb.Book.SeriesLink)
|
|
||||||
.DistinctBy(s => s.Series.AudibleSeriesId)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
// The Catalog endpoint does not require authentication.
|
|
||||||
var api = new ApiUnauthenticated(accounts[0].Locale);
|
|
||||||
|
|
||||||
var seriesParents = orphanedSeries.Select(o => o.Series.AudibleSeriesId).ToList();
|
|
||||||
var items = await api.GetCatalogProductsAsync(seriesParents, CatalogOptions.ResponseGroupOptions.ALL_OPTIONS);
|
|
||||||
|
|
||||||
List<ImportItem> newParentsImportItems = new();
|
|
||||||
foreach (var sp in orphanedSeries)
|
|
||||||
{
|
|
||||||
var seriesItem = items.First(i => i.Asin == sp.Series.AudibleSeriesId);
|
|
||||||
|
|
||||||
if (seriesItem.Relationships is null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var episode = orphanedEpisodes.First(l => l.Book.AudibleProductId == sp.Book.AudibleProductId);
|
|
||||||
|
|
||||||
seriesItem.PurchaseDate = new DateTimeOffset(episode.DateAdded);
|
|
||||||
seriesItem.Series = new AudibleApi.Common.Series[]
|
|
||||||
{
|
|
||||||
new AudibleApi.Common.Series{ Asin = seriesItem.Asin, Title = seriesItem.TitleWithSubtitle, Sequence = "-1"}
|
|
||||||
};
|
|
||||||
|
|
||||||
newParentsImportItems.Add(new ImportItem { DtoItem = seriesItem, AccountId = episode.Account, LocaleName = episode.Book.Locale });
|
|
||||||
}
|
|
||||||
|
|
||||||
var newCount = new LibraryBookImporter(context)
|
|
||||||
.Import(newParentsImportItems);
|
|
||||||
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
|
|
||||||
return newCount;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Serilog.Log.Logger.Error(ex, "An error occurred while trying to scan for orphaned episode parents.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int SaveContext(LibationContext context)
|
public static int SaveContext(LibationContext context)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -415,14 +321,16 @@ namespace ApplicationServices
|
|||||||
this Book book,
|
this Book book,
|
||||||
string tags = null,
|
string tags = null,
|
||||||
LiberatedStatus? bookStatus = null,
|
LiberatedStatus? bookStatus = null,
|
||||||
LiberatedStatus? pdfStatus = null)
|
LiberatedStatus? pdfStatus = null,
|
||||||
=> new[] { book }.UpdateUserDefinedItem(tags, bookStatus, pdfStatus);
|
Rating rating = null)
|
||||||
|
=> new[] { book }.UpdateUserDefinedItem(tags, bookStatus, pdfStatus, rating);
|
||||||
|
|
||||||
public static int UpdateUserDefinedItem(
|
public static int UpdateUserDefinedItem(
|
||||||
this IEnumerable<Book> books,
|
this IEnumerable<Book> books,
|
||||||
string tags = null,
|
string tags = null,
|
||||||
LiberatedStatus? bookStatus = null,
|
LiberatedStatus? bookStatus = null,
|
||||||
LiberatedStatus? pdfStatus = null)
|
LiberatedStatus? pdfStatus = null,
|
||||||
|
Rating rating = null)
|
||||||
=> updateUserDefinedItem(
|
=> updateUserDefinedItem(
|
||||||
books,
|
books,
|
||||||
udi => {
|
udi => {
|
||||||
@ -435,6 +343,9 @@ namespace ApplicationServices
|
|||||||
|
|
||||||
// method handles null logic
|
// method handles null logic
|
||||||
udi.SetPdfStatus(pdfStatus);
|
udi.SetPdfStatus(pdfStatus);
|
||||||
|
|
||||||
|
if (rating is not null)
|
||||||
|
udi.UpdateRating(rating.OverallRating, rating.PerformanceRating, rating.StoryRating);
|
||||||
});
|
});
|
||||||
|
|
||||||
public static int UpdateBookStatus(this Book book, LiberatedStatus bookStatus)
|
public static int UpdateBookStatus(this Book book, LiberatedStatus bookStatus)
|
||||||
@ -487,7 +398,10 @@ namespace ApplicationServices
|
|||||||
|
|
||||||
// Attach() NoTracking entities before SaveChanges()
|
// Attach() NoTracking entities before SaveChanges()
|
||||||
foreach (var book in books)
|
foreach (var book in books)
|
||||||
|
{
|
||||||
context.Attach(book.UserDefinedItem).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
|
context.Attach(book.UserDefinedItem).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
|
||||||
|
context.Attach(book.UserDefinedItem.Rating).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
|
||||||
|
}
|
||||||
|
|
||||||
var qtyChanges = context.SaveChanges();
|
var qtyChanges = context.SaveChanges();
|
||||||
if (qtyChanges > 0)
|
if (qtyChanges > 0)
|
||||||
|
|||||||
@ -43,23 +43,18 @@ namespace ApplicationServices
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var book in books)
|
foreach (var book in books)
|
||||||
{
|
UpdateUserDefinedItems(book);
|
||||||
UpdateLiberatedStatus(book);
|
|
||||||
UpdateBookTags(book);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void FullReIndex() => performSafeCommand(e =>
|
public static void FullReIndex() => performSafeCommand(fullReIndex);
|
||||||
fullReIndex(e)
|
|
||||||
);
|
|
||||||
|
|
||||||
internal static void UpdateLiberatedStatus(Book book) => performSafeCommand(e =>
|
internal static void UpdateUserDefinedItems(Book book) => performSafeCommand(e =>
|
||||||
e.UpdateLiberatedStatus(book)
|
{
|
||||||
);
|
e.UpdateLiberatedStatus(book);
|
||||||
|
e.UpdateTags(book.AudibleProductId, book.UserDefinedItem.Tags);
|
||||||
internal static void UpdateBookTags(Book book) => performSafeCommand(e =>
|
e.UpdateUserRatings(book);
|
||||||
e.UpdateTags(book.AudibleProductId, book.UserDefinedItem.Tags)
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
private static void performSafeCommand(Action<SearchEngine> action)
|
private static void performSafeCommand(Action<SearchEngine> action)
|
||||||
@ -87,7 +82,6 @@ namespace ApplicationServices
|
|||||||
isUpdating = true;
|
isUpdating = true;
|
||||||
|
|
||||||
action(new SearchEngine());
|
action(new SearchEngine());
|
||||||
|
|
||||||
if (!prevIsUpdating)
|
if (!prevIsUpdating)
|
||||||
SearchEngineUpdated?.Invoke(null, null);
|
SearchEngineUpdated?.Invoke(null, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
<DataGridCheckBoxColumn xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
x:Class="LibationAvalonia.Controls.DataGridCheckBoxColumnExt">
|
|
||||||
|
|
||||||
</DataGridCheckBoxColumn >
|
|
||||||
@ -1,10 +1,11 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using LibationAvalonia.ViewModels;
|
using LibationAvalonia.ViewModels;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace LibationAvalonia.Controls
|
namespace LibationAvalonia.Controls
|
||||||
{
|
{
|
||||||
public partial class DataGridCheckBoxColumnExt : DataGridCheckBoxColumn
|
public class DataGridCheckBoxColumnExt : DataGridCheckBoxColumn
|
||||||
{
|
{
|
||||||
protected override IControl GenerateEditingElementDirect(DataGridCell cell, object dataItem)
|
protected override IControl GenerateEditingElementDirect(DataGridCell cell, object dataItem)
|
||||||
{
|
{
|
||||||
@ -1,12 +1,55 @@
|
|||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Markup.Xaml;
|
|
||||||
using LibationAvalonia.ViewModels;
|
using LibationAvalonia.ViewModels;
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace LibationAvalonia.Controls
|
namespace LibationAvalonia.Controls
|
||||||
{
|
{
|
||||||
|
internal static class DataGridContextMenus
|
||||||
|
{
|
||||||
|
public static event EventHandler<DataGridCellContextMenuStripNeededEventArgs> CellContextMenuStripNeeded;
|
||||||
|
private static readonly ContextMenu ContextMenu = new();
|
||||||
|
private static readonly AvaloniaList<MenuItem> MenuItems = new();
|
||||||
|
private static readonly PropertyInfo OwningColumnProperty;
|
||||||
|
|
||||||
|
static DataGridContextMenus()
|
||||||
|
{
|
||||||
|
ContextMenu.Items = MenuItems;
|
||||||
|
OwningColumnProperty = typeof(DataGridCell).GetProperty("OwningColumn", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AttachContextMenu(this DataGridCell cell)
|
||||||
|
{
|
||||||
|
if (cell is not null && cell.ContextMenu is null)
|
||||||
|
{
|
||||||
|
cell.ContextRequested += Cell_ContextRequested;
|
||||||
|
cell.ContextMenu = ContextMenu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Cell_ContextRequested(object sender, ContextRequestedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is DataGridCell cell && cell.DataContext is GridEntry entry)
|
||||||
|
{
|
||||||
|
var args = new DataGridCellContextMenuStripNeededEventArgs
|
||||||
|
{
|
||||||
|
Column = OwningColumnProperty.GetValue(cell) as DataGridColumn,
|
||||||
|
GridEntry = entry,
|
||||||
|
ContextMenu = ContextMenu
|
||||||
|
};
|
||||||
|
|
||||||
|
args.ContextMenuItems.Clear();
|
||||||
|
|
||||||
|
CellContextMenuStripNeeded?.Invoke(sender, args);
|
||||||
|
|
||||||
|
e.Handled = args.ContextMenuItems.Count == 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class DataGridCellContextMenuStripNeededEventArgs
|
public class DataGridCellContextMenuStripNeededEventArgs
|
||||||
{
|
{
|
||||||
private static readonly MethodInfo GetCellValueMethod;
|
private static readonly MethodInfo GetCellValueMethod;
|
||||||
@ -19,55 +62,10 @@ namespace LibationAvalonia.Controls
|
|||||||
=> GetCellValueMethod.Invoke(column, new object[] { item, column.ClipboardContentBinding })?.ToString() ?? "";
|
=> GetCellValueMethod.Invoke(column, new object[] { item, column.ClipboardContentBinding })?.ToString() ?? "";
|
||||||
|
|
||||||
public string CellClipboardContents => GetCellValue(Column, GridEntry);
|
public string CellClipboardContents => GetCellValue(Column, GridEntry);
|
||||||
public DataGridTemplateColumnExt Column { get; init; }
|
public DataGridColumn Column { get; init; }
|
||||||
public GridEntry GridEntry { get; init; }
|
public GridEntry GridEntry { get; init; }
|
||||||
public ContextMenu ContextMenu { get; init; }
|
public ContextMenu ContextMenu { get; init; }
|
||||||
public AvaloniaList<MenuItem> ContextMenuItems
|
public AvaloniaList<MenuItem> ContextMenuItems
|
||||||
=> ContextMenu.Items as AvaloniaList<MenuItem>;
|
=> ContextMenu.Items as AvaloniaList<MenuItem>;
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class DataGridTemplateColumnExt : DataGridTemplateColumn
|
|
||||||
{
|
|
||||||
public event EventHandler<DataGridCellContextMenuStripNeededEventArgs> CellContextMenuStripNeeded;
|
|
||||||
|
|
||||||
private static readonly ContextMenu ContextMenu = new();
|
|
||||||
private static readonly AvaloniaList<MenuItem> MenuItems = new();
|
|
||||||
|
|
||||||
public DataGridTemplateColumnExt()
|
|
||||||
{
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
|
||||||
ContextMenu.Items = MenuItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Cell_ContextRequested(object sender, ContextRequestedEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is DataGridCell cell && cell.DataContext is GridEntry entry)
|
|
||||||
{
|
|
||||||
var args = new DataGridCellContextMenuStripNeededEventArgs
|
|
||||||
{
|
|
||||||
Column = this,
|
|
||||||
GridEntry = entry,
|
|
||||||
ContextMenu = ContextMenu
|
|
||||||
};
|
|
||||||
args.ContextMenuItems.Clear();
|
|
||||||
|
|
||||||
CellContextMenuStripNeeded?.Invoke(sender, args);
|
|
||||||
|
|
||||||
e.Handled = args.ContextMenuItems.Count == 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IControl GenerateElement(DataGridCell cell, object dataItem)
|
|
||||||
{
|
|
||||||
if (cell.ContextMenu is null)
|
|
||||||
{
|
|
||||||
cell.ContextRequested += Cell_ContextRequested;
|
|
||||||
cell.ContextMenu = ContextMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.GenerateElement(cell, dataItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
60
Source/LibationAvalonia/Controls/DataGridMyRatingColumn.cs
Normal file
60
Source/LibationAvalonia/Controls/DataGridMyRatingColumn.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using DataLayer;
|
||||||
|
|
||||||
|
namespace LibationAvalonia.Controls
|
||||||
|
{
|
||||||
|
public class DataGridMyRatingColumn : DataGridBoundColumn
|
||||||
|
{
|
||||||
|
private static Rating DefaultRating => new Rating(0, 0, 0);
|
||||||
|
public DataGridMyRatingColumn()
|
||||||
|
{
|
||||||
|
BindingTarget = MyRatingCellEditor.RatingProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IControl GenerateElement(DataGridCell cell, object dataItem)
|
||||||
|
{
|
||||||
|
var myRatingElement = new MyRatingCellEditor
|
||||||
|
{
|
||||||
|
Name = "CellMyRatingDisplay",
|
||||||
|
IsEditingMode = false
|
||||||
|
};
|
||||||
|
|
||||||
|
ToolTip.SetTip(myRatingElement, "Click to change ratings");
|
||||||
|
cell?.AttachContextMenu();
|
||||||
|
|
||||||
|
if (Binding != null)
|
||||||
|
{
|
||||||
|
myRatingElement.Bind(BindingTarget, Binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
return myRatingElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IControl GenerateEditingElementDirect(DataGridCell cell, object dataItem)
|
||||||
|
{
|
||||||
|
var myRatingElement = new MyRatingCellEditor
|
||||||
|
{
|
||||||
|
Name = "CellMyRatingEditor",
|
||||||
|
IsEditingMode = true
|
||||||
|
};
|
||||||
|
|
||||||
|
return myRatingElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override object PrepareCellForEdit(IControl editingElement, RoutedEventArgs editingEventArgs)
|
||||||
|
=> editingElement is MyRatingCellEditor myRating
|
||||||
|
? myRating.Rating
|
||||||
|
: DefaultRating;
|
||||||
|
|
||||||
|
protected override void CancelCellEdit(IControl editingElement, object uneditedValue)
|
||||||
|
{
|
||||||
|
if (editingElement is MyRatingCellEditor myRating)
|
||||||
|
{
|
||||||
|
var uneditedRating = uneditedValue as Rating;
|
||||||
|
myRating.Rating = uneditedRating ?? DefaultRating;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +0,0 @@
|
|||||||
<DataGridTemplateColumn xmlns="https://github.com/avaloniaui"
|
|
||||||
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"
|
|
||||||
x:Class="LibationAvalonia.Controls.DataGridTemplateColumnExt">
|
|
||||||
|
|
||||||
</DataGridTemplateColumn>
|
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace LibationAvalonia.Controls
|
||||||
|
{
|
||||||
|
public partial class DataGridTemplateColumnExt : DataGridTemplateColumn
|
||||||
|
{
|
||||||
|
protected override IControl GenerateElement(DataGridCell cell, object dataItem)
|
||||||
|
{
|
||||||
|
cell?.AttachContextMenu();
|
||||||
|
return base.GenerateElement(cell, dataItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml
Normal file
54
Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
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="115" d:DesignHeight="80"
|
||||||
|
x:Class="LibationAvalonia.Controls.MyRatingCellEditor">
|
||||||
|
|
||||||
|
<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>
|
||||||
|
</Grid.Styles>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="0" Grid.Row="0" Name="tblockOverall" Text="Overall:" />
|
||||||
|
<TextBlock Grid.Column="0" Grid.Row="1" Name="tblockPerform" Text="Perform:" />
|
||||||
|
<TextBlock Grid.Column="0" Grid.Row="2" Name="tblockStory" Text="Story:" />
|
||||||
|
|
||||||
|
<Panel Background="Transparent" PointerExited="Panel_PointerExited" Grid.Column="1" Grid.Row="0">
|
||||||
|
<StackPanel Name="panelOverall" Orientation="Horizontal">
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
</StackPanel>
|
||||||
|
</Panel>
|
||||||
|
|
||||||
|
<Panel Background="Transparent" PointerExited="Panel_PointerExited" Grid.Column="1" Grid.Row="1">
|
||||||
|
<StackPanel Name="panelPerform" Orientation="Horizontal">
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
</StackPanel>
|
||||||
|
</Panel>
|
||||||
|
|
||||||
|
<Panel Background="Transparent" PointerExited="Panel_PointerExited" Grid.Column="1" Grid.Row="2">
|
||||||
|
<StackPanel Name="panelStory" Orientation="Horizontal">
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
|
||||||
|
</StackPanel>
|
||||||
|
</Panel>
|
||||||
|
</Grid>
|
||||||
|
</Panel>
|
||||||
|
</UserControl>
|
||||||
108
Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs
Normal file
108
Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using DataLayer;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace LibationAvalonia.Controls
|
||||||
|
{
|
||||||
|
public partial class MyRatingCellEditor : UserControl
|
||||||
|
{
|
||||||
|
private const string SOLID_STAR = "★";
|
||||||
|
private const string HOLLOW_STAR = "☆";
|
||||||
|
|
||||||
|
public static readonly StyledProperty<Rating> RatingProperty =
|
||||||
|
AvaloniaProperty.Register<MyRatingCellEditor, Rating>(nameof(Rating));
|
||||||
|
|
||||||
|
public bool IsEditingMode { get; set; }
|
||||||
|
public Rating Rating { get => GetValue(RatingProperty); set => SetValue(RatingProperty, value); }
|
||||||
|
|
||||||
|
public MyRatingCellEditor()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
if (Design.IsDesignMode)
|
||||||
|
Rating = new Rating(5, 4, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||||
|
{
|
||||||
|
if (change.Property.Name == nameof(Rating) && Rating is not null)
|
||||||
|
{
|
||||||
|
var blankValue = IsEditingMode ? HOLLOW_STAR : string.Empty;
|
||||||
|
|
||||||
|
int rating = 0;
|
||||||
|
foreach (TextBlock star in panelOverall.Children)
|
||||||
|
star.Tag = star.Text = Rating.OverallRating > rating++ ? SOLID_STAR : blankValue;
|
||||||
|
|
||||||
|
rating = 0;
|
||||||
|
foreach (TextBlock star in panelPerform.Children)
|
||||||
|
star.Tag = star.Text = Rating.PerformanceRating > rating++ ? SOLID_STAR : blankValue;
|
||||||
|
|
||||||
|
rating = 0;
|
||||||
|
foreach (TextBlock star in panelStory.Children)
|
||||||
|
star.Tag = star.Text = Rating.StoryRating > rating++ ? SOLID_STAR : blankValue;
|
||||||
|
|
||||||
|
SetVisible();
|
||||||
|
}
|
||||||
|
base.OnPropertyChanged(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetVisible()
|
||||||
|
{
|
||||||
|
ratingsGrid.IsEnabled = IsEditingMode;
|
||||||
|
tblockOverall.IsVisible = panelOverall.IsVisible = IsEditingMode || Rating?.OverallRating > 0;
|
||||||
|
tblockPerform.IsVisible = panelPerform.IsVisible = IsEditingMode || Rating?.PerformanceRating > 0;
|
||||||
|
tblockStory.IsVisible = panelStory.IsVisible = IsEditingMode || Rating?.StoryRating > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Panel_PointerExited(object sender, Avalonia.Input.PointerEventArgs e)
|
||||||
|
{
|
||||||
|
var panel = sender as Panel;
|
||||||
|
var stackPanel = panel.Children.OfType<StackPanel>().Single();
|
||||||
|
|
||||||
|
//Restore defaults
|
||||||
|
foreach (TextBlock child in stackPanel.Children)
|
||||||
|
child.Text = (string)child.Tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Star_PointerEntered(object sender, Avalonia.Input.PointerEventArgs e)
|
||||||
|
{
|
||||||
|
var thisTbox = sender as TextBlock;
|
||||||
|
var stackPanel = thisTbox.Parent as StackPanel;
|
||||||
|
var star = SOLID_STAR;
|
||||||
|
|
||||||
|
foreach (TextBlock child in stackPanel.Children)
|
||||||
|
{
|
||||||
|
child.Text = star;
|
||||||
|
if (child == thisTbox) star = HOLLOW_STAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Star_Tapped(object sender, Avalonia.Input.TappedEventArgs e)
|
||||||
|
{
|
||||||
|
var overall = Rating.OverallRating;
|
||||||
|
var perform = Rating.PerformanceRating;
|
||||||
|
var story = Rating.StoryRating;
|
||||||
|
|
||||||
|
var thisTbox = sender as TextBlock;
|
||||||
|
var stackPanel = thisTbox.Parent as StackPanel;
|
||||||
|
|
||||||
|
int newRatingValue = 0;
|
||||||
|
foreach (var tbox in stackPanel.Children)
|
||||||
|
{
|
||||||
|
newRatingValue++;
|
||||||
|
if (tbox == thisTbox) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stackPanel == panelOverall)
|
||||||
|
overall = newRatingValue;
|
||||||
|
else if (stackPanel == panelPerform)
|
||||||
|
perform = newRatingValue;
|
||||||
|
else if (stackPanel == panelStory)
|
||||||
|
story = newRatingValue;
|
||||||
|
|
||||||
|
if (overall + perform + story == 0f) return;
|
||||||
|
|
||||||
|
Rating = new Rating(overall, perform, story);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -131,7 +131,7 @@ namespace LibationAvalonia.Dialogs
|
|||||||
var selectedFiles = await StorageProvider.OpenFilePickerAsync(openFileDialogOptions);
|
var selectedFiles = await StorageProvider.OpenFilePickerAsync(openFileDialogOptions);
|
||||||
var selectedFile = selectedFiles.SingleOrDefault();
|
var selectedFile = selectedFiles.SingleOrDefault();
|
||||||
|
|
||||||
if (!selectedFile.TryGetUri(out var uri)) return;
|
if (selectedFile?.TryGetUri(out var uri) is not true) return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -291,7 +291,7 @@ namespace LibationAvalonia.Dialogs
|
|||||||
|
|
||||||
var selectedFile = await StorageProvider.SaveFilePickerAsync(options);
|
var selectedFile = await StorageProvider.SaveFilePickerAsync(options);
|
||||||
|
|
||||||
if (!selectedFile.TryGetUri(out var uri)) return;
|
if (selectedFile?.TryGetUri(out var uri) is not true) return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@ -51,7 +51,7 @@ namespace LibationAvalonia.Dialogs
|
|||||||
{
|
{
|
||||||
Title = $"Save Sover Image",
|
Title = $"Save Sover Image",
|
||||||
SuggestedStartLocation = new Avalonia.Platform.Storage.FileIO.BclStorageFolder(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)),
|
SuggestedStartLocation = new Avalonia.Platform.Storage.FileIO.BclStorageFolder(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)),
|
||||||
SuggestedFileName = $"{PictureFileName}.jpg",
|
SuggestedFileName = PictureFileName,
|
||||||
DefaultExtension = "jpg",
|
DefaultExtension = "jpg",
|
||||||
ShowOverwritePrompt = true,
|
ShowOverwritePrompt = true,
|
||||||
FileTypeChoices = new FilePickerFileType[]
|
FileTypeChoices = new FilePickerFileType[]
|
||||||
@ -62,7 +62,7 @@ namespace LibationAvalonia.Dialogs
|
|||||||
|
|
||||||
var selectedFile = await StorageProvider.SaveFilePickerAsync(options);
|
var selectedFile = await StorageProvider.SaveFilePickerAsync(options);
|
||||||
|
|
||||||
if (!selectedFile.TryGetUri(out var uri)) return;
|
if (selectedFile?.TryGetUri(out var uri) is not true) return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d" d:DesignWidth="950" d:DesignHeight="550"
|
mc:Ignorable="d" d:DesignWidth="950" d:DesignHeight="650"
|
||||||
MinWidth="950" MinHeight="550"
|
MinWidth="950" MinHeight="650"
|
||||||
MaxWidth="950" MaxHeight="550"
|
MaxWidth="950" MaxHeight="650"
|
||||||
x:Class="LibationAvalonia.Dialogs.SearchSyntaxDialog"
|
x:Class="LibationAvalonia.Dialogs.SearchSyntaxDialog"
|
||||||
Title="Filter Options"
|
Title="Filter Options"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
|
|||||||
@ -13,8 +13,6 @@ namespace LibationAvalonia
|
|||||||
{
|
{
|
||||||
static class Program
|
static class Program
|
||||||
{
|
{
|
||||||
private static string EXE_DIR = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
|
|
||||||
|
|
||||||
static void Main()
|
static void Main()
|
||||||
{
|
{
|
||||||
//***********************************************//
|
//***********************************************//
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
using Avalonia.Media;
|
using ApplicationServices;
|
||||||
|
using Avalonia.Media;
|
||||||
using DataLayer;
|
using DataLayer;
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
|
using FileLiberator;
|
||||||
using LibationFileManager;
|
using LibationFileManager;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using System;
|
using System;
|
||||||
@ -8,6 +10,7 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace LibationAvalonia.ViewModels
|
namespace LibationAvalonia.ViewModels
|
||||||
{
|
{
|
||||||
@ -42,7 +45,21 @@ namespace LibationAvalonia.ViewModels
|
|||||||
public string Misc { get; protected set; }
|
public string Misc { get; protected set; }
|
||||||
public string Description { get; protected set; }
|
public string Description { get; protected set; }
|
||||||
public string ProductRating { get; protected set; }
|
public string ProductRating { get; protected set; }
|
||||||
public string MyRating { get; protected set; }
|
public string MyRatingString => MyRating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
||||||
|
protected Rating _myRating;
|
||||||
|
public Rating MyRating
|
||||||
|
{
|
||||||
|
get => _myRating;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_myRating != value
|
||||||
|
&& value.OverallRating != 0
|
||||||
|
&& updateReviewTask?.IsCompleted is not false)
|
||||||
|
{
|
||||||
|
updateReviewTask = UpdateRating(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected bool? _remove = false;
|
protected bool? _remove = false;
|
||||||
public abstract bool? Remove { get; set; }
|
public abstract bool? Remove { get; set; }
|
||||||
@ -56,6 +73,23 @@ namespace LibationAvalonia.ViewModels
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region User rating
|
||||||
|
|
||||||
|
private Task updateReviewTask;
|
||||||
|
private async Task UpdateRating(Rating rating)
|
||||||
|
{
|
||||||
|
var api = await LibraryBook.GetApiAsync();
|
||||||
|
|
||||||
|
if (await api.ReviewAsync(Book.AudibleProductId, (int)rating.OverallRating, (int)rating.PerformanceRating, (int)rating.StoryRating))
|
||||||
|
{
|
||||||
|
_myRating = rating;
|
||||||
|
LibraryBook.Book.UpdateUserDefinedItem(Book.UserDefinedItem.Tags, Book.UserDefinedItem.BookStatus, Book.UserDefinedItem.PdfStatus, rating);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.RaisePropertyChanged(nameof(MyRating));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Sorting
|
#region Sorting
|
||||||
|
|
||||||
public GridEntry() => _memberValues = CreateMemberValueDictionary();
|
public GridEntry() => _memberValues = CreateMemberValueDictionary();
|
||||||
|
|||||||
@ -65,7 +65,9 @@ namespace LibationAvalonia.ViewModels
|
|||||||
Title = Book.Title;
|
Title = Book.Title;
|
||||||
Series = Book.SeriesNames();
|
Series = Book.SeriesNames();
|
||||||
Length = Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min";
|
Length = Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min";
|
||||||
MyRating = Book.UserDefinedItem.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
//Ratings are changed using Update(), which is a problem for Avalonia data bindings because
|
||||||
|
//the reference doesn't change. Clone the rating so that it updates within Avalonia properly.
|
||||||
|
_myRating = new Rating(Book.UserDefinedItem.Rating.OverallRating, Book.UserDefinedItem.Rating.PerformanceRating, Book.UserDefinedItem.Rating.StoryRating);
|
||||||
PurchaseDate = libraryBook.DateAdded.ToString("d");
|
PurchaseDate = libraryBook.DateAdded.ToString("d");
|
||||||
ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
||||||
Authors = Book.AuthorNames();
|
Authors = Book.AuthorNames();
|
||||||
|
|||||||
@ -10,6 +10,8 @@ using ApplicationServices;
|
|||||||
using AudibleUtilities;
|
using AudibleUtilities;
|
||||||
using LibationAvalonia.Dialogs.Login;
|
using LibationAvalonia.Dialogs.Login;
|
||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
|
using LibationSearchEngine;
|
||||||
|
using Octokit.Internal;
|
||||||
|
|
||||||
namespace LibationAvalonia.ViewModels
|
namespace LibationAvalonia.ViewModels
|
||||||
{
|
{
|
||||||
@ -41,6 +43,7 @@ namespace LibationAvalonia.ViewModels
|
|||||||
|
|
||||||
public ProductsDisplayViewModel()
|
public ProductsDisplayViewModel()
|
||||||
{
|
{
|
||||||
|
SearchEngineCommands.SearchEngineUpdated += SearchEngineCommands_SearchEngineUpdated;
|
||||||
GridEntries = new(SOURCE);
|
GridEntries = new(SOURCE);
|
||||||
GridEntries.Filter = CollectionFilter;
|
GridEntries.Filter = CollectionFilter;
|
||||||
|
|
||||||
@ -156,15 +159,30 @@ namespace LibationAvalonia.ViewModels
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(searchString)) return null;
|
if (string.IsNullOrEmpty(searchString)) return null;
|
||||||
|
|
||||||
var SearchResults = SearchEngineCommands.Search(searchString);
|
var searchResultSet = SearchEngineCommands.Search(searchString);
|
||||||
|
|
||||||
var booksFilteredIn = entries.BookEntries().Join(SearchResults.Docs, lbe => lbe.AudibleProductId, d => d.ProductId, (lbe, d) => (GridEntry)lbe);
|
var booksFilteredIn = entries.BookEntries().Join(searchResultSet.Docs, lbe => lbe.AudibleProductId, d => d.ProductId, (lbe, d) => (GridEntry)lbe);
|
||||||
|
|
||||||
//Find all series containing children that match the search criteria
|
//Find all series containing children that match the search criteria
|
||||||
var seriesFilteredIn = entries.SeriesEntries().Where(s => s.Children.Join(SearchResults.Docs, lbe => lbe.AudibleProductId, d => d.ProductId, (lbe, d) => lbe).Any());
|
var seriesFilteredIn = entries.SeriesEntries().Where(s => s.Children.Join(searchResultSet.Docs, lbe => lbe.AudibleProductId, d => d.ProductId, (lbe, d) => lbe).Any());
|
||||||
|
|
||||||
return booksFilteredIn.Concat(seriesFilteredIn).ToList();
|
return booksFilteredIn.Concat(seriesFilteredIn).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void SearchEngineCommands_SearchEngineUpdated(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var filterResults = QueryResults(SOURCE, FilterString);
|
||||||
|
|
||||||
|
if (filterResults is not null && FilteredInGridEntries.Intersect(filterResults).Count() != FilteredInGridEntries.Count)
|
||||||
|
{
|
||||||
|
FilteredInGridEntries = filterResults;
|
||||||
|
|
||||||
|
if (GridEntries.IsEditingItem)
|
||||||
|
GridEntries.CommitEdit();
|
||||||
|
|
||||||
|
await Dispatcher.UIThread.InvokeAsync(GridEntries.Refresh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using Avalonia.Media;
|
using DataLayer;
|
||||||
using DataLayer;
|
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using System;
|
using System;
|
||||||
@ -69,7 +68,9 @@ namespace LibationAvalonia.ViewModels
|
|||||||
|
|
||||||
Title = Book.Title;
|
Title = Book.Title;
|
||||||
Series = Book.SeriesNames();
|
Series = Book.SeriesNames();
|
||||||
MyRating = Book.UserDefinedItem.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
//Ratings are changed using Update(), which is a problem for Avalonia data bindings because
|
||||||
|
//the reference doesn't change. Clone the rating so that it updates within Avalonia properly.
|
||||||
|
_myRating = new Rating(Book.UserDefinedItem.Rating.OverallRating, Book.UserDefinedItem.Rating.PerformanceRating, Book.UserDefinedItem.Rating.StoryRating);
|
||||||
ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
||||||
Authors = Book.AuthorNames();
|
Authors = Book.AuthorNames();
|
||||||
Narrators = Book.NarratorNames();
|
Narrators = Book.NarratorNames();
|
||||||
|
|||||||
@ -2,43 +2,24 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using Dinah.Core;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace LibationAvalonia.Views
|
namespace LibationAvalonia.Views
|
||||||
{
|
{
|
||||||
//DONE
|
|
||||||
public partial class MainWindow
|
public partial class MainWindow
|
||||||
{
|
{
|
||||||
private System.ComponentModel.BackgroundWorker updateCountsBw = new();
|
private Task updateCountsTask;
|
||||||
private void Configure_BackupCounts()
|
private void Configure_BackupCounts()
|
||||||
{
|
{
|
||||||
Load += setBackupCounts;
|
Load += setBackupCounts;
|
||||||
LibraryCommands.LibrarySizeChanged += setBackupCounts;
|
LibraryCommands.LibrarySizeChanged += setBackupCounts;
|
||||||
LibraryCommands.BookUserDefinedItemCommitted += setBackupCounts;
|
LibraryCommands.BookUserDefinedItemCommitted += setBackupCounts;
|
||||||
|
|
||||||
updateCountsBw.DoWork += UpdateCountsBw_DoWork;
|
|
||||||
updateCountsBw.RunWorkerCompleted += updateBottomNumbersAsync;
|
|
||||||
}
|
}
|
||||||
private bool runBackupCountsAgain;
|
|
||||||
private void setBackupCounts(object _, object __)
|
private void setBackupCounts(object _, object __)
|
||||||
{
|
{
|
||||||
runBackupCountsAgain = true;
|
if (updateCountsTask?.IsCompleted is not false)
|
||||||
|
updateCountsTask = Dispatcher.UIThread.InvokeAsync(() => _viewModel.LibraryStats = LibraryCommands.GetCounts());
|
||||||
if (!updateCountsBw.IsBusy)
|
|
||||||
updateCountsBw.RunWorkerAsync();
|
|
||||||
}
|
|
||||||
private void UpdateCountsBw_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
|
|
||||||
{
|
|
||||||
while (runBackupCountsAgain)
|
|
||||||
{
|
|
||||||
runBackupCountsAgain = false;
|
|
||||||
e.Result = LibraryCommands.GetCounts();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateBottomNumbersAsync(object _, System.ComponentModel.RunWorkerCompletedEventArgs e)
|
|
||||||
{
|
|
||||||
_viewModel.LibraryStats = e.Result as LibraryCommands.LibraryStats;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ namespace LibationAvalonia.Views
|
|||||||
|
|
||||||
var selectedFile = await StorageProvider.SaveFilePickerAsync(options);
|
var selectedFile = await StorageProvider.SaveFilePickerAsync(options);
|
||||||
|
|
||||||
if (!selectedFile.TryGetUri(out var uri)) return;
|
if (selectedFile?.TryGetUri(out var uri) is not true) return;
|
||||||
|
|
||||||
var ext = System.IO.Path.GetExtension(uri.LocalPath);
|
var ext = System.IO.Path.GetExtension(uri.LocalPath);
|
||||||
switch (ext)
|
switch (ext)
|
||||||
|
|||||||
@ -18,7 +18,7 @@ namespace LibationAvalonia.Views
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async void setLiberatedVisibleMenuItemAsync(object _, object __)
|
private async void setLiberatedVisibleMenuItemAsync(object _, object __)
|
||||||
=> await Task.Run(setLiberatedVisibleMenuItem);
|
=> await Dispatcher.UIThread.InvokeAsync(setLiberatedVisibleMenuItem);
|
||||||
|
|
||||||
public void liberateVisible(object sender, Avalonia.Interactivity.RoutedEventArgs args)
|
public void liberateVisible(object sender, Avalonia.Interactivity.RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
@ -114,7 +114,7 @@ namespace LibationAvalonia.Views
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var bulkSetStatus = new BulkSetDownloadStatus(_viewModel.ProductsDisplay.GetVisibleBookEntries(), dialog.SetDownloaded, dialog.SetNotDownloaded);
|
var bulkSetStatus = new BulkSetDownloadStatus(_viewModel.ProductsDisplay.GetVisibleBookEntries(), dialog.SetDownloaded, dialog.SetNotDownloaded);
|
||||||
var count = await Task.Run(() => bulkSetStatus.Discover());
|
var count = await Task.Run(bulkSetStatus.Discover);
|
||||||
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return;
|
return;
|
||||||
@ -154,7 +154,7 @@ namespace LibationAvalonia.Views
|
|||||||
{
|
{
|
||||||
_viewModel.VisibleCount = qty;
|
_viewModel.VisibleCount = qty;
|
||||||
|
|
||||||
await Task.Run(setLiberatedVisibleMenuItem);
|
await Dispatcher.UIThread.InvokeAsync(setLiberatedVisibleMenuItem);
|
||||||
}
|
}
|
||||||
void setLiberatedVisibleMenuItem()
|
void setLiberatedVisibleMenuItem()
|
||||||
=> _viewModel.VisibleNotLiberated
|
=> _viewModel.VisibleNotLiberated
|
||||||
|
|||||||
@ -20,7 +20,7 @@ namespace LibationAvalonia.Views
|
|||||||
{
|
{
|
||||||
public event EventHandler Load;
|
public event EventHandler Load;
|
||||||
public event EventHandler<List<LibraryBook>> LibraryLoaded;
|
public event EventHandler<List<LibraryBook>> LibraryLoaded;
|
||||||
private MainWindowViewModel _viewModel;
|
private readonly MainWindowViewModel _viewModel;
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
@ -77,7 +77,7 @@ namespace LibationAvalonia.Views
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
(string zipFile, UpgradeProperties upgradeProperties) = await Task.Run(() => downloadUpdate());
|
(string zipFile, UpgradeProperties upgradeProperties) = await Task.Run(downloadUpdate);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(zipFile) || !System.IO.File.Exists(zipFile))
|
if (string.IsNullOrEmpty(zipFile) || !System.IO.File.Exists(zipFile))
|
||||||
return;
|
return;
|
||||||
@ -135,11 +135,9 @@ namespace LibationAvalonia.Views
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
System.Net.Http.HttpClient cli = new();
|
System.Net.Http.HttpClient cli = new();
|
||||||
using (var fs = System.IO.File.OpenWrite(zipFile))
|
using var fs = System.IO.File.OpenWrite(zipFile);
|
||||||
{
|
using var dlStream = await cli.GetStreamAsync(new Uri(upgradeProperties.ZipUrl));
|
||||||
using (var dlStream = await cli.GetStreamAsync(new Uri(upgradeProperties.ZipUrl)))
|
await dlStream.CopyToAsync(fs);
|
||||||
await dlStream.CopyToAsync(fs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -154,8 +152,6 @@ namespace LibationAvalonia.Views
|
|||||||
var thisExe = Environment.ProcessPath;
|
var thisExe = Environment.ProcessPath;
|
||||||
var thisDir = System.IO.Path.GetDirectoryName(thisExe);
|
var thisDir = System.IO.Path.GetDirectoryName(thisExe);
|
||||||
|
|
||||||
var args = $"--input {zipFile.SurroundWithQuotes()} --output {thisDir.SurroundWithQuotes()} --executable {thisExe.SurroundWithQuotes()}";
|
|
||||||
|
|
||||||
var zipExtractor = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "ZipExtractor.exe");
|
var zipExtractor = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "ZipExtractor.exe");
|
||||||
|
|
||||||
System.IO.File.Copy("ZipExtractor.exe", zipExtractor, overwrite: true);
|
System.IO.File.Copy("ZipExtractor.exe", zipExtractor, overwrite: true);
|
||||||
@ -166,8 +162,16 @@ namespace LibationAvalonia.Views
|
|||||||
UseShellExecute = true,
|
UseShellExecute = true,
|
||||||
Verb = "runas",
|
Verb = "runas",
|
||||||
WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal,
|
WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal,
|
||||||
Arguments = args,
|
CreateNoWindow = true,
|
||||||
CreateNoWindow = true
|
ArgumentList =
|
||||||
|
{
|
||||||
|
"--input",
|
||||||
|
zipFile,
|
||||||
|
"--output",
|
||||||
|
thisDir,
|
||||||
|
"--executable",
|
||||||
|
thisExe
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
System.Diagnostics.Process.Start(psi);
|
System.Diagnostics.Process.Start(psi);
|
||||||
|
|||||||
@ -124,7 +124,7 @@
|
|||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}" Tapped="Description_Click" ToolTip.Tip="Click to see full description" >
|
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}" Tapped="Description_Click" ToolTip.Tip="Click to see full description" >
|
||||||
<TextBlock Text="{Binding Description}" />
|
<TextBlock Text="{Binding Description}" FontSize="11" VerticalAlignment="Top" />
|
||||||
</Panel>
|
</Panel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
@ -140,7 +140,7 @@
|
|||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt Width="120" Header="Product
Rating" CanUserSort="True" SortMemberPath="ProductRating" ClipboardContentBinding="{Binding ProductRating}">
|
<controls:DataGridTemplateColumnExt Width="115" Header="Product
Rating" CanUserSort="True" SortMemberPath="ProductRating" ClipboardContentBinding="{Binding ProductRating}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
||||||
@ -160,15 +160,7 @@
|
|||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt Width="120" Header="My Rating" CanUserSort="True" SortMemberPath="MyRating" ClipboardContentBinding="{Binding MyRating}">
|
<controls:DataGridMyRatingColumn IsReadOnly="false" Width="115" Header="My Rating" CanUserSort="True" SortMemberPath="MyRating" ClipboardContentBinding="{Binding MyRatingString}" Binding="{Binding MyRating, Mode=TwoWay}" />
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
|
||||||
<TextBlock Text="{Binding MyRating}" TextWrapping="NoWrap" FontSize="11" />
|
|
||||||
</Panel>
|
|
||||||
</DataTemplate>
|
|
||||||
</DataGridTemplateColumn.CellTemplate>
|
|
||||||
</controls:DataGridTemplateColumnExt>
|
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt Width="135" Header="Misc" CanUserSort="True" SortMemberPath="Misc" ClipboardContentBinding="{Binding Misc}">
|
<controls:DataGridTemplateColumnExt Width="135" Header="Misc" CanUserSort="True" SortMemberPath="Misc" ClipboardContentBinding="{Binding Misc}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
|
|||||||
@ -71,6 +71,7 @@ namespace LibationAvalonia.Views
|
|||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
|
||||||
productsGrid = this.FindControl<DataGrid>(nameof(productsGrid));
|
productsGrid = this.FindControl<DataGrid>(nameof(productsGrid));
|
||||||
|
DataGridContextMenus.CellContextMenuStripNeeded += ProductsGrid_CellContextMenuStripNeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Cell Context Menu
|
#region Cell Context Menu
|
||||||
@ -121,7 +122,7 @@ namespace LibationAvalonia.Views
|
|||||||
var selectedFiles = await this.GetParentWindow().StorageProvider.OpenFilePickerAsync(openFileDialogOptions);
|
var selectedFiles = await this.GetParentWindow().StorageProvider.OpenFilePickerAsync(openFileDialogOptions);
|
||||||
var selectedFile = selectedFiles.SingleOrDefault();
|
var selectedFile = selectedFiles.SingleOrDefault();
|
||||||
|
|
||||||
if (selectedFile.TryGetUri(out var uri))
|
if (selectedFile?.TryGetUri(out var uri) is true)
|
||||||
FilePathCache.Insert(entry.AudibleProductId, uri.LocalPath);
|
FilePathCache.Insert(entry.AudibleProductId, uri.LocalPath);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -179,10 +180,6 @@ namespace LibationAvalonia.Views
|
|||||||
|
|
||||||
foreach (var column in productsGrid.Columns)
|
foreach (var column in productsGrid.Columns)
|
||||||
{
|
{
|
||||||
//Wire up column context menu
|
|
||||||
if (column is DataGridTemplateColumnExt tc)
|
|
||||||
tc.CellContextMenuStripNeeded += ProductsGrid_CellContextMenuStripNeeded;
|
|
||||||
|
|
||||||
var itemName = column.SortMemberPath;
|
var itemName = column.SortMemberPath;
|
||||||
|
|
||||||
if (itemName == nameof(GridEntry.Remove))
|
if (itemName == nameof(GridEntry.Remove))
|
||||||
|
|||||||
@ -90,8 +90,8 @@ namespace LibationSearchEngine
|
|||||||
|
|
||||||
["ProductRating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(),
|
["ProductRating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(),
|
||||||
["Rating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(),
|
["Rating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(),
|
||||||
["UserRating"] = lb => lb.Book.UserDefinedItem.Rating.OverallRating.ToLuceneString(),
|
["UserRating"] = lb => userOverallRating(lb.Book),
|
||||||
["MyRating"] = lb => lb.Book.UserDefinedItem.Rating.OverallRating.ToLuceneString()
|
["MyRating"] = lb => userOverallRating(lb.Book)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ namespace LibationSearchEngine
|
|||||||
var narrators = lb.Book.Narrators.Select(a => a.Name).ToArray();
|
var narrators = lb.Book.Narrators.Select(a => a.Name).ToArray();
|
||||||
return authors.Intersect(narrators).Any();
|
return authors.Intersect(narrators).Any();
|
||||||
}
|
}
|
||||||
|
private static string userOverallRating(Book book) => book.UserDefinedItem.Rating.OverallRating.ToLuceneString();
|
||||||
private static bool isLiberated(Book book) => book.UserDefinedItem.BookStatus == LiberatedStatus.Liberated;
|
private static bool isLiberated(Book book) => book.UserDefinedItem.BookStatus == LiberatedStatus.Liberated;
|
||||||
private static bool liberatedError(Book book) => book.UserDefinedItem.BookStatus == LiberatedStatus.Error;
|
private static bool liberatedError(Book book) => book.UserDefinedItem.BookStatus == LiberatedStatus.Error;
|
||||||
|
|
||||||
@ -150,10 +150,10 @@ namespace LibationSearchEngine
|
|||||||
stringIndexRules[ALL_NARRATOR_NAMES],
|
stringIndexRules[ALL_NARRATOR_NAMES],
|
||||||
stringIndexRules[ALL_SERIES_NAMES]
|
stringIndexRules[ALL_SERIES_NAMES]
|
||||||
};
|
};
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region get search fields. used for display in help
|
#region get search fields. used for display in help
|
||||||
public static IEnumerable<string> GetSearchIdFields()
|
public static IEnumerable<string> GetSearchIdFields()
|
||||||
{
|
{
|
||||||
foreach (var key in idIndexRules.Keys)
|
foreach (var key in idIndexRules.Keys)
|
||||||
yield return key;
|
yield return key;
|
||||||
@ -176,29 +176,29 @@ namespace LibationSearchEngine
|
|||||||
foreach (var key in numberIndexRules.Keys)
|
foreach (var key in numberIndexRules.Keys)
|
||||||
yield return key;
|
yield return key;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region create and update index
|
#region create and update index
|
||||||
/// <summary>create new. ie: full re-index</summary>
|
/// <summary>create new. ie: full re-index</summary>
|
||||||
public void CreateNewIndex(IEnumerable<LibraryBook> library, bool overwrite = true)
|
public void CreateNewIndex(IEnumerable<LibraryBook> library, bool overwrite = true)
|
||||||
{
|
{
|
||||||
// location of index/create the index
|
// location of index/create the index
|
||||||
using var index = getIndex();
|
using var index = getIndex();
|
||||||
var exists = IndexReader.IndexExists(index);
|
var exists = IndexReader.IndexExists(index);
|
||||||
var createNewIndex = overwrite || !exists;
|
var createNewIndex = overwrite || !exists;
|
||||||
|
|
||||||
// analyzer for tokenizing text. same analyzer should be used for indexing and searching
|
// analyzer for tokenizing text. same analyzer should be used for indexing and searching
|
||||||
using var analyzer = new StandardAnalyzer(Version);
|
using var analyzer = new StandardAnalyzer(Version);
|
||||||
using var ixWriter = new IndexWriter(index, analyzer, createNewIndex, IndexWriter.MaxFieldLength.UNLIMITED);
|
using var ixWriter = new IndexWriter(index, analyzer, createNewIndex, IndexWriter.MaxFieldLength.UNLIMITED);
|
||||||
foreach (var libraryBook in library)
|
foreach (var libraryBook in library)
|
||||||
{
|
{
|
||||||
var doc = createBookIndexDocument(libraryBook);
|
var doc = createBookIndexDocument(libraryBook);
|
||||||
ixWriter.AddDocument(doc);
|
ixWriter.AddDocument(doc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Long running. Use await Task.Run(() => UpdateBook(productId))</summary>
|
/// <summary>Long running. Use await Task.Run(() => UpdateBook(productId))</summary>
|
||||||
public void UpdateBook(LibationContext context, string productId)
|
public void UpdateBook(LibationContext context, string productId)
|
||||||
{
|
{
|
||||||
var libraryBook = context.GetLibraryBook_Flat_NoTracking(productId);
|
var libraryBook = context.GetLibraryBook_Flat_NoTracking(productId);
|
||||||
var term = new Term(_ID_, productId);
|
var term = new Term(_ID_, productId);
|
||||||
@ -206,12 +206,12 @@ namespace LibationSearchEngine
|
|||||||
var document = createBookIndexDocument(libraryBook);
|
var document = createBookIndexDocument(libraryBook);
|
||||||
var createNewIndex = false;
|
var createNewIndex = false;
|
||||||
|
|
||||||
using var index = getIndex();
|
using var index = getIndex();
|
||||||
using var analyzer = new StandardAnalyzer(Version);
|
using var analyzer = new StandardAnalyzer(Version);
|
||||||
using var ixWriter = new IndexWriter(index, analyzer, createNewIndex, IndexWriter.MaxFieldLength.UNLIMITED);
|
using var ixWriter = new IndexWriter(index, analyzer, createNewIndex, IndexWriter.MaxFieldLength.UNLIMITED);
|
||||||
ixWriter.DeleteDocuments(term);
|
ixWriter.DeleteDocuments(term);
|
||||||
ixWriter.AddDocument(document);
|
ixWriter.AddDocument(document);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Document createBookIndexDocument(LibraryBook libraryBook)
|
private static Document createBookIndexDocument(LibraryBook libraryBook)
|
||||||
{
|
{
|
||||||
@ -262,7 +262,7 @@ namespace LibationSearchEngine
|
|||||||
{
|
{
|
||||||
// fields are key value pairs. MULTIPLE FIELDS CAN POTENTIALLY HAVE THE SAME KEY.
|
// fields are key value pairs. MULTIPLE FIELDS CAN POTENTIALLY HAVE THE SAME KEY.
|
||||||
// ie: must remove old before adding new else will create unwanted duplicates.
|
// ie: must remove old before adding new else will create unwanted duplicates.
|
||||||
d.RemoveField(fieldName);
|
d.RemoveField(fieldName.ToLower());
|
||||||
d.AddAnalyzed(fieldName, newValue);
|
d.AddAnalyzed(fieldName, newValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -279,16 +279,34 @@ namespace LibationSearchEngine
|
|||||||
// fields are key value pairs. MULTIPLE FIELDS CAN POTENTIALLY HAVE THE SAME KEY.
|
// fields are key value pairs. MULTIPLE FIELDS CAN POTENTIALLY HAVE THE SAME KEY.
|
||||||
// ie: must remove old before adding new else will create unwanted duplicates.
|
// ie: must remove old before adding new else will create unwanted duplicates.
|
||||||
var v1 = isLiberated(book);
|
var v1 = isLiberated(book);
|
||||||
d.RemoveField("IsLiberated");
|
d.RemoveField("isliberated");
|
||||||
d.AddBool("IsLiberated", v1);
|
d.AddBool("IsLiberated", v1);
|
||||||
d.RemoveField("Liberated");
|
d.RemoveField("liberated");
|
||||||
d.AddBool("Liberated", v1);
|
d.AddBool("Liberated", v1);
|
||||||
|
|
||||||
var v2 = liberatedError(book);
|
var v2 = liberatedError(book);
|
||||||
d.RemoveField("LiberatedError");
|
d.RemoveField("liberatederror");
|
||||||
d.AddBool("LiberatedError", v2);
|
d.AddBool("LiberatedError", v2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
public void UpdateUserRatings(Book book)
|
||||||
|
=>updateDocument(
|
||||||
|
book.AudibleProductId,
|
||||||
|
d =>
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// TODO: better synonym handling. This is too easy to mess up
|
||||||
|
//
|
||||||
|
|
||||||
|
// fields are key value pairs. MULTIPLE FIELDS CAN POTENTIALLY HAVE THE SAME KEY.
|
||||||
|
// ie: must remove old before adding new else will create unwanted duplicates.
|
||||||
|
var v1 = userOverallRating(book);
|
||||||
|
d.RemoveField("userrating");
|
||||||
|
d.AddNotAnalyzed("UserRating", v1);
|
||||||
|
d.RemoveField("myrating");
|
||||||
|
d.AddNotAnalyzed("MyRating", v1);
|
||||||
|
});
|
||||||
|
|
||||||
private static void updateDocument(string productId, Action<Document> action)
|
private static void updateDocument(string productId, Action<Document> action)
|
||||||
{
|
{
|
||||||
var productTerm = new Term(_ID_, productId);
|
var productTerm = new Term(_ID_, productId);
|
||||||
@ -315,12 +333,12 @@ namespace LibationSearchEngine
|
|||||||
using var ixWriter = new IndexWriter(index, analyzer, createNewIndex, IndexWriter.MaxFieldLength.UNLIMITED);
|
using var ixWriter = new IndexWriter(index, analyzer, createNewIndex, IndexWriter.MaxFieldLength.UNLIMITED);
|
||||||
ixWriter.UpdateDocument(productTerm, document, analyzer);
|
ixWriter.UpdateDocument(productTerm, document, analyzer);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
// the workaround which allows displaying all books when query is empty
|
// the workaround which allows displaying all books when query is empty
|
||||||
public const string ALL_QUERY = "*:*";
|
public const string ALL_QUERY = "*:*";
|
||||||
|
|
||||||
#region search
|
#region search
|
||||||
public SearchResultSet Search(string searchString)
|
public SearchResultSet Search(string searchString)
|
||||||
{
|
{
|
||||||
Serilog.Log.Logger.Debug("original search string: {@DebugInfo}", new { searchString });
|
Serilog.Log.Logger.Debug("original search string: {@DebugInfo}", new { searchString });
|
||||||
@ -353,8 +371,8 @@ namespace LibationSearchEngine
|
|||||||
return searchString;
|
return searchString;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region format query string
|
#region format query string
|
||||||
private static string parseTag(string tagSearchString)
|
private static string parseTag(string tagSearchString)
|
||||||
{
|
{
|
||||||
var allMatches = LuceneRegex
|
var allMatches = LuceneRegex
|
||||||
.TagRegex
|
.TagRegex
|
||||||
@ -419,33 +437,33 @@ namespace LibationSearchEngine
|
|||||||
{
|
{
|
||||||
var defaultField = ALL;
|
var defaultField = ALL;
|
||||||
|
|
||||||
using var index = getIndex();
|
using var index = getIndex();
|
||||||
using var searcher = new IndexSearcher(index);
|
using var searcher = new IndexSearcher(index);
|
||||||
using var analyzer = new StandardAnalyzer(Version);
|
using var analyzer = new StandardAnalyzer(Version);
|
||||||
var query = analyzer.GetQuery(defaultField, searchString);
|
var query = analyzer.GetQuery(defaultField, searchString);
|
||||||
|
|
||||||
|
|
||||||
// lucene doesn't allow only negations. eg this returns nothing:
|
// lucene doesn't allow only negations. eg this returns nothing:
|
||||||
// -tags:hidden
|
// -tags:hidden
|
||||||
// work arounds: https://kb.ucla.edu/articles/pure-negation-query-in-lucene
|
// work arounds: https://kb.ucla.edu/articles/pure-negation-query-in-lucene
|
||||||
// HOWEVER, doing this to any other type of query can cause EVERYTHING to be a match unless "Occur" is carefully set
|
// HOWEVER, doing this to any other type of query can cause EVERYTHING to be a match unless "Occur" is carefully set
|
||||||
// this should really check that all leaf nodes are MUST_NOT
|
// this should really check that all leaf nodes are MUST_NOT
|
||||||
if (query is BooleanQuery boolQuery)
|
if (query is BooleanQuery boolQuery)
|
||||||
{
|
{
|
||||||
var occurs = getOccurs_recurs(boolQuery);
|
var occurs = getOccurs_recurs(boolQuery);
|
||||||
if (occurs.Any() && occurs.All(o => o == Occur.MUST_NOT))
|
if (occurs.Any() && occurs.All(o => o == Occur.MUST_NOT))
|
||||||
boolQuery.Add(new MatchAllDocsQuery(), Occur.MUST);
|
boolQuery.Add(new MatchAllDocsQuery(), Occur.MUST);
|
||||||
}
|
}
|
||||||
|
|
||||||
var docs = searcher
|
var docs = searcher
|
||||||
.Search(query, searcher.MaxDoc + 1)
|
.Search(query, searcher.MaxDoc + 1)
|
||||||
.ScoreDocs
|
.ScoreDocs
|
||||||
.Select(ds => new ScoreDocExplicit(searcher.Doc(ds.Doc), ds.Score))
|
.Select(ds => new ScoreDocExplicit(searcher.Doc(ds.Doc), ds.Score))
|
||||||
.ToList();
|
.ToList();
|
||||||
var queryString = query.ToString();
|
var queryString = query.ToString();
|
||||||
Serilog.Log.Logger.Debug("query: {@DebugInfo}", new { queryString });
|
Serilog.Log.Logger.Debug("query: {@DebugInfo}", new { queryString });
|
||||||
return new SearchResultSet(queryString, docs);
|
return new SearchResultSet(queryString, docs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<Occur> getOccurs_recurs(BooleanQuery query)
|
private IEnumerable<Occur> getOccurs_recurs(BooleanQuery query)
|
||||||
{
|
{
|
||||||
@ -477,9 +495,9 @@ namespace LibationSearchEngine
|
|||||||
// Serilog.Log.Logger.Debug($" [{f.Name}]={f.StringValue}");
|
// Serilog.Log.Logger.Debug($" [{f.Name}]={f.StringValue}");
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private static Directory getIndex() => FSDirectory.Open(SearchEngineDirectory);
|
private static Directory getIndex() => FSDirectory.Open(SearchEngineDirectory);
|
||||||
|
|
||||||
// not customizable. don't move to config
|
// not customizable. don't move to config
|
||||||
private static string SearchEngineDirectory { get; }
|
private static string SearchEngineDirectory { get; }
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
using DataLayer;
|
using ApplicationServices;
|
||||||
|
using DataLayer;
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using Dinah.Core.DataBinding;
|
using Dinah.Core.DataBinding;
|
||||||
using Dinah.Core.WindowsDesktop.Drawing;
|
using Dinah.Core.WindowsDesktop.Drawing;
|
||||||
|
using FileLiberator;
|
||||||
using LibationFileManager;
|
using LibationFileManager;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
@ -9,6 +11,7 @@ using System.Collections.Generic;
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace LibationWinForms.GridView
|
namespace LibationWinForms.GridView
|
||||||
{
|
{
|
||||||
@ -57,14 +60,44 @@ namespace LibationWinForms.GridView
|
|||||||
public string Misc { get; protected set; }
|
public string Misc { get; protected set; }
|
||||||
public string Description { get; protected set; }
|
public string Description { get; protected set; }
|
||||||
public string ProductRating { get; protected set; }
|
public string ProductRating { get; protected set; }
|
||||||
public string MyRating { get; protected set; }
|
protected Rating _myRating;
|
||||||
|
public Rating MyRating
|
||||||
|
{
|
||||||
|
get => _myRating;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_myRating != value
|
||||||
|
&& value.OverallRating != 0
|
||||||
|
&& updateReviewTask?.IsCompleted is not false)
|
||||||
|
{
|
||||||
|
updateReviewTask = UpdateRating(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
public abstract string DisplayTags { get; }
|
public abstract string DisplayTags { get; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Sorting
|
#region User rating
|
||||||
|
|
||||||
public GridEntry() => _memberValues = CreateMemberValueDictionary();
|
private Task updateReviewTask;
|
||||||
|
private async Task UpdateRating(Rating rating)
|
||||||
|
{
|
||||||
|
var api = await LibraryBook.GetApiAsync();
|
||||||
|
|
||||||
|
if (await api.ReviewAsync(Book.AudibleProductId, (int)rating.OverallRating, (int)rating.PerformanceRating, (int)rating.StoryRating))
|
||||||
|
{
|
||||||
|
_myRating = rating;
|
||||||
|
LibraryBook.Book.UpdateUserDefinedItem(Book.UserDefinedItem.Tags, Book.UserDefinedItem.BookStatus, Book.UserDefinedItem.PdfStatus, rating);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.NotifyPropertyChanged(nameof(MyRating));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Sorting
|
||||||
|
|
||||||
|
public GridEntry() => _memberValues = CreateMemberValueDictionary();
|
||||||
|
|
||||||
// These methods are implementation of Dinah.Core.DataBinding.IMemberComparable
|
// These methods are implementation of Dinah.Core.DataBinding.IMemberComparable
|
||||||
// Used by GridEntryBindingList for all sorting
|
// Used by GridEntryBindingList for all sorting
|
||||||
|
|||||||
@ -80,7 +80,7 @@ namespace LibationWinForms.GridView
|
|||||||
Title = Book.Title;
|
Title = Book.Title;
|
||||||
Series = Book.SeriesNames();
|
Series = Book.SeriesNames();
|
||||||
Length = Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min";
|
Length = Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min";
|
||||||
MyRating = Book.UserDefinedItem.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
_myRating = Book.UserDefinedItem.Rating;
|
||||||
PurchaseDate = libraryBook.DateAdded.ToString("d");
|
PurchaseDate = libraryBook.DateAdded.ToString("d");
|
||||||
ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
||||||
Authors = Book.AuthorNames();
|
Authors = Book.AuthorNames();
|
||||||
|
|||||||
368
Source/LibationWinForms/GridView/MyRatingCellEditor.Designer.cs
generated
Normal file
368
Source/LibationWinForms/GridView/MyRatingCellEditor.Designer.cs
generated
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
namespace LibationWinForms.GridView
|
||||||
|
{
|
||||||
|
partial class MyRatingCellEditor
|
||||||
|
{
|
||||||
|
/// <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()
|
||||||
|
{
|
||||||
|
this.lblOverall = new System.Windows.Forms.Label();
|
||||||
|
this.lblPerform = new System.Windows.Forms.Label();
|
||||||
|
this.lblStory = new System.Windows.Forms.Label();
|
||||||
|
this.panelOverall = new System.Windows.Forms.Panel();
|
||||||
|
this.noBorderLabel1 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.noBorderLabel2 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.noBorderLabel3 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.noBorderLabel4 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.noBorderLabel5 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.panelPerform = new System.Windows.Forms.Panel();
|
||||||
|
this.noBorderLabel6 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.noBorderLabel7 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.noBorderLabel8 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.noBorderLabel9 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.noBorderLabel10 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.panelStory = new System.Windows.Forms.Panel();
|
||||||
|
this.noBorderLabel11 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.noBorderLabel12 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.noBorderLabel13 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.noBorderLabel14 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.noBorderLabel15 = new LibationWinForms.GridView.NoBorderLabel();
|
||||||
|
this.panelOverall.SuspendLayout();
|
||||||
|
this.panelPerform.SuspendLayout();
|
||||||
|
this.panelStory.SuspendLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// lblOverall
|
||||||
|
//
|
||||||
|
this.lblOverall.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||||
|
this.lblOverall.AutoSize = true;
|
||||||
|
this.lblOverall.Location = new System.Drawing.Point(0, 1);
|
||||||
|
this.lblOverall.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.lblOverall.Name = "lblOverall";
|
||||||
|
this.lblOverall.Size = new System.Drawing.Size(47, 15);
|
||||||
|
this.lblOverall.TabIndex = 6;
|
||||||
|
this.lblOverall.Text = "Overall:";
|
||||||
|
//
|
||||||
|
// lblPerform
|
||||||
|
//
|
||||||
|
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";
|
||||||
|
this.lblPerform.Size = new System.Drawing.Size(53, 15);
|
||||||
|
this.lblPerform.TabIndex = 8;
|
||||||
|
this.lblPerform.Text = "Perform:";
|
||||||
|
//
|
||||||
|
// lblStory
|
||||||
|
//
|
||||||
|
this.lblStory.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||||
|
this.lblStory.AutoSize = true;
|
||||||
|
this.lblStory.Location = new System.Drawing.Point(0, 31);
|
||||||
|
this.lblStory.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.lblStory.Name = "lblStory";
|
||||||
|
this.lblStory.Size = new System.Drawing.Size(37, 15);
|
||||||
|
this.lblStory.TabIndex = 10;
|
||||||
|
this.lblStory.Text = "Story:";
|
||||||
|
//
|
||||||
|
// panelOverall
|
||||||
|
//
|
||||||
|
this.panelOverall.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||||
|
this.panelOverall.Controls.Add(this.noBorderLabel1);
|
||||||
|
this.panelOverall.Controls.Add(this.noBorderLabel2);
|
||||||
|
this.panelOverall.Controls.Add(this.noBorderLabel3);
|
||||||
|
this.panelOverall.Controls.Add(this.noBorderLabel4);
|
||||||
|
this.panelOverall.Controls.Add(this.noBorderLabel5);
|
||||||
|
this.panelOverall.Location = new System.Drawing.Point(52, 4);
|
||||||
|
this.panelOverall.Name = "panelOverall";
|
||||||
|
this.panelOverall.Size = new System.Drawing.Size(50, 11);
|
||||||
|
this.panelOverall.TabIndex = 5;
|
||||||
|
//
|
||||||
|
// 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";
|
||||||
|
this.noBorderLabel1.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel1.TabIndex = 0;
|
||||||
|
this.noBorderLabel1.Text = "☆";
|
||||||
|
this.noBorderLabel1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel1.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel1.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// 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";
|
||||||
|
this.noBorderLabel2.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel2.TabIndex = 0;
|
||||||
|
this.noBorderLabel2.Text = "☆";
|
||||||
|
this.noBorderLabel2.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel2.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel2.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// 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";
|
||||||
|
this.noBorderLabel3.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel3.TabIndex = 0;
|
||||||
|
this.noBorderLabel3.Text = "☆";
|
||||||
|
this.noBorderLabel3.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel3.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel3.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// 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";
|
||||||
|
this.noBorderLabel4.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel4.TabIndex = 0;
|
||||||
|
this.noBorderLabel4.Text = "☆";
|
||||||
|
this.noBorderLabel4.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel4.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel4.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// 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";
|
||||||
|
this.noBorderLabel5.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel5.TabIndex = 0;
|
||||||
|
this.noBorderLabel5.Text = "☆";
|
||||||
|
this.noBorderLabel5.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel5.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel5.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// panelPerform
|
||||||
|
//
|
||||||
|
this.panelPerform.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||||
|
this.panelPerform.Controls.Add(this.noBorderLabel6);
|
||||||
|
this.panelPerform.Controls.Add(this.noBorderLabel7);
|
||||||
|
this.panelPerform.Controls.Add(this.noBorderLabel8);
|
||||||
|
this.panelPerform.Controls.Add(this.noBorderLabel9);
|
||||||
|
this.panelPerform.Controls.Add(this.noBorderLabel10);
|
||||||
|
this.panelPerform.Location = new System.Drawing.Point(52, 19);
|
||||||
|
this.panelPerform.Name = "panelPerform";
|
||||||
|
this.panelPerform.Size = new System.Drawing.Size(50, 11);
|
||||||
|
this.panelPerform.TabIndex = 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";
|
||||||
|
this.noBorderLabel6.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel6.TabIndex = 0;
|
||||||
|
this.noBorderLabel6.Text = "☆";
|
||||||
|
this.noBorderLabel6.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel6.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel6.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// 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";
|
||||||
|
this.noBorderLabel7.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel7.TabIndex = 0;
|
||||||
|
this.noBorderLabel7.Text = "☆";
|
||||||
|
this.noBorderLabel7.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel7.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel7.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// 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";
|
||||||
|
this.noBorderLabel8.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel8.TabIndex = 0;
|
||||||
|
this.noBorderLabel8.Text = "☆";
|
||||||
|
this.noBorderLabel8.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel8.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel8.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// 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";
|
||||||
|
this.noBorderLabel9.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel9.TabIndex = 0;
|
||||||
|
this.noBorderLabel9.Text = "☆";
|
||||||
|
this.noBorderLabel9.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel9.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel9.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// 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";
|
||||||
|
this.noBorderLabel10.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel10.TabIndex = 0;
|
||||||
|
this.noBorderLabel10.Text = "☆";
|
||||||
|
this.noBorderLabel10.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel10.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel10.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// panelStory
|
||||||
|
//
|
||||||
|
this.panelStory.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||||
|
this.panelStory.Controls.Add(this.noBorderLabel11);
|
||||||
|
this.panelStory.Controls.Add(this.noBorderLabel12);
|
||||||
|
this.panelStory.Controls.Add(this.noBorderLabel13);
|
||||||
|
this.panelStory.Controls.Add(this.noBorderLabel14);
|
||||||
|
this.panelStory.Controls.Add(this.noBorderLabel15);
|
||||||
|
this.panelStory.Location = new System.Drawing.Point(52, 34);
|
||||||
|
this.panelStory.Name = "panelStory";
|
||||||
|
this.panelStory.Size = new System.Drawing.Size(50, 11);
|
||||||
|
this.panelStory.TabIndex = 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";
|
||||||
|
this.noBorderLabel11.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel11.TabIndex = 0;
|
||||||
|
this.noBorderLabel11.Text = "☆";
|
||||||
|
this.noBorderLabel11.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel11.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel11.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// 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";
|
||||||
|
this.noBorderLabel12.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel12.TabIndex = 0;
|
||||||
|
this.noBorderLabel12.Text = "☆";
|
||||||
|
this.noBorderLabel12.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel12.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel12.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// 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";
|
||||||
|
this.noBorderLabel13.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel13.TabIndex = 0;
|
||||||
|
this.noBorderLabel13.Text = "☆";
|
||||||
|
this.noBorderLabel13.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel13.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel13.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// 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";
|
||||||
|
this.noBorderLabel14.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel14.TabIndex = 0;
|
||||||
|
this.noBorderLabel14.Text = "☆";
|
||||||
|
this.noBorderLabel14.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel14.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel14.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// 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";
|
||||||
|
this.noBorderLabel15.Size = new System.Drawing.Size(10, 11);
|
||||||
|
this.noBorderLabel15.TabIndex = 0;
|
||||||
|
this.noBorderLabel15.Text = "☆";
|
||||||
|
this.noBorderLabel15.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick);
|
||||||
|
this.noBorderLabel15.MouseEnter += new System.EventHandler(this.Star_MouseEnter);
|
||||||
|
this.noBorderLabel15.MouseLeave += new System.EventHandler(this.Star_MouseLeave);
|
||||||
|
//
|
||||||
|
// MyRatingCellEditor
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.Controls.Add(this.panelStory);
|
||||||
|
this.Controls.Add(this.panelPerform);
|
||||||
|
this.Controls.Add(this.lblStory);
|
||||||
|
this.Controls.Add(this.lblPerform);
|
||||||
|
this.Controls.Add(this.lblOverall);
|
||||||
|
this.Controls.Add(this.panelOverall);
|
||||||
|
this.Name = "MyRatingCellEditor";
|
||||||
|
this.Size = new System.Drawing.Size(110, 46);
|
||||||
|
this.panelOverall.ResumeLayout(false);
|
||||||
|
this.panelPerform.ResumeLayout(false);
|
||||||
|
this.panelStory.ResumeLayout(false);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
private System.Windows.Forms.Panel panelOverall;
|
||||||
|
private System.Windows.Forms.Label lblOverall;
|
||||||
|
private System.Windows.Forms.Label lblPerform;
|
||||||
|
private System.Windows.Forms.Label lblStory;
|
||||||
|
private NoBorderLabel noBorderLabel1;
|
||||||
|
private NoBorderLabel noBorderLabel5;
|
||||||
|
private NoBorderLabel noBorderLabel4;
|
||||||
|
private NoBorderLabel noBorderLabel3;
|
||||||
|
private NoBorderLabel noBorderLabel2;
|
||||||
|
private System.Windows.Forms.Panel panelPerform;
|
||||||
|
private NoBorderLabel noBorderLabel6;
|
||||||
|
private NoBorderLabel noBorderLabel7;
|
||||||
|
private NoBorderLabel noBorderLabel8;
|
||||||
|
private NoBorderLabel noBorderLabel9;
|
||||||
|
private NoBorderLabel noBorderLabel10;
|
||||||
|
private System.Windows.Forms.Panel panelStory;
|
||||||
|
private NoBorderLabel noBorderLabel11;
|
||||||
|
private NoBorderLabel noBorderLabel12;
|
||||||
|
private NoBorderLabel noBorderLabel13;
|
||||||
|
private NoBorderLabel noBorderLabel14;
|
||||||
|
private NoBorderLabel noBorderLabel15;
|
||||||
|
}
|
||||||
|
}
|
||||||
168
Source/LibationWinForms/GridView/MyRatingCellEditor.cs
Normal file
168
Source/LibationWinForms/GridView/MyRatingCellEditor.cs
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
using DataLayer;
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace LibationWinForms.GridView
|
||||||
|
{
|
||||||
|
public partial class MyRatingCellEditor : UserControl, IDataGridViewEditingControl
|
||||||
|
{
|
||||||
|
private const string SOLID_STAR = "★";
|
||||||
|
private const string HOLLOW_STAR = "☆";
|
||||||
|
|
||||||
|
private Rating _rating;
|
||||||
|
public Rating Rating
|
||||||
|
{
|
||||||
|
get => _rating;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_rating = value;
|
||||||
|
int rating = 0;
|
||||||
|
foreach (NoBorderLabel star in panelOverall.Controls)
|
||||||
|
star.Tag = star.Text = _rating.OverallRating > rating++ ? SOLID_STAR : HOLLOW_STAR;
|
||||||
|
|
||||||
|
rating = 0;
|
||||||
|
foreach (NoBorderLabel star in panelPerform.Controls)
|
||||||
|
star.Tag = star.Text = _rating.PerformanceRating > rating++ ? SOLID_STAR : HOLLOW_STAR;
|
||||||
|
|
||||||
|
rating = 0;
|
||||||
|
foreach (NoBorderLabel star in panelStory.Controls)
|
||||||
|
star.Tag = star.Text = _rating.StoryRating > rating++ ? SOLID_STAR : HOLLOW_STAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyRatingCellEditor()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Star_MouseEnter(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var thisTbox = sender as NoBorderLabel;
|
||||||
|
var panel = thisTbox.Parent as Panel;
|
||||||
|
var star = SOLID_STAR;
|
||||||
|
|
||||||
|
foreach (NoBorderLabel child in panel.Controls)
|
||||||
|
{
|
||||||
|
child.Text = star;
|
||||||
|
if (child == thisTbox) star = HOLLOW_STAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Star_MouseLeave(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var thisTbox = sender as NoBorderLabel;
|
||||||
|
var panel = thisTbox.Parent as Panel;
|
||||||
|
|
||||||
|
//Artifically shrink rectangle to guarantee mouse is outside when exiting from the left (negative X)
|
||||||
|
var clientPt = panel.PointToClient(MousePosition);
|
||||||
|
var rect = new Rectangle(0, 0, panel.ClientRectangle.Width - 2, panel.ClientRectangle.Height);
|
||||||
|
if (!rect.Contains(clientPt.X - 2, clientPt.Y))
|
||||||
|
{
|
||||||
|
//Restore defaults
|
||||||
|
foreach (NoBorderLabel child in panel.Controls)
|
||||||
|
child.Text = (string)child.Tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Star_MouseClick(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
var overall = Rating.OverallRating;
|
||||||
|
var perform = Rating.PerformanceRating;
|
||||||
|
var story = Rating.StoryRating;
|
||||||
|
|
||||||
|
var thisTbox = sender as NoBorderLabel;
|
||||||
|
var panel = thisTbox.Parent as Panel;
|
||||||
|
|
||||||
|
int newRatingValue = 0;
|
||||||
|
foreach (var child in panel.Controls)
|
||||||
|
{
|
||||||
|
newRatingValue++;
|
||||||
|
if (child == thisTbox) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (panel == panelOverall)
|
||||||
|
overall = newRatingValue;
|
||||||
|
else if (panel == panelPerform)
|
||||||
|
perform = newRatingValue;
|
||||||
|
else if (panel == panelStory)
|
||||||
|
story = newRatingValue;
|
||||||
|
|
||||||
|
if (overall + perform + story == 0f) return;
|
||||||
|
|
||||||
|
var newRating = new Rating(overall, perform, story);
|
||||||
|
|
||||||
|
if (newRating == Rating) return;
|
||||||
|
|
||||||
|
Rating = newRating;
|
||||||
|
EditingControlValueChanged = true;
|
||||||
|
EditingControlDataGridView.NotifyCurrentCellDirty(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnKeyDown(KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.KeyCode == Keys.Escape)
|
||||||
|
{
|
||||||
|
EditingControlDataGridView.RefreshEdit();
|
||||||
|
EditingControlDataGridView.CancelEdit();
|
||||||
|
EditingControlDataGridView.CurrentCell.DetachEditingControl();
|
||||||
|
EditingControlDataGridView.CurrentCell = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
base.OnKeyDown(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IDataGridViewEditingControl
|
||||||
|
|
||||||
|
public DataGridView EditingControlDataGridView { get; set; }
|
||||||
|
public int EditingControlRowIndex { get; set; }
|
||||||
|
public bool EditingControlValueChanged { get; set; }
|
||||||
|
public object EditingControlFormattedValue { get => Rating; set { } }
|
||||||
|
public Cursor EditingPanelCursor => Cursor;
|
||||||
|
public bool RepositionEditingControlOnValueChange => false;
|
||||||
|
|
||||||
|
public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
|
||||||
|
{
|
||||||
|
Font = dataGridViewCellStyle.Font;
|
||||||
|
ForeColor = dataGridViewCellStyle.ForeColor;
|
||||||
|
BackColor = dataGridViewCellStyle.BackColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey) => keyData == Keys.Escape;
|
||||||
|
public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) => EditingControlFormattedValue;
|
||||||
|
public void PrepareEditingControlForEdit(bool selectAll) { }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NoBorderLabel : Panel
|
||||||
|
{
|
||||||
|
private string _text;
|
||||||
|
[Description("Label text"), Category("Data")]
|
||||||
|
[Browsable(true)]
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Always)]
|
||||||
|
[AllowNull]
|
||||||
|
public override string Text
|
||||||
|
{
|
||||||
|
get => _text;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_text = value;
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Description("X and Y offset for text drawing position. May be negative."), Category("Layout")]
|
||||||
|
[Browsable(true)]
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Always)]
|
||||||
|
public Point LabelOffset { get; set; }
|
||||||
|
protected override void OnPaint(PaintEventArgs e)
|
||||||
|
{
|
||||||
|
TextRenderer.DrawText(e, Text, this.Font, LabelOffset, this.ForeColor);
|
||||||
|
base.OnPaint(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
126
Source/LibationWinForms/GridView/MyRatingCellEditor.resx
Normal file
126
Source/LibationWinForms/GridView/MyRatingCellEditor.resx
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<root>
|
||||||
|
<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>
|
||||||
|
<metadata name="lblOverall.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="lblPerform.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="lblStory.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="panelOverall.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel1.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel2.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel3.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel4.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel5.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="panelPerform.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel6.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel7.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel8.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel9.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel10.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="panelStory.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel11.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel12.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel13.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel14.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="noBorderLabel15.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="$this.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
|
<value>True</value>
|
||||||
|
</metadata>
|
||||||
|
</root>
|
||||||
62
Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs
Normal file
62
Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
using DataLayer;
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace LibationWinForms.GridView
|
||||||
|
{
|
||||||
|
public class MyRatingGridViewColumn : DataGridViewColumn
|
||||||
|
{
|
||||||
|
public MyRatingGridViewColumn() : base(new MyRatingGridViewCell()) { }
|
||||||
|
|
||||||
|
public override DataGridViewCell CellTemplate
|
||||||
|
{
|
||||||
|
get => base.CellTemplate;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value is not MyRatingGridViewCell)
|
||||||
|
throw new InvalidCastException($"Must be a {nameof(MyRatingGridViewCell)}");
|
||||||
|
|
||||||
|
base.CellTemplate = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class MyRatingGridViewCell : DataGridViewTextBoxCell
|
||||||
|
{
|
||||||
|
private static Rating DefaultRating => new Rating(0, 0, 0);
|
||||||
|
public override object DefaultNewRowValue => DefaultRating;
|
||||||
|
public override Type EditType => typeof(MyRatingCellEditor);
|
||||||
|
public override Type ValueType => typeof(Rating);
|
||||||
|
|
||||||
|
public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
|
||||||
|
{
|
||||||
|
base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
|
||||||
|
|
||||||
|
var ctl = DataGridView.EditingControl as MyRatingCellEditor;
|
||||||
|
|
||||||
|
ctl.Rating = Value is Rating rating ? rating : DefaultRating;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
|
||||||
|
{
|
||||||
|
if (value is Rating rating)
|
||||||
|
{
|
||||||
|
ToolTipText = "Click to change ratings";
|
||||||
|
|
||||||
|
var starString = rating.ToStarString();
|
||||||
|
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, starString, starString, errorText, cellStyle, advancedBorderStyle, paintParts);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, string.Empty, string.Empty, errorText, cellStyle, advancedBorderStyle, paintParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)
|
||||||
|
=> value is Rating rating ? rating.ToStarString() : value?.ToString();
|
||||||
|
|
||||||
|
public override object ParseFormattedValue(object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter)
|
||||||
|
=> formattedValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -28,39 +28,39 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
this.components = new System.ComponentModel.Container();
|
this.components = new System.ComponentModel.Container();
|
||||||
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
|
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
|
||||||
this.gridEntryDataGridView = new System.Windows.Forms.DataGridView();
|
this.gridEntryDataGridView = new System.Windows.Forms.DataGridView();
|
||||||
this.removeGVColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn();
|
this.removeGVColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn();
|
||||||
this.liberateGVColumn = new LibationWinForms.GridView.LiberateDataGridViewImageButtonColumn();
|
this.liberateGVColumn = new LibationWinForms.GridView.LiberateDataGridViewImageButtonColumn();
|
||||||
this.coverGVColumn = new System.Windows.Forms.DataGridViewImageColumn();
|
this.coverGVColumn = new System.Windows.Forms.DataGridViewImageColumn();
|
||||||
this.titleGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
this.titleGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
this.authorsGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
this.authorsGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
this.narratorsGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
this.narratorsGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
this.lengthGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
this.lengthGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
this.seriesGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
this.seriesGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
this.descriptionGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
this.descriptionGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
this.categoryGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
this.categoryGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
this.productRatingGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
this.productRatingGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
this.purchaseDateGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
this.purchaseDateGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
this.myRatingGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
this.myRatingGVColumn = new LibationWinForms.GridView.MyRatingGridViewColumn();
|
||||||
this.miscGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
this.miscGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
this.tagAndDetailsGVColumn = new LibationWinForms.GridView.EditTagsDataGridViewImageButtonColumn();
|
this.tagAndDetailsGVColumn = new LibationWinForms.GridView.EditTagsDataGridViewImageButtonColumn();
|
||||||
this.showHideColumnsContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
|
this.showHideColumnsContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||||
this.syncBindingSource = new LibationWinForms.GridView.SyncBindingSource(this.components);
|
this.syncBindingSource = new LibationWinForms.GridView.SyncBindingSource(this.components);
|
||||||
((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).BeginInit();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).BeginInit();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
// gridEntryDataGridView
|
// gridEntryDataGridView
|
||||||
//
|
//
|
||||||
this.gridEntryDataGridView.AllowUserToAddRows = false;
|
this.gridEntryDataGridView.AllowUserToAddRows = false;
|
||||||
this.gridEntryDataGridView.AllowUserToDeleteRows = false;
|
this.gridEntryDataGridView.AllowUserToDeleteRows = false;
|
||||||
this.gridEntryDataGridView.AllowUserToOrderColumns = true;
|
this.gridEntryDataGridView.AllowUserToOrderColumns = true;
|
||||||
this.gridEntryDataGridView.AllowUserToResizeRows = false;
|
this.gridEntryDataGridView.AllowUserToResizeRows = false;
|
||||||
this.gridEntryDataGridView.AutoGenerateColumns = false;
|
this.gridEntryDataGridView.AutoGenerateColumns = false;
|
||||||
this.gridEntryDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
this.gridEntryDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||||
this.gridEntryDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
this.gridEntryDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
||||||
this.removeGVColumn,
|
this.removeGVColumn,
|
||||||
this.liberateGVColumn,
|
this.liberateGVColumn,
|
||||||
this.coverGVColumn,
|
this.coverGVColumn,
|
||||||
@ -76,175 +76,176 @@
|
|||||||
this.myRatingGVColumn,
|
this.myRatingGVColumn,
|
||||||
this.miscGVColumn,
|
this.miscGVColumn,
|
||||||
this.tagAndDetailsGVColumn});
|
this.tagAndDetailsGVColumn});
|
||||||
this.gridEntryDataGridView.ContextMenuStrip = this.showHideColumnsContextMenuStrip;
|
this.gridEntryDataGridView.ContextMenuStrip = this.showHideColumnsContextMenuStrip;
|
||||||
this.gridEntryDataGridView.DataSource = this.syncBindingSource;
|
this.gridEntryDataGridView.DataSource = this.syncBindingSource;
|
||||||
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
|
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
|
||||||
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Window;
|
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Window;
|
||||||
dataGridViewCellStyle1.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
dataGridViewCellStyle1.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||||
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.ControlText;
|
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.ControlText;
|
||||||
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
|
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
|
||||||
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
|
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
|
||||||
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
|
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
|
||||||
this.gridEntryDataGridView.DefaultCellStyle = dataGridViewCellStyle1;
|
this.gridEntryDataGridView.DefaultCellStyle = dataGridViewCellStyle1;
|
||||||
this.gridEntryDataGridView.Dock = System.Windows.Forms.DockStyle.Fill;
|
this.gridEntryDataGridView.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
this.gridEntryDataGridView.Location = new System.Drawing.Point(0, 0);
|
this.gridEntryDataGridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnEnter;
|
||||||
this.gridEntryDataGridView.Name = "gridEntryDataGridView";
|
this.gridEntryDataGridView.Location = new System.Drawing.Point(0, 0);
|
||||||
this.gridEntryDataGridView.RowHeadersVisible = false;
|
this.gridEntryDataGridView.Name = "gridEntryDataGridView";
|
||||||
this.gridEntryDataGridView.RowTemplate.Height = 82;
|
this.gridEntryDataGridView.RowHeadersVisible = false;
|
||||||
this.gridEntryDataGridView.Size = new System.Drawing.Size(1570, 380);
|
this.gridEntryDataGridView.RowTemplate.Height = 82;
|
||||||
this.gridEntryDataGridView.TabIndex = 0;
|
this.gridEntryDataGridView.Size = new System.Drawing.Size(1570, 380);
|
||||||
this.gridEntryDataGridView.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.DataGridView_CellContentClick);
|
this.gridEntryDataGridView.TabIndex = 0;
|
||||||
this.gridEntryDataGridView.CellContextMenuStripNeeded += new System.Windows.Forms.DataGridViewCellContextMenuStripNeededEventHandler(this.gridEntryDataGridView_CellContextMenuStripNeeded);
|
this.gridEntryDataGridView.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.DataGridView_CellContentClick);
|
||||||
this.gridEntryDataGridView.CellToolTipTextNeeded += new System.Windows.Forms.DataGridViewCellToolTipTextNeededEventHandler(this.gridEntryDataGridView_CellToolTipTextNeeded);
|
this.gridEntryDataGridView.CellContextMenuStripNeeded += new System.Windows.Forms.DataGridViewCellContextMenuStripNeededEventHandler(this.gridEntryDataGridView_CellContextMenuStripNeeded);
|
||||||
//
|
this.gridEntryDataGridView.CellToolTipTextNeeded += new System.Windows.Forms.DataGridViewCellToolTipTextNeededEventHandler(this.gridEntryDataGridView_CellToolTipTextNeeded);
|
||||||
// removeGVColumn
|
//
|
||||||
//
|
// removeGVColumn
|
||||||
this.removeGVColumn.DataPropertyName = "Remove";
|
//
|
||||||
this.removeGVColumn.FalseValue = "";
|
this.removeGVColumn.DataPropertyName = "Remove";
|
||||||
this.removeGVColumn.Frozen = true;
|
this.removeGVColumn.FalseValue = "";
|
||||||
this.removeGVColumn.HeaderText = "Remove";
|
this.removeGVColumn.Frozen = true;
|
||||||
this.removeGVColumn.IndeterminateValue = "";
|
this.removeGVColumn.HeaderText = "Remove";
|
||||||
this.removeGVColumn.MinimumWidth = 60;
|
this.removeGVColumn.IndeterminateValue = "";
|
||||||
this.removeGVColumn.Name = "removeGVColumn";
|
this.removeGVColumn.MinimumWidth = 60;
|
||||||
this.removeGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
this.removeGVColumn.Name = "removeGVColumn";
|
||||||
this.removeGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
this.removeGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
||||||
this.removeGVColumn.ThreeState = true;
|
this.removeGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||||
this.removeGVColumn.TrueValue = "";
|
this.removeGVColumn.ThreeState = true;
|
||||||
this.removeGVColumn.Width = 60;
|
this.removeGVColumn.TrueValue = "";
|
||||||
//
|
this.removeGVColumn.Width = 60;
|
||||||
// liberateGVColumn
|
//
|
||||||
//
|
// liberateGVColumn
|
||||||
this.liberateGVColumn.DataPropertyName = "Liberate";
|
//
|
||||||
this.liberateGVColumn.HeaderText = "Liberate";
|
this.liberateGVColumn.DataPropertyName = "Liberate";
|
||||||
this.liberateGVColumn.Name = "liberateGVColumn";
|
this.liberateGVColumn.HeaderText = "Liberate";
|
||||||
this.liberateGVColumn.ReadOnly = true;
|
this.liberateGVColumn.Name = "liberateGVColumn";
|
||||||
this.liberateGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
this.liberateGVColumn.ReadOnly = true;
|
||||||
this.liberateGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
this.liberateGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
||||||
this.liberateGVColumn.Width = 75;
|
this.liberateGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||||
//
|
this.liberateGVColumn.Width = 75;
|
||||||
// coverGVColumn
|
//
|
||||||
//
|
// coverGVColumn
|
||||||
this.coverGVColumn.DataPropertyName = "Cover";
|
//
|
||||||
this.coverGVColumn.HeaderText = "Cover";
|
this.coverGVColumn.DataPropertyName = "Cover";
|
||||||
this.coverGVColumn.Name = "coverGVColumn";
|
this.coverGVColumn.HeaderText = "Cover";
|
||||||
this.coverGVColumn.ReadOnly = true;
|
this.coverGVColumn.Name = "coverGVColumn";
|
||||||
this.coverGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
this.coverGVColumn.ReadOnly = true;
|
||||||
this.coverGVColumn.ToolTipText = "Cover Art";
|
this.coverGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
||||||
this.coverGVColumn.Width = 80;
|
this.coverGVColumn.ToolTipText = "Cover Art";
|
||||||
//
|
this.coverGVColumn.Width = 80;
|
||||||
// titleGVColumn
|
//
|
||||||
//
|
// titleGVColumn
|
||||||
this.titleGVColumn.DataPropertyName = "Title";
|
//
|
||||||
this.titleGVColumn.HeaderText = "Title";
|
this.titleGVColumn.DataPropertyName = "Title";
|
||||||
this.titleGVColumn.Name = "titleGVColumn";
|
this.titleGVColumn.HeaderText = "Title";
|
||||||
this.titleGVColumn.ReadOnly = true;
|
this.titleGVColumn.Name = "titleGVColumn";
|
||||||
this.titleGVColumn.Width = 200;
|
this.titleGVColumn.ReadOnly = true;
|
||||||
//
|
this.titleGVColumn.Width = 200;
|
||||||
// authorsGVColumn
|
//
|
||||||
//
|
// authorsGVColumn
|
||||||
this.authorsGVColumn.DataPropertyName = "Authors";
|
//
|
||||||
this.authorsGVColumn.HeaderText = "Authors";
|
this.authorsGVColumn.DataPropertyName = "Authors";
|
||||||
this.authorsGVColumn.Name = "authorsGVColumn";
|
this.authorsGVColumn.HeaderText = "Authors";
|
||||||
this.authorsGVColumn.ReadOnly = true;
|
this.authorsGVColumn.Name = "authorsGVColumn";
|
||||||
//
|
this.authorsGVColumn.ReadOnly = true;
|
||||||
// narratorsGVColumn
|
//
|
||||||
//
|
// narratorsGVColumn
|
||||||
this.narratorsGVColumn.DataPropertyName = "Narrators";
|
//
|
||||||
this.narratorsGVColumn.HeaderText = "Narrators";
|
this.narratorsGVColumn.DataPropertyName = "Narrators";
|
||||||
this.narratorsGVColumn.Name = "narratorsGVColumn";
|
this.narratorsGVColumn.HeaderText = "Narrators";
|
||||||
this.narratorsGVColumn.ReadOnly = true;
|
this.narratorsGVColumn.Name = "narratorsGVColumn";
|
||||||
//
|
this.narratorsGVColumn.ReadOnly = true;
|
||||||
// lengthGVColumn
|
//
|
||||||
//
|
// lengthGVColumn
|
||||||
this.lengthGVColumn.DataPropertyName = "Length";
|
//
|
||||||
this.lengthGVColumn.HeaderText = "Length";
|
this.lengthGVColumn.DataPropertyName = "Length";
|
||||||
this.lengthGVColumn.Name = "lengthGVColumn";
|
this.lengthGVColumn.HeaderText = "Length";
|
||||||
this.lengthGVColumn.ReadOnly = true;
|
this.lengthGVColumn.Name = "lengthGVColumn";
|
||||||
this.lengthGVColumn.ToolTipText = "Recording Length";
|
this.lengthGVColumn.ReadOnly = true;
|
||||||
//
|
this.lengthGVColumn.ToolTipText = "Recording Length";
|
||||||
// seriesGVColumn
|
//
|
||||||
//
|
// seriesGVColumn
|
||||||
this.seriesGVColumn.DataPropertyName = "Series";
|
//
|
||||||
this.seriesGVColumn.HeaderText = "Series";
|
this.seriesGVColumn.DataPropertyName = "Series";
|
||||||
this.seriesGVColumn.Name = "seriesGVColumn";
|
this.seriesGVColumn.HeaderText = "Series";
|
||||||
this.seriesGVColumn.ReadOnly = true;
|
this.seriesGVColumn.Name = "seriesGVColumn";
|
||||||
//
|
this.seriesGVColumn.ReadOnly = true;
|
||||||
// descriptionGVColumn
|
//
|
||||||
//
|
// descriptionGVColumn
|
||||||
this.descriptionGVColumn.DataPropertyName = "Description";
|
//
|
||||||
this.descriptionGVColumn.HeaderText = "Description";
|
this.descriptionGVColumn.DataPropertyName = "Description";
|
||||||
this.descriptionGVColumn.Name = "descriptionGVColumn";
|
this.descriptionGVColumn.HeaderText = "Description";
|
||||||
this.descriptionGVColumn.ReadOnly = true;
|
this.descriptionGVColumn.Name = "descriptionGVColumn";
|
||||||
this.descriptionGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
this.descriptionGVColumn.ReadOnly = true;
|
||||||
//
|
this.descriptionGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
||||||
// categoryGVColumn
|
//
|
||||||
//
|
// categoryGVColumn
|
||||||
this.categoryGVColumn.DataPropertyName = "Category";
|
//
|
||||||
this.categoryGVColumn.HeaderText = "Category";
|
this.categoryGVColumn.DataPropertyName = "Category";
|
||||||
this.categoryGVColumn.Name = "categoryGVColumn";
|
this.categoryGVColumn.HeaderText = "Category";
|
||||||
this.categoryGVColumn.ReadOnly = true;
|
this.categoryGVColumn.Name = "categoryGVColumn";
|
||||||
//
|
this.categoryGVColumn.ReadOnly = true;
|
||||||
// productRatingGVColumn
|
//
|
||||||
//
|
// productRatingGVColumn
|
||||||
this.productRatingGVColumn.DataPropertyName = "ProductRating";
|
//
|
||||||
this.productRatingGVColumn.HeaderText = "Product Rating";
|
this.productRatingGVColumn.DataPropertyName = "ProductRating";
|
||||||
this.productRatingGVColumn.Name = "productRatingGVColumn";
|
this.productRatingGVColumn.HeaderText = "Product Rating";
|
||||||
this.productRatingGVColumn.ReadOnly = true;
|
this.productRatingGVColumn.Name = "productRatingGVColumn";
|
||||||
this.productRatingGVColumn.Width = 108;
|
this.productRatingGVColumn.ReadOnly = true;
|
||||||
//
|
this.productRatingGVColumn.Width = 108;
|
||||||
// purchaseDateGVColumn
|
//
|
||||||
//
|
// purchaseDateGVColumn
|
||||||
this.purchaseDateGVColumn.DataPropertyName = "PurchaseDate";
|
//
|
||||||
this.purchaseDateGVColumn.HeaderText = "Purchase Date";
|
this.purchaseDateGVColumn.DataPropertyName = "PurchaseDate";
|
||||||
this.purchaseDateGVColumn.Name = "purchaseDateGVColumn";
|
this.purchaseDateGVColumn.HeaderText = "Purchase Date";
|
||||||
this.purchaseDateGVColumn.ReadOnly = true;
|
this.purchaseDateGVColumn.Name = "purchaseDateGVColumn";
|
||||||
//
|
this.purchaseDateGVColumn.ReadOnly = true;
|
||||||
// myRatingGVColumn
|
//
|
||||||
//
|
// myRatingGVColumn
|
||||||
this.myRatingGVColumn.DataPropertyName = "MyRating";
|
//
|
||||||
this.myRatingGVColumn.HeaderText = "My Rating";
|
this.myRatingGVColumn.DataPropertyName = "MyRating";
|
||||||
this.myRatingGVColumn.Name = "myRatingGVColumn";
|
this.myRatingGVColumn.HeaderText = "My Rating";
|
||||||
this.myRatingGVColumn.ReadOnly = true;
|
this.myRatingGVColumn.Name = "myRatingGVColumn";
|
||||||
this.myRatingGVColumn.Width = 108;
|
this.myRatingGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||||
//
|
this.myRatingGVColumn.Width = 108;
|
||||||
// miscGVColumn
|
//
|
||||||
//
|
// miscGVColumn
|
||||||
this.miscGVColumn.DataPropertyName = "Misc";
|
//
|
||||||
this.miscGVColumn.HeaderText = "Misc";
|
this.miscGVColumn.DataPropertyName = "Misc";
|
||||||
this.miscGVColumn.Name = "miscGVColumn";
|
this.miscGVColumn.HeaderText = "Misc";
|
||||||
this.miscGVColumn.ReadOnly = true;
|
this.miscGVColumn.Name = "miscGVColumn";
|
||||||
this.miscGVColumn.Width = 135;
|
this.miscGVColumn.ReadOnly = true;
|
||||||
//
|
this.miscGVColumn.Width = 135;
|
||||||
// tagAndDetailsGVColumn
|
//
|
||||||
//
|
// tagAndDetailsGVColumn
|
||||||
this.tagAndDetailsGVColumn.DataPropertyName = "DisplayTags";
|
//
|
||||||
this.tagAndDetailsGVColumn.HeaderText = "Tags and Details";
|
this.tagAndDetailsGVColumn.DataPropertyName = "DisplayTags";
|
||||||
this.tagAndDetailsGVColumn.Name = "tagAndDetailsGVColumn";
|
this.tagAndDetailsGVColumn.HeaderText = "Tags and Details";
|
||||||
this.tagAndDetailsGVColumn.ReadOnly = true;
|
this.tagAndDetailsGVColumn.Name = "tagAndDetailsGVColumn";
|
||||||
this.tagAndDetailsGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
this.tagAndDetailsGVColumn.ReadOnly = true;
|
||||||
this.tagAndDetailsGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
this.tagAndDetailsGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
|
||||||
//
|
this.tagAndDetailsGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
|
||||||
// showHideColumnsContextMenuStrip
|
//
|
||||||
//
|
// showHideColumnsContextMenuStrip
|
||||||
this.showHideColumnsContextMenuStrip.Name = "contextMenuStrip1";
|
//
|
||||||
this.showHideColumnsContextMenuStrip.Size = new System.Drawing.Size(181, 26);
|
this.showHideColumnsContextMenuStrip.Name = "contextMenuStrip1";
|
||||||
//
|
this.showHideColumnsContextMenuStrip.Size = new System.Drawing.Size(61, 4);
|
||||||
// syncBindingSource
|
//
|
||||||
//
|
// syncBindingSource
|
||||||
this.syncBindingSource.DataSource = typeof(LibationWinForms.GridView.GridEntry);
|
//
|
||||||
//
|
this.syncBindingSource.DataSource = typeof(LibationWinForms.GridView.GridEntry);
|
||||||
// ProductsGrid
|
//
|
||||||
//
|
// ProductsGrid
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
//
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||||
this.AutoScroll = true;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.Controls.Add(this.gridEntryDataGridView);
|
this.AutoScroll = true;
|
||||||
this.Name = "ProductsGrid";
|
this.Controls.Add(this.gridEntryDataGridView);
|
||||||
this.Size = new System.Drawing.Size(1570, 380);
|
this.Name = "ProductsGrid";
|
||||||
this.Load += new System.EventHandler(this.ProductsGrid_Load);
|
this.Size = new System.Drawing.Size(1570, 380);
|
||||||
((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).EndInit();
|
this.Load += new System.EventHandler(this.ProductsGrid_Load);
|
||||||
((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).EndInit();
|
((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).EndInit();
|
||||||
this.ResumeLayout(false);
|
((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).EndInit();
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +266,7 @@
|
|||||||
private System.Windows.Forms.DataGridViewTextBoxColumn categoryGVColumn;
|
private System.Windows.Forms.DataGridViewTextBoxColumn categoryGVColumn;
|
||||||
private System.Windows.Forms.DataGridViewTextBoxColumn productRatingGVColumn;
|
private System.Windows.Forms.DataGridViewTextBoxColumn productRatingGVColumn;
|
||||||
private System.Windows.Forms.DataGridViewTextBoxColumn purchaseDateGVColumn;
|
private System.Windows.Forms.DataGridViewTextBoxColumn purchaseDateGVColumn;
|
||||||
private System.Windows.Forms.DataGridViewTextBoxColumn myRatingGVColumn;
|
private MyRatingGridViewColumn myRatingGVColumn;
|
||||||
private System.Windows.Forms.DataGridViewTextBoxColumn miscGVColumn;
|
private System.Windows.Forms.DataGridViewTextBoxColumn miscGVColumn;
|
||||||
private EditTagsDataGridViewImageButtonColumn tagAndDetailsGVColumn;
|
private EditTagsDataGridViewImageButtonColumn tagAndDetailsGVColumn;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -120,7 +120,7 @@ namespace LibationWinForms.GridView
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var dgv = (DataGridView)sender;
|
var dgv = (DataGridView)sender;
|
||||||
var text = dgv[e.ColumnIndex, e.RowIndex].Value.ToString();
|
var text = dgv[e.ColumnIndex, e.RowIndex].FormattedValue.ToString();
|
||||||
InteropFactory.Create().CopyTextToClipboard(text);
|
InteropFactory.Create().CopyTextToClipboard(text);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
|
|||||||
@ -89,7 +89,7 @@ namespace LibationWinForms.GridView
|
|||||||
|
|
||||||
Title = Book.Title;
|
Title = Book.Title;
|
||||||
Series = Book.SeriesNames();
|
Series = Book.SeriesNames();
|
||||||
MyRating = Book.UserDefinedItem.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
_myRating = Book.UserDefinedItem.Rating;
|
||||||
PurchaseDate = Children.Min(c => c.LibraryBook.DateAdded).ToString("d");
|
PurchaseDate = Children.Min(c => c.LibraryBook.DateAdded).ToString("d");
|
||||||
ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
||||||
Authors = Book.AuthorNames();
|
Authors = Book.AuthorNames();
|
||||||
|
|||||||
39
Source/LoadByOS/WindowsConfigApp/Form1.Designer.cs
generated
39
Source/LoadByOS/WindowsConfigApp/Form1.Designer.cs
generated
@ -1,39 +0,0 @@
|
|||||||
namespace WindowsConfigApp
|
|
||||||
{
|
|
||||||
partial class Form1
|
|
||||||
{
|
|
||||||
/// <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 Windows Form 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()
|
|
||||||
{
|
|
||||||
this.components = new System.ComponentModel.Container();
|
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
|
||||||
this.ClientSize = new System.Drawing.Size(800, 450);
|
|
||||||
this.Text = "Form1";
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
namespace WindowsConfigApp
|
|
||||||
{
|
|
||||||
public partial class Form1 : Form
|
|
||||||
{
|
|
||||||
public Form1()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -7,7 +7,6 @@ namespace WindowsConfigApp
|
|||||||
public override Type InteropFunctionsType => typeof(WinInterop);
|
public override Type InteropFunctionsType => typeof(WinInterop);
|
||||||
public override Type[] ReferencedTypes => new Type[]
|
public override Type[] ReferencedTypes => new Type[]
|
||||||
{
|
{
|
||||||
typeof(Form1),
|
|
||||||
typeof(Bitmap),
|
typeof(Bitmap),
|
||||||
typeof(Dinah.Core.WindowsDesktop.GitClient),
|
typeof(Dinah.Core.WindowsDesktop.GitClient),
|
||||||
typeof(Accessibility.IAccIdentity),
|
typeof(Accessibility.IAccIdentity),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user