Add ability to preview templates on user's books (#700)
Add template editor menu items to main grid context menu
This commit is contained in:
parent
167a021eb1
commit
e65b6c76a8
@ -21,7 +21,8 @@ namespace FileLiberator
|
|||||||
var series = libraryBook.Book.SeriesLink.SingleOrDefault();
|
var series = libraryBook.Book.SeriesLink.SingleOrDefault();
|
||||||
if (series is not null)
|
if (series is not null)
|
||||||
{
|
{
|
||||||
var seriesParent = ApplicationServices.DbContexts.GetContext().GetLibraryBook_Flat_NoTracking(series.Series.AudibleSeriesId);
|
using var context = ApplicationServices.DbContexts.GetContext();
|
||||||
|
var seriesParent = context.GetLibraryBook_Flat_NoTracking(series.Series.AudibleSeriesId);
|
||||||
|
|
||||||
if (seriesParent is not null)
|
if (seriesParent is not null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -11,6 +11,7 @@ using LibationAvalonia.Dialogs;
|
|||||||
using LibationAvalonia.ViewModels;
|
using LibationAvalonia.ViewModels;
|
||||||
using LibationFileManager;
|
using LibationFileManager;
|
||||||
using LibationUiBase.GridView;
|
using LibationUiBase.GridView;
|
||||||
|
using ReactiveUI;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -172,87 +173,70 @@ namespace LibationAvalonia.Views
|
|||||||
|
|
||||||
public void ProductsGrid_CellContextMenuStripNeeded(object sender, DataGridCellContextMenuStripNeededEventArgs args)
|
public void ProductsGrid_CellContextMenuStripNeeded(object sender, DataGridCellContextMenuStripNeededEventArgs args)
|
||||||
{
|
{
|
||||||
|
var entry = args.GridEntry;
|
||||||
|
var ctx = new GridContextMenu(entry, '_');
|
||||||
|
|
||||||
if (args.Column.SortMemberPath is not "Liberate" and not "Cover")
|
if (args.Column.SortMemberPath is not "Liberate" and not "Cover")
|
||||||
{
|
{
|
||||||
var menuItem = new MenuItem { Header = "_Copy Cell Contents" };
|
args.ContextMenuItems.Add(new MenuItem
|
||||||
|
{
|
||||||
menuItem.Click += async (s, e)
|
Header = ctx.CopyCellText,
|
||||||
=> await App.MainWindow.Clipboard.SetTextAsync(args.CellClipboardContents);
|
Command = ReactiveCommand.CreateFromTask(() => App.MainWindow.Clipboard.SetTextAsync(args.CellClipboardContents))
|
||||||
|
});
|
||||||
args.ContextMenuItems.Add(menuItem);
|
|
||||||
args.ContextMenuItems.Add(new Separator());
|
args.ContextMenuItems.Add(new Separator());
|
||||||
}
|
}
|
||||||
var entry = args.GridEntry;
|
|
||||||
|
|
||||||
#region Liberate all Episodes
|
#region Liberate all Episodes
|
||||||
|
|
||||||
if (entry.Liberate.IsSeries)
|
if (entry.Liberate.IsSeries)
|
||||||
{
|
{
|
||||||
var liberateEpisodesMenuItem = new MenuItem()
|
args.ContextMenuItems.Add(new MenuItem()
|
||||||
{
|
{
|
||||||
Header = "_Liberate All Episodes",
|
Header = ctx.LiberateEpisodesText,
|
||||||
IsEnabled = ((ISeriesEntry)entry).Children.Any(c => c.Liberate.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload)
|
IsEnabled = ctx.LiberateEpisodesEnabled,
|
||||||
};
|
Command = ReactiveCommand.Create(() => LiberateSeriesClicked?.Invoke(this, (ISeriesEntry)entry))
|
||||||
|
});
|
||||||
args.ContextMenuItems.Add(liberateEpisodesMenuItem);
|
|
||||||
|
|
||||||
liberateEpisodesMenuItem.Click += (_, _) => LiberateSeriesClicked?.Invoke(this, ((ISeriesEntry)entry));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Set Download status to Downloaded
|
#region Set Download status to Downloaded
|
||||||
|
|
||||||
var setDownloadMenuItem = new MenuItem()
|
args.ContextMenuItems.Add(new MenuItem()
|
||||||
{
|
{
|
||||||
Header = "Set Download status to '_Downloaded'",
|
Header = ctx.SetDownloadedText,
|
||||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated || entry.Liberate.IsSeries
|
IsEnabled = ctx.SetDownloadedEnabled,
|
||||||
};
|
Command = ReactiveCommand.Create(ctx.SetDownloaded)
|
||||||
|
});
|
||||||
args.ContextMenuItems.Add(setDownloadMenuItem);
|
|
||||||
|
|
||||||
if (entry.Liberate.IsSeries)
|
|
||||||
setDownloadMenuItem.Click += (_, __) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.Liberated);
|
|
||||||
else
|
|
||||||
setDownloadMenuItem.Click += (_, __) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.Liberated);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Set Download status to Not Downloaded
|
#region Set Download status to Not Downloaded
|
||||||
|
|
||||||
var setNotDownloadMenuItem = new MenuItem()
|
args.ContextMenuItems.Add(new MenuItem()
|
||||||
{
|
{
|
||||||
Header = "Set Download status to '_Not Downloaded'",
|
Header = ctx.SetNotDownloadedText,
|
||||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated || entry.Liberate.IsSeries
|
IsEnabled = ctx.SetNotDownloadedEnabled,
|
||||||
};
|
Command = ReactiveCommand.Create(ctx.SetNotDownloaded)
|
||||||
|
});
|
||||||
args.ContextMenuItems.Add(setNotDownloadMenuItem);
|
|
||||||
|
|
||||||
if (entry.Liberate.IsSeries)
|
|
||||||
setNotDownloadMenuItem.Click += (_, __) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.NotLiberated);
|
|
||||||
else
|
|
||||||
setNotDownloadMenuItem.Click += (_, __) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.NotLiberated);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Remove from library
|
#region Remove from library
|
||||||
|
|
||||||
var removeMenuItem = new MenuItem() { Header = "_Remove from library" };
|
args.ContextMenuItems.Add(new MenuItem
|
||||||
|
{
|
||||||
args.ContextMenuItems.Add(removeMenuItem);
|
Header = ctx.RemoveText,
|
||||||
|
Command = ReactiveCommand.CreateFromTask(ctx.RemoveAsync)
|
||||||
if (entry.Liberate.IsSeries)
|
});
|
||||||
removeMenuItem.Click += async (_, __) => await ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).RemoveBooksAsync();
|
|
||||||
else
|
|
||||||
removeMenuItem.Click += async (_, __) => await Task.Run(entry.LibraryBook.RemoveBook);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
if (!entry.Liberate.IsSeries)
|
if (!entry.Liberate.IsSeries)
|
||||||
{
|
{
|
||||||
#region Locate file
|
#region Locate file
|
||||||
var locateFileMenuItem = new MenuItem() { Header = "_Locate file..." };
|
|
||||||
|
|
||||||
args.ContextMenuItems.Add(locateFileMenuItem);
|
args.ContextMenuItems.Add(new MenuItem
|
||||||
|
{
|
||||||
locateFileMenuItem.Click += async (_, __) =>
|
Header = ctx.LocateFileText,
|
||||||
|
Command = ReactiveCommand.CreateFromTask(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -260,7 +244,7 @@ namespace LibationAvalonia.Views
|
|||||||
|
|
||||||
var openFileDialogOptions = new FilePickerOpenOptions
|
var openFileDialogOptions = new FilePickerOpenOptions
|
||||||
{
|
{
|
||||||
Title = $"Locate the audio file for '{entry.Book.TitleWithSubtitle}'",
|
Title = ctx.LocateFileDialogTitle,
|
||||||
AllowMultiple = false,
|
AllowMultiple = false,
|
||||||
SuggestedStartLocation = await window.StorageProvider.TryGetFolderFromPathAsync(Configuration.Instance.Books.PathWithoutPrefix),
|
SuggestedStartLocation = await window.StorageProvider.TryGetFolderFromPathAsync(Configuration.Instance.Books.PathWithoutPrefix),
|
||||||
FileTypeFilter = new FilePickerFileType[]
|
FileTypeFilter = new FilePickerFileType[]
|
||||||
@ -277,21 +261,19 @@ namespace LibationAvalonia.Views
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var msg = "Error saving book's location";
|
await MessageBox.ShowAdminAlert(null, ctx.LocateFileErrorMessage, ctx.LocateFileErrorMessage, ex);
|
||||||
await MessageBox.ShowAdminAlert(null, msg, msg, ex);
|
|
||||||
}
|
}
|
||||||
};
|
})
|
||||||
|
});
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Convert to Mp3
|
#region Convert to Mp3
|
||||||
var convertToMp3MenuItem = new MenuItem
|
args.ContextMenuItems.Add(new MenuItem
|
||||||
{
|
{
|
||||||
Header = "_Convert to Mp3",
|
Header = ctx.ConvertToMp3Text,
|
||||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
IsEnabled = ctx.ConvertToMp3Enabled,
|
||||||
};
|
Command = ReactiveCommand.Create(() => ConvertToMp3Clicked?.Invoke(this, entry.LibraryBook))
|
||||||
args.ContextMenuItems.Add(convertToMp3MenuItem);
|
});
|
||||||
|
|
||||||
convertToMp3MenuItem.Click += (_, _) => ConvertToMp3Clicked?.Invoke(this, entry.LibraryBook);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -299,34 +281,72 @@ namespace LibationAvalonia.Views
|
|||||||
#region Force Re-Download
|
#region Force Re-Download
|
||||||
if (!entry.Liberate.IsSeries)
|
if (!entry.Liberate.IsSeries)
|
||||||
{
|
{
|
||||||
var reDownloadMenuItem = new MenuItem()
|
args.ContextMenuItems.Add(new MenuItem()
|
||||||
{
|
{
|
||||||
Header = "Re-download this audiobook",
|
Header = ctx.ReDownloadText,
|
||||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
IsEnabled = ctx.ReDownloadEnabled,
|
||||||
};
|
Command = ReactiveCommand.Create(() =>
|
||||||
|
|
||||||
args.ContextMenuItems.Add(reDownloadMenuItem);
|
|
||||||
reDownloadMenuItem.Click += (s, _) =>
|
|
||||||
{
|
{
|
||||||
//No need to persist this change. It only needs to last long for the file to start downloading
|
//No need to persist this change. It only needs to last long for the file to start downloading
|
||||||
entry.Book.UserDefinedItem.BookStatus = LiberatedStatus.NotLiberated;
|
entry.Book.UserDefinedItem.BookStatus = LiberatedStatus.NotLiberated;
|
||||||
LiberateClicked?.Invoke(s, entry.LibraryBook);
|
LiberateClicked?.Invoke(this, entry.LibraryBook);
|
||||||
};
|
})
|
||||||
|
});
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
args.ContextMenuItems.Add(new Separator());
|
args.ContextMenuItems.Add(new Separator());
|
||||||
|
|
||||||
|
#region Edit Templates
|
||||||
|
async Task editTemplate<T>(LibraryBook libraryBook, string existingTemplate, Action<string> setNewTemplate)
|
||||||
|
where T : Templates, LibationFileManager.ITemplate, new()
|
||||||
|
{
|
||||||
|
var template = ctx.CreateTemplateEditor<T>(libraryBook, existingTemplate);
|
||||||
|
var form = new EditTemplateDialog(template);
|
||||||
|
if (await form.ShowDialog<DialogResult>(this.GetParentWindow()) == DialogResult.OK)
|
||||||
|
{
|
||||||
|
setNewTemplate(template.EditingTemplate.TemplateText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entry.Liberate.IsSeries)
|
||||||
|
{
|
||||||
|
args.ContextMenuItems.Add(new MenuItem
|
||||||
|
{
|
||||||
|
Header = ctx.EditTemplatesText,
|
||||||
|
ItemsSource = new[]
|
||||||
|
{
|
||||||
|
new MenuItem
|
||||||
|
{
|
||||||
|
Header = ctx.FolderTemplateText,
|
||||||
|
Command = ReactiveCommand.CreateFromTask(() => editTemplate<Templates.FolderTemplate>(entry.LibraryBook, Configuration.Instance.FolderTemplate, t => Configuration.Instance.FolderTemplate = t))
|
||||||
|
},
|
||||||
|
new MenuItem
|
||||||
|
{
|
||||||
|
Header = ctx.FileTemplateText,
|
||||||
|
Command = ReactiveCommand.CreateFromTask(() => editTemplate<Templates.FileTemplate>(entry.LibraryBook, Configuration.Instance.FileTemplate, t => Configuration.Instance.FileTemplate = t))
|
||||||
|
},
|
||||||
|
new MenuItem
|
||||||
|
{
|
||||||
|
Header = ctx.MultipartTemplateText,
|
||||||
|
Command = ReactiveCommand.CreateFromTask(() => editTemplate<Templates.ChapterFileTemplate>(entry.LibraryBook, Configuration.Instance.ChapterFileTemplate, t => Configuration.Instance.ChapterFileTemplate = t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
args.ContextMenuItems.Add(new Separator());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region View Bookmarks/Clips
|
#region View Bookmarks/Clips
|
||||||
|
|
||||||
if (!entry.Liberate.IsSeries)
|
if (!entry.Liberate.IsSeries)
|
||||||
{
|
{
|
||||||
|
args.ContextMenuItems.Add(new MenuItem
|
||||||
var bookRecordMenuItem = new MenuItem { Header = "View _Bookmarks/Clips" };
|
{
|
||||||
|
Header = ctx.ViewBookmarksText,
|
||||||
args.ContextMenuItems.Add(bookRecordMenuItem);
|
Command = ReactiveCommand.CreateFromTask(() => new BookRecordsDialog(entry.LibraryBook).ShowDialog(VisualRoot as Window))
|
||||||
|
});
|
||||||
bookRecordMenuItem.Click += async (_, _) => await new BookRecordsDialog(entry.LibraryBook).ShowDialog(VisualRoot as Window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -334,12 +354,11 @@ namespace LibationAvalonia.Views
|
|||||||
|
|
||||||
if (entry.Book.SeriesLink.Any())
|
if (entry.Book.SeriesLink.Any())
|
||||||
{
|
{
|
||||||
var header = entry.Liberate.IsSeries ? "View All Episodes in Series" : "View All Books in Series";
|
args.ContextMenuItems.Add(new MenuItem
|
||||||
var viewSeriesMenuItem = new MenuItem { Header = header };
|
{
|
||||||
|
Header = ctx.ViewSeriesText,
|
||||||
args.ContextMenuItems.Add(viewSeriesMenuItem);
|
Command = ReactiveCommand.Create(() => new SeriesViewDialog(entry.LibraryBook).Show())
|
||||||
|
});
|
||||||
viewSeriesMenuItem.Click += (_, _) => new SeriesViewDialog(entry.LibraryBook).Show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -51,7 +51,10 @@ namespace LibationFileManager
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly LibraryBookDto libraryBookDto
|
public LibraryBookDto FolderBook { get; }
|
||||||
|
public LibraryBookDto LibraryBook { get; }
|
||||||
|
|
||||||
|
private static readonly LibraryBookDto DefaultLibraryBook
|
||||||
= new()
|
= new()
|
||||||
{
|
{
|
||||||
Account = "myaccount@example.co",
|
Account = "myaccount@example.co",
|
||||||
@ -74,7 +77,7 @@ namespace LibationFileManager
|
|||||||
Language = "English"
|
Language = "English"
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly MultiConvertFileProperties partFileProperties
|
private static readonly MultiConvertFileProperties DefaultMultipartProperties
|
||||||
= new()
|
= new()
|
||||||
{
|
{
|
||||||
OutputFileName = "",
|
OutputFileName = "",
|
||||||
@ -91,23 +94,27 @@ namespace LibationFileManager
|
|||||||
* subdirectories. Without rooting, we won't be allowed to create a
|
* subdirectories. Without rooting, we won't be allowed to create a
|
||||||
* relative path longer than MAX_PATH.
|
* relative path longer than MAX_PATH.
|
||||||
*/
|
*/
|
||||||
var dir = Folder?.GetFilename(libraryBookDto, BaseDirectory, "");
|
var dir = Folder?.GetFilename(FolderBook, BaseDirectory, "");
|
||||||
if (dir is null) return null;
|
if (dir is null) return null;
|
||||||
return Path.GetRelativePath(BaseDirectory, dir);
|
return Path.GetRelativePath(BaseDirectory, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? GetFileName()
|
public string? GetFileName()
|
||||||
=> File?.GetFilename(libraryBookDto, partFileProperties, "", "");
|
=> File?.GetFilename(LibraryBook, DefaultMultipartProperties, "", "");
|
||||||
public string? GetName()
|
public string? GetName()
|
||||||
=> Name?.GetName(libraryBookDto, partFileProperties);
|
=> Name?.GetName(LibraryBook, DefaultMultipartProperties);
|
||||||
|
|
||||||
private TemplateEditor(
|
private TemplateEditor(
|
||||||
|
LibraryBookDto? folderDto,
|
||||||
|
LibraryBookDto? fileDto,
|
||||||
Templates editingTemplate,
|
Templates editingTemplate,
|
||||||
LongPath baseDirectory,
|
LongPath baseDirectory,
|
||||||
string defaultTemplate,
|
string defaultTemplate,
|
||||||
string templateName,
|
string templateName,
|
||||||
string templateDescription)
|
string templateDescription)
|
||||||
{
|
{
|
||||||
|
FolderBook = folderDto ?? DefaultLibraryBook;
|
||||||
|
LibraryBook = fileDto ?? DefaultLibraryBook;
|
||||||
_editingTemplate = editingTemplate;
|
_editingTemplate = editingTemplate;
|
||||||
BaseDirectory = baseDirectory;
|
BaseDirectory = baseDirectory;
|
||||||
DefaultTemplate = defaultTemplate;
|
DefaultTemplate = defaultTemplate;
|
||||||
@ -115,12 +122,12 @@ namespace LibationFileManager
|
|||||||
TemplateDescription = templateDescription;
|
TemplateDescription = templateDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ITemplateEditor CreateFilenameEditor(LongPath baseDir, string templateText)
|
public static ITemplateEditor CreateFilenameEditor(LongPath baseDir, string templateText, LibraryBookDto? folderDto = null, LibraryBookDto? fileDto = null)
|
||||||
{
|
{
|
||||||
if (!Templates.TryGetTemplate<T>(templateText, out var template))
|
if (!Templates.TryGetTemplate<T>(templateText, out var template))
|
||||||
throw new ArgumentException($"Failed to parse {nameof(templateText)}");
|
throw new ArgumentException($"Failed to parse {nameof(templateText)}");
|
||||||
|
|
||||||
var templateEditor = new TemplateEditor<T>(template, baseDir, T.DefaultTemplate, T.Name, T.Description);
|
var templateEditor = new TemplateEditor<T>(folderDto, fileDto, template, baseDir, T.DefaultTemplate, T.Name, T.Description);
|
||||||
|
|
||||||
if (!templateEditor.IsFolder && !templateEditor.IsFilePath)
|
if (!templateEditor.IsFolder && !templateEditor.IsFilePath)
|
||||||
throw new InvalidOperationException($"This method is only for File and Folder templates. Use {nameof(CreateNameEditor)} for name templates");
|
throw new InvalidOperationException($"This method is only for File and Folder templates. Use {nameof(CreateNameEditor)} for name templates");
|
||||||
@ -133,12 +140,12 @@ namespace LibationFileManager
|
|||||||
return templateEditor;
|
return templateEditor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ITemplateEditor CreateNameEditor(string templateText)
|
public static ITemplateEditor CreateNameEditor(string templateText, LibraryBookDto? libraryBookDto = null)
|
||||||
{
|
{
|
||||||
if (!Templates.TryGetTemplate<T>(templateText, out var nameTemplate))
|
if (!Templates.TryGetTemplate<T>(templateText, out var nameTemplate))
|
||||||
throw new ArgumentException($"Failed to parse {nameof(templateText)}");
|
throw new ArgumentException($"Failed to parse {nameof(templateText)}");
|
||||||
|
|
||||||
var templateEditor = new TemplateEditor<T>(nameTemplate, "", T.DefaultTemplate, T.Name, T.Description);
|
var templateEditor = new TemplateEditor<T>(null, libraryBookDto, nameTemplate, "", T.DefaultTemplate, T.Name, T.Description);
|
||||||
|
|
||||||
if (templateEditor.IsFolder || templateEditor.IsFilePath)
|
if (templateEditor.IsFolder || templateEditor.IsFilePath)
|
||||||
throw new InvalidOperationException($"This method is only for name templates. Use {nameof(CreateFilenameEditor)} for file templates");
|
throw new InvalidOperationException($"This method is only for name templates. Use {nameof(CreateFilenameEditor)} for file templates");
|
||||||
|
|||||||
114
Source/LibationUiBase/GridView/GridContextMenu.cs
Normal file
114
Source/LibationUiBase/GridView/GridContextMenu.cs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
using ApplicationServices;
|
||||||
|
using DataLayer;
|
||||||
|
using FileLiberator;
|
||||||
|
using LibationFileManager;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace LibationUiBase.GridView;
|
||||||
|
|
||||||
|
public class GridContextMenu
|
||||||
|
{
|
||||||
|
public string CopyCellText => $"{Accelerator}Copy Cell Contents";
|
||||||
|
public string LiberateEpisodesText => $"{Accelerator}Liberate All Episodes";
|
||||||
|
public string SetDownloadedText => $"Set Download status to '{Accelerator}Downloaded'";
|
||||||
|
public string SetNotDownloadedText => $"Set Download status to '{Accelerator}Not Downloaded'";
|
||||||
|
public string RemoveText => $"{Accelerator}Remove from library";
|
||||||
|
public string LocateFileText => $"{Accelerator}Locate file...";
|
||||||
|
public string LocateFileDialogTitle => $"Locate the audio file for '{GridEntry.Book.TitleWithSubtitle}'";
|
||||||
|
public string LocateFileErrorMessage => "Error saving book's location";
|
||||||
|
public string ConvertToMp3Text => $"{Accelerator}Convert to Mp3";
|
||||||
|
public string ReDownloadText => "Re-download this audiobook";
|
||||||
|
public string EditTemplatesText => "Edit Templates";
|
||||||
|
public string FolderTemplateText => "Folder Template";
|
||||||
|
public string FileTemplateText => "File Template";
|
||||||
|
public string MultipartTemplateText => "Multipart File Template";
|
||||||
|
public string ViewBookmarksText => "View _Bookmarks/Clips";
|
||||||
|
public string ViewSeriesText => GridEntry.Liberate.IsSeries ? "View All Episodes in Series" : "View All Books in Series";
|
||||||
|
|
||||||
|
public bool LiberateEpisodesEnabled => GridEntry is ISeriesEntry sEntry && sEntry.Children.Any(c => c.Liberate.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload);
|
||||||
|
public bool SetDownloadedEnabled => GridEntry.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated || GridEntry.Liberate.IsSeries;
|
||||||
|
public bool SetNotDownloadedEnabled => GridEntry.Book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated || GridEntry.Liberate.IsSeries;
|
||||||
|
public bool ConvertToMp3Enabled => GridEntry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated;
|
||||||
|
public bool ReDownloadEnabled => GridEntry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated;
|
||||||
|
|
||||||
|
public IGridEntry GridEntry { get; }
|
||||||
|
public char Accelerator { get; }
|
||||||
|
|
||||||
|
public GridContextMenu(IGridEntry gridEntry, char accelerator)
|
||||||
|
{
|
||||||
|
GridEntry = gridEntry;
|
||||||
|
Accelerator = accelerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetDownloaded()
|
||||||
|
{
|
||||||
|
if (GridEntry is ISeriesEntry series)
|
||||||
|
{
|
||||||
|
series.Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.Liberated);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GridEntry.LibraryBook.UpdateBookStatus(LiberatedStatus.Liberated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetNotDownloaded()
|
||||||
|
{
|
||||||
|
if (GridEntry is ISeriesEntry series)
|
||||||
|
{
|
||||||
|
series.Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.NotLiberated);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GridEntry.LibraryBook.UpdateBookStatus(LiberatedStatus.NotLiberated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RemoveAsync()
|
||||||
|
{
|
||||||
|
if (GridEntry is ISeriesEntry series)
|
||||||
|
{
|
||||||
|
await series.Children.Select(c => c.LibraryBook).RemoveBooksAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await Task.Run(GridEntry.LibraryBook.RemoveBook);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITemplateEditor CreateTemplateEditor<T>(LibraryBook libraryBook, string existingTemplate)
|
||||||
|
where T : Templates, ITemplate, new()
|
||||||
|
{
|
||||||
|
LibraryBookDto fileDto = libraryBook.ToDto(), folderDto = fileDto;
|
||||||
|
|
||||||
|
if (libraryBook.Book.IsEpisodeChild() &&
|
||||||
|
Configuration.Instance.SavePodcastsToParentFolder &&
|
||||||
|
libraryBook.Book.SeriesLink.SingleOrDefault() is SeriesBook series)
|
||||||
|
{
|
||||||
|
using var context = DbContexts.GetContext();
|
||||||
|
var seriesParent = context.GetLibraryBook_Flat_NoTracking(series.Series.AudibleSeriesId);
|
||||||
|
folderDto = seriesParent?.ToDto() ?? fileDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TemplateEditor<T>.CreateFilenameEditor(Configuration.Instance.Books, existingTemplate, folderDto, fileDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
class Command : ICommand
|
||||||
|
{
|
||||||
|
public event EventHandler CanExecuteChanged;
|
||||||
|
|
||||||
|
public bool CanExecute(object parameter)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(object parameter)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -102,19 +102,19 @@ namespace LibationWinForms.GridView
|
|||||||
|
|
||||||
private void productsGrid_CellContextMenuStripNeeded(IGridEntry entry, ContextMenuStrip ctxMenu)
|
private void productsGrid_CellContextMenuStripNeeded(IGridEntry entry, ContextMenuStrip ctxMenu)
|
||||||
{
|
{
|
||||||
|
var ctx = new GridContextMenu(entry, '&');
|
||||||
#region Liberate all Episodes
|
#region Liberate all Episodes
|
||||||
|
|
||||||
if (entry.Liberate.IsSeries)
|
if (entry.Liberate.IsSeries)
|
||||||
{
|
{
|
||||||
var liberateEpisodesMenuItem = new ToolStripMenuItem()
|
var liberateEpisodesMenuItem = new ToolStripMenuItem()
|
||||||
{
|
{
|
||||||
Text = "&Liberate All Episodes",
|
Text = ctx.LiberateEpisodesText,
|
||||||
Enabled = ((ISeriesEntry)entry).Children.Any(c => c.Liberate.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload)
|
Enabled = ctx.LiberateEpisodesEnabled
|
||||||
};
|
};
|
||||||
|
|
||||||
ctxMenu.Items.Add(liberateEpisodesMenuItem);
|
|
||||||
|
|
||||||
liberateEpisodesMenuItem.Click += (_, _) => LiberateSeriesClicked?.Invoke(this, (ISeriesEntry)entry);
|
liberateEpisodesMenuItem.Click += (_, _) => LiberateSeriesClicked?.Invoke(this, (ISeriesEntry)entry);
|
||||||
|
ctxMenu.Items.Add(liberateEpisodesMenuItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -122,61 +122,44 @@ namespace LibationWinForms.GridView
|
|||||||
|
|
||||||
var setDownloadMenuItem = new ToolStripMenuItem()
|
var setDownloadMenuItem = new ToolStripMenuItem()
|
||||||
{
|
{
|
||||||
Text = "Set Download status to '&Downloaded'",
|
Text = ctx.SetDownloadedText,
|
||||||
Enabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated || entry.Liberate.IsSeries
|
Enabled = ctx.SetDownloadedEnabled
|
||||||
};
|
};
|
||||||
|
setDownloadMenuItem.Click += (_, _) => ctx.SetDownloaded();
|
||||||
ctxMenu.Items.Add(setDownloadMenuItem);
|
ctxMenu.Items.Add(setDownloadMenuItem);
|
||||||
|
|
||||||
if (entry.Liberate.IsSeries)
|
|
||||||
setDownloadMenuItem.Click += (_, _) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.Liberated);
|
|
||||||
else
|
|
||||||
setDownloadMenuItem.Click += (_, _) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.Liberated);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Set Download status to Not Downloaded
|
#region Set Download status to Not Downloaded
|
||||||
|
|
||||||
var setNotDownloadMenuItem = new ToolStripMenuItem()
|
var setNotDownloadMenuItem = new ToolStripMenuItem()
|
||||||
{
|
{
|
||||||
Text = "Set Download status to '&Not Downloaded'",
|
Text = ctx.SetNotDownloadedText,
|
||||||
Enabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated || entry.Liberate.IsSeries
|
Enabled = ctx.SetNotDownloadedEnabled
|
||||||
};
|
};
|
||||||
|
setNotDownloadMenuItem.Click += (_, _) => ctx.SetNotDownloaded();
|
||||||
ctxMenu.Items.Add(setNotDownloadMenuItem);
|
ctxMenu.Items.Add(setNotDownloadMenuItem);
|
||||||
|
|
||||||
if (entry.Liberate.IsSeries)
|
|
||||||
setNotDownloadMenuItem.Click += (_, _) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.NotLiberated);
|
|
||||||
else
|
|
||||||
setNotDownloadMenuItem.Click += (_, _) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.NotLiberated);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Remove from library
|
#region Remove from library
|
||||||
|
|
||||||
var removeMenuItem = new ToolStripMenuItem() { Text = "&Remove from library" };
|
var removeMenuItem = new ToolStripMenuItem() { Text = ctx.RemoveText };
|
||||||
|
removeMenuItem.Click += async (_, _) => await ctx.RemoveAsync();
|
||||||
ctxMenu.Items.Add(removeMenuItem);
|
ctxMenu.Items.Add(removeMenuItem);
|
||||||
|
|
||||||
if (entry.Liberate.IsSeries)
|
|
||||||
removeMenuItem.Click += async (_, _) => await ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).RemoveBooksAsync();
|
|
||||||
else
|
|
||||||
removeMenuItem.Click += async (_, _) => await Task.Run(entry.LibraryBook.RemoveBook);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
if (!entry.Liberate.IsSeries)
|
if (!entry.Liberate.IsSeries)
|
||||||
{
|
{
|
||||||
#region Locate file
|
#region Locate file
|
||||||
var locateFileMenuItem = new ToolStripMenuItem() { Text = "&Locate file..." };
|
var locateFileMenuItem = new ToolStripMenuItem() { Text = ctx.LocateFileText };
|
||||||
|
|
||||||
ctxMenu.Items.Add(locateFileMenuItem);
|
ctxMenu.Items.Add(locateFileMenuItem);
|
||||||
|
|
||||||
locateFileMenuItem.Click += (_, _) =>
|
locateFileMenuItem.Click += (_, _) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var openFileDialog = new OpenFileDialog
|
var openFileDialog = new OpenFileDialog
|
||||||
{
|
{
|
||||||
Title = $"Locate the audio file for '{entry.Book.TitleWithSubtitle}'",
|
Title = ctx.LocateFileDialogTitle,
|
||||||
Filter = "All files (*.*)|*.*",
|
Filter = "All files (*.*)|*.*",
|
||||||
FilterIndex = 1
|
FilterIndex = 1
|
||||||
};
|
};
|
||||||
@ -185,8 +168,7 @@ namespace LibationWinForms.GridView
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var msg = "Error saving book's location";
|
MessageBoxLib.ShowAdminAlert(this, ctx.LocateFileErrorMessage, ctx.LocateFileErrorMessage, ex);
|
||||||
MessageBoxLib.ShowAdminAlert(this, msg, msg, ex);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -195,13 +177,11 @@ namespace LibationWinForms.GridView
|
|||||||
|
|
||||||
var convertToMp3MenuItem = new ToolStripMenuItem
|
var convertToMp3MenuItem = new ToolStripMenuItem
|
||||||
{
|
{
|
||||||
Text = "&Convert to Mp3",
|
Text = ctx.ConvertToMp3Text,
|
||||||
Enabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
Enabled = ctx.ConvertToMp3Enabled
|
||||||
};
|
};
|
||||||
|
|
||||||
ctxMenu.Items.Add(convertToMp3MenuItem);
|
|
||||||
|
|
||||||
convertToMp3MenuItem.Click += (_, e) => ConvertToMp3Clicked?.Invoke(this, entry.LibraryBook);
|
convertToMp3MenuItem.Click += (_, e) => ConvertToMp3Clicked?.Invoke(this, entry.LibraryBook);
|
||||||
|
ctxMenu.Items.Add(convertToMp3MenuItem);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -211,10 +191,9 @@ namespace LibationWinForms.GridView
|
|||||||
{
|
{
|
||||||
var reDownloadMenuItem = new ToolStripMenuItem()
|
var reDownloadMenuItem = new ToolStripMenuItem()
|
||||||
{
|
{
|
||||||
Text = "Re-download this audiobook",
|
Text = ctx.ReDownloadText,
|
||||||
Enabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
Enabled = ctx.ReDownloadEnabled
|
||||||
};
|
};
|
||||||
|
|
||||||
ctxMenu.Items.Add(reDownloadMenuItem);
|
ctxMenu.Items.Add(reDownloadMenuItem);
|
||||||
reDownloadMenuItem.Click += (s, _) =>
|
reDownloadMenuItem.Click += (s, _) =>
|
||||||
{
|
{
|
||||||
@ -223,6 +202,35 @@ namespace LibationWinForms.GridView
|
|||||||
LiberateClicked?.Invoke(s, entry.LibraryBook);
|
LiberateClicked?.Invoke(s, entry.LibraryBook);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
#region Edit Templates
|
||||||
|
void editTemplate<T>(LibraryBook libraryBook, string existingTemplate, Action<string> setNewTemplate)
|
||||||
|
where T : Templates, LibationFileManager.ITemplate, new()
|
||||||
|
{
|
||||||
|
var template = ctx.CreateTemplateEditor<T>(libraryBook, existingTemplate);
|
||||||
|
var form = new EditTemplateDialog(template);
|
||||||
|
if (form.ShowDialog(this) == DialogResult.OK)
|
||||||
|
{
|
||||||
|
setNewTemplate(template.EditingTemplate.TemplateText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entry.Liberate.IsSeries)
|
||||||
|
{
|
||||||
|
var folderTemplateMenuItem = new ToolStripMenuItem { Text = ctx.FolderTemplateText };
|
||||||
|
var fileTemplateMenuItem = new ToolStripMenuItem { Text = ctx.FileTemplateText };
|
||||||
|
var multiFileTemplateMenuItem = new ToolStripMenuItem { Text = ctx.MultipartTemplateText };
|
||||||
|
folderTemplateMenuItem.Click += (s, _) => editTemplate<Templates.FolderTemplate>(entry.LibraryBook, Configuration.Instance.FolderTemplate, t => Configuration.Instance.FolderTemplate = t);
|
||||||
|
fileTemplateMenuItem.Click += (s, _) => editTemplate<Templates.FileTemplate>(entry.LibraryBook, Configuration.Instance.FileTemplate, t => Configuration.Instance.FileTemplate = t);
|
||||||
|
multiFileTemplateMenuItem.Click += (s, _) => editTemplate<Templates.ChapterFileTemplate>(entry.LibraryBook, Configuration.Instance.ChapterFileTemplate, t => Configuration.Instance.ChapterFileTemplate = t);
|
||||||
|
|
||||||
|
var editTemplatesMenuItem = new ToolStripMenuItem { Text = ctx.EditTemplatesText };
|
||||||
|
editTemplatesMenuItem.DropDownItems.AddRange(new[] { folderTemplateMenuItem, fileTemplateMenuItem, multiFileTemplateMenuItem });
|
||||||
|
|
||||||
|
ctxMenu.Items.Add(new ToolStripSeparator());
|
||||||
|
ctxMenu.Items.Add(editTemplatesMenuItem);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
ctxMenu.Items.Add(new ToolStripSeparator());
|
ctxMenu.Items.Add(new ToolStripSeparator());
|
||||||
@ -231,11 +239,9 @@ namespace LibationWinForms.GridView
|
|||||||
|
|
||||||
if (!entry.Liberate.IsSeries)
|
if (!entry.Liberate.IsSeries)
|
||||||
{
|
{
|
||||||
var bookRecordMenuItem = new ToolStripMenuItem { Text = "View &Bookmarks/Clips" };
|
var bookRecordMenuItem = new ToolStripMenuItem { Text = ctx.ViewBookmarksText };
|
||||||
|
|
||||||
ctxMenu.Items.Add(bookRecordMenuItem);
|
|
||||||
|
|
||||||
bookRecordMenuItem.Click += (_, _) => new BookRecordsDialog(entry.LibraryBook).ShowDialog(this);
|
bookRecordMenuItem.Click += (_, _) => new BookRecordsDialog(entry.LibraryBook).ShowDialog(this);
|
||||||
|
ctxMenu.Items.Add(bookRecordMenuItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -243,13 +249,9 @@ namespace LibationWinForms.GridView
|
|||||||
|
|
||||||
if (entry.Book.SeriesLink.Any())
|
if (entry.Book.SeriesLink.Any())
|
||||||
{
|
{
|
||||||
var header = entry.Liberate.IsSeries ? "View All Episodes in Series" : "View All Books in Series";
|
var viewSeriesMenuItem = new ToolStripMenuItem { Text = ctx.ViewSeriesText };
|
||||||
|
|
||||||
var viewSeriesMenuItem = new ToolStripMenuItem { Text = header };
|
|
||||||
|
|
||||||
ctxMenu.Items.Add(viewSeriesMenuItem);
|
|
||||||
|
|
||||||
viewSeriesMenuItem.Click += (_, _) => new SeriesViewDialog(entry.LibraryBook).Show();
|
viewSeriesMenuItem.Click += (_, _) => new SeriesViewDialog(entry.LibraryBook).Show();
|
||||||
|
ctxMenu.Items.Add(viewSeriesMenuItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user