Merge pull request #571 from Mbucari/master

Chardonnay UI Refinements and Refactor
This commit is contained in:
rmcrackan 2023-04-05 08:00:44 -04:00 committed by GitHub
commit ca5b40b176
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 1521 additions and 1538 deletions

View File

@ -1,6 +1,7 @@
<Application xmlns="https://github.com/avaloniaui" <Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:LibationAvalonia" xmlns:local="using:LibationAvalonia"
xmlns:controls="using:LibationAvalonia.Controls"
x:Class="LibationAvalonia.App" x:Class="LibationAvalonia.App"
Name="Libation"> Name="Libation">
@ -69,6 +70,13 @@
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundBaseLowBrush}" /> <Setter Property="Background" Value="{DynamicResource SystemControlBackgroundBaseLowBrush}" />
</Style> </Style>
</Style> </Style>
<Style Selector="controls|LinkLabel">
<Setter Property="Foreground" Value="{DynamicResource HyperlinkNew}"/>
<Setter Property="ForegroundVisited" Value="{DynamicResource HyperlinkVisited}"/>
</Style>
<Style Selector="Button">
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
</Application.Styles> </Application.Styles>
<NativeMenu.Menu> <NativeMenu.Menu>

View File

@ -27,7 +27,6 @@ namespace LibationAvalonia
public static IBrush ProcessQueueBookCancelledBrush { get; private set; } public static IBrush ProcessQueueBookCancelledBrush { get; private set; }
public static IBrush ProcessQueueBookDefaultBrush { get; private set; } public static IBrush ProcessQueueBookDefaultBrush { get; private set; }
public static IBrush SeriesEntryGridBackgroundBrush { get; private set; } public static IBrush SeriesEntryGridBackgroundBrush { get; private set; }
public static IBrush HyperlinkVisited { get; private set; }
public static IAssetLoader AssetLoader { get; private set; } public static IAssetLoader AssetLoader { get; private set; }
@ -230,7 +229,6 @@ namespace LibationAvalonia
ProcessQueueBookCancelledBrush = AvaloniaUtils.GetBrushFromResources(nameof(ProcessQueueBookCancelledBrush)); ProcessQueueBookCancelledBrush = AvaloniaUtils.GetBrushFromResources(nameof(ProcessQueueBookCancelledBrush));
SeriesEntryGridBackgroundBrush = AvaloniaUtils.GetBrushFromResources(nameof(SeriesEntryGridBackgroundBrush)); SeriesEntryGridBackgroundBrush = AvaloniaUtils.GetBrushFromResources(nameof(SeriesEntryGridBackgroundBrush));
ProcessQueueBookDefaultBrush = AvaloniaUtils.GetBrushFromResources(nameof(ProcessQueueBookDefaultBrush)); ProcessQueueBookDefaultBrush = AvaloniaUtils.GetBrushFromResources(nameof(ProcessQueueBookDefaultBrush));
HyperlinkVisited = AvaloniaUtils.GetBrushFromResources(nameof(HyperlinkVisited));
} }
} }
} }

View File

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

View File

@ -36,55 +36,49 @@ namespace LibationAvalonia.Controls
get => GetValue(SubDirectoryProperty); get => GetValue(SubDirectoryProperty);
set => SetValue(SubDirectoryProperty, value); set => SetValue(SubDirectoryProperty, value);
} }
CustomState customStates = new();
private readonly DirectoryState directoryState = new();
public DirectoryOrCustomSelectControl() public DirectoryOrCustomSelectControl()
{ {
InitializeComponent(); InitializeComponent();
customDirBrowseBtn = this.Find<Button>(nameof(customDirBrowseBtn)); grid.DataContext = directoryState;
directorySelectControl = this.Find<DirectorySelectControl>(nameof(directorySelectControl));
this.Find<TextBox>(nameof(customDirTbox)).DataContext = customStates; directoryState.PropertyChanged += DirectoryState_PropertyChanged;
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; PropertyChanged += DirectoryOrCustomSelectControl_PropertyChanged;
directorySelectControl.PropertyChanged += DirectorySelectControl_PropertyChanged;
} }
private class CustomState : ViewModels.ViewModelBase private void DirectoryState_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName is nameof(DirectoryState.SelectedDirectory) or nameof(DirectoryState.KnownChecked) &&
directoryState.KnownChecked &&
directoryState.SelectedDirectory is Configuration.KnownDirectories kdir &&
kdir is not Configuration.KnownDirectories.None)
{
Directory = kdir is Configuration.KnownDirectories.AppDir ? Configuration.AppDir_Absolute : Configuration.GetKnownDirectoryPath(kdir);
}
else if (e.PropertyName is nameof(DirectoryState.CustomDir) or nameof(DirectoryState.CustomChecked) &&
directoryState.CustomChecked &&
directoryState.CustomDir is not null)
{
Directory = directoryState.CustomDir;
}
}
private class DirectoryState : ViewModels.ViewModelBase
{ {
private string _customDir; private string _customDir;
private string _subDirectory;
private bool _knownChecked; private bool _knownChecked;
private bool _customChecked; private bool _customChecked;
private Configuration.KnownDirectories? _selectedDirectory;
public string CustomDir { get => _customDir; set => this.RaiseAndSetIfChanged(ref _customDir, value); } public string CustomDir { get => _customDir; set => this.RaiseAndSetIfChanged(ref _customDir, value); }
public bool KnownChecked public string SubDirectory { get => _subDirectory; set => this.RaiseAndSetIfChanged(ref _subDirectory, value); }
{ public bool KnownChecked { get => _knownChecked; set => this.RaiseAndSetIfChanged(ref _knownChecked, value); }
get => _knownChecked; public bool CustomChecked { get => _customChecked; set => this.RaiseAndSetIfChanged(ref _customChecked, value); }
set
{ public Configuration.KnownDirectories? SelectedDirectory { get => _selectedDirectory; set => this.RaiseAndSetIfChanged(ref _selectedDirectory, value); }
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) private async void CustomDirBrowseBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
@ -96,43 +90,12 @@ namespace LibationAvalonia.Controls
var selectedFolders = await (VisualRoot as Window).StorageProvider.OpenFolderPickerAsync(options); var selectedFolders = await (VisualRoot as Window).StorageProvider.OpenFolderPickerAsync(options);
customStates.CustomDir = selectedFolders.SingleOrDefault()?.Path?.LocalPath ?? customStates.CustomDir; directoryState.CustomDir = selectedFolders.SingleOrDefault()?.Path?.LocalPath ?? directoryState.CustomDir;
}
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()
{
var selectedDir
= customStates.CustomChecked ? customStates.CustomDir
: directorySelectControl.SelectedDirectory is Configuration.KnownDirectories.AppDir ? Configuration.AppDir_Absolute
: Configuration.GetKnownDirectoryPath(directorySelectControl.SelectedDirectory);
selectedDir ??= string.Empty;
Directory = customStates.CustomChecked ? selectedDir : System.IO.Path.Combine(selectedDir, SubDirectory ?? "");
} }
private void DirectoryOrCustomSelectControl_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) private void DirectoryOrCustomSelectControl_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)
{ {
if (e.Property.Name == nameof(Directory) && e.OldValue is null) if (e.Property == DirectoryProperty)
{ {
var directory = Directory?.Trim() ?? ""; var directory = Directory?.Trim() ?? "";
@ -144,19 +107,19 @@ namespace LibationAvalonia.Controls
if (known is Configuration.KnownDirectories.None) if (known is Configuration.KnownDirectories.None)
{ {
customStates.CustomChecked = true; directoryState.CustomDir = noSubDir;
customStates.CustomDir = directory; directoryState.CustomChecked = true;
} }
else else
{ {
customStates.KnownChecked = true; directoryState.SelectedDirectory = known;
directorySelectControl.SelectedDirectory = known; directoryState.KnownChecked = true;
} }
} }
else if (e.Property.Name == nameof(KnownDirectories)) else if (e.Property == KnownDirectoriesProperty &&
directorySelectControl.KnownDirectories = KnownDirectories; KnownDirectories.Count > 0 &&
else if (e.Property.Name == nameof(SubDirectory)) directoryState.SelectedDirectory is null or Configuration.KnownDirectories.None)
directorySelectControl.SubDirectory = SubDirectory; directoryState.SelectedDirectory = KnownDirectories[0];
} }
private string RemoveSubDirectoryFromPath(string path) private string RemoveSubDirectoryFromPath(string path)

View File

@ -8,6 +8,7 @@
<UserControl.Resources> <UserControl.Resources>
<controls:KnownDirectoryConverter x:Key="KnownDirectoryConverter" /> <controls:KnownDirectoryConverter x:Key="KnownDirectoryConverter" />
<controls:KnownDirectoryPath x:Key="KnownDirectoryPath" />
</UserControl.Resources> </UserControl.Resources>
@ -20,19 +21,26 @@
<controls:WheelComboBox <controls:WheelComboBox
HorizontalContentAlignment = "Stretch" HorizontalContentAlignment = "Stretch"
HorizontalAlignment = "Stretch" HorizontalAlignment = "Stretch"
Name="combo"
MinHeight="{Binding #displayPathTbox.MinHeight}" MinHeight="{Binding #displayPathTbox.MinHeight}"
SelectedItem="{Binding $parent[1].SelectedDirectory, Mode=TwoWay}" SelectedItem="{Binding $parent[1].SelectedDirectory, Mode=TwoWay}"
Items="{Binding $parent[1].KnownDirectories}"> ItemsSource="{Binding $parent[1].KnownDirectories}">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource KnownDirectoryConverter}}" />
<TextBlock
Text="{Binding Converter={StaticResource KnownDirectoryConverter}}" />
</DataTemplate> </DataTemplate>
</ComboBox.ItemTemplate> </ComboBox.ItemTemplate>
</controls:WheelComboBox> </controls:WheelComboBox>
<TextBox Margin="0,10,0,10" IsReadOnly="True" Name="displayPathTbox" /> <TextBox Margin="0,10,0,10" IsReadOnly="True">
<TextBox.Text>
<MultiBinding Converter="{StaticResource KnownDirectoryPath}">
<MultiBinding.Bindings>
<Binding Path="#combo.SelectedItem"/>
<Binding Path="$parent[1].SubDirectory"/>
</MultiBinding.Bindings>
</MultiBinding>
</TextBox.Text>
</TextBox>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View File

@ -8,7 +8,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Reactive.Subjects;
namespace LibationAvalonia.Controls namespace LibationAvalonia.Controls
{ {
@ -26,6 +25,24 @@ namespace LibationAvalonia.Controls
return new BindingNotification(new InvalidCastException(), BindingErrorType.Error); return new BindingNotification(new InvalidCastException(), BindingErrorType.Error);
} }
} }
public class KnownDirectoryPath : IMultiValueConverter
{
public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture)
{
if (values?.Count == 2 && values[0] is Configuration.KnownDirectories kdir && kdir is not Configuration.KnownDirectories.None)
{
var subdir = values[1] as string ?? "";
var path = kdir is Configuration.KnownDirectories.AppDir ? Configuration.AppDir_Absolute : Configuration.GetKnownDirectoryPath(kdir);
return Path.Combine(path, subdir);
}
return "";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return new BindingNotification(new InvalidCastException(), BindingErrorType.Error);
}
}
public partial class DirectorySelectControl : UserControl public partial class DirectorySelectControl : UserControl
{ {
@ -39,8 +56,8 @@ namespace LibationAvalonia.Controls
Configuration.KnownDirectories.LibationFiles Configuration.KnownDirectories.LibationFiles
}; };
public static readonly StyledProperty<Configuration.KnownDirectories> SelectedDirectoryProperty = public static readonly StyledProperty<Configuration.KnownDirectories?> SelectedDirectoryProperty =
AvaloniaProperty.Register<DirectorySelectControl, Configuration.KnownDirectories>(nameof(SelectedDirectory)); AvaloniaProperty.Register<DirectorySelectControl, Configuration.KnownDirectories?>(nameof(SelectedDirectory));
public static readonly StyledProperty<List<Configuration.KnownDirectories>> KnownDirectoriesProperty = public static readonly StyledProperty<List<Configuration.KnownDirectories>> KnownDirectoriesProperty =
AvaloniaProperty.Register<DirectorySelectControl, List<Configuration.KnownDirectories>>(nameof(KnownDirectories), DefaultKnownDirectories); AvaloniaProperty.Register<DirectorySelectControl, List<Configuration.KnownDirectories>>(nameof(KnownDirectories), DefaultKnownDirectories);
@ -51,25 +68,6 @@ namespace LibationAvalonia.Controls
public DirectorySelectControl() public DirectorySelectControl()
{ {
InitializeComponent(); InitializeComponent();
displayPathTbox = this.Get<TextBox>(nameof(displayPathTbox));
displayPathTbox.Bind(TextBox.TextProperty, TextboxPath);
PropertyChanged += DirectorySelectControl_PropertyChanged;
}
private Subject<string> TextboxPath = new Subject<string>();
private void DirectorySelectControl_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)
{
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 public List<Configuration.KnownDirectories> KnownDirectories
@ -78,7 +76,7 @@ namespace LibationAvalonia.Controls
set => SetValue(KnownDirectoriesProperty, value); set => SetValue(KnownDirectoriesProperty, value);
} }
public Configuration.KnownDirectories SelectedDirectory public Configuration.KnownDirectories? SelectedDirectory
{ {
get => GetValue(SelectedDirectoryProperty); get => GetValue(SelectedDirectoryProperty);
set => SetValue(SelectedDirectoryProperty, value); set => SetValue(SelectedDirectoryProperty, value);

View File

@ -3,46 +3,53 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:LibationAvalonia.Controls" xmlns:controls="clr-namespace:LibationAvalonia.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="200" d:DesignHeight="200"
x:Class="LibationAvalonia.Controls.GroupBox"> x:Class="LibationAvalonia.Controls.GroupBox">
<ContentControl.Styles> <ContentControl.Styles>
<Style Selector="controls|GroupBox Border">
<Setter Property="BorderBrush" Value="DarkGray" />
</Style>
<Style Selector="controls|GroupBox"> <Style Selector="controls|GroupBox">
<Setter Property="BorderBrush" Value="{DynamicResource SystemBaseMediumLowColor}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="3" />
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Grid ColumnDefinitions="Auto,*,Auto" RowDefinitions="8,12,*,Auto"> <Grid ColumnDefinitions="Auto,Auto,*,Auto" RowDefinitions="Auto,*,Auto">
<Panel
Name="PART_LabelOffsetter"
Grid.Column="1"
Margin="8,9,0,0" />
<Grid <Grid
ZIndex="1" ZIndex="1"
Grid.Row="0" Grid.Row="0"
Grid.RowSpan="2" Grid.RowSpan="2"
Grid.Column="1" Margin="8,0,0,0" Grid.Column="2"
ColumnDefinitions="Auto,*" ColumnDefinitions="Auto,*"
VerticalAlignment="Top"> VerticalAlignment="Top">
<TextBlock <TextBlock
Padding="4,0,4,0" Name="PART_Label"
Padding="4,0"
Background="{DynamicResource SystemAltHighColor}" Background="{DynamicResource SystemAltHighColor}"
Text="{TemplateBinding Label}" Text="{TemplateBinding Label}"
/> />
</Grid> </Grid>
<ContentPresenter <ContentPresenter
Margin="8,0,8,5" Name="PART_ContentPresenter"
Grid.Row="2" Margin="8,10,8,5"
Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Grid.ColumnSpan="2"
Content="{TemplateBinding Content}"/> Content="{TemplateBinding Content}"/>
<Border <Border
BorderBrush="DarkGray" Name="PART_Border"
BorderThickness="{TemplateBinding BorderWidth}" BorderBrush="{TemplateBinding BorderBrush}"
CornerRadius="3" BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="3" Grid.ColumnSpan="4"
Grid.Row="1" Grid.Row="1"
Grid.RowSpan="3"/> Grid.RowSpan="2"/>
</Grid> </Grid>
</ControlTemplate> </ControlTemplate>

View File

@ -1,27 +1,19 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Styling;
namespace LibationAvalonia.Controls namespace LibationAvalonia.Controls
{ {
public partial class GroupBox : ContentControl public partial class GroupBox : ContentControl
{ {
public static readonly StyledProperty<Thickness> BorderWidthProperty =
AvaloniaProperty.Register<GroupBox, Thickness>(nameof(BorderWidth));
public static readonly StyledProperty<string> LabelProperty = public static readonly StyledProperty<string> LabelProperty =
AvaloniaProperty.Register<GroupBox, string>(nameof(Label)); AvaloniaProperty.Register<GroupBox, string>(nameof(Label));
public GroupBox() public GroupBox()
{ {
InitializeComponent(); InitializeComponent();
BorderWidth = new Thickness(3);
Label = "This is a groupbox label"; Label = "This is a groupbox label";
} }
public Thickness BorderWidth
{
get { return GetValue(BorderWidthProperty); }
set { SetValue(BorderWidthProperty, value); }
}
public string Label public string Label
{ {

View File

@ -3,10 +3,10 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:controls="using:LibationAvalonia.Controls"
x:Class="LibationAvalonia.Controls.LinkLabel"> x:Class="LibationAvalonia.Controls.LinkLabel">
<TextBlock.Styles> <TextBlock.Styles>
<Style Selector="TextBlock"> <Style Selector="controls|LinkLabel">
<Setter Property="Foreground" Value="{DynamicResource HyperlinkNew}"/>
<Setter Property="TextDecorations" Value="Underline"/> <Setter Property="TextDecorations" Value="Underline"/>
</Style> </Style>
</TextBlock.Styles> </TextBlock.Styles>

View File

@ -1,14 +1,57 @@
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Styling; using Avalonia.Styling;
using System; using System;
using System.Windows.Input;
namespace LibationAvalonia.Controls namespace LibationAvalonia.Controls
{ {
public partial class LinkLabel : TextBlock, IStyleable public partial class LinkLabel : TextBlock, IStyleable, ICommandSource
{ {
Type IStyleable.StyleKey => typeof(TextBlock); Type IStyleable.StyleKey => typeof(LinkLabel);
public static readonly StyledProperty<ICommand> CommandProperty =
AvaloniaProperty.Register<LinkLabel, ICommand>(nameof(Command), enableDataValidation: true);
public static readonly StyledProperty<object> CommandParameterProperty =
AvaloniaProperty.Register<LinkLabel, object>(nameof(CommandParameter));
public static readonly StyledProperty<IBrush> ForegroundVisitedProperty =
AvaloniaProperty.Register<LinkLabel, IBrush>(nameof(ForegroundVisited));
public static readonly RoutedEvent<RoutedEventArgs> ClickEvent =
RoutedEvent.Register<Button, RoutedEventArgs>(nameof(Click), RoutingStrategies.Bubble);
public ICommand Command
{
get => GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
public object CommandParameter
{
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
public IBrush ForegroundVisited
{
get => GetValue(ForegroundVisitedProperty);
set => SetValue(ForegroundVisitedProperty, value);
}
public event EventHandler<RoutedEventArgs> Click
{
add => AddHandler(ClickEvent, value);
remove => RemoveHandler(ClickEvent, value);
}
private static readonly Cursor HandCursor = new Cursor(StandardCursorType.Hand); private static readonly Cursor HandCursor = new Cursor(StandardCursorType.Hand);
private bool _commandCanExecute = true;
public LinkLabel() public LinkLabel()
{ {
InitializeComponent(); InitializeComponent();
@ -17,7 +60,19 @@ namespace LibationAvalonia.Controls
private void LinkLabel_Tapped(object sender, TappedEventArgs e) private void LinkLabel_Tapped(object sender, TappedEventArgs e)
{ {
Foreground = App.HyperlinkVisited; Foreground = ForegroundVisited;
if (IsEffectivelyEnabled)
{
var args = new RoutedEventArgs(ClickEvent);
RaiseEvent(args);
if (!args.Handled && Command?.CanExecute(CommandParameter) == true)
{
Command.Execute(CommandParameter);
args.Handled = true;
}
}
} }
protected override void OnPointerEntered(PointerEventArgs e) protected override void OnPointerEntered(PointerEventArgs e)
@ -30,5 +85,33 @@ namespace LibationAvalonia.Controls
this.Cursor = Cursor.Default; this.Cursor = Cursor.Default;
base.OnPointerExited(e); base.OnPointerExited(e);
} }
protected override bool IsEnabledCore => base.IsEnabledCore && _commandCanExecute;
protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception error)
{
base.UpdateDataValidation(property, state, error);
if (property == CommandProperty)
{
if (state == BindingValueType.BindingError)
{
if (_commandCanExecute)
{
_commandCanExecute = false;
UpdateIsEffectivelyEnabled();
}
}
}
}
public void CanExecuteChanged(object sender, EventArgs e)
{
var canExecute = Command == null || Command.CanExecute(CommandParameter);
if (canExecute != _commandCanExecute)
{
_commandCanExecute = canExecute;
UpdateIsEffectivelyEnabled();
}
}
} }
} }

View File

@ -0,0 +1,329 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="750" d:DesignHeight="600"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
xmlns:vm="clr-namespace:LibationAvalonia.ViewModels.Settings"
x:DataType="vm:AudioSettingsVM"
x:Class="LibationAvalonia.Controls.Settings.Audio">
<Grid
Margin="5"
RowDefinitions="Auto,*,Auto"
ColumnDefinitions="*,*">
<Grid.Styles>
<Style Selector="CheckBox">
<Setter Property="Margin" Value="0,0,0,5" />
<Style Selector="^ > TextBlock">
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
</Style>
<Style Selector="RadioButton">
<Setter Property="Margin" Value="0,0,0,5" />
<Style Selector="^ TextBlock">
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
</Style>
</Grid.Styles>
<StackPanel
Grid.Row="0"
Grid.Column="0">
<CheckBox IsChecked="{CompiledBinding CreateCueSheet, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding CreateCueSheetText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding DownloadCoverArt, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding DownloadCoverArtText}" />
</CheckBox>
<Grid ColumnDefinitions="*,Auto">
<CheckBox IsChecked="{CompiledBinding DownloadClipsBookmarks, Mode=TwoWay}">
<TextBlock Text="Download Clips, Notes and Bookmarks as" />
</CheckBox>
<controls:WheelComboBox
Margin="5,0,0,0"
Grid.Column="1"
IsEnabled="{CompiledBinding DownloadClipsBookmarks}"
ItemsSource="{CompiledBinding ClipBookmarkFormats}"
SelectedItem="{CompiledBinding ClipBookmarkFormat}"/>
</Grid>
<CheckBox IsChecked="{CompiledBinding RetainAaxFile, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding RetainAaxFileText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding MergeOpeningAndEndCredits, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding MergeOpeningEndCreditsText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding AllowLibationFixup, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding AllowLibationFixupText}" />
</CheckBox>
</StackPanel>
<controls:GroupBox
Grid.Row="1"
Label="Audiobook Fix-ups"
IsEnabled="{CompiledBinding AllowLibationFixup}">
<StackPanel Orientation="Vertical">
<CheckBox IsChecked="{CompiledBinding SplitFilesByChapter, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding SplitFilesByChapterText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding StripAudibleBrandAudio, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding StripAudibleBrandingText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding StripUnabridged, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding StripUnabridgedText}" />
</CheckBox>
<RadioButton IsChecked="{CompiledBinding !DecryptToLossy, Mode=TwoWay}">
<StackPanel VerticalAlignment="Center">
<TextBlock
Text="Download my books in the original audio format (Lossless)" />
<CheckBox
IsEnabled="{CompiledBinding !DecryptToLossy}"
IsChecked="{CompiledBinding MoveMoovToBeginning, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding MoveMoovToBeginningText}" />
</CheckBox>
</StackPanel>
</RadioButton>
<RadioButton IsChecked="{CompiledBinding DecryptToLossy, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="Download my books as .MP3 files (transcode if necessary)" />
</RadioButton>
</StackPanel>
</controls:GroupBox>
<controls:GroupBox
Grid.Column="1"
Grid.RowSpan="2"
Margin="10,0,0,0"
Label="Mp3 Encoding Options">
<Grid RowDefinitions="Auto,Auto,Auto,Auto,*">
<Grid
Margin="0,5"
ColumnDefinitions="Auto,*">
<controls:GroupBox
Grid.Column="0"
Label="Target">
<Grid ColumnDefinitions="Auto,Auto">
<RadioButton
Margin="5"
Content="Bitrate"
IsChecked="{CompiledBinding LameTargetBitrate, Mode=TwoWay}"/>
<RadioButton
Grid.Column="1"
Margin="5"
Content="Quality"
IsChecked="{CompiledBinding !LameTargetBitrate, Mode=TwoWay}"/>
</Grid>
</controls:GroupBox>
<CheckBox
HorizontalAlignment="Right"
Grid.Column="1"
IsChecked="{CompiledBinding LameDownsampleMono, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="Downsample to mono? (Recommended)" />
</CheckBox>
</Grid>
<Grid Grid.Row="1" Margin="0,5" RowDefinitions="Auto,Auto" ColumnDefinitions="Auto,*,Auto">
<TextBlock Margin="0,0,0,5" Text="Max audio sample rate:" />
<controls:WheelComboBox
Grid.Row="1"
HorizontalAlignment="Stretch"
ItemsSource="{CompiledBinding SampleRates}"
SelectedItem="{CompiledBinding SelectedSampleRate, Mode=TwoWay}"/>
<TextBlock Margin="0,0,0,5" Grid.Column="2" Text="Encoder Quality:" />
<controls:WheelComboBox
Grid.Column="2"
Grid.Row="1"
HorizontalAlignment="Stretch"
ItemsSource="{CompiledBinding EncoderQualities}"
SelectedItem="{CompiledBinding SelectedEncoderQuality, Mode=TwoWay}"/>
</Grid>
<controls:GroupBox
Grid.Row="2"
Margin="0,5"
Label="Bitrate"
IsEnabled="{CompiledBinding LameTargetBitrate}" >
<StackPanel>
<Grid ColumnDefinitions="*,25,Auto">
<Slider
Grid.Column="0"
IsEnabled="{CompiledBinding !LameMatchSource}"
Value="{CompiledBinding LameBitrate, Mode=TwoWay}"
Minimum="16"
Maximum="320"
IsSnapToTickEnabled="True" TickFrequency="16"
Ticks="16,32,48,64,80,96,112,128,144,160,176,192,208,224,240,256,272,288,304,320"
TickPlacement="Outside">
<Slider.Styles>
<Style Selector="Slider /template/ Thumb">
<Setter Property="ToolTip.Tip" Value="{CompiledBinding $parent[Slider].Value, Mode=OneWay, StringFormat='\{0:f0\} Kbps'}" />
<Setter Property="ToolTip.Placement" Value="Top" />
<Setter Property="ToolTip.VerticalOffset" Value="-10" />
<Setter Property="ToolTip.HorizontalOffset" Value="-30" />
</Style>
</Slider.Styles>
</Slider>
<TextBlock
Grid.Column="1"
HorizontalAlignment="Right"
Text="{CompiledBinding LameBitrate}" />
<TextBlock
Grid.Column="2"
Text=" Kbps" />
</Grid>
<Grid ColumnDefinitions="*,*">
<CheckBox
Grid.Column="0"
IsChecked="{CompiledBinding LameConstantBitrate, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="Restrict Encoder to Constant Bitrate?" />
</CheckBox>
<CheckBox
Grid.Column="1"
HorizontalAlignment="Right"
IsChecked="{CompiledBinding LameMatchSource, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="Match Source Bitrate?" />
</CheckBox>
</Grid>
</StackPanel>
</controls:GroupBox>
<controls:GroupBox
Grid.Row="3"
Margin="0,5"
Label="Quality"
IsEnabled="{CompiledBinding !LameTargetBitrate}">
<Grid
ColumnDefinitions="*,Auto,25"
RowDefinitions="*,Auto">
<Slider
Grid.Column="0"
Grid.ColumnSpan="2"
Value="{CompiledBinding LameVBRQuality, Mode=TwoWay}"
Minimum="0"
Maximum="9"
IsSnapToTickEnabled="True" TickFrequency="1"
Ticks="0,1,2,3,4,5,6,7,8,9"
TickPlacement="Outside">
<Slider.Styles>
<Style Selector="Slider /template/ Thumb">
<Setter Property="ToolTip.Tip" Value="{CompiledBinding $parent[Slider].Value, Mode=OneWay, StringFormat='V\{0:f0\}'}" />
<Setter Property="ToolTip.Placement" Value="Top" />
<Setter Property="ToolTip.VerticalOffset" Value="-10" />
<Setter Property="ToolTip.HorizontalOffset" Value="-30" />
</Style>
</Slider.Styles>
</Slider>
<StackPanel
Grid.Column="2"
HorizontalAlignment="Right"
Orientation="Horizontal">
<TextBlock Text="V" />
<TextBlock Text="{CompiledBinding LameVBRQuality}" />
</StackPanel>
<TextBlock
Grid.Column="0"
Grid.Row="1"
Text="Higher" />
<TextBlock
Grid.Column="1"
Grid.Row="1"
HorizontalAlignment="Right"
Text="Lower" />
</Grid>
</controls:GroupBox>
<TextBlock
Grid.Row="4"
Margin="0,5"
VerticalAlignment="Bottom"
Text="Using L.A.M.E encoding engine"
FontStyle="Oblique" />
</Grid>
</controls:GroupBox>
<controls:GroupBox
Grid.Row="2"
Grid.ColumnSpan="2"
Margin="0,10,0,0"
IsEnabled="{CompiledBinding SplitFilesByChapter}"
Label="{CompiledBinding ChapterTitleTemplateText}">
<Grid ColumnDefinitions="*,Auto" Margin="0,8" >
<TextBox
Grid.Column="0"
FontSize="14"
IsReadOnly="True"
Text="{CompiledBinding ChapterTitleTemplate}" />
<Button
Grid.Column="1"
Content="Edit"
Padding="30,0"
Margin="10,0,0,0"
VerticalAlignment="Stretch"
Click="EditChapterTitleTemplateButton_Click" />
</Grid>
</controls:GroupBox>
</Grid>
</UserControl>

View File

@ -0,0 +1,38 @@
using Avalonia.Controls;
using LibationAvalonia.Dialogs;
using LibationAvalonia.ViewModels.Settings;
using LibationFileManager;
using System.Threading.Tasks;
namespace LibationAvalonia.Controls.Settings
{
public partial class Audio : UserControl
{
private AudioSettingsVM _viewModel => DataContext as AudioSettingsVM;
public Audio()
{
InitializeComponent();
if (Design.IsDesignMode)
{
_ = Configuration.Instance.LibationFiles;
DataContext = new AudioSettingsVM(Configuration.Instance);
}
}
public async void EditChapterTitleTemplateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
if (_viewModel is null) return;
var newTemplate = await editTemplate(TemplateEditor<Templates.ChapterTitleTemplate>.CreateNameEditor(_viewModel.ChapterTitleTemplate));
if (newTemplate is not null)
_viewModel.ChapterTitleTemplate = newTemplate;
}
private async Task<string> editTemplate(ITemplateEditor template)
{
var form = new EditTemplateDialog(template);
if (await form.ShowDialog<DialogResult>(this.GetParentWindow()) == DialogResult.OK)
return template.EditingTemplate.TemplateText;
else return null;
}
}
}

View File

@ -0,0 +1,182 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="700"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
xmlns:vm="clr-namespace:LibationAvalonia.ViewModels.Settings"
x:DataType="vm:DownloadDecryptSettingsVM"
x:Class="LibationAvalonia.Controls.Settings.DownloadDecrypt">
<Grid RowDefinitions="Auto,Auto,Auto,*">
<controls:GroupBox
Grid.Row="0"
Margin="5"
Label="{CompiledBinding BadBookGroupboxText}">
<Grid
ColumnDefinitions="*,*"
RowDefinitions="Auto,Auto">
<Grid.Styles>
<Style Selector="RadioButton">
<Setter Property="Margin" Value="0,5,0,5" />
<Style Selector="^ > TextBlock">
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
</Style>
</Grid.Styles>
<RadioButton
Grid.Column="0"
Grid.Row="0"
IsChecked="{CompiledBinding BadBookAsk, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding BadBookAskText}" />
</RadioButton>
<RadioButton
Grid.Column="1"
Grid.Row="0"
IsChecked="{CompiledBinding BadBookAbort, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding BadBookAbortText}" />
</RadioButton>
<RadioButton
Grid.Column="0"
Grid.Row="1"
IsChecked="{CompiledBinding BadBookRetry, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding BadBookRetryText}" />
</RadioButton>
<RadioButton
Grid.Column="1"
Grid.Row="1"
IsChecked="{CompiledBinding BadBookIgnore, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding BadBookIgnoreText}" />
</RadioButton>
</Grid>
</controls:GroupBox>
<controls:GroupBox
Margin="5"
Grid.Row="1"
Label="Custom File Naming">
<Grid
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto"
ColumnDefinitions="*,Auto">
<Grid.Styles>
<Style Selector="TextBox">
<Setter Property="Margin" Value="0,5,10,10" />
<Setter Property="FontSize" Value="14" />
<Setter Property="IsReadOnly" Value="True" />
</Style>
<Style Selector="Button">
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Margin" Value="0,5,0,10" />
<Setter Property="Padding" Value="30,0" />
</Style>
</Grid.Styles>
<TextBlock
Grid.Row="0"
Grid.Column="0"
Margin="0,5,0,0"
Text="{CompiledBinding FolderTemplateText}" />
<TextBox
Grid.Row="1"
Grid.Column="0"
Text="{CompiledBinding FolderTemplate}" />
<Button
Grid.Row="1"
Grid.Column="1"
Content="Edit"
Click="EditFolderTemplateButton_Click" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Text="{CompiledBinding FileTemplateText}" />
<TextBox
Grid.Row="3"
Grid.Column="0"
Text="{CompiledBinding FileTemplate}" />
<Button
Grid.Row="3"
Grid.Column="1"
Content="Edit"
Click="EditFileTemplateButton_Click" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Text="{CompiledBinding ChapterFileTemplateText}" />
<TextBox
Grid.Row="5"
Grid.Column="0"
Text="{CompiledBinding ChapterFileTemplate}" />
<Button
Grid.Row="5"
Grid.Column="1"
Content="Edit"
Click="EditChapterFileTemplateButton_Click" />
<Button
Grid.Row="6"
Grid.Column="0"
Height="30"
Margin="0"
Content="{CompiledBinding EditCharReplacementText}"
Click="EditCharReplacementButton_Click" />
</Grid>
</controls:GroupBox>
<controls:GroupBox
Grid.Row="2"
Margin="5"
Label="Temporary Files Location">
<StackPanel
Margin="0,5" >
<TextBlock
Margin="0,0,0,10"
TextWrapping="Wrap"
Text="{CompiledBinding InProgressDescriptionText}" />
<controls:DirectoryOrCustomSelectControl
Directory="{CompiledBinding InProgressDirectory, Mode=TwoWay}"
KnownDirectories="{CompiledBinding KnownDirectories}" />
</StackPanel>
</controls:GroupBox>
<CheckBox
Grid.Row="3"
Margin="5"
VerticalAlignment="Top"
IsVisible="{CompiledBinding !Config.IsLinux}"
IsChecked="{CompiledBinding UseCoverAsFolderIcon, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="{CompiledBinding UseCoverAsFolderIconText}" />
</CheckBox>
</Grid>
</UserControl>

View File

@ -0,0 +1,62 @@
using Avalonia.Controls;
using LibationAvalonia.Dialogs;
using LibationAvalonia.ViewModels.Settings;
using LibationFileManager;
using System.Threading.Tasks;
namespace LibationAvalonia.Controls.Settings
{
public partial class DownloadDecrypt : UserControl
{
private DownloadDecryptSettingsVM _viewModel => DataContext as DownloadDecryptSettingsVM;
public DownloadDecrypt()
{
InitializeComponent();
if (Design.IsDesignMode)
{
_ = Configuration.Instance.LibationFiles;
DataContext = new DownloadDecryptSettingsVM(Configuration.Instance);
}
}
public async void EditFolderTemplateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
if (_viewModel is null) return;
var newTemplate = await editTemplate(TemplateEditor<Templates.FolderTemplate>.CreateFilenameEditor(_viewModel.Config.Books, _viewModel.FolderTemplate));
if (newTemplate is not null)
_viewModel.FolderTemplate = newTemplate;
}
public async void EditFileTemplateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
if (_viewModel is null) return;
var newTemplate = await editTemplate(TemplateEditor<Templates.FileTemplate>.CreateFilenameEditor(_viewModel.Config.Books, _viewModel.FileTemplate));
if (newTemplate is not null)
_viewModel.FileTemplate = newTemplate;
}
public async void EditChapterFileTemplateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
if (_viewModel is null) return;
var newTemplate = await editTemplate(TemplateEditor<Templates.ChapterFileTemplate>.CreateFilenameEditor(_viewModel.Config.Books, _viewModel.ChapterFileTemplate));
if (newTemplate is not null)
_viewModel.ChapterFileTemplate = newTemplate;
}
public async void EditCharReplacementButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
if (_viewModel is null) return;
var form = new EditReplacementChars(_viewModel.Config);
await form.ShowDialog<DialogResult>(this.GetParentWindow());
}
private async Task<string> editTemplate(ITemplateEditor template)
{
var form = new EditTemplateDialog(template);
if (await form.ShowDialog<DialogResult>(this.GetParentWindow()) == DialogResult.OK)
return template.EditingTemplate.TemplateText;
else return null;
}
}
}

View File

@ -0,0 +1,41 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="450"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
xmlns:vm="clr-namespace:LibationAvalonia.ViewModels.Settings"
x:DataType="vm:ImportSettingsVM"
x:Class="LibationAvalonia.Controls.Settings.Import">
<StackPanel Margin="5">
<StackPanel.Styles>
<Style Selector="CheckBox">
<Setter Property="Margin" Value="0,0,0,10" />
<Style Selector="^ > TextBlock">
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
</Style>
</StackPanel.Styles>
<CheckBox IsChecked="{CompiledBinding AutoScan, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding AutoScanText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding ShowImportedStats, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding ShowImportedStatsText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding ImportEpisodes, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding ImportEpisodesText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding DownloadEpisodes, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding DownloadEpisodesText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding AutoDownloadEpisodes, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding AutoDownloadEpisodesText}" />
</CheckBox>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,20 @@
using Avalonia.Controls;
using LibationAvalonia.ViewModels.Settings;
using LibationFileManager;
namespace LibationAvalonia.Controls.Settings
{
public partial class Import : UserControl
{
public Import()
{
InitializeComponent();
if (Design.IsDesignMode)
{
_ = Configuration.Instance.LibationFiles;
DataContext = new ImportSettingsVM(Configuration.Instance);
}
}
}
}

View File

@ -0,0 +1,88 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="450"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
xmlns:vm="clr-namespace:LibationAvalonia.ViewModels.Settings"
x:DataType="vm:ImportantSettingsVM"
x:Class="LibationAvalonia.Controls.Settings.Important">
<Grid RowDefinitions="Auto,Auto,*">
<controls:GroupBox
Grid.Row="0"
Margin="5"
Label="Books Location">
<StackPanel>
<TextBlock
Margin="5"
Text="{CompiledBinding BooksText}" />
<controls:DirectoryOrCustomSelectControl Margin="0,10,0,10"
SubDirectory="Books"
Directory="{CompiledBinding BooksDirectory, Mode=TwoWay}"
KnownDirectories="{CompiledBinding KnownDirectories}" />
<CheckBox IsChecked="{CompiledBinding SavePodcastsToParentFolder, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding 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="120"
Height="25"
HorizontalContentAlignment="Stretch"
SelectedItem="{CompiledBinding LoggingLevel, Mode=TwoWay}"
ItemsSource="{CompiledBinding LoggingLevels}" />
<Button
Margin="50,0,0,0"
Padding="20,0"
VerticalAlignment="Stretch"
Content="Open Log Folder"
Click="OpenLogFolderButton_Click" />
</StackPanel>
<Grid
Grid.Row="2"
ColumnDefinitions="Auto,Auto,*"
Margin="10"
VerticalAlignment="Bottom">
<TextBlock
Grid.Column="0"
FontSize="16"
VerticalAlignment="Center"
Text="Theme: "/>
<controls:WheelComboBox
Grid.Column="1"
MinWidth="80"
SelectedItem="{CompiledBinding ThemeVariant, Mode=TwoWay}"
ItemsSource="{CompiledBinding Themes}"/>
<TextBlock
Grid.Column="2"
FontSize="16"
FontWeight="Bold"
Margin="10,0"
VerticalAlignment="Center"
IsVisible="{CompiledBinding SelectionChanged}"
Text="Theme change takes effect on restart"/>
</Grid>
</Grid>
</UserControl>

View File

@ -0,0 +1,26 @@
using Avalonia.Controls;
using Dinah.Core;
using FileManager;
using LibationAvalonia.ViewModels.Settings;
using LibationFileManager;
namespace LibationAvalonia.Controls.Settings
{
public partial class Important : UserControl
{
public Important()
{
InitializeComponent();
if (Design.IsDesignMode)
{
_ = Configuration.Instance.LibationFiles;
DataContext = new ImportantSettingsVM(Configuration.Instance);
}
}
public void OpenLogFolderButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
Go.To.Folder(((LongPath)Configuration.Instance.LibationFiles).ShortPathName);
}
}
}

View File

@ -40,7 +40,7 @@
</Path> </Path>
</Canvas> </Canvas>
<controls:GroupBox Grid.Row="3" BorderWidth="2" Label="Acknowledgements" Grid.ColumnSpan="2"> <controls:GroupBox Grid.Row="3" Label="Acknowledgements" Grid.ColumnSpan="2">
<StackPanel> <StackPanel>
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto"> <Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto">
@ -54,7 +54,7 @@
<WrapPanel> <WrapPanel>
<WrapPanel.Styles> <WrapPanel.Styles>
<Style Selector="TextBlock"> <Style Selector="controls|LinkLabel">
<Setter Property="Margin" Value="5,0" /> <Setter Property="Margin" Value="5,0" />
<Setter Property="FontSize" Value="13" /> <Setter Property="FontSize" Value="13" />
</Style> </Style>

View File

@ -81,7 +81,7 @@
HorizontalContentAlignment = "Stretch" HorizontalContentAlignment = "Stretch"
HorizontalAlignment = "Stretch" HorizontalAlignment = "Stretch"
SelectedItem="{Binding SelectedLocale, Mode=TwoWay}" SelectedItem="{Binding SelectedLocale, Mode=TwoWay}"
Items="{Binding Locales}"> ItemsSource="{Binding Locales}">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>
<DataTemplate> <DataTemplate>
@ -113,14 +113,13 @@
<Button <Button
Grid.Column="0" Grid.Column="0"
Height="30" Padding="5,5"
Content="Import from audible-cli" Content="Import from audible-cli"
Click="ImportButton_Clicked" /> Click="ImportButton_Clicked" />
<Button <Button
Grid.Column="1" Grid.Column="1"
Height="30" Padding="30,5"
Padding="30,3,30,3"
Content="Save" Content="Save"
Click="SaveButton_Clicked" /> Click="SaveButton_Clicked" />
</Grid> </Grid>

View File

@ -45,7 +45,6 @@
<controls:GroupBox <controls:GroupBox
Label="Edit Tags" Label="Edit Tags"
Grid.Row="1" Grid.Row="1"
BorderWidth="1"
Margin="10,0,10,0"> Margin="10,0,10,0">
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
@ -63,7 +62,6 @@
<controls:GroupBox <controls:GroupBox
Label="Liberated status: Whether the book/pdf has been downloaded" Label="Liberated status: Whether the book/pdf has been downloaded"
Grid.Row="2" Grid.Row="2"
BorderWidth="1"
Margin="10,10,10,10"> Margin="10,10,10,10">
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
@ -95,7 +93,7 @@
Height="25" Height="25"
VerticalAlignment="Center" VerticalAlignment="Center"
SelectedItem="{Binding BookLiberatedSelectedItem, Mode=TwoWay}" SelectedItem="{Binding BookLiberatedSelectedItem, Mode=TwoWay}"
Items="{Binding BookLiberatedItems}"> ItemsSource="{Binding BookLiberatedItems}">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>
<DataTemplate> <DataTemplate>
@ -117,7 +115,7 @@
Width="150" Width="150"
VerticalAlignment="Center" VerticalAlignment="Center"
SelectedItem="{Binding PdfLiberatedSelectedItem, Mode=TwoWay}" SelectedItem="{Binding PdfLiberatedSelectedItem, Mode=TwoWay}"
Items="{Binding PdfLiberatedItems}"> ItemsSource="{Binding PdfLiberatedItems}">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>
<DataTemplate> <DataTemplate>

View File

@ -101,13 +101,13 @@
Grid.Column="0" Grid.Column="0"
Grid.Row="0" Grid.Row="0"
Content="Check All" Content="Check All"
Click="CheckAll_Click"/> Command="{Binding CheckAll}"/>
<Button <Button
Grid.Column="0" Grid.Column="0"
Grid.Row="1" Grid.Row="1"
Content="Uncheck All" Content="Uncheck All"
Click="UncheckAll_Click"/> Command="{Binding UncheckAll}"/>
<Button <Button
Grid.Column="1" Grid.Column="1"

View File

@ -77,12 +77,12 @@ namespace LibationAvalonia.Dialogs
await setControlEnabled(sender, true); await setControlEnabled(sender, true);
} }
public void CheckAll_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public void CheckAll()
{ {
foreach (var record in bookRecordEntries) foreach (var record in bookRecordEntries)
record.IsChecked = true; record.IsChecked = true;
} }
public void UncheckAll_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public void UncheckAll()
{ {
foreach (var record in bookRecordEntries) foreach (var record in bookRecordEntries)
record.IsChecked = false; record.IsChecked = false;

View File

@ -99,10 +99,10 @@
<Button <Button
Grid.Column="1" Grid.Column="1"
Height="30" Padding="30,5"
Padding="30,3,30,3" Name="saveBtn"
Content="Save" Content="Save"
Click="SaveButton_Clicked" /> Command="{Binding SaveAndClose}" />
</Grid> </Grid>
</Grid> </Grid>
</Window> </Window>

View File

@ -38,7 +38,7 @@ namespace LibationAvalonia.Dialogs
if (!accounts.Any()) if (!accounts.Any())
return; return;
ControlToFocusOnShow = this.FindControl<Button>(nameof(SaveButton_Clicked)); ControlToFocusOnShow = this.FindControl<Button>(nameof(saveBtn));
var allFilters = QuickFilters.Filters.Select(f => new Filter { FilterString = f }).ToList(); var allFilters = QuickFilters.Filters.Select(f => new Filter { FilterString = f }).ToList();
allFilters.Add(new Filter()); allFilters.Add(new Filter());
@ -100,10 +100,5 @@ namespace LibationAvalonia.Dialogs
Filters.Insert(index + 1, filter); Filters.Insert(index + 1, filter);
} }
} }
public void SaveButton_Clicked(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
SaveAndClose();
}
} }
} }

View File

@ -62,9 +62,9 @@
Margin="5" Margin="5"
Orientation="Horizontal"> Orientation="Horizontal">
<Button Margin="0,0,10,0" Click="Defaults_Click" Content="Defaults" /> <Button Margin="0,0,10,0" Command="{Binding Defaults}" Content="Defaults" />
<Button Margin="0,0,10,0" Click="LoFiDefaults_Click" Content="LoFi Defaults" /> <Button Margin="0,0,10,0" Command="{Binding LoFiDefaults}" Content="LoFi Defaults" />
<Button Click="Barebones_Click" Content="Barebones" /> <Button Command="{Binding Barebones}" Content="Barebones" />
</StackPanel> </StackPanel>
<StackPanel <StackPanel
@ -73,8 +73,8 @@
Margin="5" Margin="5"
Orientation="Horizontal"> Orientation="Horizontal">
<Button Margin="0,0,10,0" Click="Cancel_Click" Content="Cancel" /> <Button Margin="0,0,10,0" Command="{Binding Close}" Content="Cancel" />
<Button Padding="20,5,20,6" Click="Save_Click" Content="Save" /> <Button Padding="20,5,20,6" Command="{Binding SaveAndClose}" Content="Save" />
</StackPanel> </StackPanel>
</Grid> </Grid>

View File

@ -35,16 +35,12 @@ namespace LibationAvalonia.Dialogs
LoadTable(config.ReplacementCharacters.Replacements); LoadTable(config.ReplacementCharacters.Replacements);
} }
public void Defaults_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public void Defaults()
=> LoadTable(ReplacementCharacters.Default.Replacements); => LoadTable(ReplacementCharacters.Default.Replacements);
public void LoFiDefaults_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public void LoFiDefaults()
=> LoadTable(ReplacementCharacters.LoFiDefault.Replacements); => LoadTable(ReplacementCharacters.LoFiDefault.Replacements);
public void Barebones_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public void Barebones()
=> LoadTable(ReplacementCharacters.Barebones.Replacements); => LoadTable(ReplacementCharacters.Barebones.Replacements);
public void Save_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> SaveAndClose();
public void Cancel_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> Close();
protected override void SaveAndClose() protected override void SaveAndClose()
{ {

View File

@ -33,7 +33,7 @@
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
Content="Reset to Default" Content="Reset to Default"
Click="ResetButton_Click" /> Command="{Binding ResetToDefault}"/>
</Grid> </Grid>
<Grid Grid.Row="1" ColumnDefinitions="Auto,*"> <Grid Grid.Row="1" ColumnDefinitions="Auto,*">
@ -70,7 +70,6 @@
</DataGrid.Columns> </DataGrid.Columns>
</DataGrid> </DataGrid>
<Grid <Grid
Grid.Column="1" Grid.Column="1"
Margin="5,0,5,0" Margin="5,0,5,0"

View File

@ -19,14 +19,14 @@ namespace LibationAvalonia.Dialogs
public EditTemplateDialog() public EditTemplateDialog()
{ {
AvaloniaXamlLoader.Load(this); InitializeComponent();
userEditTbox = this.FindControl<TextBox>(nameof(userEditTbox));
if (Design.IsDesignMode) if (Design.IsDesignMode)
{ {
_ = Configuration.Instance.LibationFiles; _ = Configuration.Instance.LibationFiles;
var editor = TemplateEditor<Templates.FileTemplate>.CreateFilenameEditor(Configuration.Instance.Books, Configuration.Instance.FileTemplate); var editor = TemplateEditor<Templates.FileTemplate>.CreateFilenameEditor(Configuration.Instance.Books, Configuration.Instance.FileTemplate);
_viewModel = new(Configuration.Instance, editor); _viewModel = new(Configuration.Instance, editor);
_viewModel.resetTextBox(editor.EditingTemplate.TemplateText); _viewModel.ResetTextBox(editor.EditingTemplate.TemplateText);
Title = $"Edit {editor.TemplateName}"; Title = $"Edit {editor.TemplateName}";
DataContext = _viewModel; DataContext = _viewModel;
} }
@ -37,7 +37,7 @@ namespace LibationAvalonia.Dialogs
ArgumentValidator.EnsureNotNull(templateEditor, nameof(templateEditor)); ArgumentValidator.EnsureNotNull(templateEditor, nameof(templateEditor));
_viewModel = new EditTemplateViewModel(Configuration.Instance, templateEditor); _viewModel = new EditTemplateViewModel(Configuration.Instance, templateEditor);
_viewModel.resetTextBox(templateEditor.EditingTemplate.TemplateText); _viewModel.ResetTextBox(templateEditor.EditingTemplate.TemplateText);
Title = $"Edit {templateEditor.TemplateName}"; Title = $"Edit {templateEditor.TemplateName}";
DataContext = _viewModel; DataContext = _viewModel;
} }
@ -67,9 +67,6 @@ namespace LibationAvalonia.Dialogs
public async void SaveButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public async void SaveButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> await SaveAndCloseAsync(); => await SaveAndCloseAsync();
public void ResetButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> _viewModel.resetTextBox(_viewModel.TemplateEditor.DefaultTemplate);
private class EditTemplateViewModel : ViewModels.ViewModelBase private class EditTemplateViewModel : ViewModels.ViewModelBase
{ {
private readonly Configuration config; private readonly Configuration config;
@ -115,7 +112,8 @@ namespace LibationAvalonia.Dialogs
public AvaloniaList<Tuple<string, string, string>> ListItems { get; set; } public AvaloniaList<Tuple<string, string, string>> ListItems { get; set; }
public void resetTextBox(string value) => UserTemplateText = value; public void ResetTextBox(string value) => UserTemplateText = value;
public void ResetToDefault() => ResetTextBox(TemplateEditor.DefaultTemplate);
public async Task<bool> Validate() public async Task<bool> Validate()
{ {

View File

@ -27,6 +27,6 @@
Margin="5" Margin="5"
Padding="30,3,30,3" Padding="30,3,30,3"
Content="Save" Content="Save"
Click="SaveButton_Click" /> Command="{Binding SaveButtonAsync}" />
</Grid> </Grid>
</Window> </Window>

View File

@ -1,6 +1,7 @@
using Avalonia.Controls; using Avalonia.Controls;
using LibationFileManager; using LibationFileManager;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
namespace LibationAvalonia.Dialogs namespace LibationAvalonia.Dialogs
{ {
@ -27,9 +28,8 @@ namespace LibationAvalonia.Dialogs
DataContext = dirSelectOptions = new(); DataContext = dirSelectOptions = new();
} }
public async void SaveButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public async Task SaveButtonAsync()
{ {
var libationDir = dirSelectOptions.Directory; var libationDir = dirSelectOptions.Directory;
if (!System.IO.Directory.Exists(libationDir)) if (!System.IO.Directory.Exists(libationDir))

View File

@ -2,21 +2,21 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="550" d:DesignHeight="130" mc:Ignorable="d" d:DesignWidth="550" d:DesignHeight="135"
xmlns:controls="clr-namespace:LibationAvalonia.Controls" xmlns:controls="clr-namespace:LibationAvalonia.Controls"
x:Class="LibationAvalonia.Dialogs.LiberatedStatusBatchAutoDialog" x:Class="LibationAvalonia.Dialogs.LiberatedStatusBatchAutoDialog"
Title="Liberated status: Whether the book has been downloaded" Title="Liberated status: Whether the book has been downloaded"
MinHeight="130" MaxHeight="130" MinHeight="135" MaxHeight="135"
MinWidth="550" MaxWidth="550" MinWidth="550" MaxWidth="550"
Width="550" Height="130" Width="550" Height="135"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
Icon="/Assets/libation.ico"> Icon="/Assets/libation.ico">
<Grid Margin="10" RowDefinitions="Auto,Auto,Auto"> <Grid Margin="10" RowDefinitions="Auto,Auto">
<StackPanel <StackPanel
Grid.Row="0" Grid.Row="0"
Orientation="Horizontal"> Orientation="Vertical">
<CheckBox <CheckBox
Margin="0,0,0,10" Margin="0,0,0,10"
@ -26,12 +26,6 @@
TextWrapping="Wrap" TextWrapping="Wrap"
Text="If the audio file can be found, set download status to 'Downloaded'" /> Text="If the audio file can be found, set download status to 'Downloaded'" />
</CheckBox> </CheckBox>
</StackPanel>
<StackPanel
Grid.Row="1"
Orientation="Horizontal">
<CheckBox <CheckBox
Margin="0,0,0,10" Margin="0,0,0,10"
IsChecked="{Binding SetNotDownloaded, Mode=TwoWay}"> IsChecked="{Binding SetNotDownloaded, Mode=TwoWay}">
@ -43,11 +37,10 @@
</StackPanel> </StackPanel>
<Button <Button
Grid.Row="2" Grid.Row="1"
Padding="30,0,30,0" Padding="30,5"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Height="25"
Content="Save" Content="Save"
Click="SaveButton_Clicked"/> Command="{Binding SaveAndClose}"/>
</Grid> </Grid>
</Window> </Window>

View File

@ -10,8 +10,5 @@ namespace LibationAvalonia.Dialogs
InitializeComponent(); InitializeComponent();
DataContext = this; DataContext = this;
} }
public void SaveButton_Clicked(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> SaveAndClose();
} }
} }

View File

@ -2,25 +2,25 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="120" mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="100"
xmlns:controls="clr-namespace:LibationAvalonia.Controls" xmlns:controls="clr-namespace:LibationAvalonia.Controls"
x:Class="LibationAvalonia.Dialogs.LiberatedStatusBatchManualDialog" x:Class="LibationAvalonia.Dialogs.LiberatedStatusBatchManualDialog"
Title="Liberated status: Whether the book has been downloaded" Title="Liberated status: Whether the book has been downloaded"
MinWidth="400" MinHeight="120" MinWidth="400" MinHeight="100"
MaxWidth="400" MaxHeight="120" MaxWidth="400" MaxHeight="100"
Width="400" Height="120" Width="400" Height="100"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
Icon="/Assets/libation.ico"> Icon="/Assets/libation.ico">
<Grid RowDefinitions="Auto,Auto,Auto"> <Grid RowDefinitions="Auto,Auto" ColumnDefinitions="*,Auto">
<TextBlock <TextBlock
Grid.Row="0" Grid.ColumnSpan="2"
Margin="10,10,10,0" Margin="10"
Text="To download again next time: change to Not Downloaded&#xa;To not download: change to Downloaded"/> Text="To download again next time: change to Not Downloaded&#xa;To not download: change to Downloaded"/>
<StackPanel <StackPanel
Margin="10" Margin="10,0"
Grid.Row="1" Grid.Row="1"
Orientation="Horizontal"> Orientation="Horizontal">
@ -36,7 +36,7 @@
Height="25" Height="25"
VerticalAlignment="Center" VerticalAlignment="Center"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
Items="{Binding BookStatuses}"> ItemsSource="{Binding BookStatuses}">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>
<DataTemplate> <DataTemplate>
@ -51,12 +51,13 @@
</StackPanel> </StackPanel>
<Button <Button
Grid.Row="2" Grid.Row="1"
Padding="30,0,30,0" Grid.Column="1"
Margin="10,0,10,10" Margin="10,0"
Padding="30,5"
VerticalAlignment="Stretch"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Height="25"
Content="Save" Content="Save"
Click="SaveButton_Clicked"/> Click="SaveButton_Clicked" />
</Grid> </Grid>
</Window> </Window>

View File

@ -16,7 +16,7 @@
<TextBlock Text="IDs Found: " /> <TextBlock Text="IDs Found: " />
<TextBlock Text="{Binding FoundAsins}" /> <TextBlock Text="{Binding FoundAsins}" />
</StackPanel> </StackPanel>
<ListBox Margin="0,5,0,0" Grid.Row="1" Grid.ColumnSpan="2" Name="foundAudiobooksLB" Items="{Binding FoundFiles}" AutoScrollToSelectedItem="true"> <ListBox Margin="0,5,0,0" Grid.Row="1" Grid.ColumnSpan="2" Name="foundAudiobooksLB" ItemsSource="{Binding FoundFiles}" AutoScrollToSelectedItem="true">
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<Grid ColumnDefinitions="Auto,*"> <Grid ColumnDefinitions="Auto,*">

View File

@ -89,7 +89,7 @@ namespace LibationAvalonia.Dialogs
FilePathCache.Insert(book); FilePathCache.Insert(book);
var lb = context.GetLibraryBook_Flat_NoTracking(book.Id); var lb = context.GetLibraryBook_Flat_NoTracking(book.Id);
if (lb.Book.UserDefinedItem.BookStatus is not LiberatedStatus.Liberated) if (lb?.Book?.UserDefinedItem.BookStatus is not LiberatedStatus.Liberated)
await Task.Run(() => lb.UpdateBookStatus(LiberatedStatus.Liberated)); await Task.Run(() => lb.UpdateBookStatus(LiberatedStatus.Liberated));
FileFound?.Invoke(this, book); FileFound?.Invoke(this, book);

View File

@ -2,7 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="185" mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="200"
x:Class="LibationAvalonia.Dialogs.ScanAccountsDialog" x:Class="LibationAvalonia.Dialogs.ScanAccountsDialog"
MinWidth="500" MinHeight="160" MinWidth="500" MinHeight="160"
Width="500" Height="200" Width="500" Height="200"
@ -10,7 +10,7 @@
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
Icon="/Assets/libation.ico"> Icon="/Assets/libation.ico">
<Grid ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto,Auto"> <Grid ColumnDefinitions="*,Auto" RowDefinitions="Auto,*,Auto">
<Grid.Styles> <Grid.Styles>
<Style Selector="Button:focus"> <Style Selector="Button:focus">
@ -23,20 +23,19 @@
Grid.Row="0" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="2" Grid.ColumnSpan="2"
Margin="10,10,10,0" Margin="10"
Text="Check the accounts to scan and import.&#xa;To change default selections, go to: Settings > Accounts"/> Text="Check the accounts to scan and import.&#xa;To change default selections, go to: Settings > Accounts"/>
<ScrollViewer <ScrollViewer
Grid.Row="1" Grid.Row="1"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="2" Grid.ColumnSpan="2"
Margin="10,0"
VerticalAlignment="Stretch"
HorizontalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
Margin="10"
MinHeight="90"
MaxHeight="90">
<ListBox Items="{Binding Accounts}"> <ListBox ItemsSource="{Binding Accounts}">
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
@ -62,21 +61,19 @@
<Button <Button
Grid.Row="2" Grid.Row="2"
Grid.Column="0" Grid.Column="0"
Padding="20,0,20,0" Padding="20,5"
Margin="10,0,10,10" Margin="10"
Height="25"
Content="Edit Accounts" Content="Edit Accounts"
Click="EditAccountsButton_Clicked"/> Command="{Binding EditAccountsAsync}"/>
<Button <Button
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Padding="30,0,30,0" Padding="30,5"
Margin="10,0,10,10" Margin="10"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Height="25"
Content="Import" Content="Import"
Name="ImportButton" Name="ImportButton"
Click="ImportButton_Clicked"/> Command="{Binding SaveAndClose}"/>
</Grid> </Grid>
</Window> </Window>

View File

@ -4,6 +4,7 @@ using Avalonia.Interactivity;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace LibationAvalonia.Dialogs namespace LibationAvalonia.Dialogs
{ {
@ -25,7 +26,7 @@ namespace LibationAvalonia.Dialogs
InitializeComponent(); InitializeComponent();
this.HideMinMaxBtns(); this.HideMinMaxBtns();
this.Opened += ScanAccountsDialog_Opened; ControlToFocusOnShow = this.FindControl<Button>(nameof(ImportButton));
LoadAccounts(); LoadAccounts();
} }
@ -46,12 +47,7 @@ namespace LibationAvalonia.Dialogs
DataContext = this; DataContext = this;
} }
private void ScanAccountsDialog_Opened(object sender, System.EventArgs e) public async Task EditAccountsAsync()
{
this.FindControl<Button>(nameof(ImportButton)).Focus();
}
public async void EditAccountsButton_Clicked(object sender, RoutedEventArgs e)
{ {
if (await new AccountsDialog().ShowDialog<DialogResult>(this) == DialogResult.OK) if (await new AccountsDialog().ShowDialog<DialogResult>(this) == DialogResult.OK)
{ {
@ -67,7 +63,5 @@ namespace LibationAvalonia.Dialogs
base.SaveAndClose(); base.SaveAndClose();
} }
public void ImportButton_Clicked(object sender, RoutedEventArgs e) => SaveAndClose();
} }
} }

View File

@ -3,10 +3,13 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="750" mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="750"
MinWidth="900" MinHeight="700" MinWidth="900" MinHeight="750"
Width="900" Height="700" Width="900" Height="750"
x:Class="LibationAvalonia.Dialogs.SettingsDialog" x:Class="LibationAvalonia.Dialogs.SettingsDialog"
xmlns:controls="clr-namespace:LibationAvalonia.Controls" xmlns:controls="clr-namespace:LibationAvalonia.Controls"
xmlns:settings="clr-namespace:LibationAvalonia.Controls.Settings"
xmlns:vm="clr-namespace:LibationAvalonia.ViewModels.Settings"
x:DataType="vm:SettingsVM"
Title="Edit Settings" Title="Edit Settings"
Icon="/Assets/libation.ico"> Icon="/Assets/libation.ico">
@ -24,789 +27,58 @@
<TabControl Name="tabControl" Grid.Column="0"> <TabControl Name="tabControl" Grid.Column="0">
<TabControl.Styles> <TabControl.Styles>
<Style Selector="ItemsPresenter#PART_ItemsPresenter"> <Style Selector="TabControl /template/ ItemsPresenter#PART_ItemsPresenter">
<Setter Property="Height" Value="28"/> <Setter Property="Height" Value="30"/>
</Style>
<Style Selector="TabControl /template/ ContentPresenter#PART_SelectedContentHost">
<Setter Property="BorderBrush" Value="{DynamicResource SystemBaseLowColor}" />
<Setter Property="BorderThickness" Value="1" />
</Style> </Style>
<Style Selector="TabItem"> <Style Selector="TabItem">
<Setter Property="MinHeight" Value="40"/> <Setter Property="MinHeight" Value="45"/>
<Setter Property="Height" Value="40"/> <Setter Property="Height" Value="45"/>
<Setter Property="Padding" Value="8,2,8,10"/> <Setter Property="Padding" Value="8,2,8,10"/>
<Style Selector="^ > TextBlock" >
<Setter Property="FontSize" Value="14" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style> </Style>
<Style Selector="TabItem#Header TextBlock">
<Setter Property="MinHeight" Value="5"/>
</Style> </Style>
</TabControl.Styles> </TabControl.Styles>
<TabItem> <TabItem>
<TabItem.Header> <TabItem.Header>
<TextBlock Text="Important Settings"/>
<TextBlock
FontSize="14"
VerticalAlignment="Center"
Text="Important Settings"/>
</TabItem.Header> </TabItem.Header>
<Border <settings:Important DataContext="{CompiledBinding ImportantSettings}" />
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
Grid.Row="2"
ColumnDefinitions="Auto,Auto,*"
Margin="10"
VerticalAlignment="Bottom">
<TextBlock
Grid.Column="0"
FontSize="16"
VerticalAlignment="Center"
Text="Theme: "/>
<controls:WheelComboBox
Grid.Column="1"
SelectedItem="{Binding ImportantSettings.ThemeVariant, Mode=TwoWay}"
Items="{Binding ImportantSettings.Themes}" />
<TextBlock
Grid.Column="2"
FontSize="16"
FontWeight="Bold"
Margin="10,0,0,0"
VerticalAlignment="Center"
IsVisible="{Binding ImportantSettings.SelectionChanged}"
Text="Theme change takes effect on restart"/>
</Grid>
</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> <TabItem>
<TabItem.Header> <TabItem.Header>
<TextBlock Text="Import Library"/>
<TextBlock
FontSize="14"
VerticalAlignment="Center"
Text="Download/Decrypt"/>
</TabItem.Header> </TabItem.Header>
<Border <settings:Import DataContext="{CompiledBinding ImportSettings}" />
Grid.Column="0"
Grid.Row="0"
BorderThickness="2"
BorderBrush="{DynamicResource DataGridGridLinesBrush}">
<Grid RowDefinitions="Auto,Auto,Auto,*">
<controls:GroupBox
Grid.Row="0"
Margin="5"
BorderWidth="1"
Label="{Binding DownloadDecryptSettings.BadBookGroupboxText}">
<Grid
ColumnDefinitions="*,*"
RowDefinitions="Auto,Auto">
<RadioButton
Grid.Column="0"
Grid.Row="0"
Margin="0,5,0,5"
IsChecked="{Binding DownloadDecryptSettings.BadBookAsk, Mode=TwoWay}">
<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
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
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
TextWrapping="Wrap"
Text="{Binding DownloadDecryptSettings.BadBookIgnoreText}" />
</RadioButton>
</Grid>
</controls:GroupBox>
<controls:GroupBox
Margin="5"
Grid.Row="1"
BorderWidth="1"
Label="Custom File Naming">
<Grid
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto"
ColumnDefinitions="*,Auto">
<TextBlock
Grid.Row="0"
Grid.Column="0"
Margin="0,5,0,0"
Text="{Binding DownloadDecryptSettings.FolderTemplateText}" />
<TextBox
Grid.Row="1"
Grid.Column="0"
Margin="0,5,10,10"
FontSize="14"
IsReadOnly="True"
Text="{Binding DownloadDecryptSettings.FolderTemplate}" />
<Button
Grid.Row="1"
Grid.Column="1"
Content="Edit"
Height="30"
Padding="30,3,30,3"
Click="EditFolderTemplateButton_Click" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Text="{Binding DownloadDecryptSettings.FileTemplateText}" />
<TextBox
Grid.Row="3"
Grid.Column="0"
Margin="0,5,10,10"
FontSize="14"
IsReadOnly="True"
Text="{Binding DownloadDecryptSettings.FileTemplate}" />
<Button
Grid.Row="3"
Grid.Column="1"
Content="Edit"
Height="30"
Padding="30,3,30,3"
Click="EditFileTemplateButton_Click" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Text="{Binding DownloadDecryptSettings.ChapterFileTemplateText}" />
<TextBox
Grid.Row="5"
Grid.Column="0"
Margin="0,5,10,10"
FontSize="14"
IsReadOnly="True"
Text="{Binding DownloadDecryptSettings.ChapterFileTemplate}" />
<Button
Grid.Row="5"
Grid.Column="1"
Content="Edit"
Height="30"
Padding="30,3,30,3"
Click="EditChapterFileTemplateButton_Click" />
<Button
Grid.Row="6"
Grid.Column="0"
Content="{Binding DownloadDecryptSettings.EditCharReplacementText}"
Height="30"
Padding="30,3,30,3"
Click="EditCharReplacementButton_Click" />
</Grid>
</controls:GroupBox>
<controls:GroupBox
Grid.Row="2"
Margin="5"
BorderWidth="1"
Label="Temporary Files Location">
<StackPanel
Margin="5" >
<TextBlock
Margin="0,0,0,10"
Text="{Binding DownloadDecryptSettings.InProgressDescriptionText}" />
<controls:DirectoryOrCustomSelectControl
Directory="{Binding DownloadDecryptSettings.InProgressDirectory, Mode=TwoWay}"
KnownDirectories="{Binding DownloadDecryptSettings.KnownDirectories}" />
</StackPanel>
</controls:GroupBox>
<CheckBox
Grid.Row="3"
Margin="5"
VerticalAlignment="Top"
IsVisible="{Binding !IsLinux}"
IsChecked="{Binding DownloadDecryptSettings.UseCoverAsFolderIcon, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="{Binding DownloadDecryptSettings.UseCoverAsFolderIconText}" />
</CheckBox>
</Grid>
</Border>
</TabItem> </TabItem>
<TabItem> <TabItem>
<TabItem.Header> <TabItem.Header>
<TextBlock Text="Download/Decrypt"/>
<TextBlock
FontSize="14"
VerticalAlignment="Center"
Text="Audio File Settings"/>
</TabItem.Header> </TabItem.Header>
<Border <settings:DownloadDecrypt DataContext="{CompiledBinding DownloadDecryptSettings}" />
Grid.Column="0" </TabItem>
Grid.Row="0"
BorderThickness="2"
BorderBrush="{DynamicResource DataGridGridLinesBrush}">
<Grid <TabItem>
RowDefinitions="*,Auto"
ColumnDefinitions="*,*">
<StackPanel <TabItem.Header>
Margin="5" <TextBlock Text="Audio File Settings"/>
Grid.Row="0" </TabItem.Header>
Grid.Column="0">
<CheckBox <settings:Audio DataContext="{CompiledBinding AudioSettings}" />
Margin="0,0,0,5"
IsChecked="{Binding AudioSettings.CreateCueSheet, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="{Binding AudioSettings.CreateCueSheetText}" />
</CheckBox>
<CheckBox
Margin="0,0,0,5"
IsChecked="{Binding AudioSettings.DownloadCoverArt, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="{Binding AudioSettings.DownloadCoverArtText}" />
</CheckBox>
<StackPanel Orientation="Horizontal">
<CheckBox
Margin="0,0,0,5"
IsChecked="{Binding AudioSettings.DownloadClipsBookmarks, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="Download Clips, Notes and Bookmarks as" />
</CheckBox>
<controls:WheelComboBox
Margin="5,0,0,0"
IsEnabled="{Binding AudioSettings.DownloadClipsBookmarks}"
Items="{Binding AudioSettings.ClipBookmarkFormats}"
SelectedItem="{Binding AudioSettings.ClipBookmarkFormat}"/>
</StackPanel>
<CheckBox
Margin="0,0,0,5"
IsChecked="{Binding AudioSettings.RetainAaxFile, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="{Binding AudioSettings.RetainAaxFileText}" />
</CheckBox>
<CheckBox
Margin="0,0,0,5"
IsChecked="{Binding AudioSettings.MergeOpeningAndEndCredits, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="{Binding AudioSettings.MergeOpeningEndCreditsText}" />
</CheckBox>
<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
Margin="0,0,0,5"
IsChecked="{Binding AudioSettings.SplitFilesByChapter, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="{Binding AudioSettings.SplitFilesByChapterText}" />
</CheckBox>
<CheckBox
Margin="0,0,0,5"
IsChecked="{Binding AudioSettings.StripAudibleBrandAudio, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="{Binding AudioSettings.StripAudibleBrandingText}" />
</CheckBox>
<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}">
<StackPanel >
<TextBlock
TextWrapping="Wrap"
Text="Download my books in the original audio format (Lossless)" />
<CheckBox
Margin="0,0,0,5"
IsEnabled="{Binding !AudioSettings.DecryptToLossy}"
IsChecked="{Binding AudioSettings.MoveMoovToBeginning, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="{Binding AudioSettings.MoveMoovToBeginningText}" />
</CheckBox>
</StackPanel>
</RadioButton>
<RadioButton
Margin="0,5,0,5"
IsChecked="{Binding AudioSettings.DecryptToLossy, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="Download my books as .MP3 files (transcode if necessary)" />
</RadioButton>
</StackPanel>
</controls:GroupBox>
</StackPanel>
<StackPanel
Grid.Row="0"
Grid.Column="1">
<controls:GroupBox
BorderWidth="1"
Label="Mp3 Encoding Options">
<StackPanel Orientation="Vertical">
<Grid
Margin="5,5,5,0"
ColumnDefinitions="Auto,*">
<controls:GroupBox
BorderWidth="1"
Grid.Column="0"
Label="Target">
<StackPanel Orientation="Horizontal">
<RadioButton
Margin="10"
Content="Bitrate"
IsChecked="{Binding AudioSettings.LameTargetBitrate, Mode=TwoWay}"/>
<RadioButton
Margin="10"
Content="Quality"
IsChecked="{Binding !AudioSettings.LameTargetBitrate, Mode=TwoWay}"/>
</StackPanel>
</controls:GroupBox>
<CheckBox
HorizontalAlignment="Right"
Grid.Column="1"
IsChecked="{Binding AudioSettings.LameDownsampleMono, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="Downsample to mono? (Recommended)" />
</CheckBox>
</Grid>
<Grid Margin="5,5,5,0" RowDefinitions="Auto,Auto" ColumnDefinitions="Auto,*,Auto">
<TextBlock Margin="0,0,0,5" Text="Max audio sample rate:" />
<controls:WheelComboBox
Grid.Row="1"
HorizontalAlignment="Stretch"
Items="{Binding AudioSettings.SampleRates}"
SelectedItem="{Binding AudioSettings.SelectedSampleRate, Mode=TwoWay}"/>
<TextBlock Margin="0,0,0,5" Grid.Column="2" Text="Encoder Quality:" />
<controls:WheelComboBox
Grid.Column="2"
Grid.Row="1"
HorizontalAlignment="Stretch"
Items="{Binding AudioSettings.EncoderQualities}"
SelectedItem="{Binding AudioSettings.SelectedEncoderQuality, Mode=TwoWay}"/>
</Grid>
<controls:GroupBox
Margin="5,5,5,0"
BorderWidth="1"
Label="Bitrate"
IsEnabled="{Binding AudioSettings.LameTargetBitrate}" >
<StackPanel>
<Grid ColumnDefinitions="*,25,Auto">
<Slider
Grid.Column="0"
IsEnabled="{Binding !AudioSettings.LameMatchSource}"
Value="{Binding AudioSettings.LameBitrate, Mode=TwoWay}"
Minimum="16"
Maximum="320"
IsSnapToTickEnabled="True" TickFrequency="16"
Ticks="16,32,48,64,80,96,112,128,144,160,176,192,208,224,240,256,272,288,304,320"
TickPlacement="Outside">
<Slider.Styles>
<Style Selector="Slider /template/ Thumb">
<Setter Property="ToolTip.Tip" Value="{Binding $parent[Slider].Value, Mode=OneWay, StringFormat='\{0:f0\} Kbps'}" />
<Setter Property="ToolTip.Placement" Value="Top" />
<Setter Property="ToolTip.VerticalOffset" Value="-10" />
<Setter Property="ToolTip.HorizontalOffset" Value="-30" />
</Style>
</Slider.Styles>
</Slider>
<TextBlock
Grid.Column="1"
HorizontalAlignment="Right"
Text="{Binding AudioSettings.LameBitrate}" />
<TextBlock
Grid.Column="2"
Text=" Kbps" />
</Grid>
<Grid ColumnDefinitions="*,*">
<CheckBox
Grid.Column="0"
IsChecked="{Binding AudioSettings.LameConstantBitrate, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="Restrict Encoder to Constant Bitrate?" />
</CheckBox>
<CheckBox
Grid.Column="1"
HorizontalAlignment="Right"
IsChecked="{Binding AudioSettings.LameMatchSource, Mode=TwoWay}">
<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
Grid.Column="0"
Grid.ColumnSpan="2"
Value="{Binding AudioSettings.LameVBRQuality, Mode=TwoWay}"
Minimum="0"
Maximum="9"
IsSnapToTickEnabled="True" TickFrequency="1"
Ticks="0,1,2,3,4,5,6,7,8,9"
TickPlacement="Outside">
<Slider.Styles>
<Style Selector="Slider /template/ Thumb">
<Setter Property="ToolTip.Tip" Value="{Binding $parent[Slider].Value, Mode=OneWay, StringFormat='V\{0:f0\}'}" />
<Setter Property="ToolTip.Placement" Value="Top" />
<Setter Property="ToolTip.VerticalOffset" Value="-10" />
<Setter Property="ToolTip.HorizontalOffset" Value="-30" />
</Style>
</Slider.Styles>
</Slider>
<StackPanel
Grid.Column="2"
HorizontalAlignment="Right"
Orientation="Horizontal">
<TextBlock Text="V" />
<TextBlock Text="{Binding AudioSettings.LameVBRQuality}" />
</StackPanel>
<TextBlock
Grid.Column="0"
Grid.Row="1"
Margin="10,0,0,0"
Text="Higher" />
<TextBlock
Grid.Column="1"
Grid.Row="1"
Margin="0,0,10,0"
HorizontalAlignment="Right"
Text="Lower" />
</Grid>
</controls:GroupBox>
<TextBlock
Margin="5,5,5,5"
Text="Using L.A.M.E encoding engine"
FontStyle="Italic" />
</StackPanel>
</controls:GroupBox>
</StackPanel>
<controls:GroupBox
Grid.Row="1"
Grid.ColumnSpan="2"
Margin="5"
BorderWidth="1" IsEnabled="{Binding AudioSettings.SplitFilesByChapter}"
Label="{Binding AudioSettings.ChapterTitleTemplateText}">
<Grid ColumnDefinitions="*,Auto">
<TextBox
Grid.Column="0"
Margin="0,10,10,10"
FontSize="14"
IsReadOnly="True"
Text="{Binding AudioSettings.ChapterTitleTemplate}" />
<Button
Grid.Column="1"
Content="Edit"
Height="30"
Padding="30,3,30,3"
Click="EditChapterTitleTemplateButton_Click" />
</Grid>
</controls:GroupBox>
</Grid>
</Border>
</TabItem> </TabItem>
</TabControl> </TabControl>
</Grid> </Grid>

View File

@ -2,6 +2,7 @@ using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Dinah.Core; using Dinah.Core;
using FileManager; using FileManager;
using LibationAvalonia.ViewModels.Settings;
using LibationFileManager; using LibationFileManager;
using LibationUiBase; using LibationUiBase;
using ReactiveUI; using ReactiveUI;
@ -14,7 +15,7 @@ namespace LibationAvalonia.Dialogs
{ {
public partial class SettingsDialog : DialogWindow public partial class SettingsDialog : DialogWindow
{ {
private SettingsPages settingsDisp; private SettingsVM settingsDisp;
private readonly Configuration config = Configuration.Instance; private readonly Configuration config = Configuration.Instance;
public SettingsDialog() public SettingsDialog()
@ -28,8 +29,17 @@ namespace LibationAvalonia.Dialogs
protected override async Task SaveAndCloseAsync() protected override async Task SaveAndCloseAsync()
{ {
if (!await settingsDisp.SaveSettingsAsync(config)) #region validation
if (string.IsNullOrWhiteSpace(settingsDisp.ImportantSettings.BooksDirectory))
{
await MessageBox.Show(this.GetParentWindow(), "Cannot set Books Location to blank", "Location is blank", MessageBoxButtons.OK, MessageBoxIcon.Error);
return; return;
}
#endregion
settingsDisp.SaveSettings(config);
await MessageBox.VerboseLoggingWarning_ShowIfTrue(); await MessageBox.VerboseLoggingWarning_ShowIfTrue();
await base.SaveAndCloseAsync(); await base.SaveAndCloseAsync();
@ -42,489 +52,5 @@ namespace LibationAvalonia.Dialogs
{ {
Go.To.Folder(((LongPath)Configuration.Instance.LibationFiles).ShortPathName); Go.To.Folder(((LongPath)Configuration.Instance.LibationFiles).ShortPathName);
} }
public async void EditFolderTemplateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var newTemplate = await editTemplate(TemplateEditor<Templates.FolderTemplate>.CreateFilenameEditor(config.Books, settingsDisp.DownloadDecryptSettings.FolderTemplate));
if (newTemplate is not null)
settingsDisp.DownloadDecryptSettings.FolderTemplate = newTemplate;
}
public async void EditFileTemplateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var newTemplate = await editTemplate(TemplateEditor<Templates.FileTemplate>.CreateFilenameEditor(config.Books, settingsDisp.DownloadDecryptSettings.FileTemplate));
if (newTemplate is not null)
settingsDisp.DownloadDecryptSettings.FileTemplate = newTemplate;
}
public async void EditChapterFileTemplateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var newTemplate = await editTemplate(TemplateEditor<Templates.ChapterFileTemplate>.CreateFilenameEditor(config.Books, settingsDisp.DownloadDecryptSettings.ChapterFileTemplate));
if (newTemplate is not null)
settingsDisp.DownloadDecryptSettings.ChapterFileTemplate = newTemplate;
}
public async void EditCharReplacementButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var form = new EditReplacementChars(config);
await form.ShowDialog<DialogResult>(this);
}
public async void EditChapterTitleTemplateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var newTemplate = await editTemplate(TemplateEditor<Templates.ChapterTitleTemplate>.CreateNameEditor(settingsDisp.AudioSettings.ChapterTitleTemplate));
if (newTemplate is not null)
settingsDisp.AudioSettings.ChapterTitleTemplate = newTemplate;
}
private async Task<string> editTemplate(ITemplateEditor template)
{
var form = new EditTemplateDialog(template);
if (await form.ShowDialog<DialogResult>(this) == DialogResult.OK)
return template.EditingTemplate.TemplateText;
else return null;
}
}
internal interface ISettingsDisplay
{
void LoadSettings(Configuration config);
Task<bool> SaveSettingsAsync(Configuration config);
}
public class SettingsPages : ISettingsDisplay
{
public SettingsPages(Configuration config)
{
LoadSettings(config);
}
public bool IsLinux => Configuration.IsLinux;
public bool IsWindows => Configuration.IsWindows;
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 async Task<bool> SaveSettingsAsync(Configuration config)
{
var result = await ImportantSettings.SaveSettingsAsync(config);
result &= await ImportSettings.SaveSettingsAsync(config);
result &= await DownloadDecryptSettings.SaveSettingsAsync(config);
result &= await AudioSettings.SaveSettingsAsync(config);
return result;
}
}
public class ImportantSettings : ViewModels.ViewModelBase, ISettingsDisplay
{
public ImportantSettings(Configuration config)
{
LoadSettings(config);
}
public void LoadSettings(Configuration config)
{
BooksDirectory = config.Books.PathWithoutPrefix;
SavePodcastsToParentFolder = config.SavePodcastsToParentFolder;
LoggingLevel = config.LogLevel;
BetaOptIn = config.BetaOptIn;
ThemeVariant = InitialThemeVariant
= Configuration.Instance.GetString(propertyName: nameof(ThemeVariant)) is nameof(Avalonia.Styling.ThemeVariant.Dark)
? nameof(Avalonia.Styling.ThemeVariant.Dark)
: nameof(Avalonia.Styling.ThemeVariant.Light);
}
public async Task<bool> SaveSettingsAsync(Configuration config)
{
#region validation
if (string.IsNullOrWhiteSpace(BooksDirectory))
{
await MessageBox.Show("Cannot set Books Location to blank", "Location is blank", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
#endregion
LongPath lonNewBooks = BooksDirectory;
if (!System.IO.Directory.Exists(lonNewBooks))
System.IO.Directory.CreateDirectory(lonNewBooks);
config.Books = BooksDirectory;
config.SavePodcastsToParentFolder = SavePodcastsToParentFolder;
config.LogLevel = LoggingLevel;
config.BetaOptIn = BetaOptIn;
Configuration.Instance.SetString(ThemeVariant, nameof(ThemeVariant));
return true;
}
public List<Configuration.KnownDirectories> KnownDirectories { get; } = new()
{
Configuration.KnownDirectories.UserProfile,
Configuration.KnownDirectories.AppDir,
Configuration.KnownDirectories.MyDocs
};
public string BooksText { get; } = Configuration.GetDescription(nameof(Configuration.Books));
public string SavePodcastsToParentFolderText { get; } = Configuration.GetDescription(nameof(Configuration.SavePodcastsToParentFolder));
public Serilog.Events.LogEventLevel[] LoggingLevels { get; } = Enum.GetValues<Serilog.Events.LogEventLevel>();
public string BetaOptInText { get; } = Configuration.GetDescription(nameof(Configuration.BetaOptIn));
public string[] Themes { get; } = { nameof(Avalonia.Styling.ThemeVariant.Light), nameof(Avalonia.Styling.ThemeVariant.Dark) };
public string BooksDirectory { get; set; }
public bool SavePodcastsToParentFolder { get; set; }
public Serilog.Events.LogEventLevel LoggingLevel { get; set; }
public bool BetaOptIn { get; set; }
private string themeVariant;
public string ThemeVariant
{
get => themeVariant;
set
{
this.RaiseAndSetIfChanged(ref themeVariant, value);
SelectionChanged = ThemeVariant != InitialThemeVariant;
this.RaisePropertyChanged(nameof(SelectionChanged));
}
}
public string InitialThemeVariant { get; private set; }
public bool SelectionChanged { get; private set; }
}
public class ImportSettings : ISettingsDisplay
{
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 Task<bool> SaveSettingsAsync(Configuration config)
{
config.AutoScan = AutoScan;
config.ShowImportedStats = ShowImportedStats;
config.ImportEpisodes = ImportEpisodes;
config.DownloadEpisodes = DownloadEpisodes;
config.AutoDownloadEpisodes = AutoDownloadEpisodes;
return Task.FromResult(true);
}
public string AutoScanText { get; } = Configuration.GetDescription(nameof(Configuration.AutoScan));
public string ShowImportedStatsText { get; } = Configuration.GetDescription(nameof(Configuration.ShowImportedStats));
public string ImportEpisodesText { get; } = Configuration.GetDescription(nameof(Configuration.ImportEpisodes));
public string DownloadEpisodesText { get; } = Configuration.GetDescription(nameof(Configuration.DownloadEpisodes));
public string AutoDownloadEpisodesText { get; } = Configuration.GetDescription(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, ISettingsDisplay
{
private bool _badBookAsk;
private bool _badBookAbort;
private bool _badBookRetry;
private bool _badBookIgnore;
private string _folderTemplate;
private string _fileTemplate;
private string _chapterFileTemplate;
public DownloadDecryptSettings(Configuration config)
{
LoadSettings(config);
}
public List<Configuration.KnownDirectories> KnownDirectories { get; } = new()
{
Configuration.KnownDirectories.WinTemp,
Configuration.KnownDirectories.UserProfile,
Configuration.KnownDirectories.AppDir,
Configuration.KnownDirectories.MyDocs,
Configuration.KnownDirectories.LibationFiles
};
public string InProgressDirectory { get; set; }
public void LoadSettings(Configuration config)
{
BadBookAsk = config.BadBook is Configuration.BadBookAction.Ask;
BadBookAbort = config.BadBook is Configuration.BadBookAction.Abort;
BadBookRetry = config.BadBook is Configuration.BadBookAction.Retry;
BadBookIgnore = config.BadBook is Configuration.BadBookAction.Ignore;
FolderTemplate = config.FolderTemplate;
FileTemplate = config.FileTemplate;
ChapterFileTemplate = config.ChapterFileTemplate;
InProgressDirectory = config.InProgress;
UseCoverAsFolderIcon = config.UseCoverAsFolderIcon;
}
public Task<bool> SaveSettingsAsync(Configuration config)
{
config.BadBook
= BadBookAbort ? Configuration.BadBookAction.Abort
: BadBookRetry ? Configuration.BadBookAction.Retry
: BadBookIgnore ? Configuration.BadBookAction.Ignore
: Configuration.BadBookAction.Ask;
config.FolderTemplate = FolderTemplate;
config.FileTemplate = FileTemplate;
config.ChapterFileTemplate = ChapterFileTemplate;
config.InProgress = InProgressDirectory;
config.UseCoverAsFolderIcon = UseCoverAsFolderIcon;
return Task.FromResult(true);
}
public string UseCoverAsFolderIconText { get; } = Configuration.GetDescription(nameof(Configuration.UseCoverAsFolderIcon));
public string BadBookGroupboxText { get; } = Configuration.GetDescription(nameof(Configuration.BadBook));
public string BadBookAskText { get; } = Configuration.BadBookAction.Ask.GetDescription();
public string BadBookAbortText { get; } = Configuration.BadBookAction.Abort.GetDescription();
public string BadBookRetryText { get; } = Configuration.BadBookAction.Retry.GetDescription();
public string BadBookIgnoreText { get; } = Configuration.BadBookAction.Ignore.GetDescription();
public string FolderTemplateText { get; } = Configuration.GetDescription(nameof(Configuration.FolderTemplate));
public string FileTemplateText { get; } = Configuration.GetDescription(nameof(Configuration.FileTemplate));
public string ChapterFileTemplateText { get; } = Configuration.GetDescription(nameof(Configuration.ChapterFileTemplate));
public string EditCharReplacementText { get; } = Configuration.GetDescription(nameof(Configuration.ReplacementCharacters));
public string InProgressDescriptionText { get; } = Configuration.GetDescription(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); } }
public string ChapterFileTemplate { get => _chapterFileTemplate; set { this.RaiseAndSetIfChanged(ref _chapterFileTemplate, value); } }
public bool UseCoverAsFolderIcon { get; set; }
public bool BadBookAsk
{
get => _badBookAsk;
set
{
this.RaiseAndSetIfChanged(ref _badBookAsk, value);
if (value)
{
BadBookAbort = false;
BadBookRetry = false;
BadBookIgnore = false;
}
}
}
public bool BadBookAbort
{
get => _badBookAbort;
set
{
this.RaiseAndSetIfChanged(ref _badBookAbort, value);
if (value)
{
BadBookAsk = false;
BadBookRetry = false;
BadBookIgnore = false;
}
}
}
public bool BadBookRetry
{
get => _badBookRetry;
set
{
this.RaiseAndSetIfChanged(ref _badBookRetry, value);
if (value)
{
BadBookAsk = false;
BadBookAbort = false;
BadBookIgnore = false;
}
}
}
public bool BadBookIgnore
{
get => _badBookIgnore;
set
{
this.RaiseAndSetIfChanged(ref _badBookIgnore, value);
if (value)
{
BadBookAsk = false;
BadBookAbort = false;
BadBookRetry = false;
}
}
}
}
public class AudioSettings : ViewModels.ViewModelBase, ISettingsDisplay
{
private bool _downloadClipsBookmarks;
private bool _decryptToLossy;
private bool _splitFilesByChapter;
private bool _allowLibationFixup;
private bool _lameTargetBitrate;
private bool _lameMatchSource;
private int _lameBitrate;
private int _lameVBRQuality;
private string _chapterTitleTemplate;
public SampleRateSelection SelectedSampleRate { get; set; }
public NAudio.Lame.EncoderQuality SelectedEncoderQuality { get; set; }
public AvaloniaList<SampleRateSelection> SampleRates { get; }
= new(
new[]
{
AAXClean.SampleRate.Hz_44100,
AAXClean.SampleRate.Hz_32000,
AAXClean.SampleRate.Hz_24000,
AAXClean.SampleRate.Hz_22050,
AAXClean.SampleRate.Hz_16000,
AAXClean.SampleRate.Hz_12000,
}
.Select(s => new SampleRateSelection(s)));
public AvaloniaList<NAudio.Lame.EncoderQuality> EncoderQualities { get; }
= new(
new[]
{
NAudio.Lame.EncoderQuality.High,
NAudio.Lame.EncoderQuality.Standard,
NAudio.Lame.EncoderQuality.Fast,
});
public AudioSettings(Configuration config)
{
LoadSettings(config);
}
public void LoadSettings(Configuration config)
{
CreateCueSheet = config.CreateCueSheet;
AllowLibationFixup = config.AllowLibationFixup;
DownloadCoverArt = config.DownloadCoverArt;
RetainAaxFile = config.RetainAaxFile;
DownloadClipsBookmarks = config.DownloadClipsBookmarks;
ClipBookmarkFormat = config.ClipsBookmarksFileFormat;
SplitFilesByChapter = config.SplitFilesByChapter;
MergeOpeningAndEndCredits = config.MergeOpeningAndEndCredits;
StripAudibleBrandAudio = config.StripAudibleBrandAudio;
StripUnabridged = config.StripUnabridged;
ChapterTitleTemplate = config.ChapterTitleTemplate;
DecryptToLossy = config.DecryptToLossy;
MoveMoovToBeginning = config.MoveMoovToBeginning;
LameTargetBitrate = config.LameTargetBitrate;
LameDownsampleMono = config.LameDownsampleMono;
LameConstantBitrate = config.LameConstantBitrate;
LameMatchSource = config.LameMatchSourceBR;
LameBitrate = config.LameBitrate;
LameVBRQuality = config.LameVBRQuality;
SelectedSampleRate = SampleRates.FirstOrDefault(s => s.SampleRate == config.MaxSampleRate);
SelectedEncoderQuality = config.LameEncoderQuality;
}
public Task<bool> SaveSettingsAsync(Configuration config)
{
config.CreateCueSheet = CreateCueSheet;
config.AllowLibationFixup = AllowLibationFixup;
config.DownloadCoverArt = DownloadCoverArt;
config.RetainAaxFile = RetainAaxFile;
config.DownloadClipsBookmarks = DownloadClipsBookmarks;
config.ClipsBookmarksFileFormat = ClipBookmarkFormat;
config.SplitFilesByChapter = SplitFilesByChapter;
config.MergeOpeningAndEndCredits = MergeOpeningAndEndCredits;
config.StripAudibleBrandAudio = StripAudibleBrandAudio;
config.StripUnabridged = StripUnabridged;
config.ChapterTitleTemplate = ChapterTitleTemplate;
config.DecryptToLossy = DecryptToLossy;
config.MoveMoovToBeginning = MoveMoovToBeginning;
config.LameTargetBitrate = LameTargetBitrate;
config.LameDownsampleMono = LameDownsampleMono;
config.LameConstantBitrate = LameConstantBitrate;
config.LameMatchSourceBR = LameMatchSource;
config.LameBitrate = LameBitrate;
config.LameVBRQuality = LameVBRQuality;
config.LameEncoderQuality = SelectedEncoderQuality;
config.MaxSampleRate = SelectedSampleRate?.SampleRate ?? config.MaxSampleRate;
return Task.FromResult(true);
}
public AvaloniaList<Configuration.ClipBookmarkFormat> ClipBookmarkFormats { get; } = new(Enum<Configuration.ClipBookmarkFormat>.GetValues());
public string CreateCueSheetText { get; } = Configuration.GetDescription(nameof(Configuration.CreateCueSheet));
public string AllowLibationFixupText { get; } = Configuration.GetDescription(nameof(Configuration.AllowLibationFixup));
public string DownloadCoverArtText { get; } = Configuration.GetDescription(nameof(Configuration.DownloadCoverArt));
public string RetainAaxFileText { get; } = Configuration.GetDescription(nameof(Configuration.RetainAaxFile));
public string SplitFilesByChapterText { get; } = Configuration.GetDescription(nameof(Configuration.SplitFilesByChapter));
public string MergeOpeningEndCreditsText { get; } = Configuration.GetDescription(nameof(Configuration.MergeOpeningAndEndCredits));
public string StripAudibleBrandingText { get; } = Configuration.GetDescription(nameof(Configuration.StripAudibleBrandAudio));
public string StripUnabridgedText { get; } = Configuration.GetDescription(nameof(Configuration.StripUnabridged));
public string ChapterTitleTemplateText { get; } = Configuration.GetDescription(nameof(Configuration.ChapterTitleTemplate));
public string MoveMoovToBeginningText { get; } = Configuration.GetDescription(nameof(Configuration.MoveMoovToBeginning));
public bool CreateCueSheet { get; set; }
public bool DownloadCoverArt { get; set; }
public bool RetainAaxFile { get; set; }
public bool DownloadClipsBookmarks { get => _downloadClipsBookmarks; set => this.RaiseAndSetIfChanged(ref _downloadClipsBookmarks, value); }
public Configuration.ClipBookmarkFormat ClipBookmarkFormat { get; set; }
public bool MergeOpeningAndEndCredits { get; set; }
public bool StripAudibleBrandAudio { get; set; }
public bool StripUnabridged { get; set; }
public bool DecryptToLossy { get => _decryptToLossy; set => this.RaiseAndSetIfChanged(ref _decryptToLossy, value); }
public bool MoveMoovToBeginning { get; set; }
public bool LameDownsampleMono { get; set; } = Design.IsDesignMode;
public bool LameConstantBitrate { get; set; } = Design.IsDesignMode;
public bool SplitFilesByChapter { get => _splitFilesByChapter; set { this.RaiseAndSetIfChanged(ref _splitFilesByChapter, value); } }
public bool LameTargetBitrate { get => _lameTargetBitrate; set { this.RaiseAndSetIfChanged(ref _lameTargetBitrate, value); } }
public bool LameMatchSource { get => _lameMatchSource; set { this.RaiseAndSetIfChanged(ref _lameMatchSource, value); } }
public int LameBitrate { get => _lameBitrate; set { this.RaiseAndSetIfChanged(ref _lameBitrate, value); } }
public int LameVBRQuality { get => _lameVBRQuality; set { this.RaiseAndSetIfChanged(ref _lameVBRQuality, value); } }
public string ChapterTitleTemplate { get => _chapterTitleTemplate; set { this.RaiseAndSetIfChanged(ref _chapterTitleTemplate, value); } }
public bool AllowLibationFixup
{
get => _allowLibationFixup;
set
{
this.RaiseAndSetIfChanged(ref _allowLibationFixup, value);
if (!_allowLibationFixup)
{
SplitFilesByChapter = false;
StripAudibleBrandAudio = false;
StripUnabridged = false;
DecryptToLossy = false;
this.RaisePropertyChanged(nameof(SplitFilesByChapter));
this.RaisePropertyChanged(nameof(StripAudibleBrandAudio));
this.RaisePropertyChanged(nameof(StripUnabridged));
this.RaisePropertyChanged(nameof(DecryptToLossy));
}
}
}
} }
} }

View File

@ -2,33 +2,32 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="630" d:DesignHeight="110" mc:Ignorable="d" d:DesignWidth="630" d:DesignHeight="90"
x:Class="LibationAvalonia.Dialogs.TagsBatchDialog" x:Class="LibationAvalonia.Dialogs.TagsBatchDialog"
MinWidth="630" MinHeight="110" MinWidth="630" MinHeight="90"
MaxWidth="630" MaxHeight="110" MaxWidth="630" MaxHeight="90"
Width="630" Height="110" Width="630" Height="110"
Title="Replace Tags" Title="Replace Tags"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
Icon="/Assets/libation.ico"> Icon="/Assets/libation.ico">
<Grid RowDefinitions="Auto,Auto,Auto"> <Grid RowDefinitions="Auto,Auto" ColumnDefinitions="*,Auto" Margin="10">
<TextBlock <TextBlock
Grid.Row="0" Grid.ColumnSpan="2"
Margin="10,10,10,0" Margin="0,0,0,10"
Text="Tags are separated by a space. Each tag can contain letters, numbers, and underscores"/> Text="Tags are separated by a space. Each tag can contain letters, numbers, and underscores"/>
<TextBox <TextBox
Grid.Row="1" Grid.Row="1"
Margin="10"
MinHeight="25" MinHeight="25"
Name="EditTagsTb" Name="EditTagsTb"
Text="{Binding NewTags, Mode=TwoWay}" /> Text="{Binding NewTags, Mode=TwoWay}" />
<Button <Button
Grid.Row="2" Grid.Row="1"
Padding="30,0,30,0" Grid.Column="1"
Margin="10,0,10,10" Margin="10,0,0,0"
HorizontalAlignment="Right" Padding="20,3"
Height="25" VerticalAlignment="Stretch"
Content="Save" Content="Save"
Click="SaveButton_Clicked"/> Command="{Binding SaveAndClose}"/>
</Grid> </Grid>
</Window> </Window>

View File

@ -12,8 +12,5 @@ namespace LibationAvalonia.Dialogs
DataContext = this; DataContext = this;
} }
public void SaveButton_Clicked(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> SaveAndClose();
} }
} }

View File

@ -52,12 +52,12 @@
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
Content="Restore" Content="Restore"
Click="Restore_Click" /> Command="{Binding RestoreCheckedAsync}"/>
<Button <Button
IsEnabled="{Binding ControlsEnabled}" IsEnabled="{Binding ControlsEnabled}"
Grid.Column="3" Grid.Column="3"
Click="EmptyTrash_Click" > Command="{Binding PermanentlyDeleteCheckedAsync}" >
<TextBlock <TextBlock
TextAlignment="Center" TextAlignment="Center"
Text="Permanently Delete&#xa;from Libation" /> Text="Permanently Delete&#xa;from Libation" />

View File

@ -16,26 +16,19 @@ namespace LibationAvalonia.Dialogs
{ {
public partial class TrashBinDialog : Window public partial class TrashBinDialog : Window
{ {
TrashBinViewModel _viewModel;
public TrashBinDialog() public TrashBinDialog()
{ {
InitializeComponent(); InitializeComponent();
this.RestoreSizeAndLocation(Configuration.Instance); this.RestoreSizeAndLocation(Configuration.Instance);
DataContext = _viewModel = new(); DataContext = new TrashBinViewModel();
this.Closing += (_, _) => this.SaveSizeAndLocation(Configuration.Instance); this.Closing += (_, _) => this.SaveSizeAndLocation(Configuration.Instance);
this.KeyDown += TrashBinDialog_KeyDown;
}
public async void EmptyTrash_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) KeyBindings.Add(new Avalonia.Input.KeyBinding
=> await _viewModel.PermanentlyDeleteCheckedAsync();
public async void Restore_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> await _viewModel.RestoreCheckedAsync();
private void TrashBinDialog_KeyDown(object sender, Avalonia.Input.KeyEventArgs e)
{ {
if (e.Key == Avalonia.Input.Key.Escape) Gesture = new Avalonia.Input.KeyGesture(Avalonia.Input.Key.Escape),
Close(); Command = ReactiveCommand.Create(Close)
});
} }
} }

View File

@ -21,7 +21,6 @@
<controls:GroupBox <controls:GroupBox
Grid.Row="1" Grid.Row="1"
BorderWidth="2"
Label="Release Information" Label="Release Information"
Margin="0,10,0,10"> Margin="0,10,0,10">

View File

@ -0,0 +1,157 @@
using Avalonia.Collections;
using Avalonia.Controls;
using Dinah.Core;
using LibationFileManager;
using LibationUiBase;
using ReactiveUI;
using System.Linq;
namespace LibationAvalonia.ViewModels.Settings
{
public class AudioSettingsVM : ViewModelBase
{
private bool _downloadClipsBookmarks;
private bool _decryptToLossy;
private bool _splitFilesByChapter;
private bool _allowLibationFixup;
private bool _lameTargetBitrate;
private bool _lameMatchSource;
private int _lameBitrate;
private int _lameVBRQuality;
private string _chapterTitleTemplate;
public SampleRateSelection SelectedSampleRate { get; set; }
public NAudio.Lame.EncoderQuality SelectedEncoderQuality { get; set; }
public AvaloniaList<SampleRateSelection> SampleRates { get; }
= new(
new[]
{
AAXClean.SampleRate.Hz_44100,
AAXClean.SampleRate.Hz_32000,
AAXClean.SampleRate.Hz_24000,
AAXClean.SampleRate.Hz_22050,
AAXClean.SampleRate.Hz_16000,
AAXClean.SampleRate.Hz_12000,
}
.Select(s => new SampleRateSelection(s)));
public AvaloniaList<NAudio.Lame.EncoderQuality> EncoderQualities { get; }
= new(
new[]
{
NAudio.Lame.EncoderQuality.High,
NAudio.Lame.EncoderQuality.Standard,
NAudio.Lame.EncoderQuality.Fast,
});
public AudioSettingsVM(Configuration config)
{
LoadSettings(config);
}
public void LoadSettings(Configuration config)
{
CreateCueSheet = config.CreateCueSheet;
AllowLibationFixup = config.AllowLibationFixup;
DownloadCoverArt = config.DownloadCoverArt;
RetainAaxFile = config.RetainAaxFile;
DownloadClipsBookmarks = config.DownloadClipsBookmarks;
ClipBookmarkFormat = config.ClipsBookmarksFileFormat;
SplitFilesByChapter = config.SplitFilesByChapter;
MergeOpeningAndEndCredits = config.MergeOpeningAndEndCredits;
StripAudibleBrandAudio = config.StripAudibleBrandAudio;
StripUnabridged = config.StripUnabridged;
ChapterTitleTemplate = config.ChapterTitleTemplate;
DecryptToLossy = config.DecryptToLossy;
MoveMoovToBeginning = config.MoveMoovToBeginning;
LameTargetBitrate = config.LameTargetBitrate;
LameDownsampleMono = config.LameDownsampleMono;
LameConstantBitrate = config.LameConstantBitrate;
LameMatchSource = config.LameMatchSourceBR;
LameBitrate = config.LameBitrate;
LameVBRQuality = config.LameVBRQuality;
SelectedSampleRate = SampleRates.FirstOrDefault(s => s.SampleRate == config.MaxSampleRate);
SelectedEncoderQuality = config.LameEncoderQuality;
}
public void SaveSettings(Configuration config)
{
config.CreateCueSheet = CreateCueSheet;
config.AllowLibationFixup = AllowLibationFixup;
config.DownloadCoverArt = DownloadCoverArt;
config.RetainAaxFile = RetainAaxFile;
config.DownloadClipsBookmarks = DownloadClipsBookmarks;
config.ClipsBookmarksFileFormat = ClipBookmarkFormat;
config.SplitFilesByChapter = SplitFilesByChapter;
config.MergeOpeningAndEndCredits = MergeOpeningAndEndCredits;
config.StripAudibleBrandAudio = StripAudibleBrandAudio;
config.StripUnabridged = StripUnabridged;
config.ChapterTitleTemplate = ChapterTitleTemplate;
config.DecryptToLossy = DecryptToLossy;
config.MoveMoovToBeginning = MoveMoovToBeginning;
config.LameTargetBitrate = LameTargetBitrate;
config.LameDownsampleMono = LameDownsampleMono;
config.LameConstantBitrate = LameConstantBitrate;
config.LameMatchSourceBR = LameMatchSource;
config.LameBitrate = LameBitrate;
config.LameVBRQuality = LameVBRQuality;
config.LameEncoderQuality = SelectedEncoderQuality;
config.MaxSampleRate = SelectedSampleRate?.SampleRate ?? config.MaxSampleRate;
}
public AvaloniaList<Configuration.ClipBookmarkFormat> ClipBookmarkFormats { get; } = new(Enum<Configuration.ClipBookmarkFormat>.GetValues());
public string CreateCueSheetText { get; } = Configuration.GetDescription(nameof(Configuration.CreateCueSheet));
public string AllowLibationFixupText { get; } = Configuration.GetDescription(nameof(Configuration.AllowLibationFixup));
public string DownloadCoverArtText { get; } = Configuration.GetDescription(nameof(Configuration.DownloadCoverArt));
public string RetainAaxFileText { get; } = Configuration.GetDescription(nameof(Configuration.RetainAaxFile));
public string SplitFilesByChapterText { get; } = Configuration.GetDescription(nameof(Configuration.SplitFilesByChapter));
public string MergeOpeningEndCreditsText { get; } = Configuration.GetDescription(nameof(Configuration.MergeOpeningAndEndCredits));
public string StripAudibleBrandingText { get; } = Configuration.GetDescription(nameof(Configuration.StripAudibleBrandAudio));
public string StripUnabridgedText { get; } = Configuration.GetDescription(nameof(Configuration.StripUnabridged));
public string ChapterTitleTemplateText { get; } = Configuration.GetDescription(nameof(Configuration.ChapterTitleTemplate));
public string MoveMoovToBeginningText { get; } = Configuration.GetDescription(nameof(Configuration.MoveMoovToBeginning));
public bool CreateCueSheet { get; set; }
public bool DownloadCoverArt { get; set; }
public bool RetainAaxFile { get; set; }
public bool DownloadClipsBookmarks { get => _downloadClipsBookmarks; set => this.RaiseAndSetIfChanged(ref _downloadClipsBookmarks, value); }
public Configuration.ClipBookmarkFormat ClipBookmarkFormat { get; set; }
public bool MergeOpeningAndEndCredits { get; set; }
public bool StripAudibleBrandAudio { get; set; }
public bool StripUnabridged { get; set; }
public bool DecryptToLossy { get => _decryptToLossy; set => this.RaiseAndSetIfChanged(ref _decryptToLossy, value); }
public bool MoveMoovToBeginning { get; set; }
public bool LameDownsampleMono { get; set; } = Design.IsDesignMode;
public bool LameConstantBitrate { get; set; } = Design.IsDesignMode;
public bool SplitFilesByChapter { get => _splitFilesByChapter; set { this.RaiseAndSetIfChanged(ref _splitFilesByChapter, value); } }
public bool LameTargetBitrate { get => _lameTargetBitrate; set { this.RaiseAndSetIfChanged(ref _lameTargetBitrate, value); } }
public bool LameMatchSource { get => _lameMatchSource; set { this.RaiseAndSetIfChanged(ref _lameMatchSource, value); } }
public int LameBitrate { get => _lameBitrate; set { this.RaiseAndSetIfChanged(ref _lameBitrate, value); } }
public int LameVBRQuality { get => _lameVBRQuality; set { this.RaiseAndSetIfChanged(ref _lameVBRQuality, value); } }
public string ChapterTitleTemplate { get => _chapterTitleTemplate; set { this.RaiseAndSetIfChanged(ref _chapterTitleTemplate, value); } }
public bool AllowLibationFixup
{
get => _allowLibationFixup;
set
{
if (!this.RaiseAndSetIfChanged(ref _allowLibationFixup, value))
{
SplitFilesByChapter = false;
StripAudibleBrandAudio = false;
StripUnabridged = false;
DecryptToLossy = false;
this.RaisePropertyChanged(nameof(SplitFilesByChapter));
this.RaisePropertyChanged(nameof(StripAudibleBrandAudio));
this.RaisePropertyChanged(nameof(StripUnabridged));
this.RaisePropertyChanged(nameof(DecryptToLossy));
}
}
}
}
}

View File

@ -0,0 +1,83 @@
using Dinah.Core;
using LibationFileManager;
using ReactiveUI;
using System.Collections.Generic;
namespace LibationAvalonia.ViewModels.Settings
{
public class DownloadDecryptSettingsVM : ViewModelBase
{
private string _folderTemplate;
private string _fileTemplate;
private string _chapterFileTemplate;
public Configuration Config { get; }
public DownloadDecryptSettingsVM(Configuration config)
{
Config = config;
LoadSettings(config);
}
public List<Configuration.KnownDirectories> KnownDirectories { get; } = new()
{
Configuration.KnownDirectories.WinTemp,
Configuration.KnownDirectories.UserProfile,
Configuration.KnownDirectories.AppDir,
Configuration.KnownDirectories.MyDocs,
Configuration.KnownDirectories.LibationFiles
};
public void LoadSettings(Configuration config)
{
BadBookAsk = config.BadBook is Configuration.BadBookAction.Ask;
BadBookAbort = config.BadBook is Configuration.BadBookAction.Abort;
BadBookRetry = config.BadBook is Configuration.BadBookAction.Retry;
BadBookIgnore = config.BadBook is Configuration.BadBookAction.Ignore;
FolderTemplate = config.FolderTemplate;
FileTemplate = config.FileTemplate;
ChapterFileTemplate = config.ChapterFileTemplate;
InProgressDirectory = config.InProgress;
UseCoverAsFolderIcon = config.UseCoverAsFolderIcon;
}
public void SaveSettings(Configuration config)
{
config.BadBook
= BadBookAbort ? Configuration.BadBookAction.Abort
: BadBookRetry ? Configuration.BadBookAction.Retry
: BadBookIgnore ? Configuration.BadBookAction.Ignore
: Configuration.BadBookAction.Ask;
config.FolderTemplate = FolderTemplate;
config.FileTemplate = FileTemplate;
config.ChapterFileTemplate = ChapterFileTemplate;
config.InProgress = InProgressDirectory;
config.UseCoverAsFolderIcon = UseCoverAsFolderIcon;
}
public string UseCoverAsFolderIconText { get; } = Configuration.GetDescription(nameof(Configuration.UseCoverAsFolderIcon));
public string BadBookGroupboxText { get; } = Configuration.GetDescription(nameof(Configuration.BadBook));
public string BadBookAskText { get; } = Configuration.BadBookAction.Ask.GetDescription();
public string BadBookAbortText { get; } = Configuration.BadBookAction.Abort.GetDescription();
public string BadBookRetryText { get; } = Configuration.BadBookAction.Retry.GetDescription();
public string BadBookIgnoreText { get; } = Configuration.BadBookAction.Ignore.GetDescription();
public string FolderTemplateText { get; } = Configuration.GetDescription(nameof(Configuration.FolderTemplate));
public string FileTemplateText { get; } = Configuration.GetDescription(nameof(Configuration.FileTemplate));
public string ChapterFileTemplateText { get; } = Configuration.GetDescription(nameof(Configuration.ChapterFileTemplate));
public string EditCharReplacementText { get; } = Configuration.GetDescription(nameof(Configuration.ReplacementCharacters));
public string InProgressDescriptionText { get; } = Configuration.GetDescription(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); } }
public string ChapterFileTemplate { get => _chapterFileTemplate; set { this.RaiseAndSetIfChanged(ref _chapterFileTemplate, value); } }
public bool UseCoverAsFolderIcon { get; set; }
public bool BadBookAsk { get; set; }
public bool BadBookAbort { get; set; }
public bool BadBookRetry { get; set; }
public bool BadBookIgnore { get; set; }
public string InProgressDirectory { get; set; }
}
}

View File

@ -0,0 +1,42 @@
using LibationFileManager;
namespace LibationAvalonia.ViewModels.Settings
{
public class ImportSettingsVM
{
public ImportSettingsVM(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 { get; } = Configuration.GetDescription(nameof(Configuration.AutoScan));
public string ShowImportedStatsText { get; } = Configuration.GetDescription(nameof(Configuration.ShowImportedStats));
public string ImportEpisodesText { get; } = Configuration.GetDescription(nameof(Configuration.ImportEpisodes));
public string DownloadEpisodesText { get; } = Configuration.GetDescription(nameof(Configuration.DownloadEpisodes));
public string AutoDownloadEpisodesText { get; } = Configuration.GetDescription(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; }
}
}

View File

@ -0,0 +1,71 @@
using FileManager;
using LibationFileManager;
using ReactiveUI;
using System;
using System.Collections.Generic;
namespace LibationAvalonia.ViewModels.Settings
{
public class ImportantSettingsVM : ViewModelBase
{
private string themeVariant;
private string initialThemeVariant;
public ImportantSettingsVM(Configuration config)
{
LoadSettings(config);
}
public void LoadSettings(Configuration config)
{
BooksDirectory = config.Books.PathWithoutPrefix;
SavePodcastsToParentFolder = config.SavePodcastsToParentFolder;
LoggingLevel = config.LogLevel;
ThemeVariant = initialThemeVariant
= Configuration.Instance.GetString(propertyName: nameof(ThemeVariant)) is nameof(Avalonia.Styling.ThemeVariant.Dark)
? nameof(Avalonia.Styling.ThemeVariant.Dark)
: nameof(Avalonia.Styling.ThemeVariant.Light);
}
public void SaveSettings(Configuration config)
{
LongPath lonNewBooks = Configuration.GetKnownDirectory(BooksDirectory) is Configuration.KnownDirectories.None ? BooksDirectory : System.IO.Path.Combine(BooksDirectory, "Books");
if (!System.IO.Directory.Exists(lonNewBooks))
System.IO.Directory.CreateDirectory(lonNewBooks);
config.Books = lonNewBooks;
config.SavePodcastsToParentFolder = SavePodcastsToParentFolder;
config.LogLevel = LoggingLevel;
Configuration.Instance.SetString(ThemeVariant, nameof(ThemeVariant));
}
public List<Configuration.KnownDirectories> KnownDirectories { get; } = new()
{
Configuration.KnownDirectories.UserProfile,
Configuration.KnownDirectories.AppDir,
Configuration.KnownDirectories.MyDocs
};
public string BooksText { get; } = Configuration.GetDescription(nameof(Configuration.Books));
public string SavePodcastsToParentFolderText { get; } = Configuration.GetDescription(nameof(Configuration.SavePodcastsToParentFolder));
public Serilog.Events.LogEventLevel[] LoggingLevels { get; } = Enum.GetValues<Serilog.Events.LogEventLevel>();
public string BetaOptInText { get; } = Configuration.GetDescription(nameof(Configuration.BetaOptIn));
public string[] Themes { get; } = { nameof(Avalonia.Styling.ThemeVariant.Light), nameof(Avalonia.Styling.ThemeVariant.Dark) };
public string BooksDirectory { get; set; }
public bool SavePodcastsToParentFolder { get; set; }
public Serilog.Events.LogEventLevel LoggingLevel { get; set; }
public string ThemeVariant
{
get => themeVariant;
set
{
this.RaiseAndSetIfChanged(ref themeVariant, value);
SelectionChanged = ThemeVariant != initialThemeVariant;
this.RaisePropertyChanged(nameof(SelectionChanged));
}
}
public bool SelectionChanged { get; private set; }
}
}

View File

@ -0,0 +1,33 @@
using LibationFileManager;
namespace LibationAvalonia.ViewModels.Settings
{
public class SettingsVM
{
public SettingsVM(Configuration config)
{
LoadSettings(config);
}
public ImportantSettingsVM ImportantSettings { get; private set; }
public ImportSettingsVM ImportSettings { get; private set; }
public DownloadDecryptSettingsVM DownloadDecryptSettings { get; private set; }
public AudioSettingsVM AudioSettings { get; private set; }
public void LoadSettings(Configuration config)
{
ImportantSettings = new ImportantSettingsVM(config);
ImportSettings = new ImportSettingsVM(config);
DownloadDecryptSettings = new DownloadDecryptSettingsVM(config);
AudioSettings = new AudioSettingsVM(config);
}
public void SaveSettings(Configuration config)
{
ImportantSettings.SaveSettings(config);
ImportSettings.SaveSettings(config);
DownloadDecryptSettings.SaveSettings(config);
AudioSettings.SaveSettings(config);
}
}
}

View File

@ -8,7 +8,7 @@
Title="View All Items in Series"> Title="View All Items in Series">
<TabControl <TabControl
Items="{Binding TabItems}" ItemsSource="{Binding TabItems}"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"> HorizontalAlignment="Stretch">
<TabControl.Styles> <TabControl.Styles>