Added SettingsDialog

This commit is contained in:
Michael Bucari-Tovo 2022-07-18 22:59:36 -06:00
parent 10359aa5e8
commit 0c98ce000b
11 changed files with 655 additions and 260 deletions

View File

@ -0,0 +1,33 @@
<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"
xmlns:controls="clr-namespace:LibationWinForms.AvaloniaUI.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="LibationWinForms.AvaloniaUI.Controls.DirectoryOrCustomSelectControl">
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto">
<controls:DirectorySelectControl
Grid.Column="1"
Grid.Row="0"
Name="directorySelectControl"
SubDirectory="{Binding $parent.SubDirectory}"
KnownDirectories="{Binding $parent.KnownDirectories}" />
<RadioButton
Grid.Column="0"
Grid.Row="0"
Name="knownDirRadio"
IsChecked="{Binding KnownChecked, Mode=TwoWay}" />
<RadioButton
Grid.Column="0"
Grid.Row="1"
Name="customDirRadio"
IsChecked="{Binding CustomChecked, Mode=TwoWay}" />
<Grid Grid.Column="1" Grid.Row="1" ColumnDefinitions="*,Auto">
<TextBox IsEnabled="{Binding CustomChecked}" Name="customDirTbox" Grid.Column="0" IsReadOnly="True" Text="{Binding CustomDir, Mode=TwoWay}" />
<Button Name="customDirBrowseBtn" Grid.Column="1" Content="..." Margin="5,0,0,0" Padding="10,0,10,0" VerticalAlignment="Stretch" />
</Grid>
</Grid>
</UserControl>

View File

@ -0,0 +1,176 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Dinah.Core;
using LibationFileManager;
using System.Collections.Generic;
using ReactiveUI;
namespace LibationWinForms.AvaloniaUI.Controls
{
public partial class DirectoryOrCustomSelectControl : UserControl
{
public static readonly StyledProperty<List<Configuration.KnownDirectories>> KnownDirectoriesProperty =
AvaloniaProperty.Register<DirectorySelectControl, List<Configuration.KnownDirectories>>(nameof(KnownDirectories), DirectorySelectControl.DefaultKnownDirectories);
public static readonly StyledProperty<string> SubDirectoryProperty =
AvaloniaProperty.Register<DirectorySelectControl, string>(nameof(SubDirectory));
public static readonly StyledProperty<string> DirectoryProperty =
AvaloniaProperty.Register<DirectorySelectControl, string>(nameof(Directory));
public List<Configuration.KnownDirectories> KnownDirectories
{
get => GetValue(KnownDirectoriesProperty);
set => SetValue(KnownDirectoriesProperty, value);
}
public string Directory
{
get => GetValue(DirectoryProperty);
set => SetValue(DirectoryProperty, value);
}
public string SubDirectory
{
get => GetValue(SubDirectoryProperty);
set => SetValue(SubDirectoryProperty, value);
}
CustomState customStates = new();
public DirectoryOrCustomSelectControl()
{
InitializeComponent();
customDirBrowseBtn = this.Find<Button>(nameof(customDirBrowseBtn));
directorySelectControl = this.Find<DirectorySelectControl>(nameof(directorySelectControl));
this.Find<TextBox>(nameof(customDirTbox)).DataContext = customStates;
this.Find<RadioButton>(nameof(knownDirRadio)).DataContext = customStates;
this.Find<RadioButton>(nameof(customDirRadio)).DataContext = customStates;
customStates.PropertyChanged += CheckStates_PropertyChanged;
customDirBrowseBtn.Click += CustomDirBrowseBtn_Click;
PropertyChanged += DirectoryOrCustomSelectControl_PropertyChanged;
directorySelectControl.PropertyChanged += DirectorySelectControl_PropertyChanged;
}
private class CustomState: ViewModels.ViewModelBase
{
private string _customDir;
private bool _knownChecked;
private bool _customChecked;
public string CustomDir { get=> _customDir; set => this.RaiseAndSetIfChanged(ref _customDir, value); }
public bool KnownChecked
{
get => _knownChecked;
set
{
this.RaiseAndSetIfChanged(ref _knownChecked, value);
if (value)
CustomChecked = false;
else if (!CustomChecked)
CustomChecked = true;
}
}
public bool CustomChecked
{
get => _customChecked;
set
{
this.RaiseAndSetIfChanged(ref _customChecked, value);
if (value)
KnownChecked = false;
else if (!KnownChecked)
KnownChecked = true;
}
}
}
private async void CustomDirBrowseBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
OpenFolderDialog ofd = new();
customStates.CustomDir = await ofd.ShowAsync(VisualRoot as Window);
}
private void CheckStates_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName != nameof(CustomState.CustomDir))
{
directorySelectControl.IsEnabled = !customStates.CustomChecked;
customDirBrowseBtn.IsEnabled = customStates.CustomChecked;
}
setDirectory();
}
private void DirectorySelectControl_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property.Name == nameof(DirectorySelectControl.SelectedDirectory))
{
setDirectory();
}
}
private void setDirectory()
{
Directory
= customStates.CustomChecked ? customStates.CustomDir
: directorySelectControl.SelectedDirectory is Configuration.KnownDirectories.AppDir ? Configuration.AppDir_Absolute
: Configuration.GetKnownDirectoryPath(directorySelectControl.SelectedDirectory);
}
private void DirectoryOrCustomSelectControl_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property.Name == nameof(Directory) && e.OldValue is null)
{
var directory = Directory?.Trim() ?? "";
var noSubDir = RemoveSubDirectoryFromPath(directory);
var known = Configuration.GetKnownDirectory(noSubDir);
if (known == Configuration.KnownDirectories.None && noSubDir == Configuration.AppDir_Absolute)
known = Configuration.KnownDirectories.AppDir;
if (known is Configuration.KnownDirectories.None)
{
customStates.CustomChecked = true;
customStates.CustomDir = noSubDir;
}
else
{
customStates.KnownChecked = true;
directorySelectControl.SelectedDirectory = known;
}
}
else if (e.Property.Name == nameof(KnownDirectories))
directorySelectControl.KnownDirectories = KnownDirectories;
else if (e.Property.Name == nameof(SubDirectory))
directorySelectControl.SubDirectory = SubDirectory;
}
private string RemoveSubDirectoryFromPath(string path)
{
if (string.IsNullOrWhiteSpace(SubDirectory))
return path;
path = path?.Trim() ?? "";
if (string.IsNullOrWhiteSpace(path))
return path;
var bottomDir = System.IO.Path.GetFileName(path);
if (SubDirectory.EqualsInsensitive(bottomDir))
return System.IO.Path.GetDirectoryName(path);
return path;
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View File

@ -1,53 +1,40 @@
<TemplatedControl xmlns="https://github.com/avaloniaui"
<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"
xmlns:controls="clr-namespace:LibationWinForms.AvaloniaUI.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="LibationWinForms.AvaloniaUI.Controls.DirectorySelectControl">
<Design.DataContext>
</Design.DataContext>
<TemplatedControl.Styles>
<Style Selector="controls|DirectorySelectControl Border">
<Setter Property="BorderBrush" Value="DarkGray" />
</Style>
<Style Selector="controls|DirectorySelectControl">
<Setter Property="Template">
<ControlTemplate>
<StackPanel Orientation="Vertical">
<StackPanel.Styles>
<Style Selector="ItemsPresenter#PART_ItemsPresenter">
<Setter Property="Height" Value="NaN"/>
</Style>
</StackPanel.Styles>
<ComboBox
HorizontalContentAlignment = "Stretch"
HorizontalAlignment = "Stretch"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch"
SelectedItem="{Binding SelectedComboBoxItem, Mode=TwoWay}"
Items="{Binding ComboBoxItems}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock
FontSize="12"
Text="{Binding Description}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBox Margin="0,10,0,10" Text="{Binding SelectedComboBoxItem.UiDisplayPath}" />
</StackPanel>
</ControlTemplate>
</Setter>
</Style>
</TemplatedControl.Styles>
</TemplatedControl>
<UserControl.Resources>
<controls:KnownDirectoryConverter x:Key="KnownDirectoryConverter" />
</UserControl.Resources>
<StackPanel Orientation="Vertical">
<StackPanel.Styles>
<Style Selector="ItemsPresenter#PART_ItemsPresenter">
<Setter Property="Height" Value="NaN"/>
</Style>
</StackPanel.Styles>
<controls:WheelComboBox
HorizontalContentAlignment = "Stretch"
HorizontalAlignment = "Stretch"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch"
SelectedItem="{Binding $parent[1].SelectedDirectory, Mode=TwoWay}"
Items="{Binding $parent[1].KnownDirectories}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock
FontSize="12"
Text="{Binding, Converter={StaticResource KnownDirectoryConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</controls:WheelComboBox>
<TextBox Margin="0,10,0,10" IsReadOnly="True" Name="displayPathTbox" />
</StackPanel>
</UserControl>

View File

@ -4,109 +4,91 @@ using Avalonia.Markup.Xaml;
using Dinah.Core;
using LibationFileManager;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using ReactiveUI;
using Avalonia.Controls.Primitives;
using System.Collections;
using Avalonia.Data.Converters;
using System;
using System.Globalization;
using Avalonia.Data;
using System.IO;
using System.Reactive.Subjects;
namespace LibationWinForms.AvaloniaUI.Controls
{
public class TextCaseConverter : IValueConverter
public class KnownDirectoryConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Configuration.KnownDirectories dir)
{
}
return dir.GetDescription();
return new BindingNotification(new InvalidCastException(), BindingErrorType.Error);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
return new BindingNotification(new InvalidCastException(), BindingErrorType.Error);
}
}
public partial class DirectorySelectControl : TemplatedControl
public partial class DirectorySelectControl : UserControl
{
private static readonly List<Configuration.KnownDirectories> defaultList = new List<Configuration.KnownDirectories>()
{
Configuration.KnownDirectories.WinTemp,
Configuration.KnownDirectories.UserProfile,
Configuration.KnownDirectories.AppDir,
Configuration.KnownDirectories.MyDocs,
Configuration.KnownDirectories.LibationFiles
public static List<Configuration.KnownDirectories> DefaultKnownDirectories { get; }
= new()
{
Configuration.KnownDirectories.WinTemp,
Configuration.KnownDirectories.UserProfile,
Configuration.KnownDirectories.AppDir,
Configuration.KnownDirectories.MyDocs,
Configuration.KnownDirectories.LibationFiles
};
public static readonly StyledProperty<Configuration.KnownDirectories?> SelectedirectoryProperty =
AvaloniaProperty.Register<DirectorySelectControl, Configuration.KnownDirectories?>(nameof(Selectedirectory), defaultList[0]);
public static readonly StyledProperty<Configuration.KnownDirectories> SelectedDirectoryProperty =
AvaloniaProperty.Register<DirectorySelectControl, Configuration.KnownDirectories>(nameof(SelectedDirectory));
public static readonly StyledProperty<List<Configuration.KnownDirectories>> KnownDirectoriesProperty =
AvaloniaProperty.Register<DirectorySelectControl, List<Configuration.KnownDirectories>>(nameof(KnownDirectories), defaultList);
AvaloniaProperty.Register<DirectorySelectControl, List<Configuration.KnownDirectories>>(nameof(KnownDirectories), DefaultKnownDirectories);
public static readonly StyledProperty<string?> SubdirectoryProperty =
AvaloniaProperty.Register<DirectorySelectControl, string?>(nameof(Subdirectory), "subdir");
public static readonly StyledProperty<string> SubDirectoryProperty =
AvaloniaProperty.Register<DirectorySelectControl, string>(nameof(SubDirectory));
DirectorySelectViewModel DirectorySelect { get; } = new();
public DirectorySelectControl()
{
InitializeComponent();
displayPathTbox = this.Get<TextBox>(nameof(displayPathTbox));
displayPathTbox.Bind(TextBox.TextProperty, TextboxPath);
PropertyChanged += DirectorySelectControl_PropertyChanged;
}
protected override void OnInitialized()
private Subject<string> TextboxPath = new Subject<string>();
private void DirectorySelectControl_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)
{
DirectorySelect.Directories.Clear();
int insertIndex = 0;
foreach (var kd in KnownDirectories.Distinct())
DirectorySelect.Directories.Insert(insertIndex++, new(this, kd));
DataContext = DirectorySelect;
base.OnInitialized();
if (e.Property.Name == nameof(SelectedDirectory))
{
TextboxPath.OnNext(
Path.Combine(
SelectedDirectory is Configuration.KnownDirectories.None ? string.Empty
: SelectedDirectory is Configuration.KnownDirectories.AppDir ? Configuration.AppDir_Absolute
: Configuration.GetKnownDirectoryPath(SelectedDirectory)
, SubDirectory ?? string.Empty));
}
}
public List<Configuration.KnownDirectories> KnownDirectories
{
get { return GetValue(KnownDirectoriesProperty); }
set
{
SetValue(KnownDirectoriesProperty, value);
//SetDirectoryItems(KnownDirectories);
}
get => GetValue(KnownDirectoriesProperty);
set => SetValue(KnownDirectoriesProperty, value);
}
public Configuration.KnownDirectories? Selectedirectory
public Configuration.KnownDirectories SelectedDirectory
{
get { return GetValue(SelectedirectoryProperty); }
set
{
SetValue(SelectedirectoryProperty, value);
if (value is null or Configuration.KnownDirectories.None)
return;
// set default
var item = DirectorySelect.Directories.SingleOrDefault(item => item.Value == value.Value);
if (item is null)
return;
DirectorySelect.SelectedDirectory = item;
}
get => GetValue(SelectedDirectoryProperty);
set => SetValue(SelectedDirectoryProperty, value);
}
public string? Subdirectory
public string SubDirectory
{
get { return GetValue(SubdirectoryProperty); }
set
{
SetValue(SubdirectoryProperty, value);
}
get => GetValue(SubDirectoryProperty);
set => SetValue(SubDirectoryProperty, value);
}
private void InitializeComponent()
@ -114,33 +96,4 @@ namespace LibationWinForms.AvaloniaUI.Controls
AvaloniaXamlLoader.Load(this);
}
}
public class DirectorySelectViewModel : ViewModels.ViewModelBase
{
public class DirectoryComboBoxItem
{
private readonly DirectorySelectControl _parentControl;
public string Description { get; }
public Configuration.KnownDirectories Value { get; }
public string FullPath => AddSubDirectoryToPath(Configuration.GetKnownDirectoryPath(Value));
/// <summary>Displaying relative paths is confusing. UI should display absolute equivalent</summary>
public string UiDisplayPath => Value == Configuration.KnownDirectories.AppDir ? AddSubDirectoryToPath(Configuration.AppDir_Absolute) : FullPath;
public DirectoryComboBoxItem(DirectorySelectControl parentControl, Configuration.KnownDirectories knownDirectory)
{
_parentControl = parentControl;
Value = knownDirectory;
Description = Value.GetDescription();
}
internal string AddSubDirectoryToPath(string path) => string.IsNullOrWhiteSpace(_parentControl.Subdirectory) ? path : System.IO.Path.Combine(path, _parentControl.Subdirectory);
public override string ToString() => Description;
}
public ObservableCollection<DirectoryComboBoxItem> Directories { get; } = new(new());
private DirectoryComboBoxItem _selectedDirectory;
public DirectoryComboBoxItem SelectedDirectory { get => _selectedDirectory; set => this.RaiseAndSetIfChanged(ref _selectedDirectory, value); }
}
}

View File

@ -1,5 +1,9 @@
<ComboBox xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="LibationWinForms.AvaloniaUI.Controls.WheelComboBox">
<ComboBox.Styles>
<Style Selector="ItemsPresenter#PART_ItemsPresenter">
<Setter Property="Height" Value="NaN"/>
</Style>
</ComboBox.Styles>
</ComboBox>

View File

@ -2,6 +2,7 @@
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using DataLayer;
using Dinah.Core.Logging;
using LibationWinForms.AvaloniaUI.ViewModels.Dialogs;
using LibationWinForms.AvaloniaUI.Views.Dialogs;
using System;
@ -201,6 +202,23 @@ namespace LibationWinForms.AvaloniaUI
return await ShowCore(owner, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
}
public static async Task VerboseLoggingWarning_ShowIfTrue()
{
// when turning on debug (and especially Verbose) to share logs, some privacy settings may not be obscured
if (Serilog.Log.Logger.IsVerboseEnabled())
await Show(@"
Warning: verbose logging is enabled.
This should be used for debugging only. It creates many
more logs and debug files, neither of which are as
strictly anonymous.
When you are finished debugging, it's highly recommended
to set your debug MinimumLevel to Information and restart
Libation.
".Trim(), "Verbose logging enabled", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
public static async Task<DialogResult> ShowConfirmationDialog(Window owner, IEnumerable<LibraryBook> libraryBooks, string format, string title, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1)
{
if (libraryBooks is null || !libraryBooks.Any())

View File

@ -2,7 +2,7 @@
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="900" d:DesignHeight="600"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="620"
x:Class="LibationWinForms.AvaloniaUI.Views.Dialogs.SettingsDialog"
xmlns:controls="clr-namespace:LibationWinForms.AvaloniaUI.Controls"
Title="Edit Settings"
@ -19,16 +19,139 @@
Content="Save"
Click="SaveButton_Clicked" />
<TabControl Grid.Column="0">
<TabControl Grid.Column="0">
<TabControl.Styles>
<Style Selector="ItemsPresenter#PART_ItemsPresenter">
<Setter Property="Height" Value="33"/>
<Setter Property="Height" Value="18"/>
</Style>
<Style Selector="TextBlock">
<Setter Property="FontSize" Value="12"/>
<Style Selector="TabItem">
<Setter Property="MinHeight" Value="30"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Padding" Value="8,2,8,0"/>
</Style>
<Style Selector="TabItem#Header TextBlock">
<Setter Property="MinHeight" Value="5"/>
</Style>
</TabControl.Styles>
<TabItem Margin="0" Name="tabItem1">
<TabItem.Header>
<TextBlock
FontSize="14"
VerticalAlignment="Center"
Text="Important Settings"/>
</TabItem.Header>
<Border
Grid.Column="0"
Grid.Row="0"
BorderThickness="2"
BorderBrush="{DynamicResource DataGridGridLinesBrush}">
<Grid RowDefinitions="Auto,Auto,*">
<controls:GroupBox
Grid.Row="0"
Margin="5"
BorderWidth="1"
Label="Books Location">
<StackPanel>
<TextBlock
Margin="5"
Text="{Binding ImportantSettings.BooksText}" />
<controls:DirectoryOrCustomSelectControl Margin="0,10,0,10"
SubDirectory="Books"
Directory="{Binding ImportantSettings.BooksDirectory, Mode=TwoWay}"
KnownDirectories="{Binding ImportantSettings.KnownDirectories}" />
<CheckBox IsChecked="{Binding ImportantSettings.SavePodcastsToParentFolder, Mode=TwoWay}">
<TextBlock Text="{Binding ImportantSettings.SavePodcastsToParentFolderText}" />
</CheckBox>
</StackPanel>
</controls:GroupBox>
<StackPanel
Grid.Row="1" Margin="5"
Orientation="Horizontal">
<TextBlock Margin="0,0,10,0" VerticalAlignment="Center" Text="Logging level" />
<controls:WheelComboBox
Width="150"
Height="25"
HorizontalContentAlignment="Stretch"
SelectedItem="{Binding ImportantSettings.LoggingLevel, Mode=TwoWay}"
Items="{Binding ImportantSettings.LoggingLevels}" />
<Button
Margin="50,0,0,0"
Padding="20,3,20,3"
Content="Open Log Folder"
Click="OpenLogFolderButton_Click" />
</StackPanel>
<CheckBox
Grid.Row="2"
Margin="5"
VerticalAlignment="Bottom"
IsChecked="{Binding ImportantSettings.BetaOptIn, Mode=TwoWay}">
<TextBlock Text="{Binding ImportantSettings.BetaOptInText}" />
</CheckBox>
</Grid>
</Border>
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock
FontSize="14"
VerticalAlignment="Center"
Text="Import Library"/>
</TabItem.Header>
<Border
Grid.Column="0"
Grid.Row="0"
BorderThickness="2"
BorderBrush="{DynamicResource DataGridGridLinesBrush}">
<StackPanel Margin="5">
<CheckBox Margin="0,0,0,10" IsChecked="{Binding ImportSettings.AutoScan, Mode=TwoWay}">
<TextBlock TextWrapping="Wrap" Text="{Binding ImportSettings.AutoScanText}" />
</CheckBox>
<CheckBox Margin="0,0,0,10" IsChecked="{Binding ImportSettings.ShowImportedStats, Mode=TwoWay}">
<TextBlock TextWrapping="Wrap" Text="{Binding ImportSettings.ShowImportedStatsText}" />
</CheckBox>
<CheckBox Margin="0,0,0,10" IsChecked="{Binding ImportSettings.ImportEpisodes, Mode=TwoWay}">
<TextBlock TextWrapping="Wrap" Text="{Binding ImportSettings.ImportEpisodesText}" />
</CheckBox>
<CheckBox Margin="0,0,0,10" IsChecked="{Binding ImportSettings.DownloadEpisodes, Mode=TwoWay}">
<TextBlock TextWrapping="Wrap" Text="{Binding ImportSettings.DownloadEpisodesText}" />
</CheckBox>
<CheckBox Margin="0,0,0,10" IsChecked="{Binding ImportSettings.AutoDownloadEpisodes, Mode=TwoWay}">
<TextBlock TextWrapping="Wrap" Text="{Binding ImportSettings.AutoDownloadEpisodesText}" />
</CheckBox>
</StackPanel>
</Border>
</TabItem>
<TabItem>
<TabItem.Header>
@ -43,11 +166,14 @@
Grid.Column="0"
Grid.Row="0"
BorderThickness="2"
Background="WhiteSmoke"
BorderBrush="{DynamicResource DataGridGridLinesBrush}">
<Grid RowDefinitions="Auto,Auto,*">
<controls:GroupBox Grid.Row="0" BorderWidth="1" Label="{Binding DownloadDecryptSettings.BadBookGroupboxText}">
<controls:GroupBox
Grid.Row="0"
Margin="5"
BorderWidth="1"
Label="{Binding DownloadDecryptSettings.BadBookGroupboxText}">
<Grid ColumnDefinitions="*,*" RowDefinitions="Auto,Auto">
@ -56,37 +182,41 @@
Grid.Row="0"
Margin="0,5,0,5"
IsChecked="{Binding DownloadDecryptSettings.BadBookAsk, Mode=TwoWay}">
<TextBlock Text="{Binding DownloadDecryptSettings.BadBookAskText}" />
<TextBlock TextWrapping="Wrap" Text="{Binding DownloadDecryptSettings.BadBookAskText}" />
</RadioButton>
<RadioButton
Grid.Column="1"
Grid.Row="0"
Margin="0,5,0,5"
IsChecked="{Binding DownloadDecryptSettings.BadBookAbort, Mode=TwoWay}">
<TextBlock Text="{Binding DownloadDecryptSettings.BadBookAbortText}" />
<TextBlock TextWrapping="Wrap" Text="{Binding DownloadDecryptSettings.BadBookAbortText}" />
</RadioButton>
<RadioButton
Grid.Column="0"
Grid.Row="1"
Margin="0,5,0,5"
IsChecked="{Binding DownloadDecryptSettings.BadBookRetry, Mode=TwoWay}">
<TextBlock Text="{Binding DownloadDecryptSettings.BadBookRetryText}" />
<TextBlock TextWrapping="Wrap" Text="{Binding DownloadDecryptSettings.BadBookRetryText}" />
</RadioButton>
<RadioButton
Grid.Column="1"
Grid.Row="1"
Margin="0,5,0,5"
IsChecked="{Binding DownloadDecryptSettings.BadBookIgnore, Mode=TwoWay}">
<TextBlock Text="{Binding DownloadDecryptSettings.BadBookIgnoreText}" />
<TextBlock TextWrapping="Wrap" Text="{Binding DownloadDecryptSettings.BadBookIgnoreText}" />
</RadioButton>
</Grid>
</Grid>
</controls:GroupBox>
<controls:GroupBox Grid.Row="1" BorderWidth="1" Label="Custom File Naming">
<controls:GroupBox
Margin="5"
Grid.Row="1"
BorderWidth="1"
Label="Custom File Naming">
<Grid RowDefinitions="Auto,Auto,Auto,Auto" ColumnDefinitions="*,Auto">
<TextBox
Grid.Row="0"
Grid.Column="0"
@ -102,7 +232,7 @@
Height="30"
Padding="30,3,30,3"
Click="EditFolderTemplateButton_Click" />
<TextBox
Grid.Row="1"
Grid.Column="0"
@ -118,7 +248,7 @@
Height="30"
Padding="30,3,30,3"
Click="EditFileTemplateButton_Click" />
<TextBox
Grid.Row="2"
Grid.Column="0"
@ -141,18 +271,23 @@
Content="{Binding DownloadDecryptSettings.EditCharReplacementText}"
Height="30"
Padding="30,3,30,3"
Click="EditChapterTitleTemplateButton_Click" />
</Grid>
</controls:GroupBox>
<controls:DirectorySelectControl
Grid.Row="2"
Subdirectory="{Binding DownloadDecryptSettings.EditCharReplacementText}"
KnownDirectories="{Binding DownloadDecryptSettings.KnownDirectories}"
Selectedirectory="{Binding DownloadDecryptSettings.SelectedDirectory, Mode=TwoWay}" />
Click="EditCharReplacementButton_Click" />
</Grid>
</controls:GroupBox>
<StackPanel
Grid.Row="2"
Margin="5" >
<TextBlock Margin="0,0,0,10" Text="{Binding DownloadDecryptSettings.InProgressDescriptionText}" />
<controls:DirectorySelectControl
SubDirectory="Libation\DecryptInProgress"
SelectedDirectory="{Binding DownloadDecryptSettings.InProgressDirectory, Mode=TwoWay}" />
</StackPanel>
</Grid>
</Border>
@ -173,7 +308,6 @@
Grid.Column="0"
Grid.Row="0"
BorderThickness="2"
Background="WhiteSmoke"
BorderBrush="{DynamicResource DataGridGridLinesBrush}">
<Grid
@ -184,42 +318,42 @@
Grid.Row="0"
Grid.Column="0">
<CheckBox IsChecked="{Binding AudioSettings.CreateCueSheet, Mode=TwoWay}">
<TextBlock Text="{Binding AudioSettings.CreateCueSheetText}" />
<CheckBox Margin="0,0,0,5" IsChecked="{Binding AudioSettings.CreateCueSheet, Mode=TwoWay}">
<TextBlock TextWrapping="Wrap" Text="{Binding AudioSettings.CreateCueSheetText}" />
</CheckBox>
<CheckBox IsChecked="{Binding AudioSettings.DownloadCoverArt, Mode=TwoWay}">
<TextBlock Text="{Binding AudioSettings.DownloadCoverArtText}" />
<CheckBox Margin="0,0,0,5" IsChecked="{Binding AudioSettings.DownloadCoverArt, Mode=TwoWay}">
<TextBlock TextWrapping="Wrap" Text="{Binding AudioSettings.DownloadCoverArtText}" />
</CheckBox>
<CheckBox IsChecked="{Binding AudioSettings.RetainAaxFile, Mode=TwoWay}">
<TextBlock Text="{Binding AudioSettings.RetainAaxFileText}" />
<CheckBox Margin="0,0,0,5" IsChecked="{Binding AudioSettings.RetainAaxFile, Mode=TwoWay}">
<TextBlock TextWrapping="Wrap" Text="{Binding AudioSettings.RetainAaxFileText}" />
</CheckBox>
<CheckBox IsChecked="{Binding AudioSettings.MergeOpeningAndEndCredits, Mode=TwoWay}">
<TextBlock Text="{Binding AudioSettings.MergeOpeningEndCreditsText}" />
<CheckBox Margin="0,0,0,5" IsChecked="{Binding AudioSettings.MergeOpeningAndEndCredits, Mode=TwoWay}">
<TextBlock TextWrapping="Wrap" Text="{Binding AudioSettings.MergeOpeningEndCreditsText}" />
</CheckBox>
<CheckBox IsChecked="{Binding AudioSettings.AllowLibationFixup, Mode=TwoWay}">
<TextBlock Text="{Binding AudioSettings.AllowLibationFixupText}" />
<CheckBox Margin="0,0,0,5" IsChecked="{Binding AudioSettings.AllowLibationFixup, Mode=TwoWay}">
<TextBlock TextWrapping="Wrap" Text="{Binding AudioSettings.AllowLibationFixupText}" />
</CheckBox>
<controls:GroupBox BorderWidth="1" Label="Audiobook Fix-ups" IsEnabled="{Binding AudioSettings.AllowLibationFixup}">
<StackPanel Orientation="Vertical">
<CheckBox IsChecked="{Binding AudioSettings.SplitFilesByChapter, Mode=TwoWay}">
<TextBlock Text="{Binding AudioSettings.SplitFilesByChapterText}" />
<CheckBox Margin="0,0,0,5" IsChecked="{Binding AudioSettings.SplitFilesByChapter, Mode=TwoWay}">
<TextBlock TextWrapping="Wrap" Text="{Binding AudioSettings.SplitFilesByChapterText}" />
</CheckBox>
<CheckBox IsChecked="{Binding AudioSettings.StripAudibleBrandAudio, Mode=TwoWay}">
<TextBlock Text="{Binding AudioSettings.StripAudibleBrandingText}" />
<CheckBox Margin="0,0,0,5" IsChecked="{Binding AudioSettings.StripAudibleBrandAudio, Mode=TwoWay}">
<TextBlock TextWrapping="Wrap" Text="{Binding AudioSettings.StripAudibleBrandingText}" />
</CheckBox>
<CheckBox IsChecked="{Binding AudioSettings.StripUnabridged, Mode=TwoWay}">
<TextBlock Text="{Binding AudioSettings.StripUnabridgedText}" />
<CheckBox Margin="0,0,0,5" IsChecked="{Binding AudioSettings.StripUnabridged, Mode=TwoWay}">
<TextBlock TextWrapping="Wrap" Text="{Binding AudioSettings.StripUnabridgedText}" />
</CheckBox>
<RadioButton Margin="0,5,0,5" IsChecked="{Binding !AudioSettings.DecryptToLossy, Mode=TwoWay}">
<TextBlock Text="Download my books in the original audio format (Lossless)" />
<TextBlock TextWrapping="Wrap" Text="Download my books in the original audio format (Lossless)" />
</RadioButton>
<RadioButton Margin="0,5,0,5" IsChecked="{Binding AudioSettings.DecryptToLossy, Mode=TwoWay}">
<TextBlock Text="Download my books as .MP3 files (transcode if necessary)" />
<TextBlock TextWrapping="Wrap" Text="Download my books as .MP3 files (transcode if necessary)" />
</RadioButton>
</StackPanel>
@ -253,7 +387,7 @@
</controls:GroupBox>
<CheckBox HorizontalAlignment="Right" Grid.Column="1" IsChecked="{Binding AudioSettings.LameDownsampleMono, Mode=TwoWay}">
<TextBlock Text="Downsample to mono?&#xa;(Recommended)" />
<TextBlock TextWrapping="Wrap" Text="Downsample to mono? (Recommended)" />
</CheckBox>
</Grid>
<controls:GroupBox Margin="5,5,5,0" BorderWidth="1" Label="Bitrate" IsEnabled="{Binding AudioSettings.LameTargetBitrate}" >
@ -280,18 +414,18 @@
<TextBlock Grid.Column="1" HorizontalAlignment="Right" Text="{Binding AudioSettings.LameBitrate}" />
<TextBlock Grid.Column="2" Text=" Kbps" />
</Grid>
<Grid ColumnDefinitions="Auto,*">
<Grid ColumnDefinitions="*,*">
<CheckBox Grid.Column="0" IsChecked="{Binding AudioSettings.LameConstantBitrate, Mode=TwoWay}">
<TextBlock Text="Restrict Encoder to Constant Bitrate?" />
<TextBlock TextWrapping="Wrap" Text="Restrict Encoder to Constant Bitrate?" />
</CheckBox>
<CheckBox Grid.Column="1" IsChecked="{Binding AudioSettings.LameMatchSource, Mode=TwoWay}" HorizontalAlignment="Right">
<TextBlock Text="Match Source Bitrate?" />
<TextBlock TextWrapping="Wrap" Text="Match Source Bitrate?" />
</CheckBox>
</Grid>
</StackPanel>
</controls:GroupBox>
<controls:GroupBox Margin="5,5,5,0" BorderWidth="1" Label="Quality" IsEnabled="{Binding !AudioSettings.LameTargetBitrate}" >
<Grid ColumnDefinitions="*,*,25" RowDefinitions="*,Auto">
<Slider
@ -343,7 +477,7 @@
FontSize="14"
IsReadOnly="True"
Text="{Binding AudioSettings.ChapterTitleTemplate}" />
<Button
Grid.Column="1"
Content="Edit"
@ -358,48 +492,6 @@
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock
FontSize="14"
VerticalAlignment="Center"
Text="Important Settings"/>
</TabItem.Header>
<Border
Grid.Column="0"
Grid.Row="0"
BorderThickness="2"
Background="WhiteSmoke"
BorderBrush="{DynamicResource DataGridGridLinesBrush}">
</Border>
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock
FontSize="14"
VerticalAlignment="Center"
Text="Import Library"/>
</TabItem.Header>
<Border
Grid.Column="0"
Grid.Row="0"
BorderThickness="2"
Background="WhiteSmoke"
BorderBrush="{DynamicResource DataGridGridLinesBrush}">
</Border>
</TabItem>
</TabControl>
</Grid>

View File

@ -7,19 +7,31 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using ReactiveUI;
using Dinah.Core;
using System.Linq;
using FileManager;
namespace LibationWinForms.AvaloniaUI.Views.Dialogs
{
public partial class SettingsDialog : DialogWindow
{
private SettingsPages settingsDisp;
private readonly Configuration config = Configuration.Instance;
public SettingsDialog()
{
if (Design.IsDesignMode)
AudibleUtilities.AudibleApiStorage.EnsureAccountsSettingsFileExists();
InitializeComponent();
DataContext = settingsDisp = new(Configuration.Instance);
DataContext = settingsDisp = new(config);
tabItem1 = this.Find<TabItem>("tabItem1");
tabItem1.GotFocus += TabItem1_GotFocus;
}
private void TabItem1_GotFocus(object sender, Avalonia.Input.GotFocusEventArgs e)
{
}
private void InitializeComponent()
@ -28,8 +40,8 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs
}
protected override async Task SaveAndCloseAsync()
{
settingsDisp.SaveSettings(config);
await MessageBox.VerboseLoggingWarning_ShowIfTrue();
await base.SaveAndCloseAsync();
}
public async void SaveButton_Clicked(object sender, Avalonia.Interactivity.RoutedEventArgs e)
@ -37,29 +49,42 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs
public void OpenLogFolderButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
Go.To.Folder(((LongPath)Configuration.Instance.LibationFiles).ShortPathName);
}
public void EditFolderTemplateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var newTemplate = editTemplate(Templates.ChapterTitle, settingsDisp.AudioSettings.ChapterTitleTemplate);
var newTemplate = editTemplate(Templates.ChapterTitle, settingsDisp.DownloadDecryptSettings.FolderTemplate);
if (newTemplate is not null)
settingsDisp.AudioSettings.ChapterTitleTemplate = newTemplate;
settingsDisp.DownloadDecryptSettings.FolderTemplate = newTemplate;
}
public void EditFileTemplateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var newTemplate = editTemplate(Templates.ChapterTitle, settingsDisp.AudioSettings.ChapterTitleTemplate);
var newTemplate = editTemplate(Templates.ChapterTitle, settingsDisp.DownloadDecryptSettings.FileTemplate);
if (newTemplate is not null)
settingsDisp.AudioSettings.ChapterTitleTemplate = newTemplate;
settingsDisp.DownloadDecryptSettings.FileTemplate = newTemplate;
}
public void EditChapterFileTemplateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var newTemplate = editTemplate(Templates.ChapterTitle, settingsDisp.AudioSettings.ChapterTitleTemplate);
var newTemplate = editTemplate(Templates.ChapterTitle, settingsDisp.DownloadDecryptSettings.ChapterFileTemplate);
if (newTemplate is not null)
settingsDisp.AudioSettings.ChapterTitleTemplate = newTemplate;
settingsDisp.DownloadDecryptSettings.ChapterFileTemplate = newTemplate;
}
public void EditCharReplacementButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var form = new LibationWinForms.Dialogs.EditReplacementChars(config);
form.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
form.ShowDialog();
}
public void EditChapterTitleTemplateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
@ -84,19 +109,120 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs
void SaveSettings(Configuration config);
}
public class SettingsPages
public class SettingsPages : ISettingsTab
{
public Configuration config { get; }
public SettingsPages(Configuration config)
{
this.config = config;
AudioSettings = new(config);
DownloadDecryptSettings = new(config);
LoadSettings(config);
}
public ImportantSettings ImportantSettings { get; private set; }
public ImportSettings ImportSettings { get; private set; }
public DownloadDecryptSettings DownloadDecryptSettings { get; private set; }
public AudioSettings AudioSettings { get; private set; }
public void LoadSettings(Configuration config)
{
ImportantSettings = new(config);
ImportSettings = new(config);
DownloadDecryptSettings = new(config);
AudioSettings = new(config);
}
public void SaveSettings(Configuration config)
{
ImportantSettings.SaveSettings(config);
ImportSettings.SaveSettings(config);
DownloadDecryptSettings.SaveSettings(config);
AudioSettings.SaveSettings(config);
}
public AudioSettings AudioSettings { get;}
public DownloadDecryptSettings DownloadDecryptSettings { get;}
}
public class ImportantSettings : ISettingsTab
{
private static Func<string, string> desc { get; } = Configuration.GetDescription;
public ImportantSettings(Configuration config)
{
LoadSettings(config);
}
public void LoadSettings(Configuration config)
{
BooksDirectory = config.Books;
SavePodcastsToParentFolder = config.SavePodcastsToParentFolder;
LoggingLevel = config.LogLevel;
BetaOptIn = config.BetaOptIn;
}
public void SaveSettings(Configuration config)
{
config.Books = BooksDirectory;
config.SavePodcastsToParentFolder = SavePodcastsToParentFolder;
config.LogLevel = LoggingLevel;
config.BetaOptIn = BetaOptIn;
}
public List<Configuration.KnownDirectories> KnownDirectories { get; } = new()
{
Configuration.KnownDirectories.UserProfile,
Configuration.KnownDirectories.AppDir,
Configuration.KnownDirectories.MyDocs
};
public string BooksText => desc(nameof(Configuration.Books));
public string SavePodcastsToParentFolderText => desc(nameof(Configuration.SavePodcastsToParentFolder));
public Serilog.Events.LogEventLevel[] LoggingLevels { get; } = Enum.GetValues<Serilog.Events.LogEventLevel>();
public string BetaOptInText => desc(nameof(Configuration.BetaOptIn));
public string BooksDirectory { get; set; }
public bool SavePodcastsToParentFolder { get; set; }
public Serilog.Events.LogEventLevel LoggingLevel { get; set; }
public bool BetaOptIn { get; set; }
}
public class ImportSettings : ISettingsTab
{
private static Func<string, string> desc { get; } = Configuration.GetDescription;
public ImportSettings(Configuration config)
{
LoadSettings(config);
}
public void LoadSettings(Configuration config)
{
AutoScan = config.AutoScan;
ShowImportedStats = config.ShowImportedStats;
ImportEpisodes = config.ImportEpisodes;
DownloadEpisodes = config.DownloadEpisodes;
AutoDownloadEpisodes = config.AutoDownloadEpisodes;
}
public void SaveSettings(Configuration config)
{
config.AutoScan = AutoScan;
config.ShowImportedStats = ShowImportedStats;
config.ImportEpisodes = ImportEpisodes;
config.DownloadEpisodes = DownloadEpisodes;
config.AutoDownloadEpisodes = AutoDownloadEpisodes;
}
public string AutoScanText => desc(nameof(Configuration.AutoScan));
public string ShowImportedStatsText => desc(nameof(Configuration.ShowImportedStats));
public string ImportEpisodesText => desc(nameof(Configuration.ImportEpisodes));
public string DownloadEpisodesText => desc(nameof(Configuration.DownloadEpisodes));
public string AutoDownloadEpisodesText => desc(nameof(Configuration.AutoDownloadEpisodes));
public bool AutoScan { get; set; }
public bool ShowImportedStats { get; set; }
public bool ImportEpisodes { get; set; }
public bool DownloadEpisodes { get; set; }
public bool AutoDownloadEpisodes { get; set; }
}
public class DownloadDecryptSettings : ViewModels.ViewModelBase, ISettingsTab
{
private static Func<string, string> desc { get; } = Configuration.GetDescription;
@ -115,6 +241,7 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs
LoadSettings(config);
}
public Configuration.KnownDirectories InProgressDirectory { get; set; }
public void LoadSettings(Configuration config)
{
BadBookAsk = config.BadBook is Configuration.BadBookAction.Ask;
@ -124,6 +251,9 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs
FolderTemplate = config.FolderTemplate;
FileTemplate = config.FileTemplate;
ChapterFileTemplate = config.ChapterFileTemplate;
InProgressDirectory
= config.InProgress == Configuration.AppDir_Absolute ? Configuration.KnownDirectories.AppDir
: Configuration.GetKnownDirectory(config.InProgress);
}
public void SaveSettings(Configuration config)
@ -137,6 +267,9 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs
config.FolderTemplate = FolderTemplate;
config.FileTemplate = FileTemplate;
config.ChapterFileTemplate = ChapterFileTemplate;
config.InProgress
= InProgressDirectory is Configuration.KnownDirectories.AppDir ? Configuration.AppDir_Absolute
: Configuration.GetKnownDirectoryPath(InProgressDirectory);
}
public string BadBookGroupboxText => desc(nameof(Configuration.BadBook));
@ -144,11 +277,11 @@ namespace LibationWinForms.AvaloniaUI.Views.Dialogs
public string BadBookAbortText { get; } = Configuration.BadBookAction.Abort.GetDescription();
public string BadBookRetryText { get; } = Configuration.BadBookAction.Retry.GetDescription();
public string BadBookIgnoreText { get; } = Configuration.BadBookAction.Ignore.GetDescription();
public string FolderTemplateText => desc(nameof(Configuration.FolderTemplate));
public string FileTemplateText => desc(nameof(Configuration.FileTemplate));
public string ChapterFileTemplateText => desc(nameof(Configuration.ChapterFileTemplate));
public string? EditCharReplacementText => desc(nameof(Configuration.ReplacementCharacters));
public string EditCharReplacementText => desc(nameof(Configuration.ReplacementCharacters));
public string InProgressDescriptionText => desc(nameof(Configuration.InProgress));
public string FolderTemplate { get => _folderTemplate; set { this.RaiseAndSetIfChanged(ref _folderTemplate, value); } }
public string FileTemplate { get => _fileTemplate; set { this.RaiseAndSetIfChanged(ref _fileTemplate, value); } }

View File

@ -11,7 +11,7 @@ namespace LibationWinForms.AvaloniaUI.Views
public async void accountsToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) => await new Dialogs.AccountsDialog().ShowDialog(this);
public void basicSettingsToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) => new SettingsDialog().ShowDialog();
public async void basicSettingsToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) => await new Dialogs.SettingsDialog().ShowDialog(this);
public async void aboutToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> await MessageBox.Show($"Running Libation version {AppScaffolding.LibationScaffolding.BuildVersion}", $"Libation v{AppScaffolding.LibationScaffolding.BuildVersion}");

View File

@ -67,8 +67,7 @@ namespace LibationWinForms.AvaloniaUI.Views
private async void MainWindow_Opened(object sender, EventArgs e)
{
//var settings = new SettingsDialog();
//settings.Show();
}
public void ProductsDisplay_Initialized1(object sender, EventArgs e)

View File

@ -5,12 +5,12 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>x64</Platform>
<Platform>Any CPU</Platform>
<PublishDir>..\bin\publish\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0-windows</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>
</PropertyGroup>
</Project>