forked from sim0n00ps/OF-DL
Improve the filename format input field's appearance and validation
This commit is contained in:
parent
b6872a2b9e
commit
e58ac7d2a6
224
OF DL.Gui/Controls/FileNameFormatOverlayTextBlock.cs
Normal file
224
OF DL.Gui/Controls/FileNameFormatOverlayTextBlock.cs
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Linq;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Documents;
|
||||||
|
using Avalonia.Controls.Primitives;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using Avalonia.VisualTree;
|
||||||
|
using OF_DL.Gui.ViewModels;
|
||||||
|
|
||||||
|
namespace OF_DL.Gui.Controls;
|
||||||
|
|
||||||
|
public class FileNameFormatOverlayTextBlock : TextBlock
|
||||||
|
{
|
||||||
|
public static readonly StyledProperty<IEnumerable<FileNameFormatSegmentViewModel>?> SegmentsProperty =
|
||||||
|
AvaloniaProperty.Register<FileNameFormatOverlayTextBlock, IEnumerable<FileNameFormatSegmentViewModel>?>(nameof(Segments));
|
||||||
|
|
||||||
|
public static readonly StyledProperty<TextBox?> SourceTextBoxProperty =
|
||||||
|
AvaloniaProperty.Register<FileNameFormatOverlayTextBlock, TextBox?>(nameof(SourceTextBox));
|
||||||
|
|
||||||
|
private INotifyCollectionChanged? _segmentsCollection;
|
||||||
|
private TextBox? _attachedTextBox;
|
||||||
|
private ScrollViewer? _attachedScrollViewer;
|
||||||
|
|
||||||
|
static FileNameFormatOverlayTextBlock()
|
||||||
|
{
|
||||||
|
SegmentsProperty.Changed.AddClassHandler<FileNameFormatOverlayTextBlock>(OnSegmentsChanged);
|
||||||
|
SourceTextBoxProperty.Changed.AddClassHandler<FileNameFormatOverlayTextBlock>(OnSourceTextBoxChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<FileNameFormatSegmentViewModel>? Segments
|
||||||
|
{
|
||||||
|
get => GetValue(SegmentsProperty);
|
||||||
|
set => SetValue(SegmentsProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextBox? SourceTextBox
|
||||||
|
{
|
||||||
|
get => GetValue(SourceTextBoxProperty);
|
||||||
|
set => SetValue(SourceTextBoxProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnAttachedToVisualTree(e);
|
||||||
|
DetachSegmentsCollection();
|
||||||
|
AttachSegmentsCollection(Segments);
|
||||||
|
AttachSourceTextBox(SourceTextBox);
|
||||||
|
RebuildInlines();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
|
{
|
||||||
|
DetachSourceTextBox();
|
||||||
|
DetachSegmentsCollection();
|
||||||
|
base.OnDetachedFromVisualTree(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnSegmentsChanged(
|
||||||
|
FileNameFormatOverlayTextBlock sender,
|
||||||
|
AvaloniaPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
sender.DetachSegmentsCollection();
|
||||||
|
sender.AttachSegmentsCollection(e.NewValue as IEnumerable<FileNameFormatSegmentViewModel>);
|
||||||
|
sender.RebuildInlines();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnSourceTextBoxChanged(
|
||||||
|
FileNameFormatOverlayTextBlock sender,
|
||||||
|
AvaloniaPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
sender.AttachSourceTextBox(e.NewValue as TextBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AttachSegmentsCollection(IEnumerable<FileNameFormatSegmentViewModel>? segments)
|
||||||
|
{
|
||||||
|
_segmentsCollection = segments as INotifyCollectionChanged;
|
||||||
|
if (_segmentsCollection is not null)
|
||||||
|
{
|
||||||
|
_segmentsCollection.CollectionChanged += OnSegmentsCollectionChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DetachSegmentsCollection()
|
||||||
|
{
|
||||||
|
if (_segmentsCollection is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_segmentsCollection.CollectionChanged -= OnSegmentsCollectionChanged;
|
||||||
|
_segmentsCollection = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSegmentsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
RebuildInlines();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AttachSourceTextBox(TextBox? textBox)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(_attachedTextBox, textBox))
|
||||||
|
{
|
||||||
|
UpdateOverlayOffset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DetachSourceTextBox();
|
||||||
|
_attachedTextBox = textBox;
|
||||||
|
if (_attachedTextBox is null)
|
||||||
|
{
|
||||||
|
UpdateOverlayOffset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_attachedTextBox.TemplateApplied += OnSourceTextBoxTemplateApplied;
|
||||||
|
AttachScrollViewer(FindSourceScrollViewer(_attachedTextBox));
|
||||||
|
UpdateOverlayOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DetachSourceTextBox()
|
||||||
|
{
|
||||||
|
if (_attachedTextBox is not null)
|
||||||
|
{
|
||||||
|
_attachedTextBox.TemplateApplied -= OnSourceTextBoxTemplateApplied;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_attachedScrollViewer is not null)
|
||||||
|
{
|
||||||
|
_attachedScrollViewer.ScrollChanged -= OnSourceScrollChanged;
|
||||||
|
_attachedScrollViewer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_attachedTextBox = null;
|
||||||
|
UpdateOverlayOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSourceTextBoxTemplateApplied(object? sender, TemplateAppliedEventArgs e)
|
||||||
|
{
|
||||||
|
ScrollViewer? scrollViewer = e.NameScope.Find<ScrollViewer>("PART_ScrollViewer");
|
||||||
|
AttachScrollViewer(scrollViewer ?? FindSourceScrollViewer(_attachedTextBox));
|
||||||
|
UpdateOverlayOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSourceScrollChanged(object? sender, ScrollChangedEventArgs e)
|
||||||
|
{
|
||||||
|
UpdateOverlayOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AttachScrollViewer(ScrollViewer? scrollViewer)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(_attachedScrollViewer, scrollViewer))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_attachedScrollViewer is not null)
|
||||||
|
{
|
||||||
|
_attachedScrollViewer.ScrollChanged -= OnSourceScrollChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
_attachedScrollViewer = scrollViewer;
|
||||||
|
if (_attachedScrollViewer is not null)
|
||||||
|
{
|
||||||
|
_attachedScrollViewer.ScrollChanged += OnSourceScrollChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateOverlayOffset()
|
||||||
|
{
|
||||||
|
if (_attachedScrollViewer is null)
|
||||||
|
{
|
||||||
|
RenderTransform = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderTransform = new TranslateTransform(-_attachedScrollViewer.Offset.X, -_attachedScrollViewer.Offset.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ScrollViewer? FindSourceScrollViewer(TextBox? textBox)
|
||||||
|
{
|
||||||
|
if (textBox is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return textBox.GetVisualDescendants().OfType<ScrollViewer>().FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RebuildInlines()
|
||||||
|
{
|
||||||
|
if (Inlines is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Inlines.Clear();
|
||||||
|
if (Segments is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (FileNameFormatSegmentViewModel segment in Segments)
|
||||||
|
{
|
||||||
|
Run run = new()
|
||||||
|
{
|
||||||
|
Text = segment.Text ?? string.Empty,
|
||||||
|
Foreground = ParseForegroundBrush(segment.Foreground)
|
||||||
|
};
|
||||||
|
Inlines.Add(run);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IBrush ParseForegroundBrush(string? value)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(value) && Color.TryParse(value, out Color color))
|
||||||
|
{
|
||||||
|
return new SolidColorBrush(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Foreground ?? Brushes.Transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -140,7 +140,8 @@ public partial class ConfigFieldViewModel : ViewModelBase
|
|||||||
public bool IsTimeoutField =>
|
public bool IsTimeoutField =>
|
||||||
string.Equals(PropertyName, nameof(Config.Timeout), StringComparison.Ordinal);
|
string.Equals(PropertyName, nameof(Config.Timeout), StringComparison.Ordinal);
|
||||||
|
|
||||||
public bool IsRegularTextInput => IsTextInput && !IsIgnoredUsersListField && !IsCreatorConfigsField;
|
public bool IsRegularTextInput =>
|
||||||
|
IsTextInput && !IsIgnoredUsersListField && !IsCreatorConfigsField && !IsFileNameFormatField;
|
||||||
|
|
||||||
public bool HasHelpText => !string.IsNullOrWhiteSpace(HelpText);
|
public bool HasHelpText => !string.IsNullOrWhiteSpace(HelpText);
|
||||||
|
|
||||||
@ -167,6 +168,8 @@ public partial class ConfigFieldViewModel : ViewModelBase
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string _textValue = string.Empty;
|
private string _textValue = string.Empty;
|
||||||
|
|
||||||
|
private bool _isNormalizingFileNameFormatInput;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
[NotifyCanExecuteChangedFor(nameof(InsertSelectedFileNameVariableCommand))]
|
[NotifyCanExecuteChangedFor(nameof(InsertSelectedFileNameVariableCommand))]
|
||||||
private string? _selectedFileNameVariable;
|
private string? _selectedFileNameVariable;
|
||||||
@ -364,6 +367,18 @@ public partial class ConfigFieldViewModel : ViewModelBase
|
|||||||
|
|
||||||
partial void OnTextValueChanged(string value)
|
partial void OnTextValueChanged(string value)
|
||||||
{
|
{
|
||||||
|
if (IsFileNameFormatField && !_isNormalizingFileNameFormatInput)
|
||||||
|
{
|
||||||
|
string trimmedValue = value.Trim();
|
||||||
|
if (!string.Equals(value, trimmedValue, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
_isNormalizingFileNameFormatInput = true;
|
||||||
|
TextValue = trimmedValue;
|
||||||
|
_isNormalizingFileNameFormatInput = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Store actual value if not the privacy placeholder
|
// Store actual value if not the privacy placeholder
|
||||||
if (value != "[Hidden for Privacy]")
|
if (value != "[Hidden for Privacy]")
|
||||||
{
|
{
|
||||||
|
|||||||
@ -18,12 +18,16 @@ public partial class CreatorConfigModalViewModel : ViewModelBase
|
|||||||
|
|
||||||
private readonly Action<bool> _onClose;
|
private readonly Action<bool> _onClose;
|
||||||
private readonly Func<bool> _isUsernameDuplicate;
|
private readonly Func<bool> _isUsernameDuplicate;
|
||||||
|
private bool _isNormalizingUsername;
|
||||||
|
private bool _isNormalizingFileNameFormat;
|
||||||
|
|
||||||
[ObservableProperty] private bool _isOpen;
|
[ObservableProperty] private bool _isOpen;
|
||||||
[ObservableProperty] private bool _isEditMode;
|
[ObservableProperty] private bool _isEditMode;
|
||||||
[ObservableProperty] private string _originalUsername = string.Empty;
|
[ObservableProperty] private string _originalUsername = string.Empty;
|
||||||
[ObservableProperty] private string _username = string.Empty;
|
[ObservableProperty] private string _username = string.Empty;
|
||||||
[ObservableProperty] private string _usernameError = string.Empty;
|
[ObservableProperty]
|
||||||
|
[NotifyPropertyChangedFor(nameof(HasUsernameError))]
|
||||||
|
private string _usernameError = string.Empty;
|
||||||
[ObservableProperty] private string _paidPostFileNameFormat = string.Empty;
|
[ObservableProperty] private string _paidPostFileNameFormat = string.Empty;
|
||||||
[ObservableProperty] private string _postFileNameFormat = string.Empty;
|
[ObservableProperty] private string _postFileNameFormat = string.Empty;
|
||||||
[ObservableProperty] private string _paidMessageFileNameFormat = string.Empty;
|
[ObservableProperty] private string _paidMessageFileNameFormat = string.Empty;
|
||||||
@ -32,10 +36,37 @@ public partial class CreatorConfigModalViewModel : ViewModelBase
|
|||||||
[ObservableProperty] private string _selectedPostVariable = string.Empty;
|
[ObservableProperty] private string _selectedPostVariable = string.Empty;
|
||||||
[ObservableProperty] private string _selectedPaidMessageVariable = string.Empty;
|
[ObservableProperty] private string _selectedPaidMessageVariable = string.Empty;
|
||||||
[ObservableProperty] private string _selectedMessageVariable = string.Empty;
|
[ObservableProperty] private string _selectedMessageVariable = string.Empty;
|
||||||
[ObservableProperty] private string _unknownPaidPostVariablesMessage = string.Empty;
|
[ObservableProperty]
|
||||||
[ObservableProperty] private string _unknownPostVariablesMessage = string.Empty;
|
[NotifyPropertyChangedFor(nameof(HasUnknownPaidPostVariables))]
|
||||||
[ObservableProperty] private string _unknownPaidMessageVariablesMessage = string.Empty;
|
private string _unknownPaidPostVariablesMessage = string.Empty;
|
||||||
[ObservableProperty] private string _unknownMessageVariablesMessage = string.Empty;
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[NotifyPropertyChangedFor(nameof(HasUnknownPostVariables))]
|
||||||
|
private string _unknownPostVariablesMessage = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[NotifyPropertyChangedFor(nameof(HasUnknownPaidMessageVariables))]
|
||||||
|
private string _unknownPaidMessageVariablesMessage = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[NotifyPropertyChangedFor(nameof(HasUnknownMessageVariables))]
|
||||||
|
private string _unknownMessageVariablesMessage = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[NotifyPropertyChangedFor(nameof(HasPaidPostFileNameFormatError))]
|
||||||
|
private string _paidPostFileNameFormatError = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[NotifyPropertyChangedFor(nameof(HasPostFileNameFormatError))]
|
||||||
|
private string _postFileNameFormatError = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[NotifyPropertyChangedFor(nameof(HasPaidMessageFileNameFormatError))]
|
||||||
|
private string _paidMessageFileNameFormatError = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[NotifyPropertyChangedFor(nameof(HasMessageFileNameFormatError))]
|
||||||
|
private string _messageFileNameFormatError = string.Empty;
|
||||||
|
|
||||||
public ObservableCollection<string> AvailableUsers { get; }
|
public ObservableCollection<string> AvailableUsers { get; }
|
||||||
public ObservableCollection<string> PaidPostVariables { get; } = [];
|
public ObservableCollection<string> PaidPostVariables { get; } = [];
|
||||||
@ -52,6 +83,10 @@ public partial class CreatorConfigModalViewModel : ViewModelBase
|
|||||||
public bool HasUnknownPostVariables => !string.IsNullOrWhiteSpace(UnknownPostVariablesMessage);
|
public bool HasUnknownPostVariables => !string.IsNullOrWhiteSpace(UnknownPostVariablesMessage);
|
||||||
public bool HasUnknownPaidMessageVariables => !string.IsNullOrWhiteSpace(UnknownPaidMessageVariablesMessage);
|
public bool HasUnknownPaidMessageVariables => !string.IsNullOrWhiteSpace(UnknownPaidMessageVariablesMessage);
|
||||||
public bool HasUnknownMessageVariables => !string.IsNullOrWhiteSpace(UnknownMessageVariablesMessage);
|
public bool HasUnknownMessageVariables => !string.IsNullOrWhiteSpace(UnknownMessageVariablesMessage);
|
||||||
|
public bool HasPaidPostFileNameFormatError => !string.IsNullOrWhiteSpace(PaidPostFileNameFormatError);
|
||||||
|
public bool HasPostFileNameFormatError => !string.IsNullOrWhiteSpace(PostFileNameFormatError);
|
||||||
|
public bool HasPaidMessageFileNameFormatError => !string.IsNullOrWhiteSpace(PaidMessageFileNameFormatError);
|
||||||
|
public bool HasMessageFileNameFormatError => !string.IsNullOrWhiteSpace(MessageFileNameFormatError);
|
||||||
|
|
||||||
public string DialogTitle => IsEditMode ? "Edit Creator Config" : "Add Creator Config";
|
public string DialogTitle => IsEditMode ? "Edit Creator Config" : "Add Creator Config";
|
||||||
|
|
||||||
@ -85,11 +120,11 @@ public partial class CreatorConfigModalViewModel : ViewModelBase
|
|||||||
IsEditMode = false;
|
IsEditMode = false;
|
||||||
OriginalUsername = string.Empty;
|
OriginalUsername = string.Empty;
|
||||||
Username = string.Empty;
|
Username = string.Empty;
|
||||||
UsernameError = string.Empty;
|
|
||||||
PaidPostFileNameFormat = string.Empty;
|
PaidPostFileNameFormat = string.Empty;
|
||||||
PostFileNameFormat = string.Empty;
|
PostFileNameFormat = string.Empty;
|
||||||
PaidMessageFileNameFormat = string.Empty;
|
PaidMessageFileNameFormat = string.Empty;
|
||||||
MessageFileNameFormat = string.Empty;
|
MessageFileNameFormat = string.Empty;
|
||||||
|
ClearValidationErrors();
|
||||||
ClearAllPreviews();
|
ClearAllPreviews();
|
||||||
Log.Information("About to set IsOpen = true");
|
Log.Information("About to set IsOpen = true");
|
||||||
IsOpen = true;
|
IsOpen = true;
|
||||||
@ -101,11 +136,11 @@ public partial class CreatorConfigModalViewModel : ViewModelBase
|
|||||||
IsEditMode = true;
|
IsEditMode = true;
|
||||||
OriginalUsername = username;
|
OriginalUsername = username;
|
||||||
Username = username;
|
Username = username;
|
||||||
UsernameError = string.Empty;
|
|
||||||
PaidPostFileNameFormat = config.PaidPostFileNameFormat ?? string.Empty;
|
PaidPostFileNameFormat = config.PaidPostFileNameFormat ?? string.Empty;
|
||||||
PostFileNameFormat = config.PostFileNameFormat ?? string.Empty;
|
PostFileNameFormat = config.PostFileNameFormat ?? string.Empty;
|
||||||
PaidMessageFileNameFormat = config.PaidMessageFileNameFormat ?? string.Empty;
|
PaidMessageFileNameFormat = config.PaidMessageFileNameFormat ?? string.Empty;
|
||||||
MessageFileNameFormat = config.MessageFileNameFormat ?? string.Empty;
|
MessageFileNameFormat = config.MessageFileNameFormat ?? string.Empty;
|
||||||
|
ClearValidationErrors();
|
||||||
UpdateAllPreviews();
|
UpdateAllPreviews();
|
||||||
IsOpen = true;
|
IsOpen = true;
|
||||||
}
|
}
|
||||||
@ -184,32 +219,148 @@ public partial class CreatorConfigModalViewModel : ViewModelBase
|
|||||||
Log.Information("*** IsOpen property changed to: {Value} ***", value);
|
Log.Information("*** IsOpen property changed to: {Value} ***", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void OnPaidPostFileNameFormatChanged(string value) => UpdatePaidPostPreview();
|
partial void OnUsernameChanged(string value)
|
||||||
partial void OnPostFileNameFormatChanged(string value) => UpdatePostPreview();
|
{
|
||||||
partial void OnPaidMessageFileNameFormatChanged(string value) => UpdatePaidMessagePreview();
|
if (_isNormalizingUsername)
|
||||||
partial void OnMessageFileNameFormatChanged(string value) => UpdateMessagePreview();
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string trimmed = value.Trim();
|
||||||
|
if (!string.Equals(value, trimmed, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
_isNormalizingUsername = true;
|
||||||
|
Username = trimmed;
|
||||||
|
_isNormalizingUsername = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UsernameError = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnPaidPostFileNameFormatChanged(string value) =>
|
||||||
|
NormalizeFileNameFormat(
|
||||||
|
value,
|
||||||
|
trimmed => PaidPostFileNameFormat = trimmed,
|
||||||
|
() => PaidPostFileNameFormatError = string.Empty,
|
||||||
|
UpdatePaidPostPreview);
|
||||||
|
|
||||||
|
partial void OnPostFileNameFormatChanged(string value) =>
|
||||||
|
NormalizeFileNameFormat(
|
||||||
|
value,
|
||||||
|
trimmed => PostFileNameFormat = trimmed,
|
||||||
|
() => PostFileNameFormatError = string.Empty,
|
||||||
|
UpdatePostPreview);
|
||||||
|
|
||||||
|
partial void OnPaidMessageFileNameFormatChanged(string value) =>
|
||||||
|
NormalizeFileNameFormat(
|
||||||
|
value,
|
||||||
|
trimmed => PaidMessageFileNameFormat = trimmed,
|
||||||
|
() => PaidMessageFileNameFormatError = string.Empty,
|
||||||
|
UpdatePaidMessagePreview);
|
||||||
|
|
||||||
|
partial void OnMessageFileNameFormatChanged(string value) =>
|
||||||
|
NormalizeFileNameFormat(
|
||||||
|
value,
|
||||||
|
trimmed => MessageFileNameFormat = trimmed,
|
||||||
|
() => MessageFileNameFormatError = string.Empty,
|
||||||
|
UpdateMessagePreview);
|
||||||
|
|
||||||
private bool Validate()
|
private bool Validate()
|
||||||
{
|
{
|
||||||
UsernameError = string.Empty;
|
ClearValidationErrors();
|
||||||
|
TrimInputValues();
|
||||||
|
|
||||||
|
bool isValid = true;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(Username))
|
if (string.IsNullOrWhiteSpace(Username))
|
||||||
{
|
{
|
||||||
UsernameError = "Username is required.";
|
UsernameError = "Username is required.";
|
||||||
return false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
string trimmedUsername = Username.Trim();
|
string trimmedUsername = Username.Trim();
|
||||||
if (!IsEditMode || trimmedUsername != OriginalUsername)
|
if (isValid && (!IsEditMode || trimmedUsername != OriginalUsername))
|
||||||
{
|
{
|
||||||
if (_isUsernameDuplicate())
|
if (_isUsernameDuplicate())
|
||||||
{
|
{
|
||||||
UsernameError = "A config for this username already exists.";
|
UsernameError = "A config for this username already exists.";
|
||||||
return false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
ValidateFileNameFormatUniqueness(PaidPostFileNameFormat, message => PaidPostFileNameFormatError = message,
|
||||||
|
ref isValid);
|
||||||
|
ValidateFileNameFormatUniqueness(PostFileNameFormat, message => PostFileNameFormatError = message,
|
||||||
|
ref isValid);
|
||||||
|
ValidateFileNameFormatUniqueness(PaidMessageFileNameFormat, message => PaidMessageFileNameFormatError = message,
|
||||||
|
ref isValid);
|
||||||
|
ValidateFileNameFormatUniqueness(MessageFileNameFormat, message => MessageFileNameFormatError = message,
|
||||||
|
ref isValid);
|
||||||
|
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearValidationErrors()
|
||||||
|
{
|
||||||
|
UsernameError = string.Empty;
|
||||||
|
PaidPostFileNameFormatError = string.Empty;
|
||||||
|
PostFileNameFormatError = string.Empty;
|
||||||
|
PaidMessageFileNameFormatError = string.Empty;
|
||||||
|
MessageFileNameFormatError = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TrimInputValues()
|
||||||
|
{
|
||||||
|
Username = Username.Trim();
|
||||||
|
PaidPostFileNameFormat = PaidPostFileNameFormat.Trim();
|
||||||
|
PostFileNameFormat = PostFileNameFormat.Trim();
|
||||||
|
PaidMessageFileNameFormat = PaidMessageFileNameFormat.Trim();
|
||||||
|
MessageFileNameFormat = MessageFileNameFormat.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ValidateFileNameFormatUniqueness(
|
||||||
|
string format,
|
||||||
|
Action<string> setError,
|
||||||
|
ref bool isValid)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(format))
|
||||||
|
{
|
||||||
|
setError(string.Empty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasUniqueToken = format.Contains("{mediaId}", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
format.Contains("{filename}", StringComparison.OrdinalIgnoreCase);
|
||||||
|
if (hasUniqueToken)
|
||||||
|
{
|
||||||
|
setError(string.Empty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setError("Format must include {mediaId} or {filename} to avoid file collisions.");
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NormalizeFileNameFormat(
|
||||||
|
string value,
|
||||||
|
Action<string> setValue,
|
||||||
|
Action clearError,
|
||||||
|
Action updatePreview)
|
||||||
|
{
|
||||||
|
if (!_isNormalizingFileNameFormat)
|
||||||
|
{
|
||||||
|
string trimmedValue = value.Trim();
|
||||||
|
if (!string.Equals(value, trimmedValue, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
_isNormalizingFileNameFormat = true;
|
||||||
|
setValue(trimmedValue);
|
||||||
|
_isNormalizingFileNameFormat = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearError();
|
||||||
|
updatePreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClearAllPreviews()
|
private void ClearAllPreviews()
|
||||||
|
|||||||
@ -2,6 +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"
|
||||||
|
xmlns:controls="using:OF_DL.Gui.Controls"
|
||||||
xmlns:vm="using:OF_DL.Gui.ViewModels"
|
xmlns:vm="using:OF_DL.Gui.ViewModels"
|
||||||
xmlns:views="using:OF_DL.Gui.Views"
|
xmlns:views="using:OF_DL.Gui.Views"
|
||||||
x:Class="OF_DL.Gui.Views.MainWindow"
|
x:Class="OF_DL.Gui.Views.MainWindow"
|
||||||
@ -38,6 +39,10 @@
|
|||||||
<Setter Property="BorderThickness" Value="1" />
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
<Setter Property="FontWeight" Value="SemiBold" />
|
<Setter Property="FontWeight" Value="SemiBold" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="TextBox.fileNameOverlayInput:not(:empty)">
|
||||||
|
<Setter Property="Foreground" Value="Transparent" />
|
||||||
|
</Style>
|
||||||
</Window.Styles>
|
</Window.Styles>
|
||||||
|
|
||||||
<Grid RowDefinitions="Auto,Auto,*">
|
<Grid RowDefinitions="Auto,Auto,*">
|
||||||
@ -646,6 +651,26 @@
|
|||||||
<StackPanel
|
<StackPanel
|
||||||
IsVisible="{Binding IsFileNameFormatField}"
|
IsVisible="{Binding IsFileNameFormatField}"
|
||||||
Spacing="6">
|
Spacing="6">
|
||||||
|
<Grid ClipToBounds="True">
|
||||||
|
<TextBox
|
||||||
|
x:Name="ConfigFileNameFormatTextBox"
|
||||||
|
Classes="fileNameOverlayInput"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Text="{Binding TextValue}"
|
||||||
|
Padding="8,6"
|
||||||
|
CaretBrush="{DynamicResource TextPrimaryBrush}" />
|
||||||
|
<controls:FileNameFormatOverlayTextBlock
|
||||||
|
IsHitTestVisible="False"
|
||||||
|
Margin="{Binding #ConfigFileNameFormatTextBox.Padding}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Segments="{Binding FileNameFormatSegments}"
|
||||||
|
SourceTextBox="{Binding #ConfigFileNameFormatTextBox}"
|
||||||
|
FontFamily="{Binding #ConfigFileNameFormatTextBox.FontFamily}"
|
||||||
|
FontSize="{Binding #ConfigFileNameFormatTextBox.FontSize}"
|
||||||
|
FontWeight="{Binding #ConfigFileNameFormatTextBox.FontWeight}"
|
||||||
|
FontStyle="{Binding #ConfigFileNameFormatTextBox.FontStyle}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<Grid ColumnDefinitions="*,Auto">
|
<Grid ColumnDefinitions="*,Auto">
|
||||||
<ComboBox Grid.Column="0"
|
<ComboBox Grid.Column="0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
@ -658,32 +683,6 @@
|
|||||||
Command="{Binding InsertSelectedFileNameVariableCommand}" />
|
Command="{Binding InsertSelectedFileNameVariableCommand}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Border Padding="8"
|
|
||||||
Background="{DynamicResource PreviewBackgroundBrush}"
|
|
||||||
BorderBrush="{DynamicResource PreviewBorderBrush}"
|
|
||||||
BorderThickness="1"
|
|
||||||
CornerRadius="8">
|
|
||||||
<ItemsControl
|
|
||||||
ItemsSource="{Binding FileNameFormatSegments}">
|
|
||||||
<ItemsControl.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<WrapPanel
|
|
||||||
Orientation="Horizontal" />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate
|
|
||||||
x:DataType="vm:FileNameFormatSegmentViewModel">
|
|
||||||
<TextBlock
|
|
||||||
Text="{Binding Text}"
|
|
||||||
Foreground="{Binding Foreground}"
|
|
||||||
FontFamily="Consolas"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
</ItemsControl>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
IsVisible="{Binding HasUnknownFileNameVariables}"
|
IsVisible="{Binding HasUnknownFileNameVariables}"
|
||||||
Foreground="{DynamicResource ErrorTextBrush}"
|
Foreground="{DynamicResource ErrorTextBrush}"
|
||||||
@ -992,8 +991,23 @@
|
|||||||
|
|
||||||
<StackPanel Spacing="8">
|
<StackPanel Spacing="8">
|
||||||
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Paid Post Filename Format" />
|
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Paid Post Filename Format" />
|
||||||
<TextBox Text="{Binding PaidPostFileNameFormat}"
|
<Grid ClipToBounds="True">
|
||||||
Watermark="Optional: override global paid post format" />
|
<TextBox x:Name="PaidPostFileNameFormatTextBox"
|
||||||
|
Classes="fileNameOverlayInput"
|
||||||
|
Text="{Binding PaidPostFileNameFormat}"
|
||||||
|
Watermark="Optional: override global paid post format"
|
||||||
|
Padding="8,6"
|
||||||
|
CaretBrush="{DynamicResource TextPrimaryBrush}" />
|
||||||
|
<controls:FileNameFormatOverlayTextBlock IsHitTestVisible="False"
|
||||||
|
Margin="{Binding #PaidPostFileNameFormatTextBox.Padding}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Segments="{Binding PaidPostSegments}"
|
||||||
|
SourceTextBox="{Binding #PaidPostFileNameFormatTextBox}"
|
||||||
|
FontFamily="{Binding #PaidPostFileNameFormatTextBox.FontFamily}"
|
||||||
|
FontSize="{Binding #PaidPostFileNameFormatTextBox.FontSize}"
|
||||||
|
FontWeight="{Binding #PaidPostFileNameFormatTextBox.FontWeight}"
|
||||||
|
FontStyle="{Binding #PaidPostFileNameFormatTextBox.FontStyle}" />
|
||||||
|
</Grid>
|
||||||
<Grid ColumnDefinitions="*,Auto">
|
<Grid ColumnDefinitions="*,Auto">
|
||||||
<ComboBox Grid.Column="0"
|
<ComboBox Grid.Column="0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
@ -1005,37 +1019,35 @@
|
|||||||
Content="Insert"
|
Content="Insert"
|
||||||
Command="{Binding InsertPaidPostVariableCommand}" />
|
Command="{Binding InsertPaidPostVariableCommand}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Border Padding="8"
|
|
||||||
Background="{DynamicResource PreviewBackgroundBrush}"
|
|
||||||
BorderBrush="{DynamicResource PreviewBorderBrush}"
|
|
||||||
BorderThickness="1"
|
|
||||||
CornerRadius="8">
|
|
||||||
<ItemsControl ItemsSource="{Binding PaidPostSegments}">
|
|
||||||
<ItemsControl.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<WrapPanel Orientation="Horizontal" />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate x:DataType="vm:FileNameFormatSegmentViewModel">
|
|
||||||
<TextBlock Text="{Binding Text}"
|
|
||||||
Foreground="{Binding Foreground}"
|
|
||||||
FontFamily="Consolas"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
</ItemsControl>
|
|
||||||
</Border>
|
|
||||||
<TextBlock IsVisible="{Binding HasUnknownPaidPostVariables}"
|
<TextBlock IsVisible="{Binding HasUnknownPaidPostVariables}"
|
||||||
Foreground="{DynamicResource ErrorTextBrush}"
|
Foreground="{DynamicResource ErrorTextBrush}"
|
||||||
Text="{Binding UnknownPaidPostVariablesMessage}"
|
Text="{Binding UnknownPaidPostVariablesMessage}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
<TextBlock IsVisible="{Binding HasPaidPostFileNameFormatError}"
|
||||||
|
Foreground="{DynamicResource ErrorTextBrush}"
|
||||||
|
Text="{Binding PaidPostFileNameFormatError}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Spacing="8">
|
<StackPanel Spacing="8">
|
||||||
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Post Filename Format" />
|
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Post Filename Format" />
|
||||||
<TextBox Text="{Binding PostFileNameFormat}"
|
<Grid ClipToBounds="True">
|
||||||
Watermark="Optional: override global post format" />
|
<TextBox x:Name="PostFileNameFormatTextBox"
|
||||||
|
Classes="fileNameOverlayInput"
|
||||||
|
Text="{Binding PostFileNameFormat}"
|
||||||
|
Watermark="Optional: override global post format"
|
||||||
|
Padding="8,6"
|
||||||
|
CaretBrush="{DynamicResource TextPrimaryBrush}" />
|
||||||
|
<controls:FileNameFormatOverlayTextBlock IsHitTestVisible="False"
|
||||||
|
Margin="{Binding #PostFileNameFormatTextBox.Padding}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Segments="{Binding PostSegments}"
|
||||||
|
SourceTextBox="{Binding #PostFileNameFormatTextBox}"
|
||||||
|
FontFamily="{Binding #PostFileNameFormatTextBox.FontFamily}"
|
||||||
|
FontSize="{Binding #PostFileNameFormatTextBox.FontSize}"
|
||||||
|
FontWeight="{Binding #PostFileNameFormatTextBox.FontWeight}"
|
||||||
|
FontStyle="{Binding #PostFileNameFormatTextBox.FontStyle}" />
|
||||||
|
</Grid>
|
||||||
<Grid ColumnDefinitions="*,Auto">
|
<Grid ColumnDefinitions="*,Auto">
|
||||||
<ComboBox Grid.Column="0"
|
<ComboBox Grid.Column="0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
@ -1047,37 +1059,35 @@
|
|||||||
Content="Insert"
|
Content="Insert"
|
||||||
Command="{Binding InsertPostVariableCommand}" />
|
Command="{Binding InsertPostVariableCommand}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Border Padding="8"
|
|
||||||
Background="{DynamicResource PreviewBackgroundBrush}"
|
|
||||||
BorderBrush="{DynamicResource PreviewBorderBrush}"
|
|
||||||
BorderThickness="1"
|
|
||||||
CornerRadius="8">
|
|
||||||
<ItemsControl ItemsSource="{Binding PostSegments}">
|
|
||||||
<ItemsControl.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<WrapPanel Orientation="Horizontal" />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate x:DataType="vm:FileNameFormatSegmentViewModel">
|
|
||||||
<TextBlock Text="{Binding Text}"
|
|
||||||
Foreground="{Binding Foreground}"
|
|
||||||
FontFamily="Consolas"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
</ItemsControl>
|
|
||||||
</Border>
|
|
||||||
<TextBlock IsVisible="{Binding HasUnknownPostVariables}"
|
<TextBlock IsVisible="{Binding HasUnknownPostVariables}"
|
||||||
Foreground="{DynamicResource ErrorTextBrush}"
|
Foreground="{DynamicResource ErrorTextBrush}"
|
||||||
Text="{Binding UnknownPostVariablesMessage}"
|
Text="{Binding UnknownPostVariablesMessage}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
<TextBlock IsVisible="{Binding HasPostFileNameFormatError}"
|
||||||
|
Foreground="{DynamicResource ErrorTextBrush}"
|
||||||
|
Text="{Binding PostFileNameFormatError}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Spacing="8">
|
<StackPanel Spacing="8">
|
||||||
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Paid Message Filename Format" />
|
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Paid Message Filename Format" />
|
||||||
<TextBox Text="{Binding PaidMessageFileNameFormat}"
|
<Grid ClipToBounds="True">
|
||||||
Watermark="Optional: override global paid message format" />
|
<TextBox x:Name="PaidMessageFileNameFormatTextBox"
|
||||||
|
Classes="fileNameOverlayInput"
|
||||||
|
Text="{Binding PaidMessageFileNameFormat}"
|
||||||
|
Watermark="Optional: override global paid message format"
|
||||||
|
Padding="8,6"
|
||||||
|
CaretBrush="{DynamicResource TextPrimaryBrush}" />
|
||||||
|
<controls:FileNameFormatOverlayTextBlock IsHitTestVisible="False"
|
||||||
|
Margin="{Binding #PaidMessageFileNameFormatTextBox.Padding}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Segments="{Binding PaidMessageSegments}"
|
||||||
|
SourceTextBox="{Binding #PaidMessageFileNameFormatTextBox}"
|
||||||
|
FontFamily="{Binding #PaidMessageFileNameFormatTextBox.FontFamily}"
|
||||||
|
FontSize="{Binding #PaidMessageFileNameFormatTextBox.FontSize}"
|
||||||
|
FontWeight="{Binding #PaidMessageFileNameFormatTextBox.FontWeight}"
|
||||||
|
FontStyle="{Binding #PaidMessageFileNameFormatTextBox.FontStyle}" />
|
||||||
|
</Grid>
|
||||||
<Grid ColumnDefinitions="*,Auto">
|
<Grid ColumnDefinitions="*,Auto">
|
||||||
<ComboBox Grid.Column="0"
|
<ComboBox Grid.Column="0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
@ -1089,37 +1099,35 @@
|
|||||||
Content="Insert"
|
Content="Insert"
|
||||||
Command="{Binding InsertPaidMessageVariableCommand}" />
|
Command="{Binding InsertPaidMessageVariableCommand}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Border Padding="8"
|
|
||||||
Background="{DynamicResource PreviewBackgroundBrush}"
|
|
||||||
BorderBrush="{DynamicResource PreviewBorderBrush}"
|
|
||||||
BorderThickness="1"
|
|
||||||
CornerRadius="8">
|
|
||||||
<ItemsControl ItemsSource="{Binding PaidMessageSegments}">
|
|
||||||
<ItemsControl.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<WrapPanel Orientation="Horizontal" />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate x:DataType="vm:FileNameFormatSegmentViewModel">
|
|
||||||
<TextBlock Text="{Binding Text}"
|
|
||||||
Foreground="{Binding Foreground}"
|
|
||||||
FontFamily="Consolas"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
</ItemsControl>
|
|
||||||
</Border>
|
|
||||||
<TextBlock IsVisible="{Binding HasUnknownPaidMessageVariables}"
|
<TextBlock IsVisible="{Binding HasUnknownPaidMessageVariables}"
|
||||||
Foreground="{DynamicResource ErrorTextBrush}"
|
Foreground="{DynamicResource ErrorTextBrush}"
|
||||||
Text="{Binding UnknownPaidMessageVariablesMessage}"
|
Text="{Binding UnknownPaidMessageVariablesMessage}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
<TextBlock IsVisible="{Binding HasPaidMessageFileNameFormatError}"
|
||||||
|
Foreground="{DynamicResource ErrorTextBrush}"
|
||||||
|
Text="{Binding PaidMessageFileNameFormatError}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Spacing="8">
|
<StackPanel Spacing="8">
|
||||||
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Message Filename Format" />
|
<TextBlock FontWeight="SemiBold" Foreground="{DynamicResource TextPrimaryBrush}" Text="Message Filename Format" />
|
||||||
<TextBox Text="{Binding MessageFileNameFormat}"
|
<Grid ClipToBounds="True">
|
||||||
Watermark="Optional: override global message format" />
|
<TextBox x:Name="MessageFileNameFormatTextBox"
|
||||||
|
Classes="fileNameOverlayInput"
|
||||||
|
Text="{Binding MessageFileNameFormat}"
|
||||||
|
Watermark="Optional: override global message format"
|
||||||
|
Padding="8,6"
|
||||||
|
CaretBrush="{DynamicResource TextPrimaryBrush}" />
|
||||||
|
<controls:FileNameFormatOverlayTextBlock IsHitTestVisible="False"
|
||||||
|
Margin="{Binding #MessageFileNameFormatTextBox.Padding}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Segments="{Binding MessageSegments}"
|
||||||
|
SourceTextBox="{Binding #MessageFileNameFormatTextBox}"
|
||||||
|
FontFamily="{Binding #MessageFileNameFormatTextBox.FontFamily}"
|
||||||
|
FontSize="{Binding #MessageFileNameFormatTextBox.FontSize}"
|
||||||
|
FontWeight="{Binding #MessageFileNameFormatTextBox.FontWeight}"
|
||||||
|
FontStyle="{Binding #MessageFileNameFormatTextBox.FontStyle}" />
|
||||||
|
</Grid>
|
||||||
<Grid ColumnDefinitions="*,Auto">
|
<Grid ColumnDefinitions="*,Auto">
|
||||||
<ComboBox Grid.Column="0"
|
<ComboBox Grid.Column="0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
@ -1131,31 +1139,14 @@
|
|||||||
Content="Insert"
|
Content="Insert"
|
||||||
Command="{Binding InsertMessageVariableCommand}" />
|
Command="{Binding InsertMessageVariableCommand}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Border Padding="8"
|
|
||||||
Background="{DynamicResource PreviewBackgroundBrush}"
|
|
||||||
BorderBrush="{DynamicResource PreviewBorderBrush}"
|
|
||||||
BorderThickness="1"
|
|
||||||
CornerRadius="8">
|
|
||||||
<ItemsControl ItemsSource="{Binding MessageSegments}">
|
|
||||||
<ItemsControl.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<WrapPanel Orientation="Horizontal" />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate x:DataType="vm:FileNameFormatSegmentViewModel">
|
|
||||||
<TextBlock Text="{Binding Text}"
|
|
||||||
Foreground="{Binding Foreground}"
|
|
||||||
FontFamily="Consolas"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
</ItemsControl>
|
|
||||||
</Border>
|
|
||||||
<TextBlock IsVisible="{Binding HasUnknownMessageVariables}"
|
<TextBlock IsVisible="{Binding HasUnknownMessageVariables}"
|
||||||
Foreground="{DynamicResource ErrorTextBrush}"
|
Foreground="{DynamicResource ErrorTextBrush}"
|
||||||
Text="{Binding UnknownMessageVariablesMessage}"
|
Text="{Binding UnknownMessageVariablesMessage}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
<TextBlock IsVisible="{Binding HasMessageFileNameFormatError}"
|
||||||
|
Foreground="{DynamicResource ErrorTextBrush}"
|
||||||
|
Text="{Binding MessageFileNameFormatError}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal" Spacing="10" HorizontalAlignment="Right">
|
<StackPanel Orientation="Horizontal" Spacing="10" HorizontalAlignment="Right">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user