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:
MBucari 2023-08-12 17:12:38 -06:00
parent 167a021eb1
commit e65b6c76a8
5 changed files with 306 additions and 163 deletions

View File

@ -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)
{ {

View File

@ -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

View File

@ -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");

View 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();
}
}

View File

@ -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