Skip to content

Feature: Add Invalid Archive Name & Invalid Shortcut Location Warning #11997

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
19 changes: 17 additions & 2 deletions src/Files.App/Dialogs/CreateArchiveDialog.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
x:Class="Files.App.Dialogs.CreateArchiveDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:CommunityToolkit.WinUI.UI.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:helpers="using:Files.App.Helpers"
xmlns:local="using:Files.App.Dialogs"
Expand All @@ -13,12 +14,17 @@
Closing="ContentDialog_Closing"
CornerRadius="{StaticResource OverlayCornerRadius}"
DefaultButton="Primary"
IsPrimaryButtonEnabled="True"
IsPrimaryButtonEnabled="{x:Bind ViewModel.IsNameValid, Mode=OneWay}"
Loaded="ContentDialog_Loaded"
PrimaryButtonText="{helpers:ResourceString Name=Create}"
RequestedTheme="{x:Bind helpers:ThemeHelper.RootTheme}"
Style="{StaticResource DefaultContentDialogStyle}"
mc:Ignorable="d">

<ContentDialog.Resources>
<converters:BoolNegationConverter x:Key="BoolNegationConverter" />
</ContentDialog.Resources>

<StackPanel Width="440" Spacing="4">

<!-- Archive Name -->
Expand All @@ -42,7 +48,16 @@
Grid.Column="1"
Width="260"
PlaceholderText="{helpers:ResourceString Name=EnterName}"
Text="{x:Bind ViewModel.FileName, Mode=TwoWay}" />
Text="{x:Bind ViewModel.FileName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBox.Resources>
<TeachingTip
x:Name="InvalidNameWarning"
Title="{helpers:ResourceString Name=InvalidFilename/Text}"
IsOpen="{x:Bind ViewModel.IsNameValid, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
PreferredPlacement="Bottom"
Target="{x:Bind FileNameBox}" />
</TextBox.Resources>
</TextBox>
</Grid>

<!-- Archive Options -->
Expand Down
6 changes: 5 additions & 1 deletion src/Files.App/Dialogs/CreateArchiveDialog.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Files.App.Extensions;
using Files.App.Filesystem;
using Files.App.Filesystem.Archive;
using Files.Backend.Models;
using Microsoft.UI.Xaml;
Expand Down Expand Up @@ -81,6 +82,7 @@ private void ContentDialog_Loaded(object _, RoutedEventArgs e)
}
private void ContentDialog_Closing(ContentDialog _, ContentDialogClosingEventArgs e)
{
InvalidNameWarning.IsOpen = false;
Closing -= ContentDialog_Closing;
ViewModel.PropertyChanged -= ViewModel_PropertyChanged;

Expand All @@ -99,11 +101,13 @@ private void ViewModel_PropertyChanged(object? _, PropertyChangedEventArgs e)

private class DialogViewModel : ObservableObject
{
public bool IsNameValid => FilesystemHelpers.IsValidForFilename(fileName);

private string fileName = string.Empty;
public string FileName
{
get => fileName;
set => SetProperty(ref fileName, value);
set => SetProperty(ref fileName, value, nameof(IsNameValid));
}

private FileFormatItem fileFormat;
Expand Down
17 changes: 15 additions & 2 deletions src/Files.App/Dialogs/CreateShortcutDialog.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
x:Class="Files.App.Dialogs.CreateShortcutDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:CommunityToolkit.WinUI.UI.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:helpers="using:Files.App.Helpers"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Expand All @@ -15,6 +16,10 @@
Style="{StaticResource DefaultContentDialogStyle}"
mc:Ignorable="d">

<ContentDialog.Resources>
<converters:BoolNegationConverter x:Key="BoolNegationConverter" />
</ContentDialog.Resources>

<Border Width="400">
<Grid
x:Name="DestinationPathGrid"
Expand Down Expand Up @@ -49,7 +54,15 @@
Grid.Column="0"
HorizontalAlignment="Stretch"
PlaceholderText="C:\Users\"
Text="{x:Bind ViewModel.DestinationItemPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Text="{x:Bind ViewModel.DestinationItemPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBox.Resources>
<TeachingTip
x:Name="InvalidPathWarning"
Title="{helpers:ResourceString Name=InvalidLocation}"
IsOpen="{x:Bind ViewModel.IsLocationValid, Mode=OneWay, Converter={StaticResource BoolNegationConverter}, FallbackValue=False}"
PreferredPlacement="Bottom" />
</TextBox.Resources>
</TextBox>
<Button
x:Name="SelectDestination"
Grid.Row="2"
Expand All @@ -58,4 +71,4 @@
Content="{helpers:ResourceString Name=Browse}" />
</Grid>
</Border>
</ContentDialog>
</ContentDialog>
13 changes: 13 additions & 0 deletions src/Files.App/Dialogs/CreateShortcutDialog.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Files.Backend.ViewModels.Dialogs;
using Files.Shared.Enums;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
using System;
using System.Threading.Tasks;

Expand All @@ -18,6 +19,18 @@ public CreateShortcutDialogViewModel ViewModel
public CreateShortcutDialog()
{
InitializeComponent();
this.Closing += CreateShortcutDialog_Closing;

InvalidPathWarning.SetBinding(TeachingTip.TargetProperty, new Binding()
{
Source = DestinationItemPath
});
}

private void CreateShortcutDialog_Closing(ContentDialog sender, ContentDialogClosingEventArgs args)
{
this.Closing -= CreateShortcutDialog_Closing;
InvalidPathWarning.IsOpen = false;
}

public new async Task<DialogResult> ShowAsync() => (DialogResult)await base.ShowAsync();
Expand Down
43 changes: 27 additions & 16 deletions src/Files.App/Helpers/DynamicDialogFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
using Files.App.ViewModels.Dialogs;
using Files.Shared.Enums;
using Files.Shared.Extensions;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -63,18 +65,29 @@ public static DynamicDialog GetFor_RenameDialog()
PlaceholderText = "EnterAnItemName".GetLocalizedResource()
};

TextBlock tipText = new()
TeachingTip warning = new()
{
Text = "InvalidFilename/Text".GetLocalizedResource(),
Margin = new Microsoft.UI.Xaml.Thickness(0, 0, 4, 0),
TextWrapping = Microsoft.UI.Xaml.TextWrapping.Wrap,
Opacity = 0.0d
Title = "InvalidFilename/Text".GetLocalizedResource(),
PreferredPlacement = TeachingTipPlacementMode.Bottom,
DataContext = new RenameDialogViewModel(),
};

warning.SetBinding(TeachingTip.TargetProperty, new Binding()
{
Source = inputText
});
warning.SetBinding(TeachingTip.IsOpenProperty, new Binding()
{
Mode = BindingMode.OneWay,
Path = new PropertyPath("IsNameInvalid")
});

inputText.Resources.Add("InvalidNameWarningTip", warning);

inputText.TextChanged += (textBox, args) =>
{
var isInputValid = FilesystemHelpers.IsValidForFilename(inputText.Text);
tipText.Opacity = isInputValid ? 0.0d : 1.0d;
((RenameDialogViewModel)warning.DataContext).IsNameInvalid = !isInputValid;
dialog!.ViewModel.DynamicButtonsEnabled = isInputValid
? DynamicDialogButtons.Primary | DynamicDialogButtons.Cancel
: DynamicDialogButtons.Cancel;
Expand All @@ -85,7 +98,8 @@ public static DynamicDialog GetFor_RenameDialog()
inputText.Loaded += (s, e) =>
{
// dispatching to the ui thread fixes an issue where the primary dialog button would steal focus
_ = inputText.DispatcherQueue.EnqueueAsync(() => inputText.Focus(Microsoft.UI.Xaml.FocusState.Programmatic));
_ = inputText.DispatcherQueue.EnqueueAsync(() => inputText.Focus(FocusState.Programmatic));
((RenameDialogViewModel)warning.DataContext).IsNameInvalid = true;
};

dialog = new DynamicDialog(new DynamicDialogViewModel()
Expand All @@ -97,15 +111,7 @@ public static DynamicDialog GetFor_RenameDialog()
MinWidth = 300d,
Children =
{
new StackPanel()
{
Spacing = 4d,
Children =
{
inputText,
tipText
}
}
inputText
}
},
PrimaryButtonAction = (vm, e) =>
Expand All @@ -118,6 +124,11 @@ public static DynamicDialog GetFor_RenameDialog()
DynamicButtons = DynamicDialogButtons.Primary | DynamicDialogButtons.Cancel
});

dialog.Closing += (s, e) =>
{
warning.IsOpen = false;
};

return dialog;
}

Expand Down
3 changes: 3 additions & 0 deletions src/Files.App/Strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -3166,6 +3166,9 @@
<data name="CloseTab" xml:space="preserve">
<value>Closes current tab</value>
</data>
<data name="InvalidLocation" xml:space="preserve">
<value>Invalid location</value>
</data>
<data name="CopyFileWithoutProperties" xml:space="preserve">
<value>Are you sure you want to copy these files without their properties?</value>
</data>
Expand Down
14 changes: 14 additions & 0 deletions src/Files.App/ViewModels/Dialogs/RenameDialogViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using CommunityToolkit.Mvvm.ComponentModel;

namespace Files.App.ViewModels.Dialogs
{
class RenameDialogViewModel : ObservableObject
{
private bool isNameInvalid;
public bool IsNameInvalid
{
get => isNameInvalid;
set => SetProperty(ref isNameInvalid, value);
}
}
}