Skip to content

Commit 593d11e

Browse files
yaira20x5bfa
andauthored
Feature: Added support for bulk rename (#16228)
Co-authored-by: 0x5BFA <[email protected]>
1 parent e3f8f15 commit 593d11e

File tree

6 files changed

+165
-10
lines changed

6 files changed

+165
-10
lines changed

src/Files.App/Actions/FileSystem/RenameAction.cs

+12-10
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public RichGlyph Glyph
2323
context.ShellPage is not null &&
2424
IsPageTypeValid() &&
2525
context.ShellPage.SlimContentPage is not null &&
26-
IsSelectionValid();
26+
context.HasSelection;
2727

2828
public RenameAction()
2929
{
@@ -32,16 +32,18 @@ public RenameAction()
3232
context.PropertyChanged += Context_PropertyChanged;
3333
}
3434

35-
public Task ExecuteAsync(object? parameter = null)
35+
public async Task ExecuteAsync(object? parameter = null)
3636
{
37-
context.ShellPage?.SlimContentPage?.ItemManipulationModel.StartRenameItem();
38-
39-
return Task.CompletedTask;
40-
}
41-
42-
private bool IsSelectionValid()
43-
{
44-
return context.HasSelection && context.SelectedItems.Count == 1;
37+
if (context.SelectedItems.Count > 1)
38+
{
39+
var viewModel = new BulkRenameDialogViewModel();
40+
var dialogService = Ioc.Default.GetRequiredService<IDialogService>();
41+
var result = await dialogService.ShowDialogAsync(viewModel);
42+
}
43+
else
44+
{
45+
context.ShellPage?.SlimContentPage?.ItemManipulationModel.StartRenameItem();
46+
}
4547
}
4648

4749
private bool IsPageTypeValid()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<!-- Copyright (c) 2024 Files Community. Licensed under the MIT License. See the LICENSE. -->
2+
<ContentDialog
3+
x:Class="Files.App.Dialogs.BulkRenameDialog"
4+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
5+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
6+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7+
xmlns:helpers="using:Files.App.Helpers"
8+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
9+
Title="{helpers:ResourceString Name=BulkRename}"
10+
DefaultButton="Primary"
11+
HighContrastAdjustment="None"
12+
IsPrimaryButtonEnabled="{x:Bind ViewModel.IsNameValid, Mode=OneWay}"
13+
PrimaryButtonCommand="{x:Bind ViewModel.CommitRenameCommand, Mode=OneWay}"
14+
PrimaryButtonText="{helpers:ResourceString Name=Rename}"
15+
RequestedTheme="{x:Bind RootAppElement.RequestedTheme, Mode=OneWay}"
16+
SecondaryButtonText="{helpers:ResourceString Name=Cancel}"
17+
Style="{StaticResource DefaultContentDialogStyle}"
18+
mc:Ignorable="d">
19+
20+
<StackPanel Width="440" Spacing="4">
21+
22+
<!-- Name -->
23+
<Grid
24+
Padding="12"
25+
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
26+
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
27+
BorderThickness="1"
28+
ColumnSpacing="8"
29+
CornerRadius="4">
30+
<Grid.ColumnDefinitions>
31+
<ColumnDefinition Width="*" />
32+
<ColumnDefinition Width="Auto" />
33+
</Grid.ColumnDefinitions>
34+
35+
<TextBlock
36+
Grid.Column="0"
37+
VerticalAlignment="Center"
38+
Text="{helpers:ResourceString Name=Name}" />
39+
40+
<TextBox
41+
x:Name="FileNameBox"
42+
Grid.Column="1"
43+
Width="260"
44+
PlaceholderText="{helpers:ResourceString Name=EnterName}"
45+
Text="{x:Bind ViewModel.FileName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
46+
<TextBox.Resources>
47+
<TeachingTip
48+
x:Name="InvalidNameWarning"
49+
Title="{helpers:ResourceString Name=InvalidFilename/Text}"
50+
IsOpen="{x:Bind ViewModel.ShowNameWarning, Mode=OneWay}"
51+
PreferredPlacement="Bottom"
52+
Target="{x:Bind FileNameBox}" />
53+
</TextBox.Resources>
54+
</TextBox>
55+
56+
</Grid>
57+
58+
</StackPanel>
59+
</ContentDialog>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) 2024 Files Community
2+
// Licensed under the MIT License. See the LICENSE.
3+
using Microsoft.UI.Xaml;
4+
using Microsoft.UI.Xaml.Controls;
5+
6+
namespace Files.App.Dialogs
7+
{
8+
public sealed partial class BulkRenameDialog : ContentDialog, IDialog<BulkRenameDialogViewModel>
9+
{
10+
private FrameworkElement RootAppElement
11+
=> (FrameworkElement)MainWindow.Instance.Content;
12+
13+
public BulkRenameDialogViewModel ViewModel
14+
{
15+
get => (BulkRenameDialogViewModel)DataContext;
16+
set => DataContext = value;
17+
}
18+
19+
public BulkRenameDialog()
20+
{
21+
InitializeComponent();
22+
}
23+
24+
public new async Task<DialogResult> ShowAsync()
25+
{
26+
return (DialogResult)await base.ShowAsync();
27+
}
28+
}
29+
}

src/Files.App/Services/App/AppDialogService.cs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public DialogService()
3535
{ typeof(GitHubLoginDialogViewModel), () => new GitHubLoginDialog() },
3636
{ typeof(FileTooLargeDialogViewModel), () => new FileTooLargeDialog() },
3737
{ typeof(ReleaseNotesDialogViewModel), () => new ReleaseNotesDialog() },
38+
{ typeof(BulkRenameDialogViewModel), () => new BulkRenameDialog() },
3839
}.ToFrozenDictionary();
3940
}
4041

src/Files.App/Strings/en-US/Resources.resw

+3
Original file line numberDiff line numberDiff line change
@@ -3947,4 +3947,7 @@
39473947
<data name="UserID" xml:space="preserve">
39483948
<value>User ID</value>
39493949
</data>
3950+
<data name="BulkRename" xml:space="preserve">
3951+
<value>Bulk rename</value>
3952+
</data>
39503953
</root>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) 2024 Files Community
2+
// Licensed under the MIT License. See the LICENSE.
3+
4+
using Windows.Storage;
5+
6+
namespace Files.App.ViewModels.Dialogs
7+
{
8+
public sealed class BulkRenameDialogViewModel : ObservableObject
9+
{
10+
private IContentPageContext context { get; } = Ioc.Default.GetRequiredService<IContentPageContext>();
11+
12+
// Properties
13+
14+
public bool IsNameValid =>
15+
FilesystemHelpers.IsValidForFilename(_FileName) && !_FileName.Contains(".");
16+
17+
public bool ShowNameWarning =>
18+
!string.IsNullOrEmpty(_FileName) && !IsNameValid;
19+
20+
private string _FileName = string.Empty;
21+
public string FileName
22+
{
23+
get => _FileName;
24+
set
25+
{
26+
if (SetProperty(ref _FileName, value))
27+
{
28+
OnPropertyChanged(nameof(IsNameValid));
29+
OnPropertyChanged(nameof(ShowNameWarning));
30+
}
31+
}
32+
}
33+
34+
// Commands
35+
36+
public IAsyncRelayCommand CommitRenameCommand { get; private set; }
37+
38+
public BulkRenameDialogViewModel()
39+
{
40+
CommitRenameCommand = new AsyncRelayCommand(DoCommitRenameAsync);
41+
}
42+
43+
private async Task DoCommitRenameAsync()
44+
{
45+
if (context.ShellPage is null)
46+
return;
47+
48+
await Task.WhenAll(context.SelectedItems.Select(item =>
49+
{
50+
var itemType = item.PrimaryItemAttribute == StorageItemTypes.Folder ? FilesystemItemType.Directory : FilesystemItemType.File;
51+
return context.ShellPage.FilesystemHelpers.RenameAsync(
52+
StorageHelpers.FromPathAndType(item.ItemPath, itemType),
53+
FileName + item.FileExtension,
54+
NameCollisionOption.GenerateUniqueName,
55+
true,
56+
false
57+
);
58+
}));
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)